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