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