OSDN Git Service

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