PostgreSQL Source Code  git master
pg_shdepend.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * pg_shdepend.c
4  * routines to support manipulation of the pg_shdepend relation
5  *
6  * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  * src/backend/catalog/pg_shdepend.c
12  *
13  *-------------------------------------------------------------------------
14  */
15 #include "postgres.h"
16 
17 #include "access/genam.h"
18 #include "access/htup_details.h"
19 #include "access/table.h"
20 #include "access/xact.h"
21 #include "catalog/catalog.h"
22 #include "catalog/dependency.h"
23 #include "catalog/indexing.h"
24 #include "catalog/pg_authid.h"
26 #include "catalog/pg_collation.h"
27 #include "catalog/pg_conversion.h"
28 #include "catalog/pg_database.h"
29 #include "catalog/pg_default_acl.h"
31 #include "catalog/pg_extension.h"
34 #include "catalog/pg_language.h"
35 #include "catalog/pg_largeobject.h"
36 #include "catalog/pg_namespace.h"
37 #include "catalog/pg_opclass.h"
38 #include "catalog/pg_operator.h"
39 #include "catalog/pg_opfamily.h"
40 #include "catalog/pg_proc.h"
41 #include "catalog/pg_shdepend.h"
44 #include "catalog/pg_tablespace.h"
45 #include "catalog/pg_ts_config.h"
46 #include "catalog/pg_ts_dict.h"
47 #include "catalog/pg_type.h"
49 #include "commands/alter.h"
50 #include "commands/dbcommands.h"
51 #include "commands/defrem.h"
52 #include "commands/event_trigger.h"
53 #include "commands/policy.h"
55 #include "commands/schemacmds.h"
57 #include "commands/tablecmds.h"
58 #include "commands/tablespace.h"
59 #include "commands/typecmds.h"
60 #include "miscadmin.h"
61 #include "storage/lmgr.h"
62 #include "utils/acl.h"
63 #include "utils/fmgroids.h"
64 #include "utils/memutils.h"
65 #include "utils/syscache.h"
66 
67 typedef enum
68 {
73 
74 typedef struct
75 {
77  char deptype;
80 
81 static void getOidListDiff(Oid *list1, int *nlist1, Oid *list2, int *nlist2);
82 static Oid classIdGetDbId(Oid classId);
83 static void shdepChangeDep(Relation sdepRel,
84  Oid classid, Oid objid, int32 objsubid,
85  Oid refclassid, Oid refobjid,
86  SharedDependencyType deptype);
87 static void updateAclDependenciesWorker(Oid classId, Oid objectId,
88  int32 objsubId, Oid ownerId,
89  SharedDependencyType deptype,
90  int noldmembers, Oid *oldmembers,
91  int nnewmembers, Oid *newmembers);
92 static void shdepAddDependency(Relation sdepRel,
93  Oid classId, Oid objectId, int32 objsubId,
94  Oid refclassId, Oid refobjId,
95  SharedDependencyType deptype);
96 static void shdepDropDependency(Relation sdepRel,
97  Oid classId, Oid objectId, int32 objsubId,
98  bool drop_subobjects,
99  Oid refclassId, Oid refobjId,
100  SharedDependencyType deptype);
101 static void storeObjectDescription(StringInfo descs,
103  ObjectAddress *object,
104  SharedDependencyType deptype,
105  int count);
106 static void shdepReassignOwned_Owner(Form_pg_shdepend sdepForm, Oid newrole);
107 static void shdepReassignOwned_InitAcl(Form_pg_shdepend sdepForm,
108  Oid oldrole, Oid newrole);
109 
110 
111 /*
112  * recordSharedDependencyOn
113  *
114  * Record a dependency between 2 objects via their respective ObjectAddresses.
115  * The first argument is the dependent object, the second the one it
116  * references (which must be a shared object).
117  *
118  * This locks the referenced object and makes sure it still exists.
119  * Then it creates an entry in pg_shdepend. The lock is kept until
120  * the end of the transaction.
121  *
122  * Dependencies on pinned objects are not recorded.
123  */
124 void
126  ObjectAddress *referenced,
127  SharedDependencyType deptype)
128 {
129  Relation sdepRel;
130 
131  /*
132  * Objects in pg_shdepend can't have SubIds.
133  */
134  Assert(depender->objectSubId == 0);
135  Assert(referenced->objectSubId == 0);
136 
137  /*
138  * During bootstrap, do nothing since pg_shdepend may not exist yet.
139  * initdb will fill in appropriate pg_shdepend entries after bootstrap.
140  */
142  return;
143 
144  sdepRel = table_open(SharedDependRelationId, RowExclusiveLock);
145 
146  /* If the referenced object is pinned, do nothing. */
147  if (!IsPinnedObject(referenced->classId, referenced->objectId))
148  {
149  shdepAddDependency(sdepRel, depender->classId, depender->objectId,
150  depender->objectSubId,
151  referenced->classId, referenced->objectId,
152  deptype);
153  }
154 
155  table_close(sdepRel, RowExclusiveLock);
156 }
157 
158 /*
159  * recordDependencyOnOwner
160  *
161  * A convenient wrapper of recordSharedDependencyOn -- register the specified
162  * user as owner of the given object.
163  *
164  * Note: it's the caller's responsibility to ensure that there isn't an owner
165  * entry for the object already.
166  */
167 void
168 recordDependencyOnOwner(Oid classId, Oid objectId, Oid owner)
169 {
170  ObjectAddress myself,
171  referenced;
172 
173  myself.classId = classId;
174  myself.objectId = objectId;
175  myself.objectSubId = 0;
176 
177  referenced.classId = AuthIdRelationId;
178  referenced.objectId = owner;
179  referenced.objectSubId = 0;
180 
181  recordSharedDependencyOn(&myself, &referenced, SHARED_DEPENDENCY_OWNER);
182 }
183 
184 /*
185  * shdepChangeDep
186  *
187  * Update shared dependency records to account for an updated referenced
188  * object. This is an internal workhorse for operations such as changing
189  * an object's owner.
190  *
191  * There must be no more than one existing entry for the given dependent
192  * object and dependency type! So in practice this can only be used for
193  * updating SHARED_DEPENDENCY_OWNER and SHARED_DEPENDENCY_TABLESPACE
194  * entries, which should have that property.
195  *
196  * If there is no previous entry, we assume it was referencing a PINned
197  * object, so we create a new entry. If the new referenced object is
198  * PINned, we don't create an entry (and drop the old one, if any).
199  * (For tablespaces, we don't record dependencies in certain cases, so
200  * there are other possible reasons for entries to be missing.)
201  *
202  * sdepRel must be the pg_shdepend relation, already opened and suitably
203  * locked.
204  */
205 static void
207  Oid classid, Oid objid, int32 objsubid,
208  Oid refclassid, Oid refobjid,
209  SharedDependencyType deptype)
210 {
211  Oid dbid = classIdGetDbId(classid);
212  HeapTuple oldtup = NULL;
213  HeapTuple scantup;
214  ScanKeyData key[4];
215  SysScanDesc scan;
216 
217  /*
218  * Make sure the new referenced object doesn't go away while we record the
219  * dependency.
220  */
221  shdepLockAndCheckObject(refclassid, refobjid);
222 
223  /*
224  * Look for a previous entry
225  */
226  ScanKeyInit(&key[0],
227  Anum_pg_shdepend_dbid,
228  BTEqualStrategyNumber, F_OIDEQ,
229  ObjectIdGetDatum(dbid));
230  ScanKeyInit(&key[1],
231  Anum_pg_shdepend_classid,
232  BTEqualStrategyNumber, F_OIDEQ,
233  ObjectIdGetDatum(classid));
234  ScanKeyInit(&key[2],
235  Anum_pg_shdepend_objid,
236  BTEqualStrategyNumber, F_OIDEQ,
237  ObjectIdGetDatum(objid));
238  ScanKeyInit(&key[3],
239  Anum_pg_shdepend_objsubid,
240  BTEqualStrategyNumber, F_INT4EQ,
241  Int32GetDatum(objsubid));
242 
243  scan = systable_beginscan(sdepRel, SharedDependDependerIndexId, true,
244  NULL, 4, key);
245 
246  while ((scantup = systable_getnext(scan)) != NULL)
247  {
248  /* Ignore if not of the target dependency type */
249  if (((Form_pg_shdepend) GETSTRUCT(scantup))->deptype != deptype)
250  continue;
251  /* Caller screwed up if multiple matches */
252  if (oldtup)
253  elog(ERROR,
254  "multiple pg_shdepend entries for object %u/%u/%d deptype %c",
255  classid, objid, objsubid, deptype);
256  oldtup = heap_copytuple(scantup);
257  }
258 
259  systable_endscan(scan);
260 
261  if (IsPinnedObject(refclassid, refobjid))
262  {
263  /* No new entry needed, so just delete existing entry if any */
264  if (oldtup)
265  CatalogTupleDelete(sdepRel, &oldtup->t_self);
266  }
267  else if (oldtup)
268  {
269  /* Need to update existing entry */
270  Form_pg_shdepend shForm = (Form_pg_shdepend) GETSTRUCT(oldtup);
271 
272  /* Since oldtup is a copy, we can just modify it in-memory */
273  shForm->refclassid = refclassid;
274  shForm->refobjid = refobjid;
275 
276  CatalogTupleUpdate(sdepRel, &oldtup->t_self, oldtup);
277  }
278  else
279  {
280  /* Need to insert new entry */
281  Datum values[Natts_pg_shdepend];
282  bool nulls[Natts_pg_shdepend];
283 
284  memset(nulls, false, sizeof(nulls));
285 
286  values[Anum_pg_shdepend_dbid - 1] = ObjectIdGetDatum(dbid);
287  values[Anum_pg_shdepend_classid - 1] = ObjectIdGetDatum(classid);
288  values[Anum_pg_shdepend_objid - 1] = ObjectIdGetDatum(objid);
289  values[Anum_pg_shdepend_objsubid - 1] = Int32GetDatum(objsubid);
290 
291  values[Anum_pg_shdepend_refclassid - 1] = ObjectIdGetDatum(refclassid);
292  values[Anum_pg_shdepend_refobjid - 1] = ObjectIdGetDatum(refobjid);
293  values[Anum_pg_shdepend_deptype - 1] = CharGetDatum(deptype);
294 
295  /*
296  * we are reusing oldtup just to avoid declaring a new variable, but
297  * it's certainly a new tuple
298  */
299  oldtup = heap_form_tuple(RelationGetDescr(sdepRel), values, nulls);
300  CatalogTupleInsert(sdepRel, oldtup);
301  }
302 
303  if (oldtup)
304  heap_freetuple(oldtup);
305 }
306 
307 /*
308  * changeDependencyOnOwner
309  *
310  * Update the shared dependencies to account for the new owner.
311  *
312  * Note: we don't need an objsubid argument because only whole objects
313  * have owners.
314  */
315 void
316 changeDependencyOnOwner(Oid classId, Oid objectId, Oid newOwnerId)
317 {
318  Relation sdepRel;
319 
320  sdepRel = table_open(SharedDependRelationId, RowExclusiveLock);
321 
322  /* Adjust the SHARED_DEPENDENCY_OWNER entry */
323  shdepChangeDep(sdepRel,
324  classId, objectId, 0,
325  AuthIdRelationId, newOwnerId,
327 
328  /*----------
329  * There should never be a SHARED_DEPENDENCY_ACL entry for the owner,
330  * so get rid of it if there is one. This can happen if the new owner
331  * was previously granted some rights to the object.
332  *
333  * This step is analogous to aclnewowner's removal of duplicate entries
334  * in the ACL. We have to do it to handle this scenario:
335  * A grants some rights on an object to B
336  * ALTER OWNER changes the object's owner to B
337  * ALTER OWNER changes the object's owner to C
338  * The third step would remove all mention of B from the object's ACL,
339  * but we'd still have a SHARED_DEPENDENCY_ACL for B if we did not do
340  * things this way.
341  *
342  * The rule against having a SHARED_DEPENDENCY_ACL entry for the owner
343  * allows us to fix things up in just this one place, without having
344  * to make the various ALTER OWNER routines each know about it.
345  *----------
346  */
347  shdepDropDependency(sdepRel, classId, objectId, 0, true,
348  AuthIdRelationId, newOwnerId,
350 
351  /*
352  * However, nothing need be done about SHARED_DEPENDENCY_INITACL entries,
353  * since those exist whether or not the role is the object's owner, and
354  * ALTER OWNER does not modify the underlying pg_init_privs entry.
355  */
356 
357  table_close(sdepRel, RowExclusiveLock);
358 }
359 
360 /*
361  * recordDependencyOnTablespace
362  *
363  * A convenient wrapper of recordSharedDependencyOn -- register the specified
364  * tablespace as default for the given object.
365  *
366  * Note: it's the caller's responsibility to ensure that there isn't a
367  * tablespace entry for the object already.
368  */
369 void
371 {
372  ObjectAddress myself,
373  referenced;
374 
375  ObjectAddressSet(myself, classId, objectId);
376  ObjectAddressSet(referenced, TableSpaceRelationId, tablespace);
377 
378  recordSharedDependencyOn(&myself, &referenced,
380 }
381 
382 /*
383  * changeDependencyOnTablespace
384  *
385  * Update the shared dependencies to account for the new tablespace.
386  *
387  * Note: we don't need an objsubid argument because only whole objects
388  * have tablespaces.
389  */
390 void
391 changeDependencyOnTablespace(Oid classId, Oid objectId, Oid newTablespaceId)
392 {
393  Relation sdepRel;
394 
395  sdepRel = table_open(SharedDependRelationId, RowExclusiveLock);
396 
397  if (newTablespaceId != DEFAULTTABLESPACE_OID &&
398  newTablespaceId != InvalidOid)
399  shdepChangeDep(sdepRel,
400  classId, objectId, 0,
401  TableSpaceRelationId, newTablespaceId,
403  else
404  shdepDropDependency(sdepRel,
405  classId, objectId, 0, true,
408 
409  table_close(sdepRel, RowExclusiveLock);
410 }
411 
412 /*
413  * getOidListDiff
414  * Helper for updateAclDependencies.
415  *
416  * Takes two Oid arrays and removes elements that are common to both arrays,
417  * leaving just those that are in one input but not the other.
418  * We assume both arrays have been sorted and de-duped.
419  */
420 static void
421 getOidListDiff(Oid *list1, int *nlist1, Oid *list2, int *nlist2)
422 {
423  int in1,
424  in2,
425  out1,
426  out2;
427 
428  in1 = in2 = out1 = out2 = 0;
429  while (in1 < *nlist1 && in2 < *nlist2)
430  {
431  if (list1[in1] == list2[in2])
432  {
433  /* skip over duplicates */
434  in1++;
435  in2++;
436  }
437  else if (list1[in1] < list2[in2])
438  {
439  /* list1[in1] is not in list2 */
440  list1[out1++] = list1[in1++];
441  }
442  else
443  {
444  /* list2[in2] is not in list1 */
445  list2[out2++] = list2[in2++];
446  }
447  }
448 
449  /* any remaining list1 entries are not in list2 */
450  while (in1 < *nlist1)
451  {
452  list1[out1++] = list1[in1++];
453  }
454 
455  /* any remaining list2 entries are not in list1 */
456  while (in2 < *nlist2)
457  {
458  list2[out2++] = list2[in2++];
459  }
460 
461  *nlist1 = out1;
462  *nlist2 = out2;
463 }
464 
465 /*
466  * updateAclDependencies
467  * Update the pg_shdepend info for an object's ACL during GRANT/REVOKE.
468  *
469  * classId, objectId, objsubId: identify the object whose ACL this is
470  * ownerId: role owning the object
471  * noldmembers, oldmembers: array of roleids appearing in old ACL
472  * nnewmembers, newmembers: array of roleids appearing in new ACL
473  *
474  * We calculate the differences between the new and old lists of roles,
475  * and then insert or delete from pg_shdepend as appropriate.
476  *
477  * Note that we can't just insert all referenced roles blindly during GRANT,
478  * because we would end up with duplicate registered dependencies. We could
479  * check for existence of the tuples before inserting, but that seems to be
480  * more expensive than what we are doing here. Likewise we can't just delete
481  * blindly during REVOKE, because the user may still have other privileges.
482  * It is also possible that REVOKE actually adds dependencies, due to
483  * instantiation of a formerly implicit default ACL (although at present,
484  * all such dependencies should be for the owning role, which we ignore here).
485  *
486  * NOTE: Both input arrays must be sorted and de-duped. (Typically they
487  * are extracted from an ACL array by aclmembers(), which takes care of
488  * both requirements.) The arrays are pfreed before return.
489  */
490 void
491 updateAclDependencies(Oid classId, Oid objectId, int32 objsubId,
492  Oid ownerId,
493  int noldmembers, Oid *oldmembers,
494  int nnewmembers, Oid *newmembers)
495 {
496  updateAclDependenciesWorker(classId, objectId, objsubId,
497  ownerId, SHARED_DEPENDENCY_ACL,
498  noldmembers, oldmembers,
499  nnewmembers, newmembers);
500 }
501 
502 /*
503  * updateInitAclDependencies
504  * Update the pg_shdepend info for a pg_init_privs entry.
505  *
506  * Exactly like updateAclDependencies, except we are considering a
507  * pg_init_privs ACL for the specified object. Since recording of
508  * pg_init_privs role dependencies is the same for owners and non-owners,
509  * we do not need an ownerId argument.
510  */
511 void
512 updateInitAclDependencies(Oid classId, Oid objectId, int32 objsubId,
513  int noldmembers, Oid *oldmembers,
514  int nnewmembers, Oid *newmembers)
515 {
516  updateAclDependenciesWorker(classId, objectId, objsubId,
517  InvalidOid, /* ownerId will not be consulted */
519  noldmembers, oldmembers,
520  nnewmembers, newmembers);
521 }
522 
523 /* Common code for the above two functions */
524 static void
525 updateAclDependenciesWorker(Oid classId, Oid objectId, int32 objsubId,
526  Oid ownerId, SharedDependencyType deptype,
527  int noldmembers, Oid *oldmembers,
528  int nnewmembers, Oid *newmembers)
529 {
530  Relation sdepRel;
531  int i;
532 
533  /*
534  * Remove entries that are common to both lists; those represent existing
535  * dependencies we don't need to change.
536  *
537  * OK to overwrite the inputs since we'll pfree them anyway.
538  */
539  getOidListDiff(oldmembers, &noldmembers, newmembers, &nnewmembers);
540 
541  if (noldmembers > 0 || nnewmembers > 0)
542  {
543  sdepRel = table_open(SharedDependRelationId, RowExclusiveLock);
544 
545  /* Add new dependencies that weren't already present */
546  for (i = 0; i < nnewmembers; i++)
547  {
548  Oid roleid = newmembers[i];
549 
550  /*
551  * For SHARED_DEPENDENCY_ACL entries, skip the owner: she has an
552  * OWNER shdep entry instead. (This is not just a space
553  * optimization; it makes ALTER OWNER easier. See notes in
554  * changeDependencyOnOwner.) But for INITACL entries, we record
555  * the owner too.
556  */
557  if (deptype == SHARED_DEPENDENCY_ACL && roleid == ownerId)
558  continue;
559 
560  /* Skip pinned roles; they don't need dependency entries */
561  if (IsPinnedObject(AuthIdRelationId, roleid))
562  continue;
563 
564  shdepAddDependency(sdepRel, classId, objectId, objsubId,
565  AuthIdRelationId, roleid,
566  deptype);
567  }
568 
569  /* Drop no-longer-used old dependencies */
570  for (i = 0; i < noldmembers; i++)
571  {
572  Oid roleid = oldmembers[i];
573 
574  /* Skip the owner for ACL entries, same as above */
575  if (deptype == SHARED_DEPENDENCY_ACL && roleid == ownerId)
576  continue;
577 
578  /* Skip pinned roles */
579  if (IsPinnedObject(AuthIdRelationId, roleid))
580  continue;
581 
582  shdepDropDependency(sdepRel, classId, objectId, objsubId,
583  false, /* exact match on objsubId */
584  AuthIdRelationId, roleid,
585  deptype);
586  }
587 
588  table_close(sdepRel, RowExclusiveLock);
589  }
590 
591  if (oldmembers)
592  pfree(oldmembers);
593  if (newmembers)
594  pfree(newmembers);
595 }
596 
597 /*
598  * A struct to keep track of dependencies found in other databases.
599  */
600 typedef struct
601 {
603  int count;
604 } remoteDep;
605 
606 /*
607  * qsort comparator for ShDependObjectInfo items
608  */
609 static int
610 shared_dependency_comparator(const void *a, const void *b)
611 {
612  const ShDependObjectInfo *obja = (const ShDependObjectInfo *) a;
613  const ShDependObjectInfo *objb = (const ShDependObjectInfo *) b;
614 
615  /*
616  * Primary sort key is OID ascending.
617  */
618  if (obja->object.objectId < objb->object.objectId)
619  return -1;
620  if (obja->object.objectId > objb->object.objectId)
621  return 1;
622 
623  /*
624  * Next sort on catalog ID, in case identical OIDs appear in different
625  * catalogs. Sort direction is pretty arbitrary here.
626  */
627  if (obja->object.classId < objb->object.classId)
628  return -1;
629  if (obja->object.classId > objb->object.classId)
630  return 1;
631 
632  /*
633  * Sort on object subId.
634  *
635  * We sort the subId as an unsigned int so that 0 (the whole object) will
636  * come first.
637  */
638  if ((unsigned int) obja->object.objectSubId < (unsigned int) objb->object.objectSubId)
639  return -1;
640  if ((unsigned int) obja->object.objectSubId > (unsigned int) objb->object.objectSubId)
641  return 1;
642 
643  /*
644  * Last, sort on deptype, in case the same object has multiple dependency
645  * types. (Note that there's no need to consider objtype, as that's
646  * determined by the catalog OID.)
647  */
648  if (obja->deptype < objb->deptype)
649  return -1;
650  if (obja->deptype > objb->deptype)
651  return 1;
652 
653  return 0;
654 }
655 
656 /*
657  * checkSharedDependencies
658  *
659  * Check whether there are shared dependency entries for a given shared
660  * object; return true if so.
661  *
662  * In addition, return a string containing a newline-separated list of object
663  * descriptions that depend on the shared object, or NULL if none is found.
664  * We actually return two such strings; the "detail" result is suitable for
665  * returning to the client as an errdetail() string, and is limited in size.
666  * The "detail_log" string is potentially much longer, and should be emitted
667  * to the server log only.
668  *
669  * We can find three different kinds of dependencies: dependencies on objects
670  * of the current database; dependencies on shared objects; and dependencies
671  * on objects local to other databases. We can (and do) provide descriptions
672  * of the two former kinds of objects, but we can't do that for "remote"
673  * objects, so we just provide a count of them.
674  */
675 bool
676 checkSharedDependencies(Oid classId, Oid objectId,
677  char **detail_msg, char **detail_log_msg)
678 {
679  Relation sdepRel;
680  ScanKeyData key[2];
681  SysScanDesc scan;
682  HeapTuple tup;
683  int numReportedDeps = 0;
684  int numNotReportedDeps = 0;
685  int numNotReportedDbs = 0;
686  List *remDeps = NIL;
687  ListCell *cell;
688  ObjectAddress object;
689  ShDependObjectInfo *objects;
690  int numobjects;
691  int allocedobjects;
692  StringInfoData descs;
693  StringInfoData alldescs;
694 
695  /* This case can be dispatched quickly */
696  if (IsPinnedObject(classId, objectId))
697  {
698  object.classId = classId;
699  object.objectId = objectId;
700  object.objectSubId = 0;
701  ereport(ERROR,
702  (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
703  errmsg("cannot drop %s because it is required by the database system",
704  getObjectDescription(&object, false))));
705  }
706 
707  /*
708  * We limit the number of dependencies reported to the client to
709  * MAX_REPORTED_DEPS, since client software may not deal well with
710  * enormous error strings. The server log always gets a full report.
711  *
712  * For stability of regression test results, we sort local and shared
713  * objects by OID before reporting them. We don't worry about the order
714  * in which other databases are reported, though.
715  */
716 #define MAX_REPORTED_DEPS 100
717 
718  allocedobjects = 128; /* arbitrary initial array size */
719  objects = (ShDependObjectInfo *)
720  palloc(allocedobjects * sizeof(ShDependObjectInfo));
721  numobjects = 0;
722  initStringInfo(&descs);
723  initStringInfo(&alldescs);
724 
725  sdepRel = table_open(SharedDependRelationId, AccessShareLock);
726 
727  ScanKeyInit(&key[0],
728  Anum_pg_shdepend_refclassid,
729  BTEqualStrategyNumber, F_OIDEQ,
730  ObjectIdGetDatum(classId));
731  ScanKeyInit(&key[1],
732  Anum_pg_shdepend_refobjid,
733  BTEqualStrategyNumber, F_OIDEQ,
734  ObjectIdGetDatum(objectId));
735 
736  scan = systable_beginscan(sdepRel, SharedDependReferenceIndexId, true,
737  NULL, 2, key);
738 
739  while (HeapTupleIsValid(tup = systable_getnext(scan)))
740  {
741  Form_pg_shdepend sdepForm = (Form_pg_shdepend) GETSTRUCT(tup);
742 
743  object.classId = sdepForm->classid;
744  object.objectId = sdepForm->objid;
745  object.objectSubId = sdepForm->objsubid;
746 
747  /*
748  * If it's a dependency local to this database or it's a shared
749  * object, add it to the objects array.
750  *
751  * If it's a remote dependency, keep track of it so we can report the
752  * number of them later.
753  */
754  if (sdepForm->dbid == MyDatabaseId ||
755  sdepForm->dbid == InvalidOid)
756  {
757  if (numobjects >= allocedobjects)
758  {
759  allocedobjects *= 2;
760  objects = (ShDependObjectInfo *)
761  repalloc(objects,
762  allocedobjects * sizeof(ShDependObjectInfo));
763  }
764  objects[numobjects].object = object;
765  objects[numobjects].deptype = sdepForm->deptype;
766  objects[numobjects].objtype = (sdepForm->dbid == MyDatabaseId) ?
768  numobjects++;
769  }
770  else
771  {
772  /* It's not local nor shared, so it must be remote. */
773  remoteDep *dep;
774  bool stored = false;
775 
776  /*
777  * XXX this info is kept on a simple List. Maybe it's not good
778  * for performance, but using a hash table seems needlessly
779  * complex. The expected number of databases is not high anyway,
780  * I suppose.
781  */
782  foreach(cell, remDeps)
783  {
784  dep = lfirst(cell);
785  if (dep->dbOid == sdepForm->dbid)
786  {
787  dep->count++;
788  stored = true;
789  break;
790  }
791  }
792  if (!stored)
793  {
794  dep = (remoteDep *) palloc(sizeof(remoteDep));
795  dep->dbOid = sdepForm->dbid;
796  dep->count = 1;
797  remDeps = lappend(remDeps, dep);
798  }
799  }
800  }
801 
802  systable_endscan(scan);
803 
804  table_close(sdepRel, AccessShareLock);
805 
806  /*
807  * Sort and report local and shared objects.
808  */
809  if (numobjects > 1)
810  qsort(objects, numobjects,
812 
813  for (int i = 0; i < numobjects; i++)
814  {
815  if (numReportedDeps < MAX_REPORTED_DEPS)
816  {
817  numReportedDeps++;
818  storeObjectDescription(&descs,
819  objects[i].objtype,
820  &objects[i].object,
821  objects[i].deptype,
822  0);
823  }
824  else
825  numNotReportedDeps++;
826  storeObjectDescription(&alldescs,
827  objects[i].objtype,
828  &objects[i].object,
829  objects[i].deptype,
830  0);
831  }
832 
833  /*
834  * Summarize dependencies in remote databases.
835  */
836  foreach(cell, remDeps)
837  {
838  remoteDep *dep = lfirst(cell);
839 
840  object.classId = DatabaseRelationId;
841  object.objectId = dep->dbOid;
842  object.objectSubId = 0;
843 
844  if (numReportedDeps < MAX_REPORTED_DEPS)
845  {
846  numReportedDeps++;
847  storeObjectDescription(&descs, REMOTE_OBJECT, &object,
849  }
850  else
851  numNotReportedDbs++;
852  storeObjectDescription(&alldescs, REMOTE_OBJECT, &object,
854  }
855 
856  pfree(objects);
857  list_free_deep(remDeps);
858 
859  if (descs.len == 0)
860  {
861  pfree(descs.data);
862  pfree(alldescs.data);
863  *detail_msg = *detail_log_msg = NULL;
864  return false;
865  }
866 
867  if (numNotReportedDeps > 0)
868  appendStringInfo(&descs, ngettext("\nand %d other object "
869  "(see server log for list)",
870  "\nand %d other objects "
871  "(see server log for list)",
872  numNotReportedDeps),
873  numNotReportedDeps);
874  if (numNotReportedDbs > 0)
875  appendStringInfo(&descs, ngettext("\nand objects in %d other database "
876  "(see server log for list)",
877  "\nand objects in %d other databases "
878  "(see server log for list)",
879  numNotReportedDbs),
880  numNotReportedDbs);
881 
882  *detail_msg = descs.data;
883  *detail_log_msg = alldescs.data;
884  return true;
885 }
886 
887 
888 /*
889  * copyTemplateDependencies
890  *
891  * Routine to create the initial shared dependencies of a new database.
892  * We simply copy the dependencies from the template database.
893  */
894 void
895 copyTemplateDependencies(Oid templateDbId, Oid newDbId)
896 {
897  Relation sdepRel;
898  TupleDesc sdepDesc;
899  ScanKeyData key[1];
900  SysScanDesc scan;
901  HeapTuple tup;
902  CatalogIndexState indstate;
903  TupleTableSlot **slot;
904  int max_slots,
905  slot_init_count,
906  slot_stored_count;
907 
908  sdepRel = table_open(SharedDependRelationId, RowExclusiveLock);
909  sdepDesc = RelationGetDescr(sdepRel);
910 
911  /*
912  * Allocate the slots to use, but delay costly initialization until we
913  * know that they will be used.
914  */
916  slot = palloc(sizeof(TupleTableSlot *) * max_slots);
917 
918  indstate = CatalogOpenIndexes(sdepRel);
919 
920  /* Scan all entries with dbid = templateDbId */
921  ScanKeyInit(&key[0],
922  Anum_pg_shdepend_dbid,
923  BTEqualStrategyNumber, F_OIDEQ,
924  ObjectIdGetDatum(templateDbId));
925 
926  scan = systable_beginscan(sdepRel, SharedDependDependerIndexId, true,
927  NULL, 1, key);
928 
929  /* number of slots currently storing tuples */
930  slot_stored_count = 0;
931  /* number of slots currently initialized */
932  slot_init_count = 0;
933 
934  /*
935  * Copy the entries of the original database, changing the database Id to
936  * that of the new database. Note that because we are not copying rows
937  * with dbId == 0 (ie, rows describing dependent shared objects) we won't
938  * copy the ownership dependency of the template database itself; this is
939  * what we want.
940  */
941  while (HeapTupleIsValid(tup = systable_getnext(scan)))
942  {
943  Form_pg_shdepend shdep;
944 
945  if (slot_init_count < max_slots)
946  {
947  slot[slot_stored_count] = MakeSingleTupleTableSlot(sdepDesc, &TTSOpsHeapTuple);
948  slot_init_count++;
949  }
950 
951  ExecClearTuple(slot[slot_stored_count]);
952 
953  memset(slot[slot_stored_count]->tts_isnull, false,
954  slot[slot_stored_count]->tts_tupleDescriptor->natts * sizeof(bool));
955 
956  shdep = (Form_pg_shdepend) GETSTRUCT(tup);
957 
958  slot[slot_stored_count]->tts_values[Anum_pg_shdepend_dbid - 1] = ObjectIdGetDatum(newDbId);
959  slot[slot_stored_count]->tts_values[Anum_pg_shdepend_classid - 1] = shdep->classid;
960  slot[slot_stored_count]->tts_values[Anum_pg_shdepend_objid - 1] = shdep->objid;
961  slot[slot_stored_count]->tts_values[Anum_pg_shdepend_objsubid - 1] = shdep->objsubid;
962  slot[slot_stored_count]->tts_values[Anum_pg_shdepend_refclassid - 1] = shdep->refclassid;
963  slot[slot_stored_count]->tts_values[Anum_pg_shdepend_refobjid - 1] = shdep->refobjid;
964  slot[slot_stored_count]->tts_values[Anum_pg_shdepend_deptype - 1] = shdep->deptype;
965 
966  ExecStoreVirtualTuple(slot[slot_stored_count]);
967  slot_stored_count++;
968 
969  /* If slots are full, insert a batch of tuples */
970  if (slot_stored_count == max_slots)
971  {
972  CatalogTuplesMultiInsertWithInfo(sdepRel, slot, slot_stored_count, indstate);
973  slot_stored_count = 0;
974  }
975  }
976 
977  /* Insert any tuples left in the buffer */
978  if (slot_stored_count > 0)
979  CatalogTuplesMultiInsertWithInfo(sdepRel, slot, slot_stored_count, indstate);
980 
981  systable_endscan(scan);
982 
983  CatalogCloseIndexes(indstate);
984  table_close(sdepRel, RowExclusiveLock);
985 
986  /* Drop only the number of slots used */
987  for (int i = 0; i < slot_init_count; i++)
989  pfree(slot);
990 }
991 
992 /*
993  * dropDatabaseDependencies
994  *
995  * Delete pg_shdepend entries corresponding to a database that's being
996  * dropped.
997  */
998 void
1000 {
1001  Relation sdepRel;
1002  ScanKeyData key[1];
1003  SysScanDesc scan;
1004  HeapTuple tup;
1005 
1006  sdepRel = table_open(SharedDependRelationId, RowExclusiveLock);
1007 
1008  /*
1009  * First, delete all the entries that have the database Oid in the dbid
1010  * field.
1011  */
1012  ScanKeyInit(&key[0],
1013  Anum_pg_shdepend_dbid,
1014  BTEqualStrategyNumber, F_OIDEQ,
1015  ObjectIdGetDatum(databaseId));
1016  /* We leave the other index fields unspecified */
1017 
1018  scan = systable_beginscan(sdepRel, SharedDependDependerIndexId, true,
1019  NULL, 1, key);
1020 
1021  while (HeapTupleIsValid(tup = systable_getnext(scan)))
1022  {
1023  CatalogTupleDelete(sdepRel, &tup->t_self);
1024  }
1025 
1026  systable_endscan(scan);
1027 
1028  /* Now delete all entries corresponding to the database itself */
1029  shdepDropDependency(sdepRel, DatabaseRelationId, databaseId, 0, true,
1032 
1033  table_close(sdepRel, RowExclusiveLock);
1034 }
1035 
1036 /*
1037  * deleteSharedDependencyRecordsFor
1038  *
1039  * Delete all pg_shdepend entries corresponding to an object that's being
1040  * dropped or modified. The object is assumed to be either a shared object
1041  * or local to the current database (the classId tells us which).
1042  *
1043  * If objectSubId is zero, we are deleting a whole object, so get rid of
1044  * pg_shdepend entries for subobjects as well.
1045  */
1046 void
1047 deleteSharedDependencyRecordsFor(Oid classId, Oid objectId, int32 objectSubId)
1048 {
1049  Relation sdepRel;
1050 
1051  sdepRel = table_open(SharedDependRelationId, RowExclusiveLock);
1052 
1053  shdepDropDependency(sdepRel, classId, objectId, objectSubId,
1054  (objectSubId == 0),
1057 
1058  table_close(sdepRel, RowExclusiveLock);
1059 }
1060 
1061 /*
1062  * shdepAddDependency
1063  * Internal workhorse for inserting into pg_shdepend
1064  *
1065  * sdepRel must be the pg_shdepend relation, already opened and suitably
1066  * locked.
1067  */
1068 static void
1070  Oid classId, Oid objectId, int32 objsubId,
1071  Oid refclassId, Oid refobjId,
1072  SharedDependencyType deptype)
1073 {
1074  HeapTuple tup;
1075  Datum values[Natts_pg_shdepend];
1076  bool nulls[Natts_pg_shdepend];
1077 
1078  /*
1079  * Make sure the object doesn't go away while we record the dependency on
1080  * it. DROP routines should lock the object exclusively before they check
1081  * shared dependencies.
1082  */
1083  shdepLockAndCheckObject(refclassId, refobjId);
1084 
1085  memset(nulls, false, sizeof(nulls));
1086 
1087  /*
1088  * Form the new tuple and record the dependency.
1089  */
1090  values[Anum_pg_shdepend_dbid - 1] = ObjectIdGetDatum(classIdGetDbId(classId));
1091  values[Anum_pg_shdepend_classid - 1] = ObjectIdGetDatum(classId);
1092  values[Anum_pg_shdepend_objid - 1] = ObjectIdGetDatum(objectId);
1093  values[Anum_pg_shdepend_objsubid - 1] = Int32GetDatum(objsubId);
1094 
1095  values[Anum_pg_shdepend_refclassid - 1] = ObjectIdGetDatum(refclassId);
1096  values[Anum_pg_shdepend_refobjid - 1] = ObjectIdGetDatum(refobjId);
1097  values[Anum_pg_shdepend_deptype - 1] = CharGetDatum(deptype);
1098 
1099  tup = heap_form_tuple(sdepRel->rd_att, values, nulls);
1100 
1101  CatalogTupleInsert(sdepRel, tup);
1102 
1103  /* clean up */
1104  heap_freetuple(tup);
1105 }
1106 
1107 /*
1108  * shdepDropDependency
1109  * Internal workhorse for deleting entries from pg_shdepend.
1110  *
1111  * We drop entries having the following properties:
1112  * dependent object is the one identified by classId/objectId/objsubId
1113  * if refclassId isn't InvalidOid, it must match the entry's refclassid
1114  * if refobjId isn't InvalidOid, it must match the entry's refobjid
1115  * if deptype isn't SHARED_DEPENDENCY_INVALID, it must match entry's deptype
1116  *
1117  * If drop_subobjects is true, we ignore objsubId and consider all entries
1118  * matching classId/objectId.
1119  *
1120  * sdepRel must be the pg_shdepend relation, already opened and suitably
1121  * locked.
1122  */
1123 static void
1125  Oid classId, Oid objectId, int32 objsubId,
1126  bool drop_subobjects,
1127  Oid refclassId, Oid refobjId,
1128  SharedDependencyType deptype)
1129 {
1130  ScanKeyData key[4];
1131  int nkeys;
1132  SysScanDesc scan;
1133  HeapTuple tup;
1134 
1135  /* Scan for entries matching the dependent object */
1136  ScanKeyInit(&key[0],
1137  Anum_pg_shdepend_dbid,
1138  BTEqualStrategyNumber, F_OIDEQ,
1139  ObjectIdGetDatum(classIdGetDbId(classId)));
1140  ScanKeyInit(&key[1],
1141  Anum_pg_shdepend_classid,
1142  BTEqualStrategyNumber, F_OIDEQ,
1143  ObjectIdGetDatum(classId));
1144  ScanKeyInit(&key[2],
1145  Anum_pg_shdepend_objid,
1146  BTEqualStrategyNumber, F_OIDEQ,
1147  ObjectIdGetDatum(objectId));
1148  if (drop_subobjects)
1149  nkeys = 3;
1150  else
1151  {
1152  ScanKeyInit(&key[3],
1153  Anum_pg_shdepend_objsubid,
1154  BTEqualStrategyNumber, F_INT4EQ,
1155  Int32GetDatum(objsubId));
1156  nkeys = 4;
1157  }
1158 
1159  scan = systable_beginscan(sdepRel, SharedDependDependerIndexId, true,
1160  NULL, nkeys, key);
1161 
1162  while (HeapTupleIsValid(tup = systable_getnext(scan)))
1163  {
1164  Form_pg_shdepend shdepForm = (Form_pg_shdepend) GETSTRUCT(tup);
1165 
1166  /* Filter entries according to additional parameters */
1167  if (OidIsValid(refclassId) && shdepForm->refclassid != refclassId)
1168  continue;
1169  if (OidIsValid(refobjId) && shdepForm->refobjid != refobjId)
1170  continue;
1171  if (deptype != SHARED_DEPENDENCY_INVALID &&
1172  shdepForm->deptype != deptype)
1173  continue;
1174 
1175  /* OK, delete it */
1176  CatalogTupleDelete(sdepRel, &tup->t_self);
1177  }
1178 
1179  systable_endscan(scan);
1180 }
1181 
1182 /*
1183  * classIdGetDbId
1184  *
1185  * Get the database Id that should be used in pg_shdepend, given the OID
1186  * of the catalog containing the object. For shared objects, it's 0
1187  * (InvalidOid); for all other objects, it's the current database Id.
1188  */
1189 static Oid
1191 {
1192  Oid dbId;
1193 
1194  if (IsSharedRelation(classId))
1195  dbId = InvalidOid;
1196  else
1197  dbId = MyDatabaseId;
1198 
1199  return dbId;
1200 }
1201 
1202 /*
1203  * shdepLockAndCheckObject
1204  *
1205  * Lock the object that we are about to record a dependency on.
1206  * After it's locked, verify that it hasn't been dropped while we
1207  * weren't looking. If the object has been dropped, this function
1208  * does not return!
1209  */
1210 void
1211 shdepLockAndCheckObject(Oid classId, Oid objectId)
1212 {
1213  /* AccessShareLock should be OK, since we are not modifying the object */
1214  LockSharedObject(classId, objectId, 0, AccessShareLock);
1215 
1216  switch (classId)
1217  {
1218  case AuthIdRelationId:
1219  if (!SearchSysCacheExists1(AUTHOID, ObjectIdGetDatum(objectId)))
1220  ereport(ERROR,
1221  (errcode(ERRCODE_UNDEFINED_OBJECT),
1222  errmsg("role %u was concurrently dropped",
1223  objectId)));
1224  break;
1225 
1226  case TableSpaceRelationId:
1227  {
1228  /* For lack of a syscache on pg_tablespace, do this: */
1229  char *tablespace = get_tablespace_name(objectId);
1230 
1231  if (tablespace == NULL)
1232  ereport(ERROR,
1233  (errcode(ERRCODE_UNDEFINED_OBJECT),
1234  errmsg("tablespace %u was concurrently dropped",
1235  objectId)));
1236  pfree(tablespace);
1237  break;
1238  }
1239 
1240  case DatabaseRelationId:
1241  {
1242  /* For lack of a syscache on pg_database, do this: */
1243  char *database = get_database_name(objectId);
1244 
1245  if (database == NULL)
1246  ereport(ERROR,
1247  (errcode(ERRCODE_UNDEFINED_OBJECT),
1248  errmsg("database %u was concurrently dropped",
1249  objectId)));
1250  pfree(database);
1251  break;
1252  }
1253 
1254 
1255  default:
1256  elog(ERROR, "unrecognized shared classId: %u", classId);
1257  }
1258 }
1259 
1260 
1261 /*
1262  * storeObjectDescription
1263  * Append the description of a dependent object to "descs"
1264  *
1265  * While searching for dependencies of a shared object, we stash the
1266  * descriptions of dependent objects we find in a single string, which we
1267  * later pass to ereport() in the DETAIL field when somebody attempts to
1268  * drop a referenced shared object.
1269  *
1270  * When type is LOCAL_OBJECT or SHARED_OBJECT, we expect object to be the
1271  * dependent object, deptype is the dependency type, and count is not used.
1272  * When type is REMOTE_OBJECT, we expect object to be the database object,
1273  * and count to be nonzero; deptype is not used in this case.
1274  */
1275 static void
1278  ObjectAddress *object,
1279  SharedDependencyType deptype,
1280  int count)
1281 {
1282  char *objdesc = getObjectDescription(object, false);
1283 
1284  /*
1285  * An object being dropped concurrently doesn't need to be reported.
1286  */
1287  if (objdesc == NULL)
1288  return;
1289 
1290  /* separate entries with a newline */
1291  if (descs->len != 0)
1292  appendStringInfoChar(descs, '\n');
1293 
1294  switch (type)
1295  {
1296  case LOCAL_OBJECT:
1297  case SHARED_OBJECT:
1298  if (deptype == SHARED_DEPENDENCY_OWNER)
1299  appendStringInfo(descs, _("owner of %s"), objdesc);
1300  else if (deptype == SHARED_DEPENDENCY_ACL)
1301  appendStringInfo(descs, _("privileges for %s"), objdesc);
1302  else if (deptype == SHARED_DEPENDENCY_INITACL)
1303  appendStringInfo(descs, _("initial privileges for %s"), objdesc);
1304  else if (deptype == SHARED_DEPENDENCY_POLICY)
1305  appendStringInfo(descs, _("target of %s"), objdesc);
1306  else if (deptype == SHARED_DEPENDENCY_TABLESPACE)
1307  appendStringInfo(descs, _("tablespace for %s"), objdesc);
1308  else
1309  elog(ERROR, "unrecognized dependency type: %d",
1310  (int) deptype);
1311  break;
1312 
1313  case REMOTE_OBJECT:
1314  /* translator: %s will always be "database %s" */
1315  appendStringInfo(descs, ngettext("%d object in %s",
1316  "%d objects in %s",
1317  count),
1318  count, objdesc);
1319  break;
1320 
1321  default:
1322  elog(ERROR, "unrecognized object type: %d", type);
1323  }
1324 
1325  pfree(objdesc);
1326 }
1327 
1328 
1329 /*
1330  * shdepDropOwned
1331  *
1332  * Drop the objects owned by any one of the given RoleIds. If a role has
1333  * access to an object, the grant will be removed as well (but the object
1334  * will not, of course).
1335  *
1336  * We can revoke grants immediately while doing the scan, but drops are
1337  * saved up and done all at once with performMultipleDeletions. This
1338  * is necessary so that we don't get failures from trying to delete
1339  * interdependent objects in the wrong order.
1340  */
1341 void
1342 shdepDropOwned(List *roleids, DropBehavior behavior)
1343 {
1344  Relation sdepRel;
1345  ListCell *cell;
1346  ObjectAddresses *deleteobjs;
1347 
1348  deleteobjs = new_object_addresses();
1349 
1350  /*
1351  * We don't need this strong a lock here, but we'll call routines that
1352  * acquire RowExclusiveLock. Better get that right now to avoid potential
1353  * deadlock failures.
1354  */
1355  sdepRel = table_open(SharedDependRelationId, RowExclusiveLock);
1356 
1357  /*
1358  * For each role, find the dependent objects and drop them using the
1359  * regular (non-shared) dependency management.
1360  */
1361  foreach(cell, roleids)
1362  {
1363  Oid roleid = lfirst_oid(cell);
1364  ScanKeyData key[2];
1365  SysScanDesc scan;
1366  HeapTuple tuple;
1367 
1368  /* Doesn't work for pinned objects */
1369  if (IsPinnedObject(AuthIdRelationId, roleid))
1370  {
1371  ObjectAddress obj;
1372 
1373  obj.classId = AuthIdRelationId;
1374  obj.objectId = roleid;
1375  obj.objectSubId = 0;
1376 
1377  ereport(ERROR,
1378  (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
1379  errmsg("cannot drop objects owned by %s because they are "
1380  "required by the database system",
1381  getObjectDescription(&obj, false))));
1382  }
1383 
1384  ScanKeyInit(&key[0],
1385  Anum_pg_shdepend_refclassid,
1386  BTEqualStrategyNumber, F_OIDEQ,
1387  ObjectIdGetDatum(AuthIdRelationId));
1388  ScanKeyInit(&key[1],
1389  Anum_pg_shdepend_refobjid,
1390  BTEqualStrategyNumber, F_OIDEQ,
1391  ObjectIdGetDatum(roleid));
1392 
1393  scan = systable_beginscan(sdepRel, SharedDependReferenceIndexId, true,
1394  NULL, 2, key);
1395 
1396  while ((tuple = systable_getnext(scan)) != NULL)
1397  {
1398  Form_pg_shdepend sdepForm = (Form_pg_shdepend) GETSTRUCT(tuple);
1399  ObjectAddress obj;
1400 
1401  /*
1402  * We only operate on shared objects and objects in the current
1403  * database
1404  */
1405  if (sdepForm->dbid != MyDatabaseId &&
1406  sdepForm->dbid != InvalidOid)
1407  continue;
1408 
1409  switch (sdepForm->deptype)
1410  {
1411  /* Shouldn't happen */
1413  elog(ERROR, "unexpected dependency type");
1414  break;
1416 
1417  /*
1418  * Try to remove role from policy; if unable to, remove
1419  * policy.
1420  */
1421  if (!RemoveRoleFromObjectPolicy(roleid,
1422  sdepForm->classid,
1423  sdepForm->objid))
1424  {
1425  obj.classId = sdepForm->classid;
1426  obj.objectId = sdepForm->objid;
1427  obj.objectSubId = sdepForm->objsubid;
1428 
1429  /*
1430  * Acquire lock on object, then verify this dependency
1431  * is still relevant. If not, the object might have
1432  * been dropped or the policy modified. Ignore the
1433  * object in that case.
1434  */
1435  AcquireDeletionLock(&obj, 0);
1436  if (!systable_recheck_tuple(scan, tuple))
1437  {
1438  ReleaseDeletionLock(&obj);
1439  break;
1440  }
1441  add_exact_object_address(&obj, deleteobjs);
1442  }
1443  break;
1444  case SHARED_DEPENDENCY_ACL:
1445 
1446  /*
1447  * Dependencies on role grants are recorded using
1448  * SHARED_DEPENDENCY_ACL, but unlike a regular ACL list
1449  * which stores all permissions for a particular object in
1450  * a single ACL array, there's a separate catalog row for
1451  * each grant - so removing the grant just means removing
1452  * the entire row.
1453  */
1454  if (sdepForm->classid != AuthMemRelationId)
1455  {
1456  RemoveRoleFromObjectACL(roleid,
1457  sdepForm->classid,
1458  sdepForm->objid);
1459  break;
1460  }
1461  /* FALLTHROUGH */
1462 
1464 
1465  /*
1466  * Save it for deletion below, if it's a local object or a
1467  * role grant. Other shared objects, such as databases,
1468  * should not be removed here.
1469  */
1470  if (sdepForm->dbid == MyDatabaseId ||
1471  sdepForm->classid == AuthMemRelationId)
1472  {
1473  obj.classId = sdepForm->classid;
1474  obj.objectId = sdepForm->objid;
1475  obj.objectSubId = sdepForm->objsubid;
1476  /* as above */
1477  AcquireDeletionLock(&obj, 0);
1478  if (!systable_recheck_tuple(scan, tuple))
1479  {
1480  ReleaseDeletionLock(&obj);
1481  break;
1482  }
1483  add_exact_object_address(&obj, deleteobjs);
1484  }
1485  break;
1487 
1488  /*
1489  * Any mentions of the role that remain in pg_init_privs
1490  * entries are just dropped. This is the same policy as
1491  * we apply to regular ACLs.
1492  */
1493 
1494  /* Shouldn't see a role grant here */
1495  Assert(sdepForm->classid != AuthMemRelationId);
1496  RemoveRoleFromInitPriv(roleid,
1497  sdepForm->classid,
1498  sdepForm->objid,
1499  sdepForm->objsubid);
1500  break;
1501  }
1502  }
1503 
1504  systable_endscan(scan);
1505  }
1506 
1507  /*
1508  * For stability of deletion-report ordering, sort the objects into
1509  * approximate reverse creation order before deletion. (This might also
1510  * make the deletion go a bit faster, since there's less chance of having
1511  * to rearrange the objects due to dependencies.)
1512  */
1513  sort_object_addresses(deleteobjs);
1514 
1515  /* the dependency mechanism does the actual work */
1516  performMultipleDeletions(deleteobjs, behavior, 0);
1517 
1518  table_close(sdepRel, RowExclusiveLock);
1519 
1520  free_object_addresses(deleteobjs);
1521 }
1522 
1523 /*
1524  * shdepReassignOwned
1525  *
1526  * Change the owner of objects owned by any of the roles in roleids to
1527  * newrole. Grants are not touched.
1528  */
1529 void
1530 shdepReassignOwned(List *roleids, Oid newrole)
1531 {
1532  Relation sdepRel;
1533  ListCell *cell;
1534 
1535  /*
1536  * We don't need this strong a lock here, but we'll call routines that
1537  * acquire RowExclusiveLock. Better get that right now to avoid potential
1538  * deadlock problems.
1539  */
1540  sdepRel = table_open(SharedDependRelationId, RowExclusiveLock);
1541 
1542  foreach(cell, roleids)
1543  {
1544  SysScanDesc scan;
1545  ScanKeyData key[2];
1546  HeapTuple tuple;
1547  Oid roleid = lfirst_oid(cell);
1548 
1549  /* Refuse to work on pinned roles */
1550  if (IsPinnedObject(AuthIdRelationId, roleid))
1551  {
1552  ObjectAddress obj;
1553 
1554  obj.classId = AuthIdRelationId;
1555  obj.objectId = roleid;
1556  obj.objectSubId = 0;
1557 
1558  ereport(ERROR,
1559  (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
1560  errmsg("cannot reassign ownership of objects owned by %s because they are required by the database system",
1561  getObjectDescription(&obj, false))));
1562 
1563  /*
1564  * There's no need to tell the whole truth, which is that we
1565  * didn't track these dependencies at all ...
1566  */
1567  }
1568 
1569  ScanKeyInit(&key[0],
1570  Anum_pg_shdepend_refclassid,
1571  BTEqualStrategyNumber, F_OIDEQ,
1572  ObjectIdGetDatum(AuthIdRelationId));
1573  ScanKeyInit(&key[1],
1574  Anum_pg_shdepend_refobjid,
1575  BTEqualStrategyNumber, F_OIDEQ,
1576  ObjectIdGetDatum(roleid));
1577 
1578  scan = systable_beginscan(sdepRel, SharedDependReferenceIndexId, true,
1579  NULL, 2, key);
1580 
1581  while ((tuple = systable_getnext(scan)) != NULL)
1582  {
1583  Form_pg_shdepend sdepForm = (Form_pg_shdepend) GETSTRUCT(tuple);
1584  MemoryContext cxt,
1585  oldcxt;
1586 
1587  /*
1588  * We only operate on shared objects and objects in the current
1589  * database
1590  */
1591  if (sdepForm->dbid != MyDatabaseId &&
1592  sdepForm->dbid != InvalidOid)
1593  continue;
1594 
1595  /*
1596  * The various DDL routines called here tend to leak memory in
1597  * CurrentMemoryContext. That's not a problem when they're only
1598  * called once per command; but in this usage where we might be
1599  * touching many objects, it can amount to a serious memory leak.
1600  * Fix that by running each call in a short-lived context.
1601  */
1603  "shdepReassignOwned",
1605  oldcxt = MemoryContextSwitchTo(cxt);
1606 
1607  /* Perform the appropriate processing */
1608  switch (sdepForm->deptype)
1609  {
1611  shdepReassignOwned_Owner(sdepForm, newrole);
1612  break;
1614  shdepReassignOwned_InitAcl(sdepForm, roleid, newrole);
1615  break;
1616  case SHARED_DEPENDENCY_ACL:
1619  /* Nothing to do for these entry types */
1620  break;
1621  default:
1622  elog(ERROR, "unrecognized dependency type: %d",
1623  (int) sdepForm->deptype);
1624  break;
1625  }
1626 
1627  /* Clean up */
1628  MemoryContextSwitchTo(oldcxt);
1629  MemoryContextDelete(cxt);
1630 
1631  /* Make sure the next iteration will see my changes */
1633  }
1634 
1635  systable_endscan(scan);
1636  }
1637 
1638  table_close(sdepRel, RowExclusiveLock);
1639 }
1640 
1641 /*
1642  * shdepReassignOwned_Owner
1643  *
1644  * shdepReassignOwned's processing of SHARED_DEPENDENCY_OWNER entries
1645  */
1646 static void
1648 {
1649  /* Issue the appropriate ALTER OWNER call */
1650  switch (sdepForm->classid)
1651  {
1652  case TypeRelationId:
1653  AlterTypeOwner_oid(sdepForm->objid, newrole, true);
1654  break;
1655 
1656  case NamespaceRelationId:
1657  AlterSchemaOwner_oid(sdepForm->objid, newrole);
1658  break;
1659 
1660  case RelationRelationId:
1661 
1662  /*
1663  * Pass recursing = true so that we don't fail on indexes, owned
1664  * sequences, etc when we happen to visit them before their parent
1665  * table.
1666  */
1667  ATExecChangeOwner(sdepForm->objid, newrole, true, AccessExclusiveLock);
1668  break;
1669 
1670  case DefaultAclRelationId:
1671 
1672  /*
1673  * Ignore default ACLs; they should be handled by DROP OWNED, not
1674  * REASSIGN OWNED.
1675  */
1676  break;
1677 
1678  case UserMappingRelationId:
1679  /* ditto */
1680  break;
1681 
1682  case ForeignServerRelationId:
1683  AlterForeignServerOwner_oid(sdepForm->objid, newrole);
1684  break;
1685 
1686  case ForeignDataWrapperRelationId:
1687  AlterForeignDataWrapperOwner_oid(sdepForm->objid, newrole);
1688  break;
1689 
1690  case EventTriggerRelationId:
1691  AlterEventTriggerOwner_oid(sdepForm->objid, newrole);
1692  break;
1693 
1694  case PublicationRelationId:
1695  AlterPublicationOwner_oid(sdepForm->objid, newrole);
1696  break;
1697 
1698  case SubscriptionRelationId:
1699  AlterSubscriptionOwner_oid(sdepForm->objid, newrole);
1700  break;
1701 
1702  /* Generic alter owner cases */
1703  case CollationRelationId:
1704  case ConversionRelationId:
1705  case OperatorRelationId:
1706  case ProcedureRelationId:
1707  case LanguageRelationId:
1708  case LargeObjectRelationId:
1709  case OperatorFamilyRelationId:
1710  case OperatorClassRelationId:
1711  case ExtensionRelationId:
1712  case StatisticExtRelationId:
1713  case TableSpaceRelationId:
1714  case DatabaseRelationId:
1715  case TSConfigRelationId:
1716  case TSDictionaryRelationId:
1717  AlterObjectOwner_internal(sdepForm->classid,
1718  sdepForm->objid,
1719  newrole);
1720  break;
1721 
1722  default:
1723  elog(ERROR, "unexpected classid %u", sdepForm->classid);
1724  break;
1725  }
1726 }
1727 
1728 /*
1729  * shdepReassignOwned_InitAcl
1730  *
1731  * shdepReassignOwned's processing of SHARED_DEPENDENCY_INITACL entries
1732  */
1733 static void
1735 {
1736  /*
1737  * Currently, REASSIGN OWNED replaces mentions of oldrole with newrole in
1738  * pg_init_privs entries, just as it does in the object's regular ACL.
1739  * This is less than ideal, since pg_init_privs ought to retain a
1740  * historical record of the situation at the end of CREATE EXTENSION.
1741  * However, there are two big stumbling blocks to doing something
1742  * different:
1743  *
1744  * 1. If we don't replace the references, what is to happen if the old
1745  * role gets dropped? (DROP OWNED's current answer is to just delete the
1746  * pg_init_privs entry, which is surely ahistorical.)
1747  *
1748  * 2. It's unlikely that pg_dump will cope nicely with pg_init_privs
1749  * entries that are based on a different owner than the object now has ---
1750  * the more so given that pg_init_privs doesn't record the original owner
1751  * explicitly. (This problem actually exists anyway given that a bare
1752  * ALTER OWNER won't update pg_init_privs, but we don't need REASSIGN
1753  * OWNED making it worse.)
1754  */
1755  ReplaceRoleInInitPriv(oldrole, newrole,
1756  sdepForm->classid,
1757  sdepForm->objid,
1758  sdepForm->objsubid);
1759 }
void RemoveRoleFromInitPriv(Oid roleid, Oid classid, Oid objid, int32 objsubid)
Definition: aclchk.c:4917
void ReplaceRoleInInitPriv(Oid oldroleid, Oid newroleid, Oid classid, Oid objid, int32 objsubid)
Definition: aclchk.c:4808
void RemoveRoleFromObjectACL(Oid roleid, Oid classid, Oid objid)
Definition: aclchk.c:1465
void AlterObjectOwner_internal(Oid classId, Oid objectId, Oid new_ownerId)
Definition: alter.c:916
char * get_tablespace_name(Oid spc_oid)
Definition: tablespace.c:1472
static Datum values[MAXATTR]
Definition: bootstrap.c:150
signed int int32
Definition: c.h:494
#define ngettext(s, p, n)
Definition: c.h:1181
#define Assert(condition)
Definition: c.h:858
#define OidIsValid(objectId)
Definition: c.h:775
bool IsPinnedObject(Oid classId, Oid objectId)
Definition: catalog.c:334
bool IsSharedRelation(Oid relationId)
Definition: catalog.c:264
char * get_database_name(Oid dbid)
Definition: dbcommands.c:3166
void performMultipleDeletions(const ObjectAddresses *objects, DropBehavior behavior, int flags)
Definition: dependency.c:332
void sort_object_addresses(ObjectAddresses *addrs)
Definition: dependency.c:2761
void AcquireDeletionLock(const ObjectAddress *object, int flags)
Definition: dependency.c:1496
void ReleaseDeletionLock(const ObjectAddress *object)
Definition: dependency.c:1528
ObjectAddresses * new_object_addresses(void)
Definition: dependency.c:2487
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2533
void free_object_addresses(ObjectAddresses *addrs)
Definition: dependency.c:2773
SharedDependencyType
Definition: dependency.h:79
@ SHARED_DEPENDENCY_INITACL
Definition: dependency.h:82
@ SHARED_DEPENDENCY_TABLESPACE
Definition: dependency.h:84
@ SHARED_DEPENDENCY_INVALID
Definition: dependency.h:85
@ SHARED_DEPENDENCY_POLICY
Definition: dependency.h:83
@ SHARED_DEPENDENCY_ACL
Definition: dependency.h:81
@ SHARED_DEPENDENCY_OWNER
Definition: dependency.h:80
int errcode(int sqlerrcode)
Definition: elog.c:853
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define _(x)
Definition: elog.c:90
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:224
#define ereport(elevel,...)
Definition: elog.h:149
void AlterEventTriggerOwner_oid(Oid trigOid, Oid newOwnerId)
TupleTableSlot * ExecStoreVirtualTuple(TupleTableSlot *slot)
Definition: execTuples.c:1639
void ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
Definition: execTuples.c:1341
const TupleTableSlotOps TTSOpsHeapTuple
Definition: execTuples.c:85
TupleTableSlot * MakeSingleTupleTableSlot(TupleDesc tupdesc, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:1325
void AlterForeignServerOwner_oid(Oid srvId, Oid newOwnerId)
Definition: foreigncmds.c:450
void AlterForeignDataWrapperOwner_oid(Oid fwdId, Oid newOwnerId)
Definition: foreigncmds.c:313
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:596
bool systable_recheck_tuple(SysScanDesc sysscan, HeapTuple tup)
Definition: genam.c:562
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:503
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:384
Oid MyDatabaseId
Definition: globals.c:92
HeapTuple heap_copytuple(HeapTuple tuple)
Definition: heaptuple.c:776
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition: heaptuple.c:1116
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1434
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define GETSTRUCT(TUP)
Definition: htup_details.h:653
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:313
void CatalogTuplesMultiInsertWithInfo(Relation heapRel, TupleTableSlot **slot, int ntuples, CatalogIndexState indstate)
Definition: indexing.c:273
void CatalogCloseIndexes(CatalogIndexState indstate)
Definition: indexing.c:61
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:233
CatalogIndexState CatalogOpenIndexes(Relation heapRel)
Definition: indexing.c:43
void CatalogTupleDelete(Relation heapRel, ItemPointer tid)
Definition: indexing.c:365
#define MAX_CATALOG_MULTI_INSERT_BYTES
Definition: indexing.h:33
int b
Definition: isn.c:70
int a
Definition: isn.c:69
int i
Definition: isn.c:73
List * lappend(List *list, void *datum)
Definition: list.c:339
void list_free_deep(List *list)
Definition: list.c:1560
void LockSharedObject(Oid classid, Oid objid, uint16 objsubid, LOCKMODE lockmode)
Definition: lmgr.c:1073
#define AccessExclusiveLock
Definition: lockdefs.h:43
#define AccessShareLock
Definition: lockdefs.h:36
#define RowExclusiveLock
Definition: lockdefs.h:38
void pfree(void *pointer)
Definition: mcxt.c:1521
MemoryContext CurrentMemoryContext
Definition: mcxt.c:143
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1541
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:454
void * palloc(Size size)
Definition: mcxt.c:1317
#define AllocSetContextCreate
Definition: memutils.h:129
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:160
#define IsBootstrapProcessingMode()
Definition: miscadmin.h:454
char * getObjectDescription(const ObjectAddress *object, bool missing_ok)
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
DropBehavior
Definition: parsenodes.h:2333
#define lfirst(lc)
Definition: pg_list.h:172
#define NIL
Definition: pg_list.h:68
#define lfirst_oid(lc)
Definition: pg_list.h:174
static void shdepDropDependency(Relation sdepRel, Oid classId, Oid objectId, int32 objsubId, bool drop_subobjects, Oid refclassId, Oid refobjId, SharedDependencyType deptype)
Definition: pg_shdepend.c:1124
static int shared_dependency_comparator(const void *a, const void *b)
Definition: pg_shdepend.c:610
static void shdepReassignOwned_InitAcl(Form_pg_shdepend sdepForm, Oid oldrole, Oid newrole)
Definition: pg_shdepend.c:1734
void dropDatabaseDependencies(Oid databaseId)
Definition: pg_shdepend.c:999
void changeDependencyOnOwner(Oid classId, Oid objectId, Oid newOwnerId)
Definition: pg_shdepend.c:316
static void shdepReassignOwned_Owner(Form_pg_shdepend sdepForm, Oid newrole)
Definition: pg_shdepend.c:1647
static void getOidListDiff(Oid *list1, int *nlist1, Oid *list2, int *nlist2)
Definition: pg_shdepend.c:421
void copyTemplateDependencies(Oid templateDbId, Oid newDbId)
Definition: pg_shdepend.c:895
static Oid classIdGetDbId(Oid classId)
Definition: pg_shdepend.c:1190
void deleteSharedDependencyRecordsFor(Oid classId, Oid objectId, int32 objectSubId)
Definition: pg_shdepend.c:1047
void updateAclDependencies(Oid classId, Oid objectId, int32 objsubId, Oid ownerId, int noldmembers, Oid *oldmembers, int nnewmembers, Oid *newmembers)
Definition: pg_shdepend.c:491
void updateInitAclDependencies(Oid classId, Oid objectId, int32 objsubId, int noldmembers, Oid *oldmembers, int nnewmembers, Oid *newmembers)
Definition: pg_shdepend.c:512
#define MAX_REPORTED_DEPS
void recordDependencyOnOwner(Oid classId, Oid objectId, Oid owner)
Definition: pg_shdepend.c:168
bool checkSharedDependencies(Oid classId, Oid objectId, char **detail_msg, char **detail_log_msg)
Definition: pg_shdepend.c:676
void recordDependencyOnTablespace(Oid classId, Oid objectId, Oid tablespace)
Definition: pg_shdepend.c:370
static void shdepAddDependency(Relation sdepRel, Oid classId, Oid objectId, int32 objsubId, Oid refclassId, Oid refobjId, SharedDependencyType deptype)
Definition: pg_shdepend.c:1069
void shdepDropOwned(List *roleids, DropBehavior behavior)
Definition: pg_shdepend.c:1342
static void storeObjectDescription(StringInfo descs, SharedDependencyObjectType type, ObjectAddress *object, SharedDependencyType deptype, int count)
Definition: pg_shdepend.c:1276
void recordSharedDependencyOn(ObjectAddress *depender, ObjectAddress *referenced, SharedDependencyType deptype)
Definition: pg_shdepend.c:125
void shdepLockAndCheckObject(Oid classId, Oid objectId)
Definition: pg_shdepend.c:1211
void changeDependencyOnTablespace(Oid classId, Oid objectId, Oid newTablespaceId)
Definition: pg_shdepend.c:391
static void updateAclDependenciesWorker(Oid classId, Oid objectId, int32 objsubId, Oid ownerId, SharedDependencyType deptype, int noldmembers, Oid *oldmembers, int nnewmembers, Oid *newmembers)
Definition: pg_shdepend.c:525
SharedDependencyObjectType
Definition: pg_shdepend.c:68
@ SHARED_OBJECT
Definition: pg_shdepend.c:70
@ LOCAL_OBJECT
Definition: pg_shdepend.c:69
@ REMOTE_OBJECT
Definition: pg_shdepend.c:71
void shdepReassignOwned(List *roleids, Oid newrole)
Definition: pg_shdepend.c:1530
static void shdepChangeDep(Relation sdepRel, Oid classid, Oid objid, int32 objsubid, Oid refclassid, Oid refobjid, SharedDependencyType deptype)
Definition: pg_shdepend.c:206
FormData_pg_shdepend
Definition: pg_shdepend.h:66
FormData_pg_shdepend * Form_pg_shdepend
Definition: pg_shdepend.h:73
static char * tablespace
Definition: pgbench.c:216
bool RemoveRoleFromObjectPolicy(Oid roleid, Oid classid, Oid policy_id)
Definition: policy.c:416
#define qsort(a, b, c, d)
Definition: port.h:453
uintptr_t Datum
Definition: postgres.h:64
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:252
static Datum Int32GetDatum(int32 X)
Definition: postgres.h:212
static Datum CharGetDatum(char X)
Definition: postgres.h:122
#define InvalidOid
Definition: postgres_ext.h:36
unsigned int Oid
Definition: postgres_ext.h:31
void AlterPublicationOwner_oid(Oid subid, Oid newOwnerId)
MemoryContextSwitchTo(old_ctx)
#define RelationGetDescr(relation)
Definition: rel.h:531
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
void AlterSchemaOwner_oid(Oid schemaoid, Oid newOwnerId)
Definition: schemacmds.c:307
#define BTEqualStrategyNumber
Definition: stratnum.h:31
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:97
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:194
void initStringInfo(StringInfo str)
Definition: stringinfo.c:59
ItemPointerData t_self
Definition: htup.h:65
Definition: pg_list.h:54
TupleDesc rd_att
Definition: rel.h:112
ObjectAddress object
Definition: pg_shdepend.c:76
SharedDependencyObjectType objtype
Definition: pg_shdepend.c:78
Datum * tts_values
Definition: tuptable.h:125
void AlterSubscriptionOwner_oid(Oid subid, Oid newOwnerId)
#define SearchSysCacheExists1(cacheId, key1)
Definition: syscache.h:95
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:40
void ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing, LOCKMODE lockmode)
Definition: tablecmds.c:14314
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:454
void AlterTypeOwner_oid(Oid typeOid, Oid newOwnerId, bool hasDependEntry)
Definition: typecmds.c:3947
const char * type
void CommandCounterIncrement(void)
Definition: xact.c:1098