Age Owner TLA Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * alter.c
4 : * Drivers for generic alter commands
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/commands/alter.c
12 : *
13 : *-------------------------------------------------------------------------
14 : */
15 : #include "postgres.h"
16 :
17 : #include "access/htup_details.h"
18 : #include "access/relation.h"
19 : #include "access/sysattr.h"
20 : #include "access/table.h"
21 : #include "catalog/dependency.h"
22 : #include "catalog/indexing.h"
23 : #include "catalog/namespace.h"
24 : #include "catalog/objectaccess.h"
25 : #include "catalog/pg_collation.h"
26 : #include "catalog/pg_conversion.h"
27 : #include "catalog/pg_database_d.h"
28 : #include "catalog/pg_event_trigger.h"
29 : #include "catalog/pg_foreign_data_wrapper.h"
30 : #include "catalog/pg_foreign_server.h"
31 : #include "catalog/pg_language.h"
32 : #include "catalog/pg_largeobject.h"
33 : #include "catalog/pg_largeobject_metadata.h"
34 : #include "catalog/pg_namespace.h"
35 : #include "catalog/pg_opclass.h"
36 : #include "catalog/pg_opfamily.h"
37 : #include "catalog/pg_proc.h"
38 : #include "catalog/pg_statistic_ext.h"
39 : #include "catalog/pg_subscription.h"
40 : #include "catalog/pg_ts_config.h"
41 : #include "catalog/pg_ts_dict.h"
42 : #include "catalog/pg_ts_parser.h"
43 : #include "catalog/pg_ts_template.h"
44 : #include "commands/alter.h"
45 : #include "commands/collationcmds.h"
46 : #include "commands/conversioncmds.h"
47 : #include "commands/dbcommands.h"
48 : #include "commands/defrem.h"
49 : #include "commands/event_trigger.h"
50 : #include "commands/extension.h"
51 : #include "commands/policy.h"
52 : #include "commands/proclang.h"
53 : #include "commands/publicationcmds.h"
54 : #include "commands/schemacmds.h"
55 : #include "commands/subscriptioncmds.h"
56 : #include "commands/tablecmds.h"
57 : #include "commands/tablespace.h"
58 : #include "commands/trigger.h"
59 : #include "commands/typecmds.h"
60 : #include "commands/user.h"
61 : #include "miscadmin.h"
62 : #include "parser/parse_func.h"
63 : #include "replication/logicalworker.h"
64 : #include "rewrite/rewriteDefine.h"
65 : #include "tcop/utility.h"
66 : #include "utils/builtins.h"
67 : #include "utils/fmgroids.h"
68 : #include "utils/lsyscache.h"
69 : #include "utils/rel.h"
70 : #include "utils/syscache.h"
71 :
72 : static Oid AlterObjectNamespace_internal(Relation rel, Oid objid, Oid nspOid);
73 :
74 : /*
75 : * Raise an error to the effect that an object of the given name is already
76 : * present in the given namespace.
77 : */
78 : static void
3730 alvherre 79 GIC 12 : report_name_conflict(Oid classId, const char *name)
80 : {
3602 bruce 81 ECB : char *msgfmt;
82 :
3730 alvherre 83 GIC 12 : switch (classId)
84 : {
3730 alvherre 85 CBC 3 : case EventTriggerRelationId:
3730 alvherre 86 GIC 3 : msgfmt = gettext_noop("event trigger \"%s\" already exists");
3730 alvherre 87 CBC 3 : break;
88 3 : case ForeignDataWrapperRelationId:
89 3 : msgfmt = gettext_noop("foreign-data wrapper \"%s\" already exists");
90 3 : break;
91 3 : case ForeignServerRelationId:
92 3 : msgfmt = gettext_noop("server \"%s\" already exists");
93 3 : break;
94 3 : case LanguageRelationId:
95 3 : msgfmt = gettext_noop("language \"%s\" already exists");
96 3 : break;
2228 peter_e 97 LBC 0 : case PublicationRelationId:
98 0 : msgfmt = gettext_noop("publication \"%s\" already exists");
2228 peter_e 99 UBC 0 : break;
100 0 : case SubscriptionRelationId:
101 0 : msgfmt = gettext_noop("subscription \"%s\" already exists");
102 0 : break;
3730 alvherre 103 0 : default:
152 peter 104 UNC 0 : elog(ERROR, "unsupported object class: %u", classId);
3730 alvherre 105 EUB : break;
106 : }
107 :
3730 alvherre 108 GIC 12 : ereport(ERROR,
109 : (errcode(ERRCODE_DUPLICATE_OBJECT),
3730 alvherre 110 ECB : errmsg(msgfmt, name)));
111 : }
112 :
113 : static void
3730 alvherre 114 GIC 36 : report_namespace_conflict(Oid classId, const char *name, Oid nspOid)
115 : {
3602 bruce 116 ECB : char *msgfmt;
117 :
3730 alvherre 118 GIC 36 : Assert(OidIsValid(nspOid));
119 :
3730 alvherre 120 CBC 36 : switch (classId)
121 : {
122 6 : case ConversionRelationId:
3730 alvherre 123 GIC 6 : Assert(OidIsValid(nspOid));
3730 alvherre 124 CBC 6 : msgfmt = gettext_noop("conversion \"%s\" already exists in schema \"%s\"");
125 6 : break;
2207 126 6 : case StatisticExtRelationId:
127 6 : Assert(OidIsValid(nspOid));
2156 tgl 128 6 : msgfmt = gettext_noop("statistics object \"%s\" already exists in schema \"%s\"");
2207 alvherre 129 6 : break;
3730 130 6 : case TSParserRelationId:
131 6 : Assert(OidIsValid(nspOid));
132 6 : msgfmt = gettext_noop("text search parser \"%s\" already exists in schema \"%s\"");
133 6 : break;
134 6 : case TSDictionaryRelationId:
135 6 : Assert(OidIsValid(nspOid));
136 6 : msgfmt = gettext_noop("text search dictionary \"%s\" already exists in schema \"%s\"");
137 6 : break;
138 6 : case TSTemplateRelationId:
139 6 : Assert(OidIsValid(nspOid));
140 6 : msgfmt = gettext_noop("text search template \"%s\" already exists in schema \"%s\"");
141 6 : break;
142 6 : case TSConfigRelationId:
143 6 : Assert(OidIsValid(nspOid));
144 6 : msgfmt = gettext_noop("text search configuration \"%s\" already exists in schema \"%s\"");
145 6 : break;
3730 alvherre 146 LBC 0 : default:
152 peter 147 UNC 0 : elog(ERROR, "unsupported object class: %u", classId);
3730 alvherre 148 EUB : break;
149 : }
150 :
3730 alvherre 151 GIC 36 : ereport(ERROR,
152 : (errcode(ERRCODE_DUPLICATE_OBJECT),
3730 alvherre 153 ECB : errmsg(msgfmt, name, get_namespace_name(nspOid))));
154 : }
155 :
156 : /*
157 : * AlterObjectRename_internal
158 : *
159 : * Generic function to rename the given object, for simple cases (won't
160 : * work for tables, nor other cases where we need to do more than change
161 : * the name column of a single catalog entry).
162 : *
163 : * rel: catalog relation containing object (RowExclusiveLock'd by caller)
164 : * objectId: OID of object to be renamed
165 : * new_name: CString representation of new name
166 : */
167 : static void
3730 alvherre 168 GIC 208 : AlterObjectRename_internal(Relation rel, Oid objectId, const char *new_name)
169 : {
3730 alvherre 170 CBC 208 : Oid classId = RelationGetRelid(rel);
3730 alvherre 171 GIC 208 : int oidCacheId = get_object_catcache_oid(classId);
3730 alvherre 172 CBC 208 : int nameCacheId = get_object_catcache_name(classId);
173 208 : AttrNumber Anum_name = get_object_attnum_name(classId);
174 208 : AttrNumber Anum_namespace = get_object_attnum_namespace(classId);
175 208 : AttrNumber Anum_owner = get_object_attnum_owner(classId);
3730 alvherre 176 ECB : HeapTuple oldtup;
177 : HeapTuple newtup;
178 : Datum datum;
179 : bool isnull;
180 : Oid namespaceId;
181 : Oid ownerId;
182 : char *old_name;
183 : AclResult aclresult;
184 : Datum *values;
185 : bool *nulls;
186 : bool *replaces;
187 : NameData nameattrdata;
188 :
3730 alvherre 189 GIC 208 : oldtup = SearchSysCache1(oidCacheId, ObjectIdGetDatum(objectId));
190 208 : if (!HeapTupleIsValid(oldtup))
3730 alvherre 191 LBC 0 : elog(ERROR, "cache lookup failed for object %u of catalog \"%s\"",
3730 alvherre 192 ECB : objectId, RelationGetRelationName(rel));
3917 rhaas 193 EUB :
3730 alvherre 194 GIC 208 : datum = heap_getattr(oldtup, Anum_name,
195 : RelationGetDescr(rel), &isnull);
3730 alvherre 196 CBC 208 : Assert(!isnull);
3730 alvherre 197 GIC 208 : old_name = NameStr(*(DatumGetName(datum)));
7226 peter_e 198 ECB :
3730 alvherre 199 : /* Get OID of namespace */
3730 alvherre 200 GIC 208 : if (Anum_namespace > 0)
201 : {
3730 alvherre 202 CBC 141 : datum = heap_getattr(oldtup, Anum_namespace,
203 : RelationGetDescr(rel), &isnull);
204 141 : Assert(!isnull);
3730 alvherre 205 GIC 141 : namespaceId = DatumGetObjectId(datum);
3730 alvherre 206 ECB : }
207 : else
3730 alvherre 208 GIC 67 : namespaceId = InvalidOid;
209 :
3730 alvherre 210 ECB : /* Permission checks ... superusers can always do it */
3730 alvherre 211 GIC 208 : if (!superuser())
212 : {
3730 alvherre 213 ECB : /* Fail if object does not have an explicit owner */
3730 alvherre 214 GIC 123 : if (Anum_owner <= 0)
3730 alvherre 215 UIC 0 : ereport(ERROR,
3730 alvherre 216 ECB : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1165 alvherre 217 EUB : errmsg("must be superuser to rename %s",
218 : getObjectDescriptionOids(classId, objectId))));
219 :
220 : /* Otherwise, must be owner of the existing object */
3730 alvherre 221 GIC 123 : datum = heap_getattr(oldtup, Anum_owner,
222 : RelationGetDescr(rel), &isnull);
3730 alvherre 223 CBC 123 : Assert(!isnull);
3730 alvherre 224 GIC 123 : ownerId = DatumGetObjectId(datum);
3730 alvherre 225 ECB :
3730 alvherre 226 CBC 123 : if (!has_privs_of_role(GetUserId(), DatumGetObjectId(ownerId)))
1251 tgl 227 GIC 36 : aclcheck_error(ACLCHECK_NOT_OWNER, get_object_type(classId, objectId),
1251 tgl 228 ECB : old_name);
3730 alvherre 229 :
230 : /* User must have CREATE privilege on the namespace */
3730 alvherre 231 GIC 87 : if (OidIsValid(namespaceId))
232 : {
147 peter 233 GNC 72 : aclresult = object_aclcheck(NamespaceRelationId, namespaceId, GetUserId(),
234 : ACL_CREATE);
3730 alvherre 235 CBC 72 : if (aclresult != ACLCHECK_OK)
1954 peter_e 236 UIC 0 : aclcheck_error(aclresult, OBJECT_SCHEMA,
3730 alvherre 237 LBC 0 : get_namespace_name(namespaceId));
3730 alvherre 238 EUB : }
239 :
10 rhaas 240 GNC 87 : if (classId == SubscriptionRelationId)
241 : {
242 : Form_pg_subscription form;
243 :
244 : /* must have CREATE privilege on database */
245 9 : aclresult = object_aclcheck(DatabaseRelationId, MyDatabaseId,
246 : GetUserId(), ACL_CREATE);
247 9 : if (aclresult != ACLCHECK_OK)
248 3 : aclcheck_error(aclresult, OBJECT_DATABASE,
249 3 : get_database_name(MyDatabaseId));
250 :
251 : /*
252 : * Don't allow non-superuser modification of a subscription with
253 : * password_required=false.
254 : */
255 6 : form = (Form_pg_subscription) GETSTRUCT(oldtup);
256 6 : if (!form->subpasswordrequired && !superuser())
10 rhaas 257 UNC 0 : ereport(ERROR,
258 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
259 : errmsg("password_required=false is superuser-only"),
260 : errhint("Subscriptions with the password_required option set to false may only be created or modified by the superuser.")));
261 : }
3730 alvherre 262 EUB : }
263 :
264 : /*
3602 bruce 265 ECB : * Check for duplicate name (more friendly than unique-index failure).
266 : * Since this is just a friendliness check, we can just skip it in cases
267 : * where there isn't suitable support.
268 : */
3730 alvherre 269 GIC 169 : if (classId == ProcedureRelationId)
3730 alvherre 270 ECB : {
3730 alvherre 271 GIC 36 : Form_pg_proc proc = (Form_pg_proc) GETSTRUCT(oldtup);
3730 alvherre 272 ECB :
3730 alvherre 273 CBC 36 : IsThereFunctionInNamespace(new_name, proc->pronargs,
3588 noah 274 ECB : &proc->proargtypes, proc->pronamespace);
275 : }
3730 alvherre 276 GIC 133 : else if (classId == CollationRelationId)
277 : {
278 12 : Form_pg_collation coll = (Form_pg_collation) GETSTRUCT(oldtup);
279 :
3730 alvherre 280 CBC 12 : IsThereCollationInNamespace(new_name, coll->collnamespace);
3730 alvherre 281 ECB : }
3730 alvherre 282 GBC 121 : else if (classId == OperatorClassRelationId)
283 : {
3730 alvherre 284 GIC 9 : Form_pg_opclass opc = (Form_pg_opclass) GETSTRUCT(oldtup);
285 :
286 9 : IsThereOpClassInNamespace(new_name, opc->opcmethod,
287 : opc->opcnamespace);
288 : }
289 112 : else if (classId == OperatorFamilyRelationId)
290 : {
291 9 : Form_pg_opfamily opf = (Form_pg_opfamily) GETSTRUCT(oldtup);
292 :
293 9 : IsThereOpFamilyInNamespace(new_name, opf->opfmethod,
3730 alvherre 294 ECB : opf->opfnamespace);
295 : }
2228 peter_e 296 CBC 103 : else if (classId == SubscriptionRelationId)
297 : {
298 13 : if (SearchSysCacheExists2(SUBSCRIPTIONNAME, MyDatabaseId,
299 : CStringGetDatum(new_name)))
2228 peter_e 300 UIC 0 : report_name_conflict(classId, new_name);
1380 tgl 301 ECB :
302 : /* Also enforce regression testing naming rules, if enabled */
303 : #ifdef ENFORCE_REGRESSION_TEST_NAME_RESTRICTIONS
304 : if (strncmp(new_name, "regress_", 8) != 0)
305 : elog(WARNING, "subscriptions created by regression test cases should have names starting with \"regress_\"");
306 : #endif
307 :
308 : /* Wake up related replication workers to handle this change quickly */
93 tgl 309 GNC 13 : LogicalRepWorkersWakeupAtCommit(objectId);
2228 peter_e 310 ECB : }
3730 alvherre 311 GIC 90 : else if (nameCacheId >= 0)
3730 alvherre 312 ECB : {
3730 alvherre 313 GIC 90 : if (OidIsValid(namespaceId))
3730 alvherre 314 ECB : {
3730 alvherre 315 GIC 48 : if (SearchSysCacheExists2(nameCacheId,
316 : CStringGetDatum(new_name),
3730 alvherre 317 ECB : ObjectIdGetDatum(namespaceId)))
3730 alvherre 318 GIC 18 : report_namespace_conflict(classId, new_name, namespaceId);
3730 alvherre 319 ECB : }
320 : else
321 : {
3730 alvherre 322 GIC 42 : if (SearchSysCacheExists1(nameCacheId,
323 : CStringGetDatum(new_name)))
3730 alvherre 324 CBC 12 : report_name_conflict(classId, new_name);
325 : }
3730 alvherre 326 ECB : }
327 :
3730 alvherre 328 EUB : /* Build modified tuple */
3730 alvherre 329 GIC 121 : values = palloc0(RelationGetNumberOfAttributes(rel) * sizeof(Datum));
330 121 : nulls = palloc0(RelationGetNumberOfAttributes(rel) * sizeof(bool));
331 121 : replaces = palloc0(RelationGetNumberOfAttributes(rel) * sizeof(bool));
3588 noah 332 121 : namestrcpy(&nameattrdata, new_name);
333 121 : values[Anum_name - 1] = NameGetDatum(&nameattrdata);
3730 alvherre 334 121 : replaces[Anum_name - 1] = true;
335 121 : newtup = heap_modify_tuple(oldtup, RelationGetDescr(rel),
336 : values, nulls, replaces);
3730 alvherre 337 ECB :
338 : /* Perform actual update */
2259 alvherre 339 CBC 121 : CatalogTupleUpdate(rel, &oldtup->t_self, newtup);
340 :
3675 rhaas 341 121 : InvokeObjectPostAlterHook(classId, objectId, 0);
342 :
3730 alvherre 343 ECB : /* Release memory */
3730 alvherre 344 GIC 121 : pfree(values);
345 121 : pfree(nulls);
3730 alvherre 346 CBC 121 : pfree(replaces);
3730 alvherre 347 GIC 121 : heap_freetuple(newtup);
348 :
349 121 : ReleaseSysCache(oldtup);
3730 alvherre 350 CBC 121 : }
351 :
3730 alvherre 352 ECB : /*
353 : * Executes an ALTER OBJECT / RENAME TO statement. Based on the object
354 : * type, the function appropriate to that type is executed.
355 : *
356 : * Return value is the address of the renamed object.
357 : */
2959 358 : ObjectAddress
3730 alvherre 359 CBC 750 : ExecRenameStmt(RenameStmt *stmt)
3730 alvherre 360 ECB : {
3730 alvherre 361 CBC 750 : switch (stmt->renameType)
3730 alvherre 362 ECB : {
3029 alvherre 363 CBC 39 : case OBJECT_TABCONSTRAINT:
364 : case OBJECT_DOMCONSTRAINT:
3730 alvherre 365 GIC 39 : return RenameConstraint(stmt);
366 :
3730 alvherre 367 LBC 0 : case OBJECT_DATABASE:
3730 alvherre 368 UIC 0 : return RenameDatabase(stmt->subname, stmt->newname);
5920 tgl 369 ECB :
6494 tgl 370 GIC 15 : case OBJECT_ROLE:
3759 rhaas 371 15 : return RenameRole(stmt->subname, stmt->newname);
6494 tgl 372 ECB :
7226 peter_e 373 CBC 10 : case OBJECT_SCHEMA:
3759 rhaas 374 10 : return RenameSchema(stmt->subname, stmt->newname);
7226 peter_e 375 ECB :
6862 tgl 376 GIC 3 : case OBJECT_TABLESPACE:
3759 rhaas 377 CBC 3 : return RenameTableSpace(stmt->subname, stmt->newname);
6862 tgl 378 ECB :
7226 peter_e 379 GIC 255 : case OBJECT_TABLE:
380 : case OBJECT_SEQUENCE:
381 : case OBJECT_VIEW:
382 : case OBJECT_MATVIEW:
383 : case OBJECT_INDEX:
384 : case OBJECT_FOREIGN_TABLE:
3759 rhaas 385 255 : return RenameRelation(stmt);
386 :
7226 peter_e 387 CBC 149 : case OBJECT_COLUMN:
388 : case OBJECT_ATTRIBUTE:
3759 rhaas 389 149 : return renameatt(stmt);
390 :
3712 tgl 391 17 : case OBJECT_RULE:
3712 tgl 392 GIC 17 : return RenameRewriteRule(stmt->relation, stmt->subname,
3712 tgl 393 CBC 17 : stmt->newname);
394 :
7226 peter_e 395 GBC 20 : case OBJECT_TRIGGER:
3759 rhaas 396 20 : return renametrig(stmt);
397 :
3124 sfrost 398 CBC 9 : case OBJECT_POLICY:
399 9 : return rename_policy(stmt);
400 :
3730 alvherre 401 16 : case OBJECT_DOMAIN:
3730 alvherre 402 ECB : case OBJECT_TYPE:
3730 alvherre 403 GIC 16 : return RenameType(stmt);
5710 tgl 404 ECB :
3730 alvherre 405 CBC 217 : case OBJECT_AGGREGATE:
406 : case OBJECT_COLLATION:
3730 alvherre 407 ECB : case OBJECT_CONVERSION:
408 : case OBJECT_EVENT_TRIGGER:
409 : case OBJECT_FDW:
410 : case OBJECT_FOREIGN_SERVER:
411 : case OBJECT_FUNCTION:
412 : case OBJECT_OPCLASS:
413 : case OBJECT_OPFAMILY:
414 : case OBJECT_LANGUAGE:
1956 peter_e 415 : case OBJECT_PROCEDURE:
416 : case OBJECT_ROUTINE:
2207 alvherre 417 : case OBJECT_STATISTIC_EXT:
418 : case OBJECT_TSCONFIGURATION:
5710 tgl 419 : case OBJECT_TSDICTIONARY:
3730 alvherre 420 : case OBJECT_TSPARSER:
5710 tgl 421 : case OBJECT_TSTEMPLATE:
422 : case OBJECT_PUBLICATION:
2228 peter_e 423 : case OBJECT_SUBSCRIPTION:
3730 alvherre 424 : {
425 : ObjectAddress address;
3602 bruce 426 : Relation catalog;
427 : Relation relation;
428 :
3730 alvherre 429 CBC 217 : address = get_object_address(stmt->renameType,
430 : stmt->object,
3730 alvherre 431 ECB : &relation,
432 : AccessExclusiveLock, false);
3730 alvherre 433 CBC 208 : Assert(relation == NULL);
434 :
1539 andres 435 GIC 208 : catalog = table_open(address.classId, RowExclusiveLock);
3730 alvherre 436 208 : AlterObjectRename_internal(catalog,
437 : address.objectId,
438 208 : stmt->newname);
1539 andres 439 121 : table_close(catalog, RowExclusiveLock);
440 :
2959 alvherre 441 121 : return address;
442 : }
443 :
7226 peter_e 444 UIC 0 : default:
7203 tgl 445 0 : elog(ERROR, "unrecognized rename stmt type: %d",
446 : (int) stmt->renameType);
447 : return InvalidObjectAddress; /* keep compiler happy */
448 : }
449 : }
450 :
451 : /*
452 : * Executes an ALTER OBJECT / [NO] DEPENDS ON EXTENSION statement.
453 : *
454 : * Return value is the address of the altered object. refAddress is an output
455 : * argument which, if not null, receives the address of the object that the
456 : * altered object now depends on.
2560 alvherre 457 ECB : */
458 : ObjectAddress
2560 alvherre 459 GIC 23 : ExecAlterObjectDependsStmt(AlterObjectDependsStmt *stmt, ObjectAddress *refAddress)
460 : {
2495 rhaas 461 ECB : ObjectAddress address;
462 : ObjectAddress refAddr;
463 : Relation rel;
2560 alvherre 464 :
465 : address =
2339 peter_e 466 CBC 23 : get_object_address_rv(stmt->objectType, stmt->relation, (List *) stmt->object,
2153 bruce 467 ECB : &rel, AccessExclusiveLock, false);
468 :
1154 alvherre 469 : /*
470 : * Verify that the user is entitled to run the command.
471 : *
1154 alvherre 472 EUB : * We don't check any privileges on the extension, because that's not
473 : * needed. The object owner is stipulating, by running this command, that
474 : * the extension owner can drop the object whenever they feel like it,
475 : * which is not considered a problem.
476 : */
1154 alvherre 477 GIC 23 : check_object_ownership(GetUserId(),
478 : stmt->objectType, address, stmt->object, rel);
479 :
480 : /*
481 : * If a relation was involved, it would have been opened and locked. We
482 : * don't need the relation here, but we'll retain the lock until commit.
483 : */
2560 484 23 : if (rel)
1539 andres 485 17 : table_close(rel, NoLock);
486 :
2339 peter_e 487 CBC 23 : refAddr = get_object_address(OBJECT_EXTENSION, (Node *) stmt->extname,
488 : &rel, AccessExclusiveLock, false);
2560 alvherre 489 GIC 23 : Assert(rel == NULL);
490 23 : if (refAddress)
491 23 : *refAddress = refAddr;
492 :
1084 493 23 : if (stmt->remove)
1084 alvherre 494 ECB : {
1084 alvherre 495 GIC 4 : deleteDependencyRecordsForSpecific(address.classId, address.objectId,
496 : DEPENDENCY_AUTO_EXTENSION,
497 : refAddr.classId, refAddr.objectId);
498 : }
499 : else
500 : {
501 : List *currexts;
502 :
503 : /* Avoid duplicates */
504 19 : currexts = getAutoExtensionsOfObject(address.classId,
1084 alvherre 505 ECB : address.objectId);
1084 alvherre 506 GIC 19 : if (!list_member_oid(currexts, refAddr.objectId))
507 18 : recordDependencyOn(&address, &refAddr, DEPENDENCY_AUTO_EXTENSION);
508 : }
509 :
2560 510 23 : return address;
511 : }
2560 alvherre 512 ECB :
6460 tgl 513 : /*
514 : * Executes an ALTER OBJECT / SET SCHEMA statement. Based on the object
515 : * type, the function appropriate to that type is executed.
516 : *
2959 alvherre 517 : * Return value is that of the altered object.
518 : *
519 : * oldSchemaAddr is an output argument which, if not NULL, is set to the object
520 : * address of the original schema.
6460 tgl 521 : */
522 : ObjectAddress
2959 alvherre 523 CBC 194 : ExecAlterObjectSchemaStmt(AlterObjectSchemaStmt *stmt,
524 : ObjectAddress *oldSchemaAddr)
525 : {
526 : ObjectAddress address;
527 : Oid oldNspOid;
528 :
6460 tgl 529 GIC 194 : switch (stmt->objectType)
530 : {
4443 531 3 : case OBJECT_EXTENSION:
577 peter 532 CBC 3 : address = AlterExtensionNamespace(strVal(stmt->object), stmt->newschema,
533 : oldSchemaAddr ? &oldNspOid : NULL);
2959 alvherre 534 2 : break;
4443 tgl 535 ECB :
3736 alvherre 536 GIC 49 : case OBJECT_FOREIGN_TABLE:
537 : case OBJECT_SEQUENCE:
6460 tgl 538 ECB : case OBJECT_TABLE:
539 : case OBJECT_VIEW:
540 : case OBJECT_MATVIEW:
2959 alvherre 541 GIC 49 : address = AlterTableNamespace(stmt,
542 : oldSchemaAddr ? &oldNspOid : NULL);
543 48 : break;
544 :
3846 545 9 : case OBJECT_DOMAIN:
546 : case OBJECT_TYPE:
2339 peter_e 547 9 : address = AlterTypeNamespace(castNode(List, stmt->object), stmt->newschema,
548 : stmt->objectType,
549 : oldSchemaAddr ? &oldNspOid : NULL);
2959 alvherre 550 9 : break;
4517 rhaas 551 ECB :
552 : /* generic code path */
3736 alvherre 553 GIC 133 : case OBJECT_AGGREGATE:
554 : case OBJECT_COLLATION:
555 : case OBJECT_CONVERSION:
556 : case OBJECT_FUNCTION:
3846 alvherre 557 ECB : case OBJECT_OPERATOR:
558 : case OBJECT_OPCLASS:
559 : case OBJECT_OPFAMILY:
1956 peter_e 560 : case OBJECT_PROCEDURE:
561 : case OBJECT_ROUTINE:
2207 alvherre 562 : case OBJECT_STATISTIC_EXT:
563 : case OBJECT_TSCONFIGURATION:
4517 rhaas 564 : case OBJECT_TSDICTIONARY:
565 : case OBJECT_TSPARSER:
566 : case OBJECT_TSTEMPLATE:
567 : {
568 : Relation catalog;
3846 alvherre 569 : Relation relation;
570 : Oid classId;
571 : Oid nspOid;
572 :
3846 alvherre 573 CBC 133 : address = get_object_address(stmt->objectType,
574 : stmt->object,
3846 alvherre 575 ECB : &relation,
576 : AccessExclusiveLock,
577 : false);
3846 alvherre 578 CBC 130 : Assert(relation == NULL);
3846 alvherre 579 GIC 130 : classId = address.classId;
1539 andres 580 130 : catalog = table_open(classId, RowExclusiveLock);
3846 alvherre 581 CBC 130 : nspOid = LookupCreationNamespace(stmt->newschema);
582 :
2959 alvherre 583 GIC 130 : oldNspOid = AlterObjectNamespace_internal(catalog, address.objectId,
584 : nspOid);
1539 andres 585 73 : table_close(catalog, RowExclusiveLock);
586 : }
6460 tgl 587 73 : break;
588 :
6460 tgl 589 UIC 0 : default:
590 0 : elog(ERROR, "unrecognized AlterObjectSchemaStmt type: %d",
591 : (int) stmt->objectType);
592 : return InvalidObjectAddress; /* keep compiler happy */
593 : }
594 :
2959 alvherre 595 GIC 132 : if (oldSchemaAddr)
596 132 : ObjectAddressSet(*oldSchemaAddr, NamespaceRelationId, oldNspOid);
597 :
598 132 : return address;
599 : }
600 :
4443 tgl 601 ECB : /*
602 : * Change an object's namespace given its classOid and object Oid.
603 : *
604 : * Objects that don't have a namespace should be ignored.
605 : *
606 : * This function is currently used only by ALTER EXTENSION SET SCHEMA,
607 : * so it only needs to cover object types that can be members of an
608 : * extension, and it doesn't have to deal with certain special cases
609 : * such as not wanting to process array types --- those should never
610 : * be direct members of an extension anyway. Nonetheless, we insist
2156 611 : * on listing all OCLASS types in the switch.
612 : *
4443 613 : * Returns the OID of the object's previous namespace, or InvalidOid if
614 : * object doesn't have a schema.
615 : */
616 : Oid
3812 alvherre 617 GBC 3 : AlterObjectNamespace_oid(Oid classId, Oid objid, Oid nspOid,
3812 alvherre 618 EUB : ObjectAddresses *objsMoved)
619 : {
4443 tgl 620 GIC 3 : Oid oldNspOid = InvalidOid;
621 : ObjectAddress dep;
622 :
4443 tgl 623 CBC 3 : dep.classId = classId;
624 3 : dep.objectId = objid;
4443 tgl 625 GIC 3 : dep.objectSubId = 0;
4443 tgl 626 ECB :
4443 tgl 627 GIC 3 : switch (getObjectClass(&dep))
628 : {
4443 tgl 629 UIC 0 : case OCLASS_CLASS:
630 : {
631 : Relation rel;
632 :
4382 bruce 633 0 : rel = relation_open(objid, AccessExclusiveLock);
634 0 : oldNspOid = RelationGetNamespace(rel);
635 :
3812 alvherre 636 0 : AlterTableNamespaceInternal(rel, oldNspOid, nspOid, objsMoved);
637 :
4382 bruce 638 0 : relation_close(rel, NoLock);
639 0 : break;
640 : }
641 :
4443 tgl 642 0 : case OCLASS_TYPE:
3812 alvherre 643 0 : oldNspOid = AlterTypeNamespace_oid(objid, nspOid, objsMoved);
4443 tgl 644 0 : break;
4443 tgl 645 ECB :
2156 tgl 646 GIC 3 : case OCLASS_PROC:
647 : case OCLASS_COLLATION:
4443 tgl 648 ECB : case OCLASS_CONVERSION:
649 : case OCLASS_OPERATOR:
650 : case OCLASS_OPCLASS:
651 : case OCLASS_OPFAMILY:
2156 652 : case OCLASS_STATISTIC_EXT:
4443 653 : case OCLASS_TSPARSER:
654 : case OCLASS_TSDICT:
655 : case OCLASS_TSTEMPLATE:
656 : case OCLASS_TSCONFIG:
3846 alvherre 657 EUB : {
658 : Relation catalog;
659 :
1539 andres 660 GIC 3 : catalog = table_open(classId, RowExclusiveLock);
3846 alvherre 661 EUB :
3846 alvherre 662 GBC 3 : oldNspOid = AlterObjectNamespace_internal(catalog, objid,
663 : nspOid);
3846 alvherre 664 EUB :
1539 andres 665 GIC 3 : table_close(catalog, RowExclusiveLock);
3846 alvherre 666 EUB : }
4443 tgl 667 GBC 3 : break;
668 :
2156 tgl 669 UIC 0 : case OCLASS_CAST:
2156 tgl 670 EUB : case OCLASS_CONSTRAINT:
671 : case OCLASS_DEFAULT:
672 : case OCLASS_LANGUAGE:
673 : case OCLASS_LARGEOBJECT:
2156 tgl 674 ECB : case OCLASS_AM:
675 : case OCLASS_AMOP:
676 : case OCLASS_AMPROC:
677 : case OCLASS_REWRITE:
678 : case OCLASS_TRIGGER:
679 : case OCLASS_SCHEMA:
680 : case OCLASS_ROLE:
681 : case OCLASS_ROLE_MEMBERSHIP:
682 : case OCLASS_DATABASE:
683 : case OCLASS_TBLSPACE:
684 : case OCLASS_FDW:
685 : case OCLASS_FOREIGN_SERVER:
686 : case OCLASS_USER_MAPPING:
687 : case OCLASS_DEFACL:
688 : case OCLASS_EXTENSION:
689 : case OCLASS_EVENT_TRIGGER:
690 : case OCLASS_PARAMETER_ACL:
691 : case OCLASS_POLICY:
692 : case OCLASS_PUBLICATION:
693 : case OCLASS_PUBLICATION_NAMESPACE:
694 : case OCLASS_PUBLICATION_REL:
695 : case OCLASS_SUBSCRIPTION:
696 : case OCLASS_TRANSFORM:
697 : /* ignore object types that don't have schema-qualified names */
4443 tgl 698 UBC 0 : break;
699 :
700 : /*
701 : * There's intentionally no default: case here; we want the
702 : * compiler to warn if a new OCLASS hasn't been handled above.
703 : */
704 : }
705 :
4443 tgl 706 GIC 3 : return oldNspOid;
707 : }
708 :
709 : /*
710 : * Generic function to change the namespace of a given object, for simple
711 : * cases (won't work for tables, nor other cases where we need to do more
712 : * than change the namespace column of a single catalog entry).
713 : *
714 : * rel: catalog relation containing object (RowExclusiveLock'd by caller)
715 : * objid: OID of object to change the namespace of
716 : * nspOid: OID of new namespace
717 : *
718 : * Returns the OID of the object's previous namespace.
719 : */
720 : static Oid
3846 alvherre 721 133 : AlterObjectNamespace_internal(Relation rel, Oid objid, Oid nspOid)
722 : {
4443 tgl 723 133 : Oid classId = RelationGetRelid(rel);
3846 alvherre 724 133 : int oidCacheId = get_object_catcache_oid(classId);
725 133 : int nameCacheId = get_object_catcache_name(classId);
726 133 : AttrNumber Anum_name = get_object_attnum_name(classId);
3846 alvherre 727 GBC 133 : AttrNumber Anum_namespace = get_object_attnum_namespace(classId);
3846 alvherre 728 GIC 133 : AttrNumber Anum_owner = get_object_attnum_owner(classId);
729 : Oid oldNspOid;
730 : Datum name,
731 : namespace;
732 : bool isnull;
733 : HeapTuple tup,
734 : newtup;
4517 rhaas 735 ECB : Datum *values;
736 : bool *nulls;
737 : bool *replaces;
738 :
4443 tgl 739 GIC 133 : tup = SearchSysCacheCopy1(oidCacheId, ObjectIdGetDatum(objid));
4517 rhaas 740 133 : if (!HeapTupleIsValid(tup)) /* should not happen */
4443 tgl 741 UIC 0 : elog(ERROR, "cache lookup failed for object %u of catalog \"%s\"",
742 : objid, RelationGetRelationName(rel));
743 :
4443 tgl 744 GIC 133 : name = heap_getattr(tup, Anum_name, RelationGetDescr(rel), &isnull);
745 133 : Assert(!isnull);
3846 alvherre 746 133 : namespace = heap_getattr(tup, Anum_namespace, RelationGetDescr(rel),
747 : &isnull);
4443 tgl 748 133 : Assert(!isnull);
4517 rhaas 749 133 : oldNspOid = DatumGetObjectId(namespace);
4517 rhaas 750 ECB :
751 : /*
2495 752 : * If the object is already in the correct namespace, we don't need to do
753 : * anything except fire the object access hook.
2698 754 : */
2698 rhaas 755 CBC 133 : if (oldNspOid == nspOid)
2698 rhaas 756 ECB : {
2698 rhaas 757 CBC 3 : InvokeObjectPostAlterHook(classId, objid, 0);
2698 rhaas 758 GIC 3 : return oldNspOid;
759 : }
760 :
761 : /* Check basic namespace related issues */
762 130 : CheckSetNamespace(oldNspOid, nspOid);
763 :
764 : /* Permission checks ... superusers can always do it */
4517 765 130 : if (!superuser())
766 : {
767 : Datum owner;
4517 rhaas 768 ECB : Oid ownerId;
769 : AclResult aclresult;
4517 rhaas 770 EUB :
771 : /* Fail if object does not have an explicit owner */
4443 tgl 772 GIC 78 : if (Anum_owner <= 0)
4517 rhaas 773 LBC 0 : ereport(ERROR,
4517 rhaas 774 ECB : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1165 alvherre 775 : errmsg("must be superuser to set schema of %s",
776 : getObjectDescriptionOids(classId, objid))));
4517 rhaas 777 :
778 : /* Otherwise, must be owner of the existing object */
4443 tgl 779 GIC 78 : owner = heap_getattr(tup, Anum_owner, RelationGetDescr(rel), &isnull);
780 78 : Assert(!isnull);
4517 rhaas 781 78 : ownerId = DatumGetObjectId(owner);
782 :
783 78 : if (!has_privs_of_role(GetUserId(), ownerId))
1251 tgl 784 CBC 27 : aclcheck_error(ACLCHECK_NOT_OWNER, get_object_type(classId, objid),
4517 rhaas 785 GIC 27 : NameStr(*(DatumGetName(name))));
4517 rhaas 786 ECB :
4443 tgl 787 : /* User must have CREATE privilege on new namespace */
147 peter 788 GNC 51 : aclresult = object_aclcheck(NamespaceRelationId, nspOid, GetUserId(), ACL_CREATE);
4517 rhaas 789 GIC 51 : if (aclresult != ACLCHECK_OK)
1954 peter_e 790 UIC 0 : aclcheck_error(aclresult, OBJECT_SCHEMA,
4443 tgl 791 LBC 0 : get_namespace_name(nspOid));
792 : }
793 :
4443 tgl 794 ECB : /*
795 : * Check for duplicate name (more friendly than unique-index failure).
796 : * Since this is just a friendliness check, we can just skip it in cases
797 : * where there isn't suitable support.
798 : */
3736 alvherre 799 GIC 103 : if (classId == ProcedureRelationId)
800 : {
3730 alvherre 801 CBC 22 : Form_pg_proc proc = (Form_pg_proc) GETSTRUCT(tup);
3736 alvherre 802 EUB :
3736 alvherre 803 GIC 22 : IsThereFunctionInNamespace(NameStr(proc->proname), proc->pronargs,
804 : &proc->proargtypes, nspOid);
805 : }
806 81 : else if (classId == CollationRelationId)
807 : {
3730 alvherre 808 CBC 6 : Form_pg_collation coll = (Form_pg_collation) GETSTRUCT(tup);
3730 alvherre 809 ECB :
3730 alvherre 810 CBC 6 : IsThereCollationInNamespace(NameStr(coll->collname), nspOid);
811 : }
812 75 : else if (classId == OperatorClassRelationId)
3730 alvherre 813 ECB : {
3730 alvherre 814 CBC 9 : Form_pg_opclass opc = (Form_pg_opclass) GETSTRUCT(tup);
815 :
3730 alvherre 816 GIC 9 : IsThereOpClassInNamespace(NameStr(opc->opcname),
3730 alvherre 817 ECB : opc->opcmethod, nspOid);
818 : }
3730 alvherre 819 GBC 66 : else if (classId == OperatorFamilyRelationId)
3730 alvherre 820 EUB : {
3730 alvherre 821 GIC 9 : Form_pg_opfamily opf = (Form_pg_opfamily) GETSTRUCT(tup);
822 :
823 9 : IsThereOpFamilyInNamespace(NameStr(opf->opfname),
824 : opf->opfmethod, nspOid);
825 : }
3736 826 108 : else if (nameCacheId >= 0 &&
827 51 : SearchSysCacheExists2(nameCacheId, name,
3736 alvherre 828 ECB : ObjectIdGetDatum(nspOid)))
3736 alvherre 829 GIC 18 : report_namespace_conflict(classId,
3736 alvherre 830 CBC 18 : NameStr(*(DatumGetName(name))),
831 : nspOid);
4443 tgl 832 ECB :
833 : /* Build modified tuple */
4443 tgl 834 GIC 73 : values = palloc0(RelationGetNumberOfAttributes(rel) * sizeof(Datum));
4443 tgl 835 CBC 73 : nulls = palloc0(RelationGetNumberOfAttributes(rel) * sizeof(bool));
4443 tgl 836 GIC 73 : replaces = palloc0(RelationGetNumberOfAttributes(rel) * sizeof(bool));
4443 tgl 837 CBC 73 : values[Anum_namespace - 1] = ObjectIdGetDatum(nspOid);
4517 rhaas 838 GIC 73 : replaces[Anum_namespace - 1] = true;
4443 tgl 839 CBC 73 : newtup = heap_modify_tuple(tup, RelationGetDescr(rel),
840 : values, nulls, replaces);
4517 rhaas 841 ECB :
842 : /* Perform actual update */
2259 alvherre 843 CBC 73 : CatalogTupleUpdate(rel, &tup->t_self, newtup);
844 :
4517 rhaas 845 ECB : /* Release memory */
4517 rhaas 846 GIC 73 : pfree(values);
847 73 : pfree(nulls);
4517 rhaas 848 CBC 73 : pfree(replaces);
849 :
4517 rhaas 850 ECB : /* update dependencies to point to the new schema */
4517 rhaas 851 GIC 73 : changeDependencyFor(classId, objid,
4517 rhaas 852 ECB : NamespaceRelationId, oldNspOid, nspOid);
853 :
3675 rhaas 854 GIC 73 : InvokeObjectPostAlterHook(classId, objid, 0);
3675 rhaas 855 ECB :
4443 tgl 856 CBC 73 : return oldNspOid;
857 : }
4517 rhaas 858 ECB :
6862 tgl 859 : /*
860 : * Executes an ALTER OBJECT / OWNER TO statement. Based on the object
861 : * type, the function appropriate to that type is executed.
862 : */
2959 alvherre 863 : ObjectAddress
6862 tgl 864 CBC 1014 : ExecAlterOwnerStmt(AlterOwnerStmt *stmt)
6862 tgl 865 ECB : {
2953 alvherre 866 CBC 1014 : Oid newowner = get_rolespec_oid(stmt->newowner, false);
6862 tgl 867 ECB :
6862 tgl 868 CBC 1005 : switch (stmt->objectType)
869 : {
6862 tgl 870 GIC 18 : case OBJECT_DATABASE:
577 peter 871 18 : return AlterDatabaseOwner(strVal(stmt->object), newowner);
6862 tgl 872 ECB :
6862 tgl 873 GIC 26 : case OBJECT_SCHEMA:
577 peter 874 26 : return AlterSchemaOwner(strVal(stmt->object), newowner);
6862 tgl 875 ECB :
6862 tgl 876 CBC 48 : case OBJECT_TYPE:
6862 tgl 877 ECB : case OBJECT_DOMAIN: /* same as TYPE */
2339 peter_e 878 GIC 48 : return AlterTypeOwner(castNode(List, stmt->object), newowner, stmt->objectType);
879 : break;
6862 tgl 880 ECB :
5224 peter_e 881 GIC 10 : case OBJECT_FDW:
577 peter 882 10 : return AlterForeignDataWrapperOwner(strVal(stmt->object),
3759 rhaas 883 ECB : newowner);
884 :
5224 peter_e 885 CBC 34 : case OBJECT_FOREIGN_SERVER:
577 peter 886 GIC 34 : return AlterForeignServerOwner(strVal(stmt->object),
887 : newowner);
888 :
3917 rhaas 889 6 : case OBJECT_EVENT_TRIGGER:
577 peter 890 6 : return AlterEventTriggerOwner(strVal(stmt->object),
891 : newowner);
892 :
2271 peter_e 893 CBC 12 : case OBJECT_PUBLICATION:
577 peter 894 GIC 12 : return AlterPublicationOwner(strVal(stmt->object),
2271 peter_e 895 ECB : newowner);
896 :
2271 peter_e 897 CBC 6 : case OBJECT_SUBSCRIPTION:
577 peter 898 GIC 6 : return AlterSubscriptionOwner(strVal(stmt->object),
2271 peter_e 899 ECB : newowner);
900 :
901 : /* Generic cases */
3840 alvherre 902 CBC 845 : case OBJECT_AGGREGATE:
3840 alvherre 903 ECB : case OBJECT_COLLATION:
904 : case OBJECT_CONVERSION:
905 : case OBJECT_FUNCTION:
906 : case OBJECT_LANGUAGE:
907 : case OBJECT_LARGEOBJECT:
908 : case OBJECT_OPERATOR:
909 : case OBJECT_OPCLASS:
910 : case OBJECT_OPFAMILY:
1956 peter_e 911 : case OBJECT_PROCEDURE:
912 : case OBJECT_ROUTINE:
913 : case OBJECT_STATISTIC_EXT:
3840 alvherre 914 : case OBJECT_TABLESPACE:
915 : case OBJECT_TSDICTIONARY:
916 : case OBJECT_TSCONFIGURATION:
917 : {
918 : Relation catalog;
919 : Relation relation;
920 : Oid classId;
921 : ObjectAddress address;
922 :
3840 alvherre 923 CBC 845 : address = get_object_address(stmt->objectType,
924 : stmt->object,
925 : &relation,
3840 alvherre 926 ECB : AccessExclusiveLock,
927 : false);
3840 alvherre 928 GIC 841 : Assert(relation == NULL);
929 841 : classId = address.classId;
930 :
3840 alvherre 931 ECB : /*
932 : * XXX - get_object_address returns Oid of pg_largeobject
933 : * catalog for OBJECT_LARGEOBJECT because of historical
934 : * reasons. Fix up it here.
935 : */
3840 alvherre 936 GIC 841 : if (classId == LargeObjectRelationId)
937 6 : classId = LargeObjectMetadataRelationId;
938 :
1539 andres 939 841 : catalog = table_open(classId, RowExclusiveLock);
940 :
3840 alvherre 941 841 : AlterObjectOwner_internal(catalog, address.objectId, newowner);
1539 andres 942 754 : table_close(catalog, RowExclusiveLock);
943 :
2959 alvherre 944 754 : return address;
945 : }
946 : break;
947 :
6862 tgl 948 UIC 0 : default:
949 0 : elog(ERROR, "unrecognized AlterOwnerStmt type: %d",
950 : (int) stmt->objectType);
951 : return InvalidObjectAddress; /* keep compiler happy */
6862 tgl 952 ECB : }
953 : }
954 :
955 : /*
956 : * Generic function to change the ownership of a given object, for simple
3840 alvherre 957 : * cases (won't work for tables, nor other cases where we need to do more than
958 : * change the ownership column of a single catalog entry).
959 : *
960 : * rel: catalog relation containing object (RowExclusiveLock'd by caller)
961 : * objectId: OID of object to change the ownership of
962 : * new_ownerId: OID of new object owner
963 : */
964 : void
3840 alvherre 965 CBC 844 : AlterObjectOwner_internal(Relation rel, Oid objectId, Oid new_ownerId)
3840 alvherre 966 ECB : {
3840 alvherre 967 GIC 844 : Oid classId = RelationGetRelid(rel);
1601 andres 968 CBC 844 : AttrNumber Anum_oid = get_object_attnum_oid(classId);
3840 alvherre 969 GIC 844 : AttrNumber Anum_owner = get_object_attnum_owner(classId);
3840 alvherre 970 CBC 844 : AttrNumber Anum_namespace = get_object_attnum_namespace(classId);
971 844 : AttrNumber Anum_acl = get_object_attnum_acl(classId);
3840 alvherre 972 GIC 844 : AttrNumber Anum_name = get_object_attnum_name(classId);
3840 alvherre 973 ECB : HeapTuple oldtup;
974 : Datum datum;
975 : bool isnull;
976 : Oid old_ownerId;
3840 alvherre 977 GBC 844 : Oid namespaceId = InvalidOid;
3840 alvherre 978 EUB :
1601 andres 979 GIC 844 : oldtup = get_catalog_object_by_oid(rel, Anum_oid, objectId);
3840 alvherre 980 844 : if (oldtup == NULL)
3840 alvherre 981 UIC 0 : elog(ERROR, "cache lookup failed for object %u of catalog \"%s\"",
982 : objectId, RelationGetRelationName(rel));
983 :
3840 alvherre 984 GIC 844 : datum = heap_getattr(oldtup, Anum_owner,
985 : RelationGetDescr(rel), &isnull);
986 844 : Assert(!isnull);
987 844 : old_ownerId = DatumGetObjectId(datum);
988 :
989 844 : if (Anum_namespace != InvalidAttrNumber)
990 : {
991 509 : datum = heap_getattr(oldtup, Anum_namespace,
992 : RelationGetDescr(rel), &isnull);
993 509 : Assert(!isnull);
3840 alvherre 994 CBC 509 : namespaceId = DatumGetObjectId(datum);
995 : }
3840 alvherre 996 ECB :
3840 alvherre 997 CBC 844 : if (old_ownerId != new_ownerId)
3840 alvherre 998 ECB : {
999 : AttrNumber nattrs;
1000 : HeapTuple newtup;
1001 : Datum *values;
1002 : bool *nulls;
1003 : bool *replaces;
1004 :
1005 : /* Superusers can bypass permission checks */
3840 alvherre 1006 CBC 179 : if (!superuser())
1007 : {
3840 alvherre 1008 ECB : /* must be owner */
3840 alvherre 1009 CBC 117 : if (!has_privs_of_role(GetUserId(), old_ownerId))
3840 alvherre 1010 EUB : {
1011 : char *objname;
1012 : char namebuf[NAMEDATALEN];
3840 alvherre 1013 ECB :
3840 alvherre 1014 GIC 30 : if (Anum_name != InvalidAttrNumber)
3840 alvherre 1015 ECB : {
3840 alvherre 1016 CBC 30 : datum = heap_getattr(oldtup, Anum_name,
1017 : RelationGetDescr(rel), &isnull);
1018 30 : Assert(!isnull);
3840 alvherre 1019 GIC 30 : objname = NameStr(*DatumGetName(datum));
3840 alvherre 1020 ECB : }
1021 : else
1022 : {
1601 andres 1023 LBC 0 : snprintf(namebuf, sizeof(namebuf), "%u", objectId);
3840 alvherre 1024 UIC 0 : objname = namebuf;
1025 : }
1251 tgl 1026 CBC 30 : aclcheck_error(ACLCHECK_NOT_OWNER, get_object_type(classId, objectId),
1027 : objname);
1028 : }
1029 : /* Must be able to become new owner */
142 rhaas 1030 GNC 87 : check_can_set_role(GetUserId(), new_ownerId);
1031 :
1032 : /* New owner must have CREATE privilege on namespace */
3840 alvherre 1033 GIC 30 : if (OidIsValid(namespaceId))
1034 : {
3602 bruce 1035 ECB : AclResult aclresult;
1036 :
147 peter 1037 GNC 27 : aclresult = object_aclcheck(NamespaceRelationId, namespaceId, new_ownerId,
3840 alvherre 1038 ECB : ACL_CREATE);
3840 alvherre 1039 GIC 27 : if (aclresult != ACLCHECK_OK)
1954 peter_e 1040 UIC 0 : aclcheck_error(aclresult, OBJECT_SCHEMA,
3840 alvherre 1041 0 : get_namespace_name(namespaceId));
1042 : }
3840 alvherre 1043 ECB : }
1044 :
1045 : /* Build a modified tuple */
3840 alvherre 1046 GIC 92 : nattrs = RelationGetNumberOfAttributes(rel);
3840 alvherre 1047 CBC 92 : values = palloc0(nattrs * sizeof(Datum));
1048 92 : nulls = palloc0(nattrs * sizeof(bool));
3840 alvherre 1049 GIC 92 : replaces = palloc0(nattrs * sizeof(bool));
1050 92 : values[Anum_owner - 1] = ObjectIdGetDatum(new_ownerId);
1051 92 : replaces[Anum_owner - 1] = true;
3840 alvherre 1052 EUB :
1053 : /*
1054 : * Determine the modified ACL for the new owner. This is only
3840 alvherre 1055 ECB : * necessary when the ACL is non-null.
1056 : */
3840 alvherre 1057 GIC 92 : if (Anum_acl != InvalidAttrNumber)
1058 : {
3840 alvherre 1059 CBC 41 : datum = heap_getattr(oldtup,
1060 : Anum_acl, RelationGetDescr(rel), &isnull);
3840 alvherre 1061 GIC 41 : if (!isnull)
3840 alvherre 1062 ECB : {
1063 : Acl *newAcl;
1064 :
3840 alvherre 1065 GIC 1 : newAcl = aclnewowner(DatumGetAclP(datum),
3840 alvherre 1066 ECB : old_ownerId, new_ownerId);
3840 alvherre 1067 GIC 1 : values[Anum_acl - 1] = PointerGetDatum(newAcl);
3840 alvherre 1068 CBC 1 : replaces[Anum_acl - 1] = true;
3840 alvherre 1069 EUB : }
1070 : }
1071 :
3840 alvherre 1072 GIC 92 : newtup = heap_modify_tuple(oldtup, RelationGetDescr(rel),
1073 : values, nulls, replaces);
1074 :
3840 alvherre 1075 ECB : /* Perform actual update */
2259 alvherre 1076 CBC 92 : CatalogTupleUpdate(rel, &newtup->t_self, newtup);
3840 alvherre 1077 ECB :
1078 : /* Update owner dependency reference */
3840 alvherre 1079 CBC 92 : if (classId == LargeObjectMetadataRelationId)
1080 3 : classId = LargeObjectRelationId;
1601 andres 1081 GIC 92 : changeDependencyOnOwner(classId, objectId, new_ownerId);
1082 :
1083 : /* Release memory */
3840 alvherre 1084 92 : pfree(values);
1085 92 : pfree(nulls);
3840 alvherre 1086 CBC 92 : pfree(replaces);
1087 : }
3675 rhaas 1088 ECB :
3675 rhaas 1089 GIC 757 : InvokeObjectPostAlterHook(classId, objectId, 0);
3840 alvherre 1090 CBC 757 : }
|