staticvoid getOidListDiff(Oid *list1, int *nlist1, Oid *list2, int *nlist2); static Oid classIdGetDbId(Oid classId); staticvoid shdepChangeDep(Relation sdepRel,
Oid classid, Oid objid, int32 objsubid,
Oid refclassid, Oid refobjid,
SharedDependencyType deptype); staticvoid updateAclDependenciesWorker(Oid classId, Oid objectId,
int32 objsubId, Oid ownerId,
SharedDependencyType deptype, int noldmembers, Oid *oldmembers, int nnewmembers, Oid *newmembers); staticvoid shdepAddDependency(Relation sdepRel,
Oid classId, Oid objectId, int32 objsubId,
Oid refclassId, Oid refobjId,
SharedDependencyType deptype); staticvoid shdepDropDependency(Relation sdepRel,
Oid classId, Oid objectId, int32 objsubId, bool drop_subobjects,
Oid refclassId, Oid refobjId,
SharedDependencyType deptype); staticvoid storeObjectDescription(StringInfo descs,
SharedDependencyObjectType type,
ObjectAddress *object,
SharedDependencyType deptype, int count); staticvoid shdepReassignOwned_Owner(Form_pg_shdepend sdepForm, Oid newrole); staticvoid shdepReassignOwned_InitAcl(Form_pg_shdepend sdepForm,
Oid oldrole, Oid newrole);
/* If the referenced object is pinned, do nothing. */ if (!IsPinnedObject(referenced->classId, referenced->objectId))
{
shdepAddDependency(sdepRel, depender->classId, depender->objectId,
depender->objectSubId,
referenced->classId, referenced->objectId,
deptype);
}
table_close(sdepRel, RowExclusiveLock);
}
/* *recordDependencyOnOwner * *AconvenientwrapperofrecordSharedDependencyOn--registerthespecified *userasownerofthegivenobject. * *Note:it'sthecaller'sresponsibilitytoensurethatthereisn'tanowner *entryfortheobjectalready.
*/ void
recordDependencyOnOwner(Oid classId, Oid objectId, Oid owner)
{
ObjectAddress myself,
referenced;
while ((scantup = systable_getnext(scan)) != NULL)
{ /* Ignore if not of the target dependency type */ if (((Form_pg_shdepend) GETSTRUCT(scantup))->deptype != deptype) continue; /* Caller screwed up if multiple matches */ if (oldtup)
elog(ERROR, "multiple pg_shdepend entries for object %u/%u/%d deptype %c",
classid, objid, objsubid, deptype);
oldtup = heap_copytuple(scantup);
}
systable_endscan(scan);
if (IsPinnedObject(refclassid, refobjid))
{ /* No new entry needed, so just delete existing entry if any */ if (oldtup)
CatalogTupleDelete(sdepRel, &oldtup->t_self);
} elseif (oldtup)
{ /* Need to update existing entry */
Form_pg_shdepend shForm = (Form_pg_shdepend) GETSTRUCT(oldtup);
/* Since oldtup is a copy, we can just modify it in-memory */
shForm->refclassid = refclassid;
shForm->refobjid = refobjid;
CatalogTupleUpdate(sdepRel, &oldtup->t_self, oldtup);
} else
{ /* Need to insert new entry */
Datum values[Natts_pg_shdepend]; bool nulls[Natts_pg_shdepend];
/* *getOidListDiff *HelperforupdateAclDependencies. * *TakestwoOidarraysandremoveselementsthatarecommontobotharrays, *leavingjustthosethatareinoneinputbutnottheother. *Weassumebotharrayshavebeensortedandde-duped.
*/ staticvoid
getOidListDiff(Oid *list1, int *nlist1, Oid *list2, int *nlist2)
{ int in1,
in2,
out1,
out2;
in1 = in2 = out1 = out2 = 0; while (in1 < *nlist1 && in2 < *nlist2)
{ if (list1[in1] == list2[in2])
{ /* skip over duplicates */
in1++;
in2++;
} elseif (list1[in1] < list2[in2])
{ /* list1[in1] is not in list2 */
list1[out1++] = list1[in1++];
} else
{ /* list2[in2] is not in list1 */
list2[out2++] = list2[in2++];
}
}
/* any remaining list1 entries are not in list2 */ while (in1 < *nlist1)
{
list1[out1++] = list1[in1++];
}
/* any remaining list2 entries are not in list1 */ while (in2 < *nlist2)
{
list2[out2++] = list2[in2++];
}
*nlist1 = out1;
*nlist2 = out2;
}
/* *updateAclDependencies *Updatethepg_shdependinfoforanobject'sACLduringGRANT/REVOKE. * *classId,objectId,objsubId:identifytheobjectwhoseACLthisis *ownerId:roleowningtheobject *noldmembers,oldmembers:arrayofroleidsappearinginoldACL *nnewmembers,newmembers:arrayofroleidsappearinginnewACL * *Wecalculatethedifferencesbetweenthenewandoldlistsofroles, *andtheninsertordeletefrompg_shdependasappropriate. * *Notethatwecan'tjustinsertallreferencedrolesblindlyduringGRANT, *becausewewouldendupwithduplicateregistereddependencies.Wecould *checkforexistenceofthetuplesbeforeinserting,butthatseemstobe *moreexpensivethanwhatwearedoinghere.Likewisewecan'tjustdelete *blindlyduringREVOKE,becausetheusermaystillhaveotherprivileges. *ItisalsopossiblethatREVOKEactuallyaddsdependencies,dueto *instantiationofaformerlyimplicitdefaultACL(althoughatpresent, *allsuchdependenciesshouldbefortheowningrole,whichweignorehere). * *NOTE:Bothinputarraysmustbesortedandde-duped.(Typicallythey *areextractedfromanACLarraybyaclmembers(),whichtakescareof *bothrequirements.)Thearraysarepfreedbeforereturn.
*/ void
updateAclDependencies(Oid classId, Oid objectId, int32 objsubId,
Oid ownerId, int noldmembers, Oid *oldmembers, int nnewmembers, Oid *newmembers)
{
updateAclDependenciesWorker(classId, objectId, objsubId,
ownerId, SHARED_DEPENDENCY_ACL,
noldmembers, oldmembers,
nnewmembers, newmembers);
}
/* *updateInitAclDependencies *Updatethepg_shdependinfoforapg_init_privsentry. * *ExactlylikeupdateAclDependencies,exceptweareconsideringa *pg_init_privsACLforthespecifiedobject.Sincerecordingof *pg_init_privsroledependenciesisthesameforownersandnon-owners, *wedonotneedanownerIdargument.
*/ void
updateInitAclDependencies(Oid classId, Oid objectId, int32 objsubId, int noldmembers, Oid *oldmembers, int nnewmembers, Oid *newmembers)
{
updateAclDependenciesWorker(classId, objectId, objsubId,
InvalidOid, /* ownerId will not be consulted */
SHARED_DEPENDENCY_INITACL,
noldmembers, oldmembers,
nnewmembers, newmembers);
}
/* Common code for the above two functions */ staticvoid
updateAclDependenciesWorker(Oid classId, Oid objectId, int32 objsubId,
Oid ownerId, SharedDependencyType deptype, int noldmembers, Oid *oldmembers, int nnewmembers, Oid *newmembers)
{
Relation sdepRel; int i;
/* *Last,sortondeptype,incasethesameobjecthasmultipledependency *types.(Notethatthere'snoneedtoconsiderobjtype,asthat's *determinedbythecatalogOID.)
*/ if (obja->deptype < objb->deptype) return -1; if (obja->deptype > objb->deptype) return1;
return0;
}
/* *checkSharedDependencies * *Checkwhetherthereareshareddependencyentriesforagivenshared *object;returntrueifso. * *Inaddition,returnastringcontaininganewline-separatedlistofobject *descriptionsthatdependonthesharedobject,orNULLifnoneisfound. *Weactuallyreturntwosuchstrings;the"detail"resultissuitablefor *returningtotheclientasanerrdetail()string,andislimitedinsize. *The"detail_log"stringispotentiallymuchlonger,andshouldbeemitted *totheserverlogonly. * *Wecanfindthreedifferentkindsofdependencies:dependenciesonobjects *ofthecurrentdatabase;dependenciesonsharedobjects;anddependencies *onobjectslocaltootherdatabases.Wecan(anddo)providedescriptions *ofthetwoformerkindsofobjects,butwecan'tdothatfor"remote" *objects,sowejustprovideacountofthem.
*/ bool
checkSharedDependencies(Oid classId, Oid objectId, char **detail_msg, char **detail_log_msg)
{
Relation sdepRel;
ScanKeyData key[2];
SysScanDesc scan;
HeapTuple tup; int numReportedDeps = 0; int numNotReportedDeps = 0; int numNotReportedDbs = 0;
List *remDeps = NIL;
ListCell *cell;
ObjectAddress object;
ShDependObjectInfo *objects; int numobjects; int allocedobjects;
StringInfoData descs;
StringInfoData alldescs;
/* This case can be dispatched quickly */ if (IsPinnedObject(classId, objectId))
{
object.classId = classId;
object.objectId = objectId;
object.objectSubId = 0;
ereport(ERROR,
(errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
errmsg("cannot drop %s because it is required by the database system",
getObjectDescription(&object, false))));
}
if (numNotReportedDeps > 0)
appendStringInfo(&descs, ngettext("\nand %d other object " "(see server log for list)", "\nand %d other objects " "(see server log for list)",
numNotReportedDeps),
numNotReportedDeps); if (numNotReportedDbs > 0)
appendStringInfo(&descs, ngettext("\nand objects in %d other database " "(see server log for list)", "\nand objects in %d other databases " "(see server log for list)",
numNotReportedDbs),
numNotReportedDbs);
/* If slots are full, insert a batch of tuples */ if (slot_stored_count == max_slots)
{
CatalogTuplesMultiInsertWithInfo(sdepRel, slot, slot_stored_count, indstate);
slot_stored_count = 0;
}
}
/* Insert any tuples left in the buffer */ if (slot_stored_count > 0)
CatalogTuplesMultiInsertWithInfo(sdepRel, slot, slot_stored_count, indstate);
/* *First,deletealltheentriesthathavethedatabaseOidinthedbid *field.
*/
ScanKeyInit(&key[0],
Anum_pg_shdepend_dbid,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(databaseId)); /* We leave the other index fields unspecified */
while (HeapTupleIsValid(tup = systable_getnext(scan)))
{
CatalogTupleDelete(sdepRel, &tup->t_self);
}
systable_endscan(scan);
/* Now delete all entries corresponding to the database itself */
shdepDropDependency(sdepRel, DatabaseRelationId, databaseId, 0, true,
InvalidOid, InvalidOid,
SHARED_DEPENDENCY_INVALID);
while (HeapTupleIsValid(tup = systable_getnext(scan)))
{
Form_pg_shdepend shdepForm = (Form_pg_shdepend) GETSTRUCT(tup);
/* Filter entries according to additional parameters */ if (OidIsValid(refclassId) && shdepForm->refclassid != refclassId) continue; if (OidIsValid(refobjId) && shdepForm->refobjid != refobjId) continue; if (deptype != SHARED_DEPENDENCY_INVALID &&
shdepForm->deptype != deptype) continue;
/* OK, delete it */
CatalogTupleDelete(sdepRel, &tup->t_self);
}
systable_endscan(scan);
}
/* *classIdGetDbId * *GetthedatabaseIdthatshouldbeusedinpg_shdepend,giventheOID *ofthecatalogcontainingtheobject.Forsharedobjects,it's0 *(InvalidOid);forallotherobjects,it'sthecurrentdatabaseId.
*/ static Oid
classIdGetDbId(Oid classId)
{
Oid dbId;
if (IsSharedRelation(classId))
dbId = InvalidOid; else
dbId = MyDatabaseId;
return dbId;
}
/* *shdepLockAndCheckObject * *Locktheobjectthatweareabouttorecordadependencyon. *Afterit'slocked,verifythatithasn'tbeendroppedwhilewe *weren'tlooking.Iftheobjecthasbeendropped,thisfunction *doesnotreturn!
*/ void
shdepLockAndCheckObject(Oid classId, Oid objectId)
{ /* AccessShareLock should be OK, since we are not modifying the object */
LockSharedObject(classId, objectId, 0, AccessShareLock);
switch (classId)
{ case AuthIdRelationId: if (!SearchSysCacheExists1(AUTHOID, ObjectIdGetDatum(objectId)))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("role %u was concurrently dropped",
objectId))); break;
case TableSpaceRelationId:
{ /* For lack of a syscache on pg_tablespace, do this: */ char *tablespace = get_tablespace_name(objectId);
if (tablespace == NULL)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("tablespace %u was concurrently dropped",
objectId)));
pfree(tablespace); break;
}
case DatabaseRelationId:
{ /* For lack of a syscache on pg_database, do this: */ char *database = get_database_name(objectId);
if (database == NULL)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("database %u was concurrently dropped",
objectId)));
pfree(database); break;
}
/* *Anobjectbeingdroppedconcurrentlydoesn'tneedtobereported.
*/ if (objdesc == NULL) return;
/* separate entries with a newline */ if (descs->len != 0)
appendStringInfoChar(descs, '\n');
switch (type)
{ case LOCAL_OBJECT: case SHARED_OBJECT: if (deptype == SHARED_DEPENDENCY_OWNER)
appendStringInfo(descs, _("owner of %s"), objdesc); elseif (deptype == SHARED_DEPENDENCY_ACL)
appendStringInfo(descs, _("privileges for %s"), objdesc); elseif (deptype == SHARED_DEPENDENCY_INITACL)
appendStringInfo(descs, _("initial privileges for %s"), objdesc); elseif (deptype == SHARED_DEPENDENCY_POLICY)
appendStringInfo(descs, _("target of %s"), objdesc); elseif (deptype == SHARED_DEPENDENCY_TABLESPACE)
appendStringInfo(descs, _("tablespace for %s"), objdesc); else
elog(ERROR, "unrecognized dependency type: %d",
(int) deptype); break;
case REMOTE_OBJECT: /* translator: %s will always be "database %s" */
appendStringInfo(descs, ngettext("%d object in %s", "%d objects in %s",
count),
count, objdesc); break;
ereport(ERROR,
(errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
errmsg("cannot drop objects owned by %s because they are " "required by the database system",
getObjectDescription(&obj, false))));
}
/* Shouldn't see a role grant here */
Assert(sdepForm->classid != AuthMemRelationId);
RemoveRoleFromInitPriv(roleid,
sdepForm->classid,
sdepForm->objid,
sdepForm->objsubid); break;
}
}
ereport(ERROR,
(errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
errmsg("cannot reassign ownership of objects owned by %s because they are required by the database system",
getObjectDescription(&obj, false))));
/* Perform the appropriate processing */ switch (sdepForm->deptype)
{ case SHARED_DEPENDENCY_OWNER:
shdepReassignOwned_Owner(sdepForm, newrole); break; case SHARED_DEPENDENCY_INITACL:
shdepReassignOwned_InitAcl(sdepForm, roleid, newrole); break; case SHARED_DEPENDENCY_ACL: case SHARED_DEPENDENCY_POLICY: case SHARED_DEPENDENCY_TABLESPACE: /* Nothing to do for these entry types */ break; default:
elog(ERROR, "unrecognized dependency type: %d",
(int) sdepForm->deptype); break;
}
/* Clean up */
MemoryContextSwitchTo(oldcxt);
MemoryContextDelete(cxt);
/* Make sure the next iteration will see my changes */
CommandCounterIncrement();
}
systable_endscan(scan);
}
table_close(sdepRel, RowExclusiveLock);
}
/* *shdepReassignOwned_Owner * *shdepReassignOwned'sprocessingofSHARED_DEPENDENCY_OWNERentries
*/ staticvoid
shdepReassignOwned_Owner(Form_pg_shdepend sdepForm, Oid newrole)
{ /* Issue the appropriate ALTER OWNER call */ switch (sdepForm->classid)
{ case TypeRelationId:
AlterTypeOwner_oid(sdepForm->objid, newrole, true); break;
case NamespaceRelationId:
AlterSchemaOwner_oid(sdepForm->objid, newrole); break;
case ForeignServerRelationId:
AlterForeignServerOwner_oid(sdepForm->objid, newrole); break;
case ForeignDataWrapperRelationId:
AlterForeignDataWrapperOwner_oid(sdepForm->objid, newrole); break;
case EventTriggerRelationId:
AlterEventTriggerOwner_oid(sdepForm->objid, newrole); break;
case PublicationRelationId:
AlterPublicationOwner_oid(sdepForm->objid, newrole); break;
case SubscriptionRelationId:
AlterSubscriptionOwner_oid(sdepForm->objid, newrole); break;
/* Generic alter owner cases */ case CollationRelationId: case ConversionRelationId: case OperatorRelationId: case ProcedureRelationId: case LanguageRelationId: case LargeObjectRelationId: case OperatorFamilyRelationId: case OperatorClassRelationId: case ExtensionRelationId: case StatisticExtRelationId: case TableSpaceRelationId: case DatabaseRelationId: case TSConfigRelationId: case TSDictionaryRelationId:
AlterObjectOwner_internal(sdepForm->classid,
sdepForm->objid,
newrole); break;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.