PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
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-2017, 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/heapam.h"
19 #include "access/htup_details.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"
25 #include "catalog/pg_collation.h"
26 #include "catalog/pg_conversion.h"
27 #include "catalog/pg_database.h"
28 #include "catalog/pg_default_acl.h"
30 #include "catalog/pg_extension.h"
33 #include "catalog/pg_language.h"
34 #include "catalog/pg_largeobject.h"
36 #include "catalog/pg_namespace.h"
37 #include "catalog/pg_operator.h"
38 #include "catalog/pg_opclass.h"
39 #include "catalog/pg_opfamily.h"
40 #include "catalog/pg_proc.h"
41 #include "catalog/pg_shdepend.h"
43 #include "catalog/pg_tablespace.h"
44 #include "catalog/pg_ts_config.h"
45 #include "catalog/pg_ts_dict.h"
46 #include "catalog/pg_type.h"
48 #include "commands/alter.h"
49 #include "commands/dbcommands.h"
50 #include "commands/collationcmds.h"
52 #include "commands/defrem.h"
53 #include "commands/event_trigger.h"
54 #include "commands/extension.h"
55 #include "commands/policy.h"
56 #include "commands/proclang.h"
58 #include "commands/schemacmds.h"
60 #include "commands/tablecmds.h"
61 #include "commands/typecmds.h"
62 #include "storage/lmgr.h"
63 #include "miscadmin.h"
64 #include "utils/acl.h"
65 #include "utils/fmgroids.h"
66 #include "utils/syscache.h"
67 #include "utils/tqual.h"
68 
69 
70 typedef enum
71 {
76 
77 static void getOidListDiff(Oid *list1, int *nlist1, Oid *list2, int *nlist2);
78 static Oid classIdGetDbId(Oid classId);
79 static void shdepChangeDep(Relation sdepRel,
80  Oid classid, Oid objid, int32 objsubid,
81  Oid refclassid, Oid refobjid,
82  SharedDependencyType deptype);
83 static void shdepAddDependency(Relation sdepRel,
84  Oid classId, Oid objectId, int32 objsubId,
85  Oid refclassId, Oid refobjId,
86  SharedDependencyType deptype);
87 static void shdepDropDependency(Relation sdepRel,
88  Oid classId, Oid objectId, int32 objsubId,
89  bool drop_subobjects,
90  Oid refclassId, Oid refobjId,
91  SharedDependencyType deptype);
92 static void storeObjectDescription(StringInfo descs,
94  ObjectAddress *object,
95  SharedDependencyType deptype,
96  int count);
97 static bool isSharedObjectPinned(Oid classId, Oid objectId, Relation sdepRel);
98 
99 
100 /*
101  * recordSharedDependencyOn
102  *
103  * Record a dependency between 2 objects via their respective ObjectAddresses.
104  * The first argument is the dependent object, the second the one it
105  * references (which must be a shared object).
106  *
107  * This locks the referenced object and makes sure it still exists.
108  * Then it creates an entry in pg_shdepend. The lock is kept until
109  * the end of the transaction.
110  *
111  * Dependencies on pinned objects are not recorded.
112  */
113 void
115  ObjectAddress *referenced,
116  SharedDependencyType deptype)
117 {
118  Relation sdepRel;
119 
120  /*
121  * Objects in pg_shdepend can't have SubIds.
122  */
123  Assert(depender->objectSubId == 0);
124  Assert(referenced->objectSubId == 0);
125 
126  /*
127  * During bootstrap, do nothing since pg_shdepend may not exist yet.
128  * initdb will fill in appropriate pg_shdepend entries after bootstrap.
129  */
131  return;
132 
134 
135  /* If the referenced object is pinned, do nothing. */
136  if (!isSharedObjectPinned(referenced->classId, referenced->objectId,
137  sdepRel))
138  {
139  shdepAddDependency(sdepRel, depender->classId, depender->objectId,
140  depender->objectSubId,
141  referenced->classId, referenced->objectId,
142  deptype);
143  }
144 
145  heap_close(sdepRel, RowExclusiveLock);
146 }
147 
148 /*
149  * recordDependencyOnOwner
150  *
151  * A convenient wrapper of recordSharedDependencyOn -- register the specified
152  * user as owner of the given object.
153  *
154  * Note: it's the caller's responsibility to ensure that there isn't an owner
155  * entry for the object already.
156  */
157 void
158 recordDependencyOnOwner(Oid classId, Oid objectId, Oid owner)
159 {
160  ObjectAddress myself,
161  referenced;
162 
163  myself.classId = classId;
164  myself.objectId = objectId;
165  myself.objectSubId = 0;
166 
167  referenced.classId = AuthIdRelationId;
168  referenced.objectId = owner;
169  referenced.objectSubId = 0;
170 
171  recordSharedDependencyOn(&myself, &referenced, SHARED_DEPENDENCY_OWNER);
172 }
173 
174 /*
175  * shdepChangeDep
176  *
177  * Update shared dependency records to account for an updated referenced
178  * object. This is an internal workhorse for operations such as changing
179  * an object's owner.
180  *
181  * There must be no more than one existing entry for the given dependent
182  * object and dependency type! So in practice this can only be used for
183  * updating SHARED_DEPENDENCY_OWNER entries, which should have that property.
184  *
185  * If there is no previous entry, we assume it was referencing a PINned
186  * object, so we create a new entry. If the new referenced object is
187  * PINned, we don't create an entry (and drop the old one, if any).
188  *
189  * sdepRel must be the pg_shdepend relation, already opened and suitably
190  * locked.
191  */
192 static void
194  Oid classid, Oid objid, int32 objsubid,
195  Oid refclassid, Oid refobjid,
196  SharedDependencyType deptype)
197 {
198  Oid dbid = classIdGetDbId(classid);
199  HeapTuple oldtup = NULL;
200  HeapTuple scantup;
201  ScanKeyData key[4];
202  SysScanDesc scan;
203 
204  /*
205  * Make sure the new referenced object doesn't go away while we record the
206  * dependency.
207  */
208  shdepLockAndCheckObject(refclassid, refobjid);
209 
210  /*
211  * Look for a previous entry
212  */
213  ScanKeyInit(&key[0],
215  BTEqualStrategyNumber, F_OIDEQ,
216  ObjectIdGetDatum(dbid));
217  ScanKeyInit(&key[1],
219  BTEqualStrategyNumber, F_OIDEQ,
220  ObjectIdGetDatum(classid));
221  ScanKeyInit(&key[2],
223  BTEqualStrategyNumber, F_OIDEQ,
224  ObjectIdGetDatum(objid));
225  ScanKeyInit(&key[3],
227  BTEqualStrategyNumber, F_INT4EQ,
228  Int32GetDatum(objsubid));
229 
230  scan = systable_beginscan(sdepRel, SharedDependDependerIndexId, true,
231  NULL, 4, key);
232 
233  while ((scantup = systable_getnext(scan)) != NULL)
234  {
235  /* Ignore if not of the target dependency type */
236  if (((Form_pg_shdepend) GETSTRUCT(scantup))->deptype != deptype)
237  continue;
238  /* Caller screwed up if multiple matches */
239  if (oldtup)
240  elog(ERROR,
241  "multiple pg_shdepend entries for object %u/%u/%d deptype %c",
242  classid, objid, objsubid, deptype);
243  oldtup = heap_copytuple(scantup);
244  }
245 
246  systable_endscan(scan);
247 
248  if (isSharedObjectPinned(refclassid, refobjid, sdepRel))
249  {
250  /* No new entry needed, so just delete existing entry if any */
251  if (oldtup)
252  CatalogTupleDelete(sdepRel, &oldtup->t_self);
253  }
254  else if (oldtup)
255  {
256  /* Need to update existing entry */
257  Form_pg_shdepend shForm = (Form_pg_shdepend) GETSTRUCT(oldtup);
258 
259  /* Since oldtup is a copy, we can just modify it in-memory */
260  shForm->refclassid = refclassid;
261  shForm->refobjid = refobjid;
262 
263  CatalogTupleUpdate(sdepRel, &oldtup->t_self, oldtup);
264  }
265  else
266  {
267  /* Need to insert new entry */
269  bool nulls[Natts_pg_shdepend];
270 
271  memset(nulls, false, sizeof(nulls));
272 
273  values[Anum_pg_shdepend_dbid - 1] = ObjectIdGetDatum(dbid);
274  values[Anum_pg_shdepend_classid - 1] = ObjectIdGetDatum(classid);
275  values[Anum_pg_shdepend_objid - 1] = ObjectIdGetDatum(objid);
276  values[Anum_pg_shdepend_objsubid - 1] = Int32GetDatum(objsubid);
277 
278  values[Anum_pg_shdepend_refclassid - 1] = ObjectIdGetDatum(refclassid);
279  values[Anum_pg_shdepend_refobjid - 1] = ObjectIdGetDatum(refobjid);
280  values[Anum_pg_shdepend_deptype - 1] = CharGetDatum(deptype);
281 
282  /*
283  * we are reusing oldtup just to avoid declaring a new variable, but
284  * it's certainly a new tuple
285  */
286  oldtup = heap_form_tuple(RelationGetDescr(sdepRel), values, nulls);
287  CatalogTupleInsert(sdepRel, oldtup);
288  }
289 
290  if (oldtup)
291  heap_freetuple(oldtup);
292 }
293 
294 /*
295  * changeDependencyOnOwner
296  *
297  * Update the shared dependencies to account for the new owner.
298  *
299  * Note: we don't need an objsubid argument because only whole objects
300  * have owners.
301  */
302 void
303 changeDependencyOnOwner(Oid classId, Oid objectId, Oid newOwnerId)
304 {
305  Relation sdepRel;
306 
308 
309  /* Adjust the SHARED_DEPENDENCY_OWNER entry */
310  shdepChangeDep(sdepRel,
311  classId, objectId, 0,
312  AuthIdRelationId, newOwnerId,
314 
315  /*----------
316  * There should never be a SHARED_DEPENDENCY_ACL entry for the owner,
317  * so get rid of it if there is one. This can happen if the new owner
318  * was previously granted some rights to the object.
319  *
320  * This step is analogous to aclnewowner's removal of duplicate entries
321  * in the ACL. We have to do it to handle this scenario:
322  * A grants some rights on an object to B
323  * ALTER OWNER changes the object's owner to B
324  * ALTER OWNER changes the object's owner to C
325  * The third step would remove all mention of B from the object's ACL,
326  * but we'd still have a SHARED_DEPENDENCY_ACL for B if we did not do
327  * things this way.
328  *
329  * The rule against having a SHARED_DEPENDENCY_ACL entry for the owner
330  * allows us to fix things up in just this one place, without having
331  * to make the various ALTER OWNER routines each know about it.
332  *----------
333  */
334  shdepDropDependency(sdepRel, classId, objectId, 0, true,
335  AuthIdRelationId, newOwnerId,
337 
338  heap_close(sdepRel, RowExclusiveLock);
339 }
340 
341 /*
342  * getOidListDiff
343  * Helper for updateAclDependencies.
344  *
345  * Takes two Oid arrays and removes elements that are common to both arrays,
346  * leaving just those that are in one input but not the other.
347  * We assume both arrays have been sorted and de-duped.
348  */
349 static void
350 getOidListDiff(Oid *list1, int *nlist1, Oid *list2, int *nlist2)
351 {
352  int in1,
353  in2,
354  out1,
355  out2;
356 
357  in1 = in2 = out1 = out2 = 0;
358  while (in1 < *nlist1 && in2 < *nlist2)
359  {
360  if (list1[in1] == list2[in2])
361  {
362  /* skip over duplicates */
363  in1++;
364  in2++;
365  }
366  else if (list1[in1] < list2[in2])
367  {
368  /* list1[in1] is not in list2 */
369  list1[out1++] = list1[in1++];
370  }
371  else
372  {
373  /* list2[in2] is not in list1 */
374  list2[out2++] = list2[in2++];
375  }
376  }
377 
378  /* any remaining list1 entries are not in list2 */
379  while (in1 < *nlist1)
380  {
381  list1[out1++] = list1[in1++];
382  }
383 
384  /* any remaining list2 entries are not in list1 */
385  while (in2 < *nlist2)
386  {
387  list2[out2++] = list2[in2++];
388  }
389 
390  *nlist1 = out1;
391  *nlist2 = out2;
392 }
393 
394 /*
395  * updateAclDependencies
396  * Update the pg_shdepend info for an object's ACL during GRANT/REVOKE.
397  *
398  * classId, objectId, objsubId: identify the object whose ACL this is
399  * ownerId: role owning the object
400  * noldmembers, oldmembers: array of roleids appearing in old ACL
401  * nnewmembers, newmembers: array of roleids appearing in new ACL
402  *
403  * We calculate the differences between the new and old lists of roles,
404  * and then insert or delete from pg_shdepend as appropriate.
405  *
406  * Note that we can't just insert all referenced roles blindly during GRANT,
407  * because we would end up with duplicate registered dependencies. We could
408  * check for existence of the tuples before inserting, but that seems to be
409  * more expensive than what we are doing here. Likewise we can't just delete
410  * blindly during REVOKE, because the user may still have other privileges.
411  * It is also possible that REVOKE actually adds dependencies, due to
412  * instantiation of a formerly implicit default ACL (although at present,
413  * all such dependencies should be for the owning role, which we ignore here).
414  *
415  * NOTE: Both input arrays must be sorted and de-duped. (Typically they
416  * are extracted from an ACL array by aclmembers(), which takes care of
417  * both requirements.) The arrays are pfreed before return.
418  */
419 void
420 updateAclDependencies(Oid classId, Oid objectId, int32 objsubId,
421  Oid ownerId,
422  int noldmembers, Oid *oldmembers,
423  int nnewmembers, Oid *newmembers)
424 {
425  Relation sdepRel;
426  int i;
427 
428  /*
429  * Remove entries that are common to both lists; those represent existing
430  * dependencies we don't need to change.
431  *
432  * OK to overwrite the inputs since we'll pfree them anyway.
433  */
434  getOidListDiff(oldmembers, &noldmembers, newmembers, &nnewmembers);
435 
436  if (noldmembers > 0 || nnewmembers > 0)
437  {
439 
440  /* Add new dependencies that weren't already present */
441  for (i = 0; i < nnewmembers; i++)
442  {
443  Oid roleid = newmembers[i];
444 
445  /*
446  * Skip the owner: he has an OWNER shdep entry instead. (This is
447  * not just a space optimization; it makes ALTER OWNER easier. See
448  * notes in changeDependencyOnOwner.)
449  */
450  if (roleid == ownerId)
451  continue;
452 
453  /* Skip pinned roles; they don't need dependency entries */
454  if (isSharedObjectPinned(AuthIdRelationId, roleid, sdepRel))
455  continue;
456 
457  shdepAddDependency(sdepRel, classId, objectId, objsubId,
458  AuthIdRelationId, roleid,
460  }
461 
462  /* Drop no-longer-used old dependencies */
463  for (i = 0; i < noldmembers; i++)
464  {
465  Oid roleid = oldmembers[i];
466 
467  /* Skip the owner, same as above */
468  if (roleid == ownerId)
469  continue;
470 
471  /* Skip pinned roles */
472  if (isSharedObjectPinned(AuthIdRelationId, roleid, sdepRel))
473  continue;
474 
475  shdepDropDependency(sdepRel, classId, objectId, objsubId,
476  false, /* exact match on objsubId */
477  AuthIdRelationId, roleid,
479  }
480 
481  heap_close(sdepRel, RowExclusiveLock);
482  }
483 
484  if (oldmembers)
485  pfree(oldmembers);
486  if (newmembers)
487  pfree(newmembers);
488 }
489 
490 /*
491  * A struct to keep track of dependencies found in other databases.
492  */
493 typedef struct
494 {
496  int count;
497 } remoteDep;
498 
499 /*
500  * checkSharedDependencies
501  *
502  * Check whether there are shared dependency entries for a given shared
503  * object; return true if so.
504  *
505  * In addition, return a string containing a newline-separated list of object
506  * descriptions that depend on the shared object, or NULL if none is found.
507  * We actually return two such strings; the "detail" result is suitable for
508  * returning to the client as an errdetail() string, and is limited in size.
509  * The "detail_log" string is potentially much longer, and should be emitted
510  * to the server log only.
511  *
512  * We can find three different kinds of dependencies: dependencies on objects
513  * of the current database; dependencies on shared objects; and dependencies
514  * on objects local to other databases. We can (and do) provide descriptions
515  * of the two former kinds of objects, but we can't do that for "remote"
516  * objects, so we just provide a count of them.
517  *
518  * If we find a SHARED_DEPENDENCY_PIN entry, we can error out early.
519  */
520 bool
521 checkSharedDependencies(Oid classId, Oid objectId,
522  char **detail_msg, char **detail_log_msg)
523 {
524  Relation sdepRel;
525  ScanKeyData key[2];
526  SysScanDesc scan;
527  HeapTuple tup;
528  int numReportedDeps = 0;
529  int numNotReportedDeps = 0;
530  int numNotReportedDbs = 0;
531  List *remDeps = NIL;
532  ListCell *cell;
533  ObjectAddress object;
534  StringInfoData descs;
535  StringInfoData alldescs;
536 
537  /*
538  * We limit the number of dependencies reported to the client to
539  * MAX_REPORTED_DEPS, since client software may not deal well with
540  * enormous error strings. The server log always gets a full report.
541  */
542 #define MAX_REPORTED_DEPS 100
543 
544  initStringInfo(&descs);
545  initStringInfo(&alldescs);
546 
548 
549  ScanKeyInit(&key[0],
551  BTEqualStrategyNumber, F_OIDEQ,
552  ObjectIdGetDatum(classId));
553  ScanKeyInit(&key[1],
555  BTEqualStrategyNumber, F_OIDEQ,
556  ObjectIdGetDatum(objectId));
557 
558  scan = systable_beginscan(sdepRel, SharedDependReferenceIndexId, true,
559  NULL, 2, key);
560 
561  while (HeapTupleIsValid(tup = systable_getnext(scan)))
562  {
563  Form_pg_shdepend sdepForm = (Form_pg_shdepend) GETSTRUCT(tup);
564 
565  /* This case can be dispatched quickly */
566  if (sdepForm->deptype == SHARED_DEPENDENCY_PIN)
567  {
568  object.classId = classId;
569  object.objectId = objectId;
570  object.objectSubId = 0;
571  ereport(ERROR,
572  (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
573  errmsg("cannot drop %s because it is required by the database system",
574  getObjectDescription(&object))));
575  }
576 
577  object.classId = sdepForm->classid;
578  object.objectId = sdepForm->objid;
579  object.objectSubId = sdepForm->objsubid;
580 
581  /*
582  * If it's a dependency local to this database or it's a shared
583  * object, describe it.
584  *
585  * If it's a remote dependency, keep track of it so we can report the
586  * number of them later.
587  */
588  if (sdepForm->dbid == MyDatabaseId)
589  {
590  if (numReportedDeps < MAX_REPORTED_DEPS)
591  {
592  numReportedDeps++;
593  storeObjectDescription(&descs, LOCAL_OBJECT, &object,
594  sdepForm->deptype, 0);
595  }
596  else
597  numNotReportedDeps++;
598  storeObjectDescription(&alldescs, LOCAL_OBJECT, &object,
599  sdepForm->deptype, 0);
600  }
601  else if (sdepForm->dbid == InvalidOid)
602  {
603  if (numReportedDeps < MAX_REPORTED_DEPS)
604  {
605  numReportedDeps++;
606  storeObjectDescription(&descs, SHARED_OBJECT, &object,
607  sdepForm->deptype, 0);
608  }
609  else
610  numNotReportedDeps++;
611  storeObjectDescription(&alldescs, SHARED_OBJECT, &object,
612  sdepForm->deptype, 0);
613  }
614  else
615  {
616  /* It's not local nor shared, so it must be remote. */
617  remoteDep *dep;
618  bool stored = false;
619 
620  /*
621  * XXX this info is kept on a simple List. Maybe it's not good
622  * for performance, but using a hash table seems needlessly
623  * complex. The expected number of databases is not high anyway,
624  * I suppose.
625  */
626  foreach(cell, remDeps)
627  {
628  dep = lfirst(cell);
629  if (dep->dbOid == sdepForm->dbid)
630  {
631  dep->count++;
632  stored = true;
633  break;
634  }
635  }
636  if (!stored)
637  {
638  dep = (remoteDep *) palloc(sizeof(remoteDep));
639  dep->dbOid = sdepForm->dbid;
640  dep->count = 1;
641  remDeps = lappend(remDeps, dep);
642  }
643  }
644  }
645 
646  systable_endscan(scan);
647 
648  heap_close(sdepRel, AccessShareLock);
649 
650  /*
651  * Summarize dependencies in remote databases.
652  */
653  foreach(cell, remDeps)
654  {
655  remoteDep *dep = lfirst(cell);
656 
657  object.classId = DatabaseRelationId;
658  object.objectId = dep->dbOid;
659  object.objectSubId = 0;
660 
661  if (numReportedDeps < MAX_REPORTED_DEPS)
662  {
663  numReportedDeps++;
664  storeObjectDescription(&descs, REMOTE_OBJECT, &object,
666  }
667  else
668  numNotReportedDbs++;
669  storeObjectDescription(&alldescs, REMOTE_OBJECT, &object,
671  }
672 
673  list_free_deep(remDeps);
674 
675  if (descs.len == 0)
676  {
677  pfree(descs.data);
678  pfree(alldescs.data);
679  *detail_msg = *detail_log_msg = NULL;
680  return false;
681  }
682 
683  if (numNotReportedDeps > 0)
684  appendStringInfo(&descs, ngettext("\nand %d other object "
685  "(see server log for list)",
686  "\nand %d other objects "
687  "(see server log for list)",
688  numNotReportedDeps),
689  numNotReportedDeps);
690  if (numNotReportedDbs > 0)
691  appendStringInfo(&descs, ngettext("\nand objects in %d other database "
692  "(see server log for list)",
693  "\nand objects in %d other databases "
694  "(see server log for list)",
695  numNotReportedDbs),
696  numNotReportedDbs);
697 
698  *detail_msg = descs.data;
699  *detail_log_msg = alldescs.data;
700  return true;
701 }
702 
703 /*
704  * copyTemplateDependencies
705  *
706  * Routine to create the initial shared dependencies of a new database.
707  * We simply copy the dependencies from the template database.
708  */
709 void
710 copyTemplateDependencies(Oid templateDbId, Oid newDbId)
711 {
712  Relation sdepRel;
713  TupleDesc sdepDesc;
714  ScanKeyData key[1];
715  SysScanDesc scan;
716  HeapTuple tup;
717  CatalogIndexState indstate;
719  bool nulls[Natts_pg_shdepend];
720  bool replace[Natts_pg_shdepend];
721 
723  sdepDesc = RelationGetDescr(sdepRel);
724 
725  indstate = CatalogOpenIndexes(sdepRel);
726 
727  /* Scan all entries with dbid = templateDbId */
728  ScanKeyInit(&key[0],
730  BTEqualStrategyNumber, F_OIDEQ,
731  ObjectIdGetDatum(templateDbId));
732 
733  scan = systable_beginscan(sdepRel, SharedDependDependerIndexId, true,
734  NULL, 1, key);
735 
736  /* Set up to copy the tuples except for inserting newDbId */
737  memset(values, 0, sizeof(values));
738  memset(nulls, false, sizeof(nulls));
739  memset(replace, false, sizeof(replace));
740 
741  replace[Anum_pg_shdepend_dbid - 1] = true;
742  values[Anum_pg_shdepend_dbid - 1] = ObjectIdGetDatum(newDbId);
743 
744  /*
745  * Copy the entries of the original database, changing the database Id to
746  * that of the new database. Note that because we are not copying rows
747  * with dbId == 0 (ie, rows describing dependent shared objects) we won't
748  * copy the ownership dependency of the template database itself; this is
749  * what we want.
750  */
751  while (HeapTupleIsValid(tup = systable_getnext(scan)))
752  {
753  HeapTuple newtup;
754 
755  newtup = heap_modify_tuple(tup, sdepDesc, values, nulls, replace);
756  CatalogTupleInsertWithInfo(sdepRel, newtup, indstate);
757 
758  heap_freetuple(newtup);
759  }
760 
761  systable_endscan(scan);
762 
763  CatalogCloseIndexes(indstate);
764  heap_close(sdepRel, RowExclusiveLock);
765 }
766 
767 /*
768  * dropDatabaseDependencies
769  *
770  * Delete pg_shdepend entries corresponding to a database that's being
771  * dropped.
772  */
773 void
775 {
776  Relation sdepRel;
777  ScanKeyData key[1];
778  SysScanDesc scan;
779  HeapTuple tup;
780 
782 
783  /*
784  * First, delete all the entries that have the database Oid in the dbid
785  * field.
786  */
787  ScanKeyInit(&key[0],
789  BTEqualStrategyNumber, F_OIDEQ,
790  ObjectIdGetDatum(databaseId));
791  /* We leave the other index fields unspecified */
792 
793  scan = systable_beginscan(sdepRel, SharedDependDependerIndexId, true,
794  NULL, 1, key);
795 
796  while (HeapTupleIsValid(tup = systable_getnext(scan)))
797  {
798  CatalogTupleDelete(sdepRel, &tup->t_self);
799  }
800 
801  systable_endscan(scan);
802 
803  /* Now delete all entries corresponding to the database itself */
804  shdepDropDependency(sdepRel, DatabaseRelationId, databaseId, 0, true,
807 
808  heap_close(sdepRel, RowExclusiveLock);
809 }
810 
811 /*
812  * deleteSharedDependencyRecordsFor
813  *
814  * Delete all pg_shdepend entries corresponding to an object that's being
815  * dropped or modified. The object is assumed to be either a shared object
816  * or local to the current database (the classId tells us which).
817  *
818  * If objectSubId is zero, we are deleting a whole object, so get rid of
819  * pg_shdepend entries for subobjects as well.
820  */
821 void
822 deleteSharedDependencyRecordsFor(Oid classId, Oid objectId, int32 objectSubId)
823 {
824  Relation sdepRel;
825 
827 
828  shdepDropDependency(sdepRel, classId, objectId, objectSubId,
829  (objectSubId == 0),
832 
833  heap_close(sdepRel, RowExclusiveLock);
834 }
835 
836 /*
837  * shdepAddDependency
838  * Internal workhorse for inserting into pg_shdepend
839  *
840  * sdepRel must be the pg_shdepend relation, already opened and suitably
841  * locked.
842  */
843 static void
845  Oid classId, Oid objectId, int32 objsubId,
846  Oid refclassId, Oid refobjId,
847  SharedDependencyType deptype)
848 {
849  HeapTuple tup;
851  bool nulls[Natts_pg_shdepend];
852 
853  /*
854  * Make sure the object doesn't go away while we record the dependency on
855  * it. DROP routines should lock the object exclusively before they check
856  * shared dependencies.
857  */
858  shdepLockAndCheckObject(refclassId, refobjId);
859 
860  memset(nulls, false, sizeof(nulls));
861 
862  /*
863  * Form the new tuple and record the dependency.
864  */
865  values[Anum_pg_shdepend_dbid - 1] = ObjectIdGetDatum(classIdGetDbId(classId));
866  values[Anum_pg_shdepend_classid - 1] = ObjectIdGetDatum(classId);
867  values[Anum_pg_shdepend_objid - 1] = ObjectIdGetDatum(objectId);
868  values[Anum_pg_shdepend_objsubid - 1] = Int32GetDatum(objsubId);
869 
870  values[Anum_pg_shdepend_refclassid - 1] = ObjectIdGetDatum(refclassId);
871  values[Anum_pg_shdepend_refobjid - 1] = ObjectIdGetDatum(refobjId);
872  values[Anum_pg_shdepend_deptype - 1] = CharGetDatum(deptype);
873 
874  tup = heap_form_tuple(sdepRel->rd_att, values, nulls);
875 
876  CatalogTupleInsert(sdepRel, tup);
877 
878  /* clean up */
879  heap_freetuple(tup);
880 }
881 
882 /*
883  * shdepDropDependency
884  * Internal workhorse for deleting entries from pg_shdepend.
885  *
886  * We drop entries having the following properties:
887  * dependent object is the one identified by classId/objectId/objsubId
888  * if refclassId isn't InvalidOid, it must match the entry's refclassid
889  * if refobjId isn't InvalidOid, it must match the entry's refobjid
890  * if deptype isn't SHARED_DEPENDENCY_INVALID, it must match entry's deptype
891  *
892  * If drop_subobjects is true, we ignore objsubId and consider all entries
893  * matching classId/objectId.
894  *
895  * sdepRel must be the pg_shdepend relation, already opened and suitably
896  * locked.
897  */
898 static void
900  Oid classId, Oid objectId, int32 objsubId,
901  bool drop_subobjects,
902  Oid refclassId, Oid refobjId,
903  SharedDependencyType deptype)
904 {
905  ScanKeyData key[4];
906  int nkeys;
907  SysScanDesc scan;
908  HeapTuple tup;
909 
910  /* Scan for entries matching the dependent object */
911  ScanKeyInit(&key[0],
913  BTEqualStrategyNumber, F_OIDEQ,
914  ObjectIdGetDatum(classIdGetDbId(classId)));
915  ScanKeyInit(&key[1],
917  BTEqualStrategyNumber, F_OIDEQ,
918  ObjectIdGetDatum(classId));
919  ScanKeyInit(&key[2],
921  BTEqualStrategyNumber, F_OIDEQ,
922  ObjectIdGetDatum(objectId));
923  if (drop_subobjects)
924  nkeys = 3;
925  else
926  {
927  ScanKeyInit(&key[3],
929  BTEqualStrategyNumber, F_INT4EQ,
930  Int32GetDatum(objsubId));
931  nkeys = 4;
932  }
933 
934  scan = systable_beginscan(sdepRel, SharedDependDependerIndexId, true,
935  NULL, nkeys, key);
936 
937  while (HeapTupleIsValid(tup = systable_getnext(scan)))
938  {
939  Form_pg_shdepend shdepForm = (Form_pg_shdepend) GETSTRUCT(tup);
940 
941  /* Filter entries according to additional parameters */
942  if (OidIsValid(refclassId) && shdepForm->refclassid != refclassId)
943  continue;
944  if (OidIsValid(refobjId) && shdepForm->refobjid != refobjId)
945  continue;
946  if (deptype != SHARED_DEPENDENCY_INVALID &&
947  shdepForm->deptype != deptype)
948  continue;
949 
950  /* OK, delete it */
951  CatalogTupleDelete(sdepRel, &tup->t_self);
952  }
953 
954  systable_endscan(scan);
955 }
956 
957 /*
958  * classIdGetDbId
959  *
960  * Get the database Id that should be used in pg_shdepend, given the OID
961  * of the catalog containing the object. For shared objects, it's 0
962  * (InvalidOid); for all other objects, it's the current database Id.
963  */
964 static Oid
966 {
967  Oid dbId;
968 
969  if (IsSharedRelation(classId))
970  dbId = InvalidOid;
971  else
972  dbId = MyDatabaseId;
973 
974  return dbId;
975 }
976 
977 /*
978  * shdepLockAndCheckObject
979  *
980  * Lock the object that we are about to record a dependency on.
981  * After it's locked, verify that it hasn't been dropped while we
982  * weren't looking. If the object has been dropped, this function
983  * does not return!
984  */
985 void
986 shdepLockAndCheckObject(Oid classId, Oid objectId)
987 {
988  /* AccessShareLock should be OK, since we are not modifying the object */
989  LockSharedObject(classId, objectId, 0, AccessShareLock);
990 
991  switch (classId)
992  {
993  case AuthIdRelationId:
995  ereport(ERROR,
996  (errcode(ERRCODE_UNDEFINED_OBJECT),
997  errmsg("role %u was concurrently dropped",
998  objectId)));
999  break;
1000 
1001  /*
1002  * Currently, this routine need not support any other shared
1003  * object types besides roles. If we wanted to record explicit
1004  * dependencies on databases or tablespaces, we'd need code along
1005  * these lines:
1006  */
1007 #ifdef NOT_USED
1008  case TableSpaceRelationId:
1009  {
1010  /* For lack of a syscache on pg_tablespace, do this: */
1011  char *tablespace = get_tablespace_name(objectId);
1012 
1013  if (tablespace == NULL)
1014  ereport(ERROR,
1015  (errcode(ERRCODE_UNDEFINED_OBJECT),
1016  errmsg("tablespace %u was concurrently dropped",
1017  objectId)));
1018  pfree(tablespace);
1019  break;
1020  }
1021 #endif
1022 
1023  case DatabaseRelationId:
1024  {
1025  /* For lack of a syscache on pg_database, do this: */
1026  char *database = get_database_name(objectId);
1027 
1028  if (database == NULL)
1029  ereport(ERROR,
1030  (errcode(ERRCODE_UNDEFINED_OBJECT),
1031  errmsg("database %u was concurrently dropped",
1032  objectId)));
1033  pfree(database);
1034  break;
1035  }
1036 
1037 
1038  default:
1039  elog(ERROR, "unrecognized shared classId: %u", classId);
1040  }
1041 }
1042 
1043 
1044 /*
1045  * storeObjectDescription
1046  * Append the description of a dependent object to "descs"
1047  *
1048  * While searching for dependencies of a shared object, we stash the
1049  * descriptions of dependent objects we find in a single string, which we
1050  * later pass to ereport() in the DETAIL field when somebody attempts to
1051  * drop a referenced shared object.
1052  *
1053  * When type is LOCAL_OBJECT or SHARED_OBJECT, we expect object to be the
1054  * dependent object, deptype is the dependency type, and count is not used.
1055  * When type is REMOTE_OBJECT, we expect object to be the database object,
1056  * and count to be nonzero; deptype is not used in this case.
1057  */
1058 static void
1061  ObjectAddress *object,
1062  SharedDependencyType deptype,
1063  int count)
1064 {
1065  char *objdesc = getObjectDescription(object);
1066 
1067  /* separate entries with a newline */
1068  if (descs->len != 0)
1069  appendStringInfoChar(descs, '\n');
1070 
1071  switch (type)
1072  {
1073  case LOCAL_OBJECT:
1074  case SHARED_OBJECT:
1075  if (deptype == SHARED_DEPENDENCY_OWNER)
1076  appendStringInfo(descs, _("owner of %s"), objdesc);
1077  else if (deptype == SHARED_DEPENDENCY_ACL)
1078  appendStringInfo(descs, _("privileges for %s"), objdesc);
1079  else if (deptype == SHARED_DEPENDENCY_POLICY)
1080  appendStringInfo(descs, _("target of %s"), objdesc);
1081  else
1082  elog(ERROR, "unrecognized dependency type: %d",
1083  (int) deptype);
1084  break;
1085 
1086  case REMOTE_OBJECT:
1087  /* translator: %s will always be "database %s" */
1088  appendStringInfo(descs, ngettext("%d object in %s",
1089  "%d objects in %s",
1090  count),
1091  count, objdesc);
1092  break;
1093 
1094  default:
1095  elog(ERROR, "unrecognized object type: %d", type);
1096  }
1097 
1098  pfree(objdesc);
1099 }
1100 
1101 
1102 /*
1103  * isSharedObjectPinned
1104  * Return whether a given shared object has a SHARED_DEPENDENCY_PIN entry.
1105  *
1106  * sdepRel must be the pg_shdepend relation, already opened and suitably
1107  * locked.
1108  */
1109 static bool
1110 isSharedObjectPinned(Oid classId, Oid objectId, Relation sdepRel)
1111 {
1112  bool result = false;
1113  ScanKeyData key[2];
1114  SysScanDesc scan;
1115  HeapTuple tup;
1116 
1117  ScanKeyInit(&key[0],
1119  BTEqualStrategyNumber, F_OIDEQ,
1120  ObjectIdGetDatum(classId));
1121  ScanKeyInit(&key[1],
1123  BTEqualStrategyNumber, F_OIDEQ,
1124  ObjectIdGetDatum(objectId));
1125 
1126  scan = systable_beginscan(sdepRel, SharedDependReferenceIndexId, true,
1127  NULL, 2, key);
1128 
1129  /*
1130  * Since we won't generate additional pg_shdepend entries for pinned
1131  * objects, there can be at most one entry referencing a pinned object.
1132  * Hence, it's sufficient to look at the first returned tuple; we don't
1133  * need to loop.
1134  */
1135  tup = systable_getnext(scan);
1136  if (HeapTupleIsValid(tup))
1137  {
1138  Form_pg_shdepend shdepForm = (Form_pg_shdepend) GETSTRUCT(tup);
1139 
1140  if (shdepForm->deptype == SHARED_DEPENDENCY_PIN)
1141  result = true;
1142  }
1143 
1144  systable_endscan(scan);
1145 
1146  return result;
1147 }
1148 
1149 /*
1150  * shdepDropOwned
1151  *
1152  * Drop the objects owned by any one of the given RoleIds. If a role has
1153  * access to an object, the grant will be removed as well (but the object
1154  * will not, of course).
1155  *
1156  * We can revoke grants immediately while doing the scan, but drops are
1157  * saved up and done all at once with performMultipleDeletions. This
1158  * is necessary so that we don't get failures from trying to delete
1159  * interdependent objects in the wrong order.
1160  */
1161 void
1162 shdepDropOwned(List *roleids, DropBehavior behavior)
1163 {
1164  Relation sdepRel;
1165  ListCell *cell;
1166  ObjectAddresses *deleteobjs;
1167 
1168  deleteobjs = new_object_addresses();
1169 
1170  /*
1171  * We don't need this strong a lock here, but we'll call routines that
1172  * acquire RowExclusiveLock. Better get that right now to avoid potential
1173  * deadlock failures.
1174  */
1176 
1177  /*
1178  * For each role, find the dependent objects and drop them using the
1179  * regular (non-shared) dependency management.
1180  */
1181  foreach(cell, roleids)
1182  {
1183  Oid roleid = lfirst_oid(cell);
1184  ScanKeyData key[2];
1185  SysScanDesc scan;
1186  HeapTuple tuple;
1187 
1188  /* Doesn't work for pinned objects */
1189  if (isSharedObjectPinned(AuthIdRelationId, roleid, sdepRel))
1190  {
1191  ObjectAddress obj;
1192 
1193  obj.classId = AuthIdRelationId;
1194  obj.objectId = roleid;
1195  obj.objectSubId = 0;
1196 
1197  ereport(ERROR,
1198  (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
1199  errmsg("cannot drop objects owned by %s because they are "
1200  "required by the database system",
1201  getObjectDescription(&obj))));
1202  }
1203 
1204  ScanKeyInit(&key[0],
1206  BTEqualStrategyNumber, F_OIDEQ,
1208  ScanKeyInit(&key[1],
1210  BTEqualStrategyNumber, F_OIDEQ,
1211  ObjectIdGetDatum(roleid));
1212 
1213  scan = systable_beginscan(sdepRel, SharedDependReferenceIndexId, true,
1214  NULL, 2, key);
1215 
1216  while ((tuple = systable_getnext(scan)) != NULL)
1217  {
1218  Form_pg_shdepend sdepForm = (Form_pg_shdepend) GETSTRUCT(tuple);
1219  ObjectAddress obj;
1220 
1221  /*
1222  * We only operate on shared objects and objects in the current
1223  * database
1224  */
1225  if (sdepForm->dbid != MyDatabaseId &&
1226  sdepForm->dbid != InvalidOid)
1227  continue;
1228 
1229  switch (sdepForm->deptype)
1230  {
1231  /* Shouldn't happen */
1232  case SHARED_DEPENDENCY_PIN:
1234  elog(ERROR, "unexpected dependency type");
1235  break;
1236  case SHARED_DEPENDENCY_ACL:
1237  RemoveRoleFromObjectACL(roleid,
1238  sdepForm->classid,
1239  sdepForm->objid);
1240  break;
1242  /* If unable to remove role from policy, remove policy. */
1243  if (!RemoveRoleFromObjectPolicy(roleid,
1244  sdepForm->classid,
1245  sdepForm->objid))
1246  {
1247  obj.classId = sdepForm->classid;
1248  obj.objectId = sdepForm->objid;
1249  obj.objectSubId = sdepForm->objsubid;
1250  add_exact_object_address(&obj, deleteobjs);
1251  }
1252  break;
1254  /* If a local object, save it for deletion below */
1255  if (sdepForm->dbid == MyDatabaseId)
1256  {
1257  obj.classId = sdepForm->classid;
1258  obj.objectId = sdepForm->objid;
1259  obj.objectSubId = sdepForm->objsubid;
1260  add_exact_object_address(&obj, deleteobjs);
1261  }
1262  break;
1263  }
1264  }
1265 
1266  systable_endscan(scan);
1267  }
1268 
1269  /* the dependency mechanism does the actual work */
1270  performMultipleDeletions(deleteobjs, behavior, 0);
1271 
1272  heap_close(sdepRel, RowExclusiveLock);
1273 
1274  free_object_addresses(deleteobjs);
1275 }
1276 
1277 /*
1278  * shdepReassignOwned
1279  *
1280  * Change the owner of objects owned by any of the roles in roleids to
1281  * newrole. Grants are not touched.
1282  */
1283 void
1284 shdepReassignOwned(List *roleids, Oid newrole)
1285 {
1286  Relation sdepRel;
1287  ListCell *cell;
1288 
1289  /*
1290  * We don't need this strong a lock here, but we'll call routines that
1291  * acquire RowExclusiveLock. Better get that right now to avoid potential
1292  * deadlock problems.
1293  */
1295 
1296  foreach(cell, roleids)
1297  {
1298  SysScanDesc scan;
1299  ScanKeyData key[2];
1300  HeapTuple tuple;
1301  Oid roleid = lfirst_oid(cell);
1302 
1303  /* Refuse to work on pinned roles */
1304  if (isSharedObjectPinned(AuthIdRelationId, roleid, sdepRel))
1305  {
1306  ObjectAddress obj;
1307 
1308  obj.classId = AuthIdRelationId;
1309  obj.objectId = roleid;
1310  obj.objectSubId = 0;
1311 
1312  ereport(ERROR,
1313  (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
1314  errmsg("cannot reassign ownership of objects owned by %s because they are required by the database system",
1315  getObjectDescription(&obj))));
1316 
1317  /*
1318  * There's no need to tell the whole truth, which is that we
1319  * didn't track these dependencies at all ...
1320  */
1321  }
1322 
1323  ScanKeyInit(&key[0],
1325  BTEqualStrategyNumber, F_OIDEQ,
1327  ScanKeyInit(&key[1],
1329  BTEqualStrategyNumber, F_OIDEQ,
1330  ObjectIdGetDatum(roleid));
1331 
1332  scan = systable_beginscan(sdepRel, SharedDependReferenceIndexId, true,
1333  NULL, 2, key);
1334 
1335  while ((tuple = systable_getnext(scan)) != NULL)
1336  {
1337  Form_pg_shdepend sdepForm = (Form_pg_shdepend) GETSTRUCT(tuple);
1338 
1339  /*
1340  * We only operate on shared objects and objects in the current
1341  * database
1342  */
1343  if (sdepForm->dbid != MyDatabaseId &&
1344  sdepForm->dbid != InvalidOid)
1345  continue;
1346 
1347  /* Unexpected because we checked for pins above */
1348  if (sdepForm->deptype == SHARED_DEPENDENCY_PIN)
1349  elog(ERROR, "unexpected shared pin");
1350 
1351  /* We leave non-owner dependencies alone */
1352  if (sdepForm->deptype != SHARED_DEPENDENCY_OWNER)
1353  continue;
1354 
1355  /* Issue the appropriate ALTER OWNER call */
1356  switch (sdepForm->classid)
1357  {
1358  case TypeRelationId:
1359  AlterTypeOwner_oid(sdepForm->objid, newrole, true);
1360  break;
1361 
1362  case NamespaceRelationId:
1363  AlterSchemaOwner_oid(sdepForm->objid, newrole);
1364  break;
1365 
1366  case RelationRelationId:
1367 
1368  /*
1369  * Pass recursing = true so that we don't fail on indexes,
1370  * owned sequences, etc when we happen to visit them
1371  * before their parent table.
1372  */
1373  ATExecChangeOwner(sdepForm->objid, newrole, true, AccessExclusiveLock);
1374  break;
1375 
1376  case DefaultAclRelationId:
1377 
1378  /*
1379  * Ignore default ACLs; they should be handled by DROP
1380  * OWNED, not REASSIGN OWNED.
1381  */
1382  break;
1383 
1384  case UserMappingRelationId:
1385  /* ditto */
1386  break;
1387 
1389  AlterForeignServerOwner_oid(sdepForm->objid, newrole);
1390  break;
1391 
1393  AlterForeignDataWrapperOwner_oid(sdepForm->objid, newrole);
1394  break;
1395 
1397  AlterEventTriggerOwner_oid(sdepForm->objid, newrole);
1398  break;
1399 
1400  case PublicationRelationId:
1401  AlterPublicationOwner_oid(sdepForm->objid, newrole);
1402  break;
1403 
1405  AlterSubscriptionOwner_oid(sdepForm->objid, newrole);
1406  break;
1407 
1408  /* Generic alter owner cases */
1409  case CollationRelationId:
1410  case ConversionRelationId:
1411  case OperatorRelationId:
1412  case ProcedureRelationId:
1413  case LanguageRelationId:
1414  case LargeObjectRelationId:
1417  case ExtensionRelationId:
1418  case TableSpaceRelationId:
1419  case DatabaseRelationId:
1420  case TSConfigRelationId:
1422  {
1423  Oid classId = sdepForm->classid;
1424  Relation catalog;
1425 
1426  if (classId == LargeObjectRelationId)
1428 
1429  catalog = heap_open(classId, RowExclusiveLock);
1430 
1431  AlterObjectOwner_internal(catalog, sdepForm->objid,
1432  newrole);
1433 
1434  heap_close(catalog, NoLock);
1435  }
1436  break;
1437 
1438  default:
1439  elog(ERROR, "unexpected classid %u", sdepForm->classid);
1440  break;
1441  }
1442  /* Make sure the next iteration will see my changes */
1444  }
1445 
1446  systable_endscan(scan);
1447  }
1448 
1449  heap_close(sdepRel, RowExclusiveLock);
1450 }
HeapTuple heap_copytuple(HeapTuple tuple)
Definition: heaptuple.c:608
#define NIL
Definition: pg_list.h:69
void updateAclDependencies(Oid classId, Oid objectId, int32 objsubId, Oid ownerId, int noldmembers, Oid *oldmembers, int nnewmembers, Oid *newmembers)
Definition: pg_shdepend.c:420
void shdepDropOwned(List *roleids, DropBehavior behavior)
Definition: pg_shdepend.c:1162
#define NamespaceRelationId
Definition: pg_namespace.h:34
void recordSharedDependencyOn(ObjectAddress *depender, ObjectAddress *referenced, SharedDependencyType deptype)
Definition: pg_shdepend.c:114
#define OperatorRelationId
Definition: pg_operator.h:32
#define Anum_pg_shdepend_refclassid
Definition: pg_shdepend.h:75
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:493
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
#define SharedDependDependerIndexId
Definition: indexing.h:222
void AlterForeignDataWrapperOwner_oid(Oid fwdId, Oid newOwnerId)
Definition: foreigncmds.c:312
static bool isSharedObjectPinned(Oid classId, Oid objectId, Relation sdepRel)
Definition: pg_shdepend.c:1110
#define SharedDependRelationId
Definition: pg_shdepend.h:29
#define RelationGetDescr(relation)
Definition: rel.h:425
static void shdepChangeDep(Relation sdepRel, Oid classid, Oid objid, int32 objsubid, Oid refclassid, Oid refobjid, SharedDependencyType deptype)
Definition: pg_shdepend.c:193
static void getOidListDiff(Oid *list1, int *nlist1, Oid *list2, int *nlist2)
Definition: pg_shdepend.c:350
#define Anum_pg_shdepend_objsubid
Definition: pg_shdepend.h:74
void AlterSchemaOwner_oid(Oid oid, Oid newOwnerId)
Definition: schemacmds.c:297
#define ProcedureRelationId
Definition: pg_proc.h:33
FormData_pg_shdepend * Form_pg_shdepend
Definition: pg_shdepend.h:64
#define DatabaseRelationId
Definition: pg_database.h:29
#define RelationRelationId
Definition: pg_class.h:29
static void shdepAddDependency(Relation sdepRel, Oid classId, Oid objectId, int32 objsubId, Oid refclassId, Oid refobjId, SharedDependencyType deptype)
Definition: pg_shdepend.c:844
void AlterForeignServerOwner_oid(Oid srvId, Oid newOwnerId)
Definition: foreigncmds.c:447
#define AccessShareLock
Definition: lockdefs.h:36
#define OperatorClassRelationId
Definition: pg_opclass.h:49
#define MAX_REPORTED_DEPS
#define OperatorFamilyRelationId
Definition: pg_opfamily.h:29
static void storeObjectDescription(StringInfo descs, SharedDependencyObjectType type, ObjectAddress *object, SharedDependencyType deptype, int count)
Definition: pg_shdepend.c:1059
int errcode(int sqlerrcode)
Definition: elog.c:575
#define PublicationRelationId
#define Anum_pg_shdepend_classid
Definition: pg_shdepend.h:72
void CatalogTupleDelete(Relation heapRel, ItemPointer tid)
Definition: indexing.c:255
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2081
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:692
#define heap_close(r, l)
Definition: heapam.h:97
void RemoveRoleFromObjectACL(Oid roleid, Oid classid, Oid objid)
Definition: aclchk.c:1326
void recordDependencyOnOwner(Oid classId, Oid objectId, Oid owner)
Definition: pg_shdepend.c:158
ObjectAddresses * new_object_addresses(void)
Definition: dependency.c:2026
void free_object_addresses(ObjectAddresses *addrs)
Definition: dependency.c:2297
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1374
unsigned int Oid
Definition: postgres_ext.h:31
#define TypeRelationId
Definition: pg_type.h:34
#define OidIsValid(objectId)
Definition: c.h:533
void list_free_deep(List *list)
Definition: list.c:1147
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:322
#define DefaultAclRelationId
char * getObjectDescription(const ObjectAddress *object)
signed int int32
Definition: c.h:253
#define AuthIdRelationId
Definition: pg_authid.h:42
bool RemoveRoleFromObjectPolicy(Oid roleid, Oid classid, Oid policy_id)
Definition: policy.c:435
#define TSConfigRelationId
Definition: pg_ts_config.h:31
void changeDependencyOnOwner(Oid classId, Oid objectId, Oid newOwnerId)
Definition: pg_shdepend.c:303
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:410
#define SearchSysCacheExists1(cacheId, key1)
Definition: syscache.h:167
void pfree(void *pointer)
Definition: mcxt.c:992
#define Anum_pg_shdepend_refobjid
Definition: pg_shdepend.h:76
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:110
#define ObjectIdGetDatum(X)
Definition: postgres.h:515
#define ERROR
Definition: elog.h:43
Oid CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:162
#define TSDictionaryRelationId
Definition: pg_ts_dict.h:31
SharedDependencyObjectType
Definition: pg_shdepend.c:70
void shdepLockAndCheckObject(Oid classId, Oid objectId)
Definition: pg_shdepend.c:986
ItemPointerData t_self
Definition: htup.h:65
void AlterTypeOwner_oid(Oid typeOid, Oid newOwnerId, bool hasDependEntry)
Definition: typecmds.c:3321
char * get_database_name(Oid dbid)
Definition: dbcommands.c:2049
#define SubscriptionRelationId
void AlterObjectOwner_internal(Relation rel, Oid objectId, Oid new_ownerId)
Definition: alter.c:843
#define NoLock
Definition: lockdefs.h:34
void shdepReassignOwned(List *roleids, Oid newrole)
Definition: pg_shdepend.c:1284
#define RowExclusiveLock
Definition: lockdefs.h:38
char * tablespace
Definition: pgbench.c:146
#define Anum_pg_shdepend_deptype
Definition: pg_shdepend.h:77
#define ereport(elevel, rest)
Definition: elog.h:122
#define Anum_pg_shdepend_dbid
Definition: pg_shdepend.h:71
void copyTemplateDependencies(Oid templateDbId, Oid newDbId)
Definition: pg_shdepend.c:710
void deleteSharedDependencyRecordsFor(Oid classId, Oid objectId, int32 objectSubId)
Definition: pg_shdepend.c:822
List * lappend(List *list, void *datum)
Definition: list.c:128
void ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing, LOCKMODE lockmode)
Definition: tablecmds.c:9465
SharedDependencyType
Definition: dependency.h:113
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:201
void initStringInfo(StringInfo str)
Definition: stringinfo.c:65
void dropDatabaseDependencies(Oid databaseId)
Definition: pg_shdepend.c:774
#define Anum_pg_shdepend_objid
Definition: pg_shdepend.h:73
#define ngettext(s, p, n)
Definition: c.h:127
DropBehavior
Definition: parsenodes.h:1588
uintptr_t Datum
Definition: postgres.h:374
void CommandCounterIncrement(void)
Definition: xact.c:921
Oid MyDatabaseId
Definition: globals.c:76
bool IsSharedRelation(Oid relationId)
Definition: catalog.c:219
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1287
void LockSharedObject(Oid classid, Oid objid, uint16 objsubid, LOCKMODE lockmode)
Definition: lmgr.c:871
#define CollationRelationId
Definition: pg_collation.h:30
TupleDesc rd_att
Definition: rel.h:114
#define InvalidOid
Definition: postgres_ext.h:36
void AlterEventTriggerOwner_oid(Oid trigOid, Oid newOwnerId)
static void shdepDropDependency(Relation sdepRel, Oid classId, Oid objectId, int32 objsubId, bool drop_subobjects, Oid refclassId, Oid refobjId, SharedDependencyType deptype)
Definition: pg_shdepend.c:899
#define ForeignServerRelationId
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define NULL
Definition: c.h:226
#define Assert(condition)
Definition: c.h:670
#define lfirst(lc)
Definition: pg_list.h:106
#define EventTriggerRelationId
#define LargeObjectMetadataRelationId
CatalogIndexState CatalogOpenIndexes(Relation heapRel)
Definition: indexing.c:40
static Oid classIdGetDbId(Oid classId)
Definition: pg_shdepend.c:965
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:210
#define ForeignDataWrapperRelationId
#define CharGetDatum(X)
Definition: postgres.h:424
#define TableSpaceRelationId
Definition: pg_tablespace.h:29
static Datum values[MAXATTR]
Definition: bootstrap.c:162
#define IsBootstrapProcessingMode()
Definition: miscadmin.h:365
#define AccessExclusiveLock
Definition: lockdefs.h:46
#define Int32GetDatum(X)
Definition: postgres.h:487
void * palloc(Size size)
Definition: mcxt.c:891
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define UserMappingRelationId
char * get_tablespace_name(Oid spc_oid)
Definition: tablespace.c:1427
int i
void AlterSubscriptionOwner_oid(Oid subid, Oid newOwnerId)
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
void CatalogCloseIndexes(CatalogIndexState indstate)
Definition: indexing.c:58
#define LanguageRelationId
Definition: pg_language.h:29
void AlterPublicationOwner_oid(Oid subid, Oid newOwnerId)
void performMultipleDeletions(const ObjectAddresses *objects, DropBehavior behavior, int flags)
Definition: dependency.c:360
#define elog
Definition: elog.h:219
bool checkSharedDependencies(Oid classId, Oid objectId, char **detail_msg, char **detail_log_msg)
Definition: pg_shdepend.c:521
#define SharedDependReferenceIndexId
Definition: indexing.h:224
Oid CatalogTupleInsertWithInfo(Relation heapRel, HeapTuple tup, CatalogIndexState indstate)
Definition: indexing.c:186
#define Natts_pg_shdepend
Definition: pg_shdepend.h:70
#define ExtensionRelationId
Definition: pg_extension.h:29
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *replValues, bool *replIsnull, bool *doReplace)
Definition: heaptuple.c:793
#define LargeObjectRelationId
Definition: pg_list.h:45
#define ConversionRelationId
Definition: pg_conversion.h:38
#define _(x)
Definition: elog.c:84
#define BTEqualStrategyNumber
Definition: stratnum.h:31
#define lfirst_oid(lc)
Definition: pg_list.h:108