1 /*-------------------------------------------------------------------------
4 * routines to support manipulation of the pg_shdepend relation
6 * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * $PostgreSQL: pgsql/src/backend/catalog/pg_shdepend.c,v 1.3 2005/10/15 02:49:14 momjian Exp $
13 *-------------------------------------------------------------------------
17 #include "access/genam.h"
18 #include "access/heapam.h"
19 #include "catalog/dependency.h"
20 #include "catalog/indexing.h"
21 #include "catalog/pg_authid.h"
22 #include "catalog/pg_database.h"
23 #include "catalog/pg_shdepend.h"
24 #include "lib/stringinfo.h"
25 #include "miscadmin.h"
26 #include "utils/fmgroids.h"
27 #include "utils/inval.h"
28 #include "utils/syscache.h"
38 static int getOidListDiff(Oid *list1, int nlist1, Oid *list2, int nlist2,
40 static Oid classIdGetDbId(Oid classId);
41 static void shdepLockAndCheckObject(Oid classId, Oid objectId);
42 static void shdepChangeDep(Relation sdepRel, Oid classid, Oid objid,
43 Oid refclassid, Oid refobjid,
44 SharedDependencyType deptype);
45 static void shdepAddDependency(Relation sdepRel, Oid classId, Oid objectId,
46 Oid refclassId, Oid refobjId,
47 SharedDependencyType deptype);
48 static void shdepDropDependency(Relation sdepRel, Oid classId, Oid objectId,
49 Oid refclassId, Oid refobjId,
50 SharedDependencyType deptype);
51 static void storeObjectDescription(StringInfo descs, objectType type,
52 ObjectAddress *object,
53 SharedDependencyType deptype,
55 static bool isSharedObjectPinned(Oid classId, Oid objectId, Relation sdepRel);
59 * recordSharedDependencyOn
61 * Record a dependency between 2 objects via their respective ObjectAddresses.
62 * The first argument is the dependent object, the second the one it
63 * references (which must be a shared object).
65 * This locks the referenced object and makes sure it still exists.
66 * Then it creates an entry in pg_shdepend. The lock is kept until
67 * the end of the transaction.
69 * Dependencies on pinned objects are not recorded.
72 recordSharedDependencyOn(ObjectAddress *depender,
73 ObjectAddress *referenced,
74 SharedDependencyType deptype)
79 * Objects in pg_shdepend can't have SubIds.
81 Assert(depender->objectSubId == 0);
82 Assert(referenced->objectSubId == 0);
85 * During bootstrap, do nothing since pg_shdepend may not exist yet.
86 * initdb will fill in appropriate pg_shdepend entries after bootstrap.
88 if (IsBootstrapProcessingMode())
91 sdepRel = heap_open(SharedDependRelationId, RowExclusiveLock);
93 /* If the referenced object is pinned, do nothing. */
94 if (!isSharedObjectPinned(referenced->classId, referenced->objectId,
97 shdepAddDependency(sdepRel, depender->classId, depender->objectId,
98 referenced->classId, referenced->objectId,
102 heap_close(sdepRel, RowExclusiveLock);
106 * recordDependencyOnOwner
108 * A convenient wrapper of recordSharedDependencyOn -- register the specified
109 * user as owner of the given object.
111 * Note: it's the caller's responsibility to ensure that there isn't an owner
112 * entry for the object already.
115 recordDependencyOnOwner(Oid classId, Oid objectId, Oid owner)
117 ObjectAddress myself,
120 myself.classId = classId;
121 myself.objectId = objectId;
122 myself.objectSubId = 0;
124 referenced.classId = AuthIdRelationId;
125 referenced.objectId = owner;
126 referenced.objectSubId = 0;
128 recordSharedDependencyOn(&myself, &referenced, SHARED_DEPENDENCY_OWNER);
134 * Update shared dependency records to account for an updated referenced
135 * object. This is an internal workhorse for operations such as changing
138 * There must be no more than one existing entry for the given dependent
139 * object and dependency type! So in practice this can only be used for
140 * updating SHARED_DEPENDENCY_OWNER entries, which should have that property.
142 * If there is no previous entry, we assume it was referencing a PINned
143 * object, so we create a new entry. If the new referenced object is
144 * PINned, we don't create an entry (and drop the old one, if any).
146 * sdepRel must be the pg_shdepend relation, already opened and suitably
150 shdepChangeDep(Relation sdepRel, Oid classid, Oid objid,
151 Oid refclassid, Oid refobjid,
152 SharedDependencyType deptype)
154 Oid dbid = classIdGetDbId(classid);
155 HeapTuple oldtup = NULL;
161 * Make sure the new referenced object doesn't go away while we record the
164 shdepLockAndCheckObject(refclassid, refobjid);
167 * Look for a previous entry
170 Anum_pg_shdepend_dbid,
171 BTEqualStrategyNumber, F_OIDEQ,
172 ObjectIdGetDatum(dbid));
174 Anum_pg_shdepend_classid,
175 BTEqualStrategyNumber, F_OIDEQ,
176 ObjectIdGetDatum(classid));
178 Anum_pg_shdepend_objid,
179 BTEqualStrategyNumber, F_OIDEQ,
180 ObjectIdGetDatum(objid));
182 scan = systable_beginscan(sdepRel, SharedDependDependerIndexId, true,
183 SnapshotNow, 3, key);
185 while ((scantup = systable_getnext(scan)) != NULL)
187 /* Ignore if not of the target dependency type */
188 if (((Form_pg_shdepend) GETSTRUCT(scantup))->deptype != deptype)
190 /* Caller screwed up if multiple matches */
193 "multiple pg_shdepend entries for object %u/%u deptype %c",
194 classid, objid, deptype);
195 oldtup = heap_copytuple(scantup);
198 systable_endscan(scan);
200 if (isSharedObjectPinned(refclassid, refobjid, sdepRel))
202 /* No new entry needed, so just delete existing entry if any */
204 simple_heap_delete(sdepRel, &oldtup->t_self);
208 /* Need to update existing entry */
209 Form_pg_shdepend shForm = (Form_pg_shdepend) GETSTRUCT(oldtup);
211 /* Since oldtup is a copy, we can just modify it in-memory */
212 shForm->refclassid = refclassid;
213 shForm->refobjid = refobjid;
215 simple_heap_update(sdepRel, &oldtup->t_self, oldtup);
217 /* keep indexes current */
218 CatalogUpdateIndexes(sdepRel, oldtup);
222 /* Need to insert new entry */
223 Datum values[Natts_pg_shdepend];
224 bool nulls[Natts_pg_shdepend];
226 memset(nulls, 0, sizeof(nulls));
228 values[Anum_pg_shdepend_dbid - 1] = ObjectIdGetDatum(dbid);
229 values[Anum_pg_shdepend_classid - 1] = ObjectIdGetDatum(classid);
230 values[Anum_pg_shdepend_objid - 1] = ObjectIdGetDatum(objid);
232 values[Anum_pg_shdepend_refclassid - 1] = ObjectIdGetDatum(refclassid);
233 values[Anum_pg_shdepend_refobjid - 1] = ObjectIdGetDatum(refobjid);
234 values[Anum_pg_shdepend_deptype - 1] = CharGetDatum(deptype);
237 * we are reusing oldtup just to avoid declaring a new variable, but
238 * it's certainly a new tuple
240 oldtup = heap_form_tuple(RelationGetDescr(sdepRel), values, nulls);
241 simple_heap_insert(sdepRel, oldtup);
243 /* keep indexes current */
244 CatalogUpdateIndexes(sdepRel, oldtup);
248 heap_freetuple(oldtup);
252 * changeDependencyOnOwner
254 * Update the shared dependencies to account for the new owner.
257 changeDependencyOnOwner(Oid classId, Oid objectId, Oid newOwnerId)
261 sdepRel = heap_open(SharedDependRelationId, RowExclusiveLock);
263 /* Adjust the SHARED_DEPENDENCY_OWNER entry */
264 shdepChangeDep(sdepRel, classId, objectId,
265 AuthIdRelationId, newOwnerId,
266 SHARED_DEPENDENCY_OWNER);
269 * There should never be a SHARED_DEPENDENCY_ACL entry for the owner,
270 * so get rid of it if there is one. This can happen if the new owner
271 * was previously granted some rights to the object.
273 * This step is analogous to aclnewowner's removal of duplicate entries
274 * in the ACL. We have to do it to handle this scenario:
275 * A grants some rights on an object to B
276 * ALTER OWNER changes the object's owner to B
277 * ALTER OWNER changes the object's owner to C
278 * The third step would remove all mention of B from the object's ACL,
279 * but we'd still have a SHARED_DEPENDENCY_ACL for B if we did not do
282 * The rule against having a SHARED_DEPENDENCY_ACL entry for the owner
283 * allows us to fix things up in just this one place, without having
284 * to make the various ALTER OWNER routines each know about it.
287 shdepDropDependency(sdepRel, classId, objectId,
288 AuthIdRelationId, newOwnerId,
289 SHARED_DEPENDENCY_ACL);
291 heap_close(sdepRel, RowExclusiveLock);
296 * Helper for updateAclDependencies.
298 * Takes two Oid arrays and returns elements from the first not found in the
299 * second. We assume both arrays are sorted and de-duped, and that the
300 * second array does not contain any values not found in the first.
302 * NOTE: Both input arrays are pfreed.
305 getOidListDiff(Oid *list1, int nlist1, Oid *list2, int nlist2, Oid **diff)
312 AssertArg(nlist1 >= nlist2 && nlist2 >= 0);
314 result = palloc(sizeof(Oid) * (nlist1 - nlist2));
317 for (i = 0, j = 0; i < nlist1 && j < nlist2;)
319 if (list1[i] == list2[j])
324 else if (list1[i] < list2[j])
326 result[k++] = list1[i];
332 elog(WARNING, "invalid element %u in shorter list", list2[j]);
337 for (; i < nlist1; i++)
338 result[k++] = list1[i];
340 /* We should have copied the exact number of elements */
341 AssertState(k == (nlist1 - nlist2));
352 * updateAclDependencies
353 * Update the pg_shdepend info for an object's ACL during GRANT/REVOKE.
355 * classId, objectId: identify the object whose ACL this is
356 * ownerId: role owning the object
357 * isGrant: are we adding or removing ACL entries?
358 * noldmembers, oldmembers: array of roleids appearing in old ACL
359 * nnewmembers, newmembers: array of roleids appearing in new ACL
361 * We calculate the difference between the new and old lists of roles,
362 * and then insert (if it's a grant) or delete (if it's a revoke) from
363 * pg_shdepend as appropiate.
365 * Note that we can't insert blindly at grant, because we would end up with
366 * duplicate registered dependencies. We could check for existence of the
367 * tuple before inserting, but that seems to be more expensive than what we are
368 * doing now. On the other hand, we can't just delete the tuples blindly at
369 * revoke, because the user may still have other privileges.
371 * NOTE: Both input arrays must be sorted and de-duped. They are pfreed
375 updateAclDependencies(Oid classId, Oid objectId, Oid ownerId, bool isGrant,
376 int noldmembers, Oid *oldmembers,
377 int nnewmembers, Oid *newmembers)
385 * Calculate the differences between the old and new lists.
388 ndiff = getOidListDiff(newmembers, nnewmembers,
389 oldmembers, noldmembers, &diff);
391 ndiff = getOidListDiff(oldmembers, noldmembers,
392 newmembers, nnewmembers, &diff);
396 sdepRel = heap_open(SharedDependRelationId, RowExclusiveLock);
398 /* Add or drop the respective dependency */
399 for (i = 0; i < ndiff; i++)
401 Oid roleid = diff[i];
404 * Skip the owner: he has an OWNER shdep entry instead. (This is
405 * not just a space optimization; it makes ALTER OWNER easier.
406 * See notes in changeDependencyOnOwner.)
408 if (roleid == ownerId)
411 /* Skip pinned roles */
412 if (isSharedObjectPinned(AuthIdRelationId, roleid, sdepRel))
416 shdepAddDependency(sdepRel, classId, objectId,
417 AuthIdRelationId, roleid,
418 SHARED_DEPENDENCY_ACL);
420 shdepDropDependency(sdepRel, classId, objectId,
421 AuthIdRelationId, roleid,
422 SHARED_DEPENDENCY_ACL);
425 heap_close(sdepRel, RowExclusiveLock);
432 * A struct to keep track of dependencies found in other databases.
441 * checkSharedDependencies
443 * Check whether there are shared dependency entries for a given shared
444 * object. Returns a string containing a newline-separated list of object
445 * descriptions that depend on the shared object, or NULL if none is found.
447 * We can find three different kinds of dependencies: dependencies on objects
448 * of the current database; dependencies on shared objects; and dependencies
449 * on objects local to other databases. We can (and do) provide descriptions
450 * of the two former kinds of objects, but we can't do that for "remote"
451 * objects, so we just provide a count of them.
453 * If we find a SHARED_DEPENDENCY_PIN entry, we can error out early.
456 checkSharedDependencies(Oid classId, Oid objectId)
463 int numLocalDeps = 0;
464 int numSharedDeps = 0;
467 ObjectAddress object;
468 StringInfoData descs;
471 * We try to limit the number of reported dependencies to something sane,
472 * both for the user's sake and to avoid blowing out memory.
474 #define MAX_REPORTED_DEPS 100
476 initStringInfo(&descs);
478 sdepRel = heap_open(SharedDependRelationId, AccessShareLock);
481 Anum_pg_shdepend_refclassid,
482 BTEqualStrategyNumber, F_OIDEQ,
483 ObjectIdGetDatum(classId));
485 Anum_pg_shdepend_refobjid,
486 BTEqualStrategyNumber, F_OIDEQ,
487 ObjectIdGetDatum(objectId));
489 scan = systable_beginscan(sdepRel, SharedDependReferenceIndexId, true,
490 SnapshotNow, 2, key);
492 while (HeapTupleIsValid(tup = systable_getnext(scan)))
494 Form_pg_shdepend sdepForm = (Form_pg_shdepend) GETSTRUCT(tup);
496 /* This case can be dispatched quickly */
497 if (sdepForm->deptype == SHARED_DEPENDENCY_PIN)
499 object.classId = classId;
500 object.objectId = objectId;
501 object.objectSubId = 0;
503 (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
504 errmsg("cannot drop %s because it is required by the database system",
505 getObjectDescription(&object))));
508 object.classId = sdepForm->classid;
509 object.objectId = sdepForm->objid;
510 object.objectSubId = 0;
513 * If it's a dependency local to this database or it's a shared
514 * object, describe it.
516 * If it's a remote dependency, keep track of it so we can report the
517 * number of them later.
519 if (sdepForm->dbid == MyDatabaseId)
522 if (++totalDeps <= MAX_REPORTED_DEPS)
523 storeObjectDescription(&descs, LOCAL_OBJECT, &object,
524 sdepForm->deptype, 0);
526 else if (sdepForm->dbid == InvalidOid)
529 if (++totalDeps <= MAX_REPORTED_DEPS)
530 storeObjectDescription(&descs, SHARED_OBJECT, &object,
531 sdepForm->deptype, 0);
535 /* It's not local nor shared, so it must be remote. */
540 * XXX this info is kept on a simple List. Maybe it's not good
541 * for performance, but using a hash table seems needlessly
542 * complex. The expected number of databases is not high anyway,
545 foreach(cell, remDeps)
548 if (dep->dbOid == sdepForm->dbid)
557 dep = (remoteDep *) palloc(sizeof(remoteDep));
558 dep->dbOid = sdepForm->dbid;
560 remDeps = lappend(remDeps, dep);
566 systable_endscan(scan);
568 heap_close(sdepRel, AccessShareLock);
570 if (totalDeps > MAX_REPORTED_DEPS)
573 * Report seems unreasonably long, so reduce it to per-database info
575 * Note: we don't ever suppress per-database totals, which should be OK
576 * as long as there aren't too many databases ...
578 descs.len = 0; /* reset to empty */
579 descs.data[0] = '\0';
581 if (numLocalDeps > 0)
583 appendStringInfo(&descs, _("%d objects in this database"),
585 if (numSharedDeps > 0)
586 appendStringInfoChar(&descs, '\n');
588 if (numSharedDeps > 0)
589 appendStringInfo(&descs, _("%d shared objects"),
593 foreach(cell, remDeps)
595 remoteDep *dep = lfirst(cell);
597 object.classId = DatabaseRelationId;
598 object.objectId = dep->dbOid;
599 object.objectSubId = 0;
601 storeObjectDescription(&descs, REMOTE_OBJECT, &object,
602 SHARED_DEPENDENCY_INVALID, dep->count);
605 list_free_deep(remDeps);
617 * copyTemplateDependencies
619 * Routine to create the initial shared dependencies of a new database.
620 * We simply copy the dependencies from the template database.
623 copyTemplateDependencies(Oid templateDbId, Oid newDbId)
630 CatalogIndexState indstate;
631 Datum values[Natts_pg_shdepend];
632 bool nulls[Natts_pg_shdepend];
633 bool replace[Natts_pg_shdepend];
635 sdepRel = heap_open(SharedDependRelationId, RowExclusiveLock);
636 sdepDesc = RelationGetDescr(sdepRel);
638 indstate = CatalogOpenIndexes(sdepRel);
640 /* Scan all entries with dbid = templateDbId */
642 Anum_pg_shdepend_dbid,
643 BTEqualStrategyNumber, F_OIDEQ,
644 ObjectIdGetDatum(templateDbId));
646 scan = systable_beginscan(sdepRel, SharedDependDependerIndexId, true,
647 SnapshotNow, 1, key);
649 /* Set up to copy the tuples except for inserting newDbId */
650 memset(values, 0, sizeof(values));
651 memset(nulls, false, sizeof(nulls));
652 memset(replace, false, sizeof(replace));
654 replace[Anum_pg_shdepend_dbid - 1] = true;
655 values[Anum_pg_shdepend_dbid - 1] = ObjectIdGetDatum(newDbId);
658 * Copy the entries of the original database, changing the database Id to
659 * that of the new database. Note that because we are not copying rows
660 * with dbId == 0 (ie, rows describing dependent shared objects) we won't
661 * copy the ownership dependency of the template database itself; this is
664 while (HeapTupleIsValid(tup = systable_getnext(scan)))
668 newtup = heap_modify_tuple(tup, sdepDesc, values, nulls, replace);
669 simple_heap_insert(sdepRel, newtup);
671 /* Keep indexes current */
672 CatalogIndexInsert(indstate, newtup);
674 heap_freetuple(newtup);
677 systable_endscan(scan);
679 CatalogCloseIndexes(indstate);
680 heap_close(sdepRel, RowExclusiveLock);
684 * dropDatabaseDependencies
686 * Delete pg_shdepend entries corresponding to a database that's being
690 dropDatabaseDependencies(Oid databaseId)
697 sdepRel = heap_open(SharedDependRelationId, RowExclusiveLock);
700 * First, delete all the entries that have the database Oid in the dbid
704 Anum_pg_shdepend_dbid,
705 BTEqualStrategyNumber, F_OIDEQ,
706 ObjectIdGetDatum(databaseId));
707 /* We leave the other index fields unspecified */
709 scan = systable_beginscan(sdepRel, SharedDependDependerIndexId, true,
710 SnapshotNow, 1, key);
712 while (HeapTupleIsValid(tup = systable_getnext(scan)))
714 simple_heap_delete(sdepRel, &tup->t_self);
717 systable_endscan(scan);
719 /* Now delete all entries corresponding to the database itself */
720 shdepDropDependency(sdepRel, DatabaseRelationId, databaseId,
721 InvalidOid, InvalidOid,
722 SHARED_DEPENDENCY_INVALID);
724 heap_close(sdepRel, RowExclusiveLock);
728 * deleteSharedDependencyRecordsFor
730 * Delete all pg_shdepend entries corresponding to an object that's being
731 * dropped or modified. The object is assumed to be either a shared object
732 * or local to the current database (the classId tells us which).
735 deleteSharedDependencyRecordsFor(Oid classId, Oid objectId)
739 sdepRel = heap_open(SharedDependRelationId, RowExclusiveLock);
741 shdepDropDependency(sdepRel, classId, objectId,
742 InvalidOid, InvalidOid,
743 SHARED_DEPENDENCY_INVALID);
745 heap_close(sdepRel, RowExclusiveLock);
750 * Internal workhorse for inserting into pg_shdepend
752 * sdepRel must be the pg_shdepend relation, already opened and suitably
756 shdepAddDependency(Relation sdepRel, Oid classId, Oid objectId,
757 Oid refclassId, Oid refobjId,
758 SharedDependencyType deptype)
761 Datum values[Natts_pg_shdepend];
762 bool nulls[Natts_pg_shdepend];
765 * Make sure the object doesn't go away while we record the dependency on
766 * it. DROP routines should lock the object exclusively before they check
767 * shared dependencies.
769 shdepLockAndCheckObject(refclassId, refobjId);
771 memset(nulls, false, sizeof(nulls));
774 * Form the new tuple and record the dependency.
776 values[Anum_pg_shdepend_dbid - 1] = ObjectIdGetDatum(classIdGetDbId(classId));
777 values[Anum_pg_shdepend_classid - 1] = ObjectIdGetDatum(classId);
778 values[Anum_pg_shdepend_objid - 1] = ObjectIdGetDatum(objectId);
780 values[Anum_pg_shdepend_refclassid - 1] = ObjectIdGetDatum(refclassId);
781 values[Anum_pg_shdepend_refobjid - 1] = ObjectIdGetDatum(refobjId);
782 values[Anum_pg_shdepend_deptype - 1] = CharGetDatum(deptype);
784 tup = heap_form_tuple(sdepRel->rd_att, values, nulls);
786 simple_heap_insert(sdepRel, tup);
788 /* keep indexes current */
789 CatalogUpdateIndexes(sdepRel, tup);
796 * shdepDropDependency
797 * Internal workhorse for deleting entries from pg_shdepend.
799 * We drop entries having the following properties:
800 * dependent object is the one identified by classId/objectId
801 * if refclassId isn't InvalidOid, it must match the entry's refclassid
802 * if refobjId isn't InvalidOid, it must match the entry's refobjid
803 * if deptype isn't SHARED_DEPENDENCY_INVALID, it must match entry's deptype
805 * sdepRel must be the pg_shdepend relation, already opened and suitably
809 shdepDropDependency(Relation sdepRel, Oid classId, Oid objectId,
810 Oid refclassId, Oid refobjId,
811 SharedDependencyType deptype)
817 /* Scan for entries matching the dependent object */
819 Anum_pg_shdepend_dbid,
820 BTEqualStrategyNumber, F_OIDEQ,
821 ObjectIdGetDatum(classIdGetDbId(classId)));
823 Anum_pg_shdepend_classid,
824 BTEqualStrategyNumber, F_OIDEQ,
825 ObjectIdGetDatum(classId));
827 Anum_pg_shdepend_objid,
828 BTEqualStrategyNumber, F_OIDEQ,
829 ObjectIdGetDatum(objectId));
831 scan = systable_beginscan(sdepRel, SharedDependDependerIndexId, true,
832 SnapshotNow, 3, key);
834 while (HeapTupleIsValid(tup = systable_getnext(scan)))
836 Form_pg_shdepend shdepForm = (Form_pg_shdepend) GETSTRUCT(tup);
838 /* Filter entries according to additional parameters */
839 if (OidIsValid(refclassId) && shdepForm->refclassid != refclassId)
841 if (OidIsValid(refobjId) && shdepForm->refobjid != refobjId)
843 if (deptype != SHARED_DEPENDENCY_INVALID &&
844 shdepForm->deptype != deptype)
848 simple_heap_delete(sdepRel, &tup->t_self);
851 systable_endscan(scan);
857 * Get the database Id that should be used in pg_shdepend, given the OID
858 * of the catalog containing the object. For shared objects, it's 0
859 * (InvalidOid); for all other objects, it's the current database Id.
861 * XXX it's awfully tempting to hard-wire this instead of doing a syscache
862 * lookup ... but resist the temptation, unless you can prove it's a
866 classIdGetDbId(Oid classId)
871 tup = SearchSysCache(RELOID,
872 ObjectIdGetDatum(classId),
874 if (!HeapTupleIsValid(tup))
875 elog(ERROR, "cache lookup failed for relation %u", classId);
877 if (((Form_pg_class) GETSTRUCT(tup))->relisshared)
882 ReleaseSysCache(tup);
888 * shdepLockAndCheckObject
890 * Lock the object that we are about to record a dependency on.
891 * After it's locked, verify that it hasn't been dropped while we
892 * weren't looking. If the object has been dropped, this function
896 shdepLockAndCheckObject(Oid classId, Oid objectId)
898 /* AccessShareLock should be OK, since we are not modifying the object */
899 LockSharedObject(classId, objectId, 0, AccessShareLock);
902 * We have to recognize sinval updates here, else our local syscache may
903 * still contain the object even if it was just dropped.
905 AcceptInvalidationMessages();
909 case AuthIdRelationId:
910 if (!SearchSysCacheExists(AUTHOID,
911 ObjectIdGetDatum(objectId),
914 (errcode(ERRCODE_UNDEFINED_OBJECT),
915 errmsg("role %u was concurrently dropped",
920 * Currently, this routine need not support any other shared
921 * object types besides roles. If we wanted to record explicit
922 * dependencies on databases or tablespaces, we'd need code along
926 case TableSpaceRelationId:
928 /* For lack of a syscache on pg_tablespace, do this: */
929 char *tablespace = get_tablespace_name(objectId);
931 if (tablespace == NULL)
933 (errcode(ERRCODE_UNDEFINED_OBJECT),
934 errmsg("tablespace %u was concurrently dropped",
942 elog(ERROR, "unrecognized shared classId: %u", classId);
948 * storeObjectDescription
949 * Append the description of a dependent object to "descs"
951 * While searching for dependencies of a shared object, we stash the
952 * descriptions of dependent objects we find in a single string, which we
953 * later pass to ereport() in the DETAIL field when somebody attempts to
954 * drop a referenced shared object.
956 * When type is LOCAL_OBJECT or SHARED_OBJECT, we expect object to be the
957 * dependent object, deptype is the dependency type, and count is not used.
958 * When type is REMOTE_OBJECT, we expect object to be the database object,
959 * and count to be nonzero; deptype is not used in this case.
962 storeObjectDescription(StringInfo descs, objectType type,
963 ObjectAddress *object,
964 SharedDependencyType deptype,
967 char *objdesc = getObjectDescription(object);
969 /* separate entries with a newline */
971 appendStringInfoChar(descs, '\n');
977 if (deptype == SHARED_DEPENDENCY_OWNER)
978 appendStringInfo(descs, _("owner of %s"), objdesc);
979 else if (deptype == SHARED_DEPENDENCY_ACL)
980 appendStringInfo(descs, _("access to %s"), objdesc);
982 elog(ERROR, "unrecognized dependency type: %d",
987 /* translator: %s will always be "database %s" */
988 appendStringInfo(descs, _("%d objects in %s"), count, objdesc);
992 elog(ERROR, "unrecognized object type: %d", type);
1000 * isSharedObjectPinned
1001 * Return whether a given shared object has a SHARED_DEPENDENCY_PIN entry.
1003 * sdepRel must be the pg_shdepend relation, already opened and suitably
1007 isSharedObjectPinned(Oid classId, Oid objectId, Relation sdepRel)
1009 bool result = false;
1014 ScanKeyInit(&key[0],
1015 Anum_pg_shdepend_refclassid,
1016 BTEqualStrategyNumber, F_OIDEQ,
1017 ObjectIdGetDatum(classId));
1018 ScanKeyInit(&key[1],
1019 Anum_pg_shdepend_refobjid,
1020 BTEqualStrategyNumber, F_OIDEQ,
1021 ObjectIdGetDatum(objectId));
1023 scan = systable_beginscan(sdepRel, SharedDependReferenceIndexId, true,
1024 SnapshotNow, 2, key);
1027 * Since we won't generate additional pg_shdepend entries for pinned
1028 * objects, there can be at most one entry referencing a pinned object.
1029 * Hence, it's sufficient to look at the first returned tuple; we don't
1032 tup = systable_getnext(scan);
1033 if (HeapTupleIsValid(tup))
1035 Form_pg_shdepend shdepForm = (Form_pg_shdepend) GETSTRUCT(tup);
1037 if (shdepForm->deptype == SHARED_DEPENDENCY_PIN)
1041 systable_endscan(scan);