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