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