1 /*-------------------------------------------------------------------------
4 * Drivers for generic alter commands
6 * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * src/backend/commands/alter.c
13 *-------------------------------------------------------------------------
17 #include "catalog/dependency.h"
18 #include "catalog/indexing.h"
19 #include "catalog/namespace.h"
20 #include "catalog/pg_largeobject.h"
21 #include "catalog/pg_namespace.h"
22 #include "commands/alter.h"
23 #include "commands/collationcmds.h"
24 #include "commands/conversioncmds.h"
25 #include "commands/dbcommands.h"
26 #include "commands/defrem.h"
27 #include "commands/extension.h"
28 #include "commands/proclang.h"
29 #include "commands/schemacmds.h"
30 #include "commands/tablecmds.h"
31 #include "commands/tablespace.h"
32 #include "commands/trigger.h"
33 #include "commands/typecmds.h"
34 #include "commands/user.h"
35 #include "miscadmin.h"
36 #include "parser/parse_clause.h"
37 #include "tcop/utility.h"
38 #include "utils/acl.h"
39 #include "utils/builtins.h"
40 #include "utils/lsyscache.h"
41 #include "utils/syscache.h"
45 * Executes an ALTER OBJECT / RENAME TO statement. Based on the object
46 * type, the function appropriate to that type is executed.
49 ExecRenameStmt(RenameStmt *stmt)
51 switch (stmt->renameType)
53 case OBJECT_AGGREGATE:
54 RenameAggregate(stmt->object, stmt->objarg, stmt->newname);
57 case OBJECT_COLLATION:
58 RenameCollation(stmt->object, stmt->newname);
61 case OBJECT_CONVERSION:
62 RenameConversion(stmt->object, stmt->newname);
66 RenameDatabase(stmt->subname, stmt->newname);
70 RenameFunction(stmt->object, stmt->objarg, stmt->newname);
74 RenameLanguage(stmt->subname, stmt->newname);
78 RenameOpClass(stmt->object, stmt->subname, stmt->newname);
82 RenameOpFamily(stmt->object, stmt->subname, stmt->newname);
86 RenameRole(stmt->subname, stmt->newname);
90 RenameSchema(stmt->subname, stmt->newname);
93 case OBJECT_TABLESPACE:
94 RenameTableSpace(stmt->subname, stmt->newname);
102 case OBJECT_ATTRIBUTE:
104 case OBJECT_FOREIGN_TABLE:
108 CheckRelationOwnership(stmt->relation, true);
110 relid = RangeVarGetRelid(stmt->relation, false);
112 switch (stmt->renameType)
115 case OBJECT_SEQUENCE:
118 case OBJECT_FOREIGN_TABLE:
121 * RENAME TABLE requires that we (still) hold
122 * CREATE rights on the containing namespace, as
123 * well as ownership of the table.
125 Oid namespaceId = get_rel_namespace(relid);
128 aclresult = pg_namespace_aclcheck(namespaceId,
131 if (aclresult != ACLCHECK_OK)
132 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
133 get_namespace_name(namespaceId));
135 RenameRelation(relid, stmt->newname, stmt->renameType);
139 case OBJECT_ATTRIBUTE:
140 renameatt(relid, stmt);
144 stmt->subname, /* old att name */
145 stmt->newname); /* new att name */
153 case OBJECT_TSPARSER:
154 RenameTSParser(stmt->object, stmt->newname);
157 case OBJECT_TSDICTIONARY:
158 RenameTSDictionary(stmt->object, stmt->newname);
161 case OBJECT_TSTEMPLATE:
162 RenameTSTemplate(stmt->object, stmt->newname);
165 case OBJECT_TSCONFIGURATION:
166 RenameTSConfiguration(stmt->object, stmt->newname);
170 RenameType(stmt->object, stmt->newname);
174 elog(ERROR, "unrecognized rename stmt type: %d",
175 (int) stmt->renameType);
180 * Executes an ALTER OBJECT / SET SCHEMA statement. Based on the object
181 * type, the function appropriate to that type is executed.
184 ExecAlterObjectSchemaStmt(AlterObjectSchemaStmt *stmt)
186 switch (stmt->objectType)
188 case OBJECT_AGGREGATE:
189 AlterFunctionNamespace(stmt->object, stmt->objarg, true,
193 case OBJECT_COLLATION:
194 AlterCollationNamespace(stmt->object, stmt->newschema);
197 case OBJECT_CONVERSION:
198 AlterConversionNamespace(stmt->object, stmt->newschema);
201 case OBJECT_EXTENSION:
202 AlterExtensionNamespace(stmt->object, stmt->newschema);
205 case OBJECT_FUNCTION:
206 AlterFunctionNamespace(stmt->object, stmt->objarg, false,
210 case OBJECT_OPERATOR:
211 AlterOperatorNamespace(stmt->object, stmt->objarg, stmt->newschema);
215 AlterOpClassNamespace(stmt->object, stmt->addname, stmt->newschema);
218 case OBJECT_OPFAMILY:
219 AlterOpFamilyNamespace(stmt->object, stmt->addname, stmt->newschema);
222 case OBJECT_SEQUENCE:
225 case OBJECT_FOREIGN_TABLE:
226 CheckRelationOwnership(stmt->relation, true);
227 AlterTableNamespace(stmt->relation, stmt->newschema,
228 stmt->objectType, AccessExclusiveLock);
231 case OBJECT_TSPARSER:
232 AlterTSParserNamespace(stmt->object, stmt->newschema);
235 case OBJECT_TSDICTIONARY:
236 AlterTSDictionaryNamespace(stmt->object, stmt->newschema);
239 case OBJECT_TSTEMPLATE:
240 AlterTSTemplateNamespace(stmt->object, stmt->newschema);
243 case OBJECT_TSCONFIGURATION:
244 AlterTSConfigurationNamespace(stmt->object, stmt->newschema);
249 AlterTypeNamespace(stmt->object, stmt->newschema);
253 elog(ERROR, "unrecognized AlterObjectSchemaStmt type: %d",
254 (int) stmt->objectType);
259 * Change an object's namespace given its classOid and object Oid.
261 * Objects that don't have a namespace should be ignored.
263 * This function is currently used only by ALTER EXTENSION SET SCHEMA,
264 * so it only needs to cover object types that can be members of an
265 * extension, and it doesn't have to deal with certain special cases
266 * such as not wanting to process array types --- those should never
267 * be direct members of an extension anyway.
269 * Returns the OID of the object's previous namespace, or InvalidOid if
270 * object doesn't have a schema.
273 AlterObjectNamespace_oid(Oid classId, Oid objid, Oid nspOid)
275 Oid oldNspOid = InvalidOid;
278 dep.classId = classId;
279 dep.objectId = objid;
282 switch (getObjectClass(&dep))
289 rel = relation_open(objid, AccessExclusiveLock);
290 oldNspOid = RelationGetNamespace(rel);
292 classRel = heap_open(RelationRelationId, RowExclusiveLock);
294 AlterRelationNamespaceInternal(classRel,
300 heap_close(classRel, RowExclusiveLock);
302 relation_close(rel, NoLock);
307 oldNspOid = AlterFunctionNamespace_oid(objid, nspOid);
311 oldNspOid = AlterTypeNamespace_oid(objid, nspOid);
314 case OCLASS_COLLATION:
315 oldNspOid = AlterCollationNamespace_oid(objid, nspOid);
318 case OCLASS_CONVERSION:
319 oldNspOid = AlterConversionNamespace_oid(objid, nspOid);
322 case OCLASS_OPERATOR:
323 oldNspOid = AlterOperatorNamespace_oid(objid, nspOid);
327 oldNspOid = AlterOpClassNamespace_oid(objid, nspOid);
330 case OCLASS_OPFAMILY:
331 oldNspOid = AlterOpFamilyNamespace_oid(objid, nspOid);
334 case OCLASS_TSPARSER:
335 oldNspOid = AlterTSParserNamespace_oid(objid, nspOid);
339 oldNspOid = AlterTSDictionaryNamespace_oid(objid, nspOid);
342 case OCLASS_TSTEMPLATE:
343 oldNspOid = AlterTSTemplateNamespace_oid(objid, nspOid);
346 case OCLASS_TSCONFIG:
347 oldNspOid = AlterTSConfigurationNamespace_oid(objid, nspOid);
358 * Generic function to change the namespace of a given object, for simple
359 * cases (won't work for tables, nor other cases where we need to do more
360 * than change the namespace column of a single catalog entry).
362 * The AlterFooNamespace() calls just above will call a function whose job
363 * is to lookup the arguments for the generic function here.
365 * rel: catalog relation containing object (RowExclusiveLock'd by caller)
366 * oidCacheId: syscache that indexes this catalog by OID
367 * nameCacheId: syscache that indexes this catalog by name and namespace
368 * (pass -1 if there is none)
369 * objid: OID of object to change the namespace of
370 * nspOid: OID of new namespace
371 * Anum_name: column number of catalog's name column
372 * Anum_namespace: column number of catalog's namespace column
373 * Anum_owner: column number of catalog's owner column, or -1 if none
374 * acl_kind: ACL type for object, or -1 if none assigned
376 * If the object does not have an owner or permissions, pass -1 for
377 * Anum_owner and acl_kind. In this case the calling user must be superuser.
379 * Returns the OID of the object's previous namespace.
382 AlterObjectNamespace(Relation rel, int oidCacheId, int nameCacheId,
383 Oid objid, Oid nspOid,
384 int Anum_name, int Anum_namespace, int Anum_owner,
385 AclObjectKind acl_kind)
387 Oid classId = RelationGetRelid(rel);
398 tup = SearchSysCacheCopy1(oidCacheId, ObjectIdGetDatum(objid));
399 if (!HeapTupleIsValid(tup)) /* should not happen */
400 elog(ERROR, "cache lookup failed for object %u of catalog \"%s\"",
401 objid, RelationGetRelationName(rel));
403 name = heap_getattr(tup, Anum_name, RelationGetDescr(rel), &isnull);
405 namespace = heap_getattr(tup, Anum_namespace, RelationGetDescr(rel), &isnull);
407 oldNspOid = DatumGetObjectId(namespace);
409 /* Check basic namespace related issues */
410 CheckSetNamespace(oldNspOid, nspOid, classId, objid);
412 /* Permission checks ... superusers can always do it */
419 /* Fail if object does not have an explicit owner */
422 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
423 (errmsg("must be superuser to SET SCHEMA of %s",
424 getObjectDescriptionOids(classId, objid)))));
426 /* Otherwise, must be owner of the existing object */
427 owner = heap_getattr(tup, Anum_owner, RelationGetDescr(rel), &isnull);
429 ownerId = DatumGetObjectId(owner);
431 if (!has_privs_of_role(GetUserId(), ownerId))
432 aclcheck_error(ACLCHECK_NOT_OWNER, acl_kind,
433 NameStr(*(DatumGetName(name))));
435 /* User must have CREATE privilege on new namespace */
436 aclresult = pg_namespace_aclcheck(nspOid, GetUserId(), ACL_CREATE);
437 if (aclresult != ACLCHECK_OK)
438 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
439 get_namespace_name(nspOid));
443 * Check for duplicate name (more friendly than unique-index failure).
444 * Since this is just a friendliness check, we can just skip it in cases
445 * where there isn't a suitable syscache available.
447 if (nameCacheId >= 0 &&
448 SearchSysCacheExists2(nameCacheId, name, ObjectIdGetDatum(nspOid)))
450 (errcode(ERRCODE_DUPLICATE_OBJECT),
451 errmsg("%s already exists in schema \"%s\"",
452 getObjectDescriptionOids(classId, objid),
453 get_namespace_name(nspOid))));
455 /* Build modified tuple */
456 values = palloc0(RelationGetNumberOfAttributes(rel) * sizeof(Datum));
457 nulls = palloc0(RelationGetNumberOfAttributes(rel) * sizeof(bool));
458 replaces = palloc0(RelationGetNumberOfAttributes(rel) * sizeof(bool));
459 values[Anum_namespace - 1] = ObjectIdGetDatum(nspOid);
460 replaces[Anum_namespace - 1] = true;
461 newtup = heap_modify_tuple(tup, RelationGetDescr(rel),
462 values, nulls, replaces);
464 /* Perform actual update */
465 simple_heap_update(rel, &tup->t_self, newtup);
466 CatalogUpdateIndexes(rel, newtup);
473 /* update dependencies to point to the new schema */
474 changeDependencyFor(classId, objid,
475 NamespaceRelationId, oldNspOid, nspOid);
482 * Executes an ALTER OBJECT / OWNER TO statement. Based on the object
483 * type, the function appropriate to that type is executed.
486 ExecAlterOwnerStmt(AlterOwnerStmt *stmt)
488 Oid newowner = get_role_oid(stmt->newowner, false);
490 switch (stmt->objectType)
492 case OBJECT_AGGREGATE:
493 AlterAggregateOwner(stmt->object, stmt->objarg, newowner);
496 case OBJECT_COLLATION:
497 AlterCollationOwner(stmt->object, newowner);
500 case OBJECT_CONVERSION:
501 AlterConversionOwner(stmt->object, newowner);
504 case OBJECT_DATABASE:
505 AlterDatabaseOwner(strVal(linitial(stmt->object)), newowner);
508 case OBJECT_FUNCTION:
509 AlterFunctionOwner(stmt->object, stmt->objarg, newowner);
512 case OBJECT_LANGUAGE:
513 AlterLanguageOwner(strVal(linitial(stmt->object)), newowner);
516 case OBJECT_LARGEOBJECT:
517 LargeObjectAlterOwner(oidparse(linitial(stmt->object)), newowner);
520 case OBJECT_OPERATOR:
521 Assert(list_length(stmt->objarg) == 2);
522 AlterOperatorOwner(stmt->object,
523 (TypeName *) linitial(stmt->objarg),
524 (TypeName *) lsecond(stmt->objarg),
529 AlterOpClassOwner(stmt->object, stmt->addname, newowner);
532 case OBJECT_OPFAMILY:
533 AlterOpFamilyOwner(stmt->object, stmt->addname, newowner);
537 AlterSchemaOwner(strVal(linitial(stmt->object)), newowner);
540 case OBJECT_TABLESPACE:
541 AlterTableSpaceOwner(strVal(linitial(stmt->object)), newowner);
545 case OBJECT_DOMAIN: /* same as TYPE */
546 AlterTypeOwner(stmt->object, newowner);
549 case OBJECT_TSDICTIONARY:
550 AlterTSDictionaryOwner(stmt->object, newowner);
553 case OBJECT_TSCONFIGURATION:
554 AlterTSConfigurationOwner(stmt->object, newowner);
558 AlterForeignDataWrapperOwner(strVal(linitial(stmt->object)),
562 case OBJECT_FOREIGN_SERVER:
563 AlterForeignServerOwner(strVal(linitial(stmt->object)), newowner);
567 elog(ERROR, "unrecognized AlterOwnerStmt type: %d",
568 (int) stmt->objectType);