2003-06-27 16:45:32 +02:00
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* alter.c
|
|
|
|
* Drivers for generic alter commands
|
|
|
|
*
|
2012-01-02 00:01:58 +01:00
|
|
|
* Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
|
2003-06-27 16:45:32 +02:00
|
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* IDENTIFICATION
|
2010-09-20 22:08:53 +02:00
|
|
|
* src/backend/commands/alter.c
|
2003-06-27 16:45:32 +02:00
|
|
|
*
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
#include "postgres.h"
|
|
|
|
|
2010-11-26 23:27:23 +01:00
|
|
|
#include "catalog/dependency.h"
|
|
|
|
#include "catalog/indexing.h"
|
2003-06-27 16:45:32 +02:00
|
|
|
#include "catalog/namespace.h"
|
2009-12-11 04:34:57 +01:00
|
|
|
#include "catalog/pg_largeobject.h"
|
2010-11-26 23:27:23 +01:00
|
|
|
#include "catalog/pg_namespace.h"
|
2003-06-27 16:45:32 +02:00
|
|
|
#include "commands/alter.h"
|
2011-02-12 14:54:13 +01:00
|
|
|
#include "commands/collationcmds.h"
|
2003-06-27 16:45:32 +02:00
|
|
|
#include "commands/conversioncmds.h"
|
|
|
|
#include "commands/dbcommands.h"
|
|
|
|
#include "commands/defrem.h"
|
2011-02-08 22:08:41 +01:00
|
|
|
#include "commands/extension.h"
|
2003-06-27 16:45:32 +02:00
|
|
|
#include "commands/proclang.h"
|
|
|
|
#include "commands/schemacmds.h"
|
|
|
|
#include "commands/tablecmds.h"
|
2004-06-25 23:55:59 +02:00
|
|
|
#include "commands/tablespace.h"
|
2003-06-27 16:45:32 +02:00
|
|
|
#include "commands/trigger.h"
|
2004-06-25 23:55:59 +02:00
|
|
|
#include "commands/typecmds.h"
|
2003-06-27 16:45:32 +02:00
|
|
|
#include "commands/user.h"
|
|
|
|
#include "miscadmin.h"
|
2003-07-22 21:00:12 +02:00
|
|
|
#include "tcop/utility.h"
|
2010-06-13 19:43:13 +02:00
|
|
|
#include "utils/builtins.h"
|
2003-06-27 16:45:32 +02:00
|
|
|
#include "utils/lsyscache.h"
|
2011-02-23 18:18:09 +01:00
|
|
|
#include "utils/rel.h"
|
2010-11-26 23:27:23 +01:00
|
|
|
#include "utils/syscache.h"
|
2003-06-27 16:45:32 +02:00
|
|
|
|
|
|
|
|
2004-06-25 23:55:59 +02:00
|
|
|
/*
|
2004-08-29 07:07:03 +02:00
|
|
|
* Executes an ALTER OBJECT / RENAME TO statement. Based on the object
|
2004-06-25 23:55:59 +02:00
|
|
|
* type, the function appropriate to that type is executed.
|
|
|
|
*/
|
2003-06-27 16:45:32 +02:00
|
|
|
void
|
|
|
|
ExecRenameStmt(RenameStmt *stmt)
|
|
|
|
{
|
|
|
|
switch (stmt->renameType)
|
|
|
|
{
|
|
|
|
case OBJECT_AGGREGATE:
|
2006-04-15 19:45:46 +02:00
|
|
|
RenameAggregate(stmt->object, stmt->objarg, stmt->newname);
|
2003-06-27 16:45:32 +02:00
|
|
|
break;
|
|
|
|
|
2011-02-12 14:54:13 +01:00
|
|
|
case OBJECT_COLLATION:
|
|
|
|
RenameCollation(stmt->object, stmt->newname);
|
|
|
|
break;
|
|
|
|
|
2003-06-27 16:45:32 +02:00
|
|
|
case OBJECT_CONVERSION:
|
|
|
|
RenameConversion(stmt->object, stmt->newname);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OBJECT_DATABASE:
|
|
|
|
RenameDatabase(stmt->subname, stmt->newname);
|
|
|
|
break;
|
|
|
|
|
2011-12-09 19:42:30 +01:00
|
|
|
case OBJECT_FDW:
|
|
|
|
RenameForeignDataWrapper(stmt->subname, stmt->newname);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OBJECT_FOREIGN_SERVER:
|
|
|
|
RenameForeignServer(stmt->subname, stmt->newname);
|
|
|
|
break;
|
|
|
|
|
2003-06-27 16:45:32 +02:00
|
|
|
case OBJECT_FUNCTION:
|
|
|
|
RenameFunction(stmt->object, stmt->objarg, stmt->newname);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OBJECT_LANGUAGE:
|
|
|
|
RenameLanguage(stmt->subname, stmt->newname);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OBJECT_OPCLASS:
|
|
|
|
RenameOpClass(stmt->object, stmt->subname, stmt->newname);
|
|
|
|
break;
|
|
|
|
|
2007-01-23 06:07:18 +01:00
|
|
|
case OBJECT_OPFAMILY:
|
|
|
|
RenameOpFamily(stmt->object, stmt->subname, stmt->newname);
|
|
|
|
break;
|
|
|
|
|
2005-06-28 07:09:14 +02:00
|
|
|
case OBJECT_ROLE:
|
|
|
|
RenameRole(stmt->subname, stmt->newname);
|
|
|
|
break;
|
|
|
|
|
2003-06-27 16:45:32 +02:00
|
|
|
case OBJECT_SCHEMA:
|
|
|
|
RenameSchema(stmt->subname, stmt->newname);
|
|
|
|
break;
|
|
|
|
|
2004-06-25 23:55:59 +02:00
|
|
|
case OBJECT_TABLESPACE:
|
|
|
|
RenameTableSpace(stmt->subname, stmt->newname);
|
|
|
|
break;
|
|
|
|
|
2003-06-27 16:45:32 +02:00
|
|
|
case OBJECT_TABLE:
|
2007-07-03 03:30:37 +02:00
|
|
|
case OBJECT_SEQUENCE:
|
|
|
|
case OBJECT_VIEW:
|
2004-08-22 02:08:28 +02:00
|
|
|
case OBJECT_INDEX:
|
Improve behavior of concurrent rename statements.
Previously, renaming a table, sequence, view, index, foreign table,
column, or trigger checked permissions before locking the object, which
meant that if permissions were revoked during the lock wait, we would
still allow the operation. Similarly, if the original object is dropped
and a new one with the same name is created, the operation will be allowed
if we had permissions on the old object; the permissions on the new
object don't matter. All this is now fixed.
Along the way, attempting to rename a trigger on a foreign table now gives
the same error message as trying to create one there in the first place
(i.e. that it's not a table or view) rather than simply stating that no
trigger by that name exists.
Patch by me; review by Noah Misch.
2011-12-16 00:51:46 +01:00
|
|
|
case OBJECT_FOREIGN_TABLE:
|
|
|
|
RenameRelation(stmt);
|
|
|
|
break;
|
|
|
|
|
2003-06-27 16:45:32 +02:00
|
|
|
case OBJECT_COLUMN:
|
2010-09-26 13:41:03 +02:00
|
|
|
case OBJECT_ATTRIBUTE:
|
Improve behavior of concurrent rename statements.
Previously, renaming a table, sequence, view, index, foreign table,
column, or trigger checked permissions before locking the object, which
meant that if permissions were revoked during the lock wait, we would
still allow the operation. Similarly, if the original object is dropped
and a new one with the same name is created, the operation will be allowed
if we had permissions on the old object; the permissions on the new
object don't matter. All this is now fixed.
Along the way, attempting to rename a trigger on a foreign table now gives
the same error message as trying to create one there in the first place
(i.e. that it's not a table or view) rather than simply stating that no
trigger by that name exists.
Patch by me; review by Noah Misch.
2011-12-16 00:51:46 +01:00
|
|
|
renameatt(stmt);
|
|
|
|
break;
|
|
|
|
|
2003-06-27 16:45:32 +02:00
|
|
|
case OBJECT_TRIGGER:
|
Improve behavior of concurrent rename statements.
Previously, renaming a table, sequence, view, index, foreign table,
column, or trigger checked permissions before locking the object, which
meant that if permissions were revoked during the lock wait, we would
still allow the operation. Similarly, if the original object is dropped
and a new one with the same name is created, the operation will be allowed
if we had permissions on the old object; the permissions on the new
object don't matter. All this is now fixed.
Along the way, attempting to rename a trigger on a foreign table now gives
the same error message as trying to create one there in the first place
(i.e. that it's not a table or view) rather than simply stating that no
trigger by that name exists.
Patch by me; review by Noah Misch.
2011-12-16 00:51:46 +01:00
|
|
|
renametrig(stmt);
|
|
|
|
break;
|
2003-06-27 16:45:32 +02:00
|
|
|
|
2007-08-21 03:11:32 +02:00
|
|
|
case OBJECT_TSPARSER:
|
|
|
|
RenameTSParser(stmt->object, stmt->newname);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OBJECT_TSDICTIONARY:
|
|
|
|
RenameTSDictionary(stmt->object, stmt->newname);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OBJECT_TSTEMPLATE:
|
|
|
|
RenameTSTemplate(stmt->object, stmt->newname);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OBJECT_TSCONFIGURATION:
|
|
|
|
RenameTSConfiguration(stmt->object, stmt->newname);
|
|
|
|
break;
|
|
|
|
|
2011-12-22 21:43:56 +01:00
|
|
|
case OBJECT_DOMAIN:
|
2008-03-19 19:38:30 +01:00
|
|
|
case OBJECT_TYPE:
|
2011-12-22 21:43:56 +01:00
|
|
|
RenameType(stmt);
|
2008-03-19 19:38:30 +01:00
|
|
|
break;
|
|
|
|
|
2003-06-27 16:45:32 +02:00
|
|
|
default:
|
2003-07-20 23:56:35 +02:00
|
|
|
elog(ERROR, "unrecognized rename stmt type: %d",
|
|
|
|
(int) stmt->renameType);
|
2003-06-27 16:45:32 +02:00
|
|
|
}
|
|
|
|
}
|
2004-06-25 23:55:59 +02:00
|
|
|
|
2005-08-01 06:03:59 +02:00
|
|
|
/*
|
|
|
|
* Executes an ALTER OBJECT / SET SCHEMA statement. Based on the object
|
|
|
|
* type, the function appropriate to that type is executed.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
ExecAlterObjectSchemaStmt(AlterObjectSchemaStmt *stmt)
|
|
|
|
{
|
|
|
|
switch (stmt->objectType)
|
|
|
|
{
|
|
|
|
case OBJECT_AGGREGATE:
|
2006-04-15 19:45:46 +02:00
|
|
|
AlterFunctionNamespace(stmt->object, stmt->objarg, true,
|
|
|
|
stmt->newschema);
|
|
|
|
break;
|
|
|
|
|
2011-02-12 14:54:13 +01:00
|
|
|
case OBJECT_COLLATION:
|
|
|
|
AlterCollationNamespace(stmt->object, stmt->newschema);
|
|
|
|
break;
|
|
|
|
|
2010-11-26 23:27:23 +01:00
|
|
|
case OBJECT_CONVERSION:
|
|
|
|
AlterConversionNamespace(stmt->object, stmt->newschema);
|
|
|
|
break;
|
|
|
|
|
2011-02-08 22:08:41 +01:00
|
|
|
case OBJECT_EXTENSION:
|
|
|
|
AlterExtensionNamespace(stmt->object, stmt->newschema);
|
|
|
|
break;
|
|
|
|
|
2005-08-01 06:03:59 +02:00
|
|
|
case OBJECT_FUNCTION:
|
2006-04-15 19:45:46 +02:00
|
|
|
AlterFunctionNamespace(stmt->object, stmt->objarg, false,
|
2005-08-01 06:03:59 +02:00
|
|
|
stmt->newschema);
|
|
|
|
break;
|
2005-10-15 04:49:52 +02:00
|
|
|
|
2010-11-26 23:27:23 +01:00
|
|
|
case OBJECT_OPERATOR:
|
|
|
|
AlterOperatorNamespace(stmt->object, stmt->objarg, stmt->newschema);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OBJECT_OPCLASS:
|
2011-01-04 04:08:55 +01:00
|
|
|
AlterOpClassNamespace(stmt->object, stmt->addname, stmt->newschema);
|
2010-11-26 23:27:23 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
case OBJECT_OPFAMILY:
|
2011-01-04 04:08:55 +01:00
|
|
|
AlterOpFamilyNamespace(stmt->object, stmt->addname, stmt->newschema);
|
2010-11-26 23:27:23 +01:00
|
|
|
break;
|
|
|
|
|
2005-08-01 06:03:59 +02:00
|
|
|
case OBJECT_SEQUENCE:
|
|
|
|
case OBJECT_TABLE:
|
2008-06-15 03:25:54 +02:00
|
|
|
case OBJECT_VIEW:
|
2011-01-02 05:48:11 +01:00
|
|
|
case OBJECT_FOREIGN_TABLE:
|
2012-01-07 04:42:26 +01:00
|
|
|
AlterTableNamespace(stmt);
|
2005-08-01 06:03:59 +02:00
|
|
|
break;
|
2005-10-15 04:49:52 +02:00
|
|
|
|
2010-11-26 23:27:23 +01:00
|
|
|
case OBJECT_TSPARSER:
|
|
|
|
AlterTSParserNamespace(stmt->object, stmt->newschema);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OBJECT_TSDICTIONARY:
|
|
|
|
AlterTSDictionaryNamespace(stmt->object, stmt->newschema);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OBJECT_TSTEMPLATE:
|
|
|
|
AlterTSTemplateNamespace(stmt->object, stmt->newschema);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OBJECT_TSCONFIGURATION:
|
|
|
|
AlterTSConfigurationNamespace(stmt->object, stmt->newschema);
|
|
|
|
break;
|
|
|
|
|
2005-08-01 06:03:59 +02:00
|
|
|
case OBJECT_TYPE:
|
|
|
|
case OBJECT_DOMAIN:
|
2012-01-27 20:20:34 +01:00
|
|
|
AlterTypeNamespace(stmt->object, stmt->newschema, stmt->objectType);
|
2005-08-01 06:03:59 +02:00
|
|
|
break;
|
2005-10-15 04:49:52 +02:00
|
|
|
|
2005-08-01 06:03:59 +02:00
|
|
|
default:
|
|
|
|
elog(ERROR, "unrecognized AlterObjectSchemaStmt type: %d",
|
|
|
|
(int) stmt->objectType);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-02-08 22:08:41 +01:00
|
|
|
/*
|
|
|
|
* Change an object's namespace given its classOid and object Oid.
|
|
|
|
*
|
|
|
|
* Objects that don't have a namespace should be ignored.
|
|
|
|
*
|
|
|
|
* This function is currently used only by ALTER EXTENSION SET SCHEMA,
|
|
|
|
* so it only needs to cover object types that can be members of an
|
|
|
|
* extension, and it doesn't have to deal with certain special cases
|
|
|
|
* such as not wanting to process array types --- those should never
|
|
|
|
* be direct members of an extension anyway.
|
|
|
|
*
|
|
|
|
* Returns the OID of the object's previous namespace, or InvalidOid if
|
|
|
|
* object doesn't have a schema.
|
|
|
|
*/
|
|
|
|
Oid
|
|
|
|
AlterObjectNamespace_oid(Oid classId, Oid objid, Oid nspOid)
|
|
|
|
{
|
|
|
|
Oid oldNspOid = InvalidOid;
|
|
|
|
ObjectAddress dep;
|
|
|
|
|
|
|
|
dep.classId = classId;
|
|
|
|
dep.objectId = objid;
|
|
|
|
dep.objectSubId = 0;
|
|
|
|
|
|
|
|
switch (getObjectClass(&dep))
|
|
|
|
{
|
|
|
|
case OCLASS_CLASS:
|
2011-04-10 17:42:00 +02:00
|
|
|
{
|
|
|
|
Relation rel;
|
|
|
|
Relation classRel;
|
2011-02-08 22:08:41 +01:00
|
|
|
|
2011-04-10 17:42:00 +02:00
|
|
|
rel = relation_open(objid, AccessExclusiveLock);
|
|
|
|
oldNspOid = RelationGetNamespace(rel);
|
2011-02-08 22:08:41 +01:00
|
|
|
|
2011-04-10 17:42:00 +02:00
|
|
|
classRel = heap_open(RelationRelationId, RowExclusiveLock);
|
2011-02-08 22:08:41 +01:00
|
|
|
|
2011-04-10 17:42:00 +02:00
|
|
|
AlterRelationNamespaceInternal(classRel,
|
|
|
|
objid,
|
|
|
|
oldNspOid,
|
|
|
|
nspOid,
|
|
|
|
true);
|
2011-02-08 22:08:41 +01:00
|
|
|
|
2011-04-10 17:42:00 +02:00
|
|
|
heap_close(classRel, RowExclusiveLock);
|
2011-02-08 22:08:41 +01:00
|
|
|
|
2011-04-10 17:42:00 +02:00
|
|
|
relation_close(rel, NoLock);
|
|
|
|
break;
|
|
|
|
}
|
2011-02-08 22:08:41 +01:00
|
|
|
|
|
|
|
case OCLASS_PROC:
|
|
|
|
oldNspOid = AlterFunctionNamespace_oid(objid, nspOid);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OCLASS_TYPE:
|
|
|
|
oldNspOid = AlterTypeNamespace_oid(objid, nspOid);
|
|
|
|
break;
|
|
|
|
|
2011-02-12 14:54:13 +01:00
|
|
|
case OCLASS_COLLATION:
|
|
|
|
oldNspOid = AlterCollationNamespace_oid(objid, nspOid);
|
|
|
|
break;
|
|
|
|
|
2011-02-08 22:08:41 +01:00
|
|
|
case OCLASS_CONVERSION:
|
|
|
|
oldNspOid = AlterConversionNamespace_oid(objid, nspOid);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OCLASS_OPERATOR:
|
|
|
|
oldNspOid = AlterOperatorNamespace_oid(objid, nspOid);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OCLASS_OPCLASS:
|
|
|
|
oldNspOid = AlterOpClassNamespace_oid(objid, nspOid);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OCLASS_OPFAMILY:
|
|
|
|
oldNspOid = AlterOpFamilyNamespace_oid(objid, nspOid);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OCLASS_TSPARSER:
|
|
|
|
oldNspOid = AlterTSParserNamespace_oid(objid, nspOid);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OCLASS_TSDICT:
|
|
|
|
oldNspOid = AlterTSDictionaryNamespace_oid(objid, nspOid);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OCLASS_TSTEMPLATE:
|
|
|
|
oldNspOid = AlterTSTemplateNamespace_oid(objid, nspOid);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OCLASS_TSCONFIG:
|
|
|
|
oldNspOid = AlterTSConfigurationNamespace_oid(objid, nspOid);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return oldNspOid;
|
|
|
|
}
|
|
|
|
|
2010-11-26 23:27:23 +01:00
|
|
|
/*
|
|
|
|
* Generic function to change the namespace of a given object, for simple
|
2011-02-08 22:08:41 +01:00
|
|
|
* cases (won't work for tables, nor other cases where we need to do more
|
|
|
|
* than change the namespace column of a single catalog entry).
|
2010-11-26 23:27:23 +01:00
|
|
|
*
|
|
|
|
* The AlterFooNamespace() calls just above will call a function whose job
|
|
|
|
* is to lookup the arguments for the generic function here.
|
|
|
|
*
|
2011-02-08 22:08:41 +01:00
|
|
|
* rel: catalog relation containing object (RowExclusiveLock'd by caller)
|
|
|
|
* oidCacheId: syscache that indexes this catalog by OID
|
|
|
|
* nameCacheId: syscache that indexes this catalog by name and namespace
|
|
|
|
* (pass -1 if there is none)
|
|
|
|
* objid: OID of object to change the namespace of
|
|
|
|
* nspOid: OID of new namespace
|
|
|
|
* Anum_name: column number of catalog's name column
|
|
|
|
* Anum_namespace: column number of catalog's namespace column
|
|
|
|
* Anum_owner: column number of catalog's owner column, or -1 if none
|
|
|
|
* acl_kind: ACL type for object, or -1 if none assigned
|
|
|
|
*
|
|
|
|
* If the object does not have an owner or permissions, pass -1 for
|
|
|
|
* Anum_owner and acl_kind. In this case the calling user must be superuser.
|
|
|
|
*
|
|
|
|
* Returns the OID of the object's previous namespace.
|
2010-11-26 23:27:23 +01:00
|
|
|
*/
|
2011-02-08 22:08:41 +01:00
|
|
|
Oid
|
|
|
|
AlterObjectNamespace(Relation rel, int oidCacheId, int nameCacheId,
|
|
|
|
Oid objid, Oid nspOid,
|
2010-11-26 23:27:23 +01:00
|
|
|
int Anum_name, int Anum_namespace, int Anum_owner,
|
2011-02-08 22:08:41 +01:00
|
|
|
AclObjectKind acl_kind)
|
2010-11-26 23:27:23 +01:00
|
|
|
{
|
2011-02-08 22:08:41 +01:00
|
|
|
Oid classId = RelationGetRelid(rel);
|
2010-11-26 23:27:23 +01:00
|
|
|
Oid oldNspOid;
|
2011-04-10 17:42:00 +02:00
|
|
|
Datum name,
|
|
|
|
namespace;
|
|
|
|
bool isnull;
|
|
|
|
HeapTuple tup,
|
|
|
|
newtup;
|
2010-11-26 23:27:23 +01:00
|
|
|
Datum *values;
|
|
|
|
bool *nulls;
|
|
|
|
bool *replaces;
|
|
|
|
|
2011-02-08 22:08:41 +01:00
|
|
|
tup = SearchSysCacheCopy1(oidCacheId, ObjectIdGetDatum(objid));
|
2010-11-26 23:27:23 +01:00
|
|
|
if (!HeapTupleIsValid(tup)) /* should not happen */
|
2011-02-08 22:08:41 +01:00
|
|
|
elog(ERROR, "cache lookup failed for object %u of catalog \"%s\"",
|
|
|
|
objid, RelationGetRelationName(rel));
|
2010-11-26 23:27:23 +01:00
|
|
|
|
2011-02-08 22:08:41 +01:00
|
|
|
name = heap_getattr(tup, Anum_name, RelationGetDescr(rel), &isnull);
|
|
|
|
Assert(!isnull);
|
|
|
|
namespace = heap_getattr(tup, Anum_namespace, RelationGetDescr(rel), &isnull);
|
|
|
|
Assert(!isnull);
|
2010-11-26 23:27:23 +01:00
|
|
|
oldNspOid = DatumGetObjectId(namespace);
|
|
|
|
|
|
|
|
/* Check basic namespace related issues */
|
|
|
|
CheckSetNamespace(oldNspOid, nspOid, classId, objid);
|
|
|
|
|
2011-02-08 22:08:41 +01:00
|
|
|
/* Permission checks ... superusers can always do it */
|
2010-11-26 23:27:23 +01:00
|
|
|
if (!superuser())
|
|
|
|
{
|
2011-04-10 17:42:00 +02:00
|
|
|
Datum owner;
|
2010-11-26 23:27:23 +01:00
|
|
|
Oid ownerId;
|
|
|
|
AclResult aclresult;
|
|
|
|
|
2011-02-08 22:08:41 +01:00
|
|
|
/* Fail if object does not have an explicit owner */
|
|
|
|
if (Anum_owner <= 0)
|
2010-11-26 23:27:23 +01:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
2011-07-08 06:37:04 +02:00
|
|
|
(errmsg("must be superuser to set schema of %s",
|
2010-11-26 23:27:23 +01:00
|
|
|
getObjectDescriptionOids(classId, objid)))));
|
|
|
|
|
|
|
|
/* Otherwise, must be owner of the existing object */
|
2011-02-08 22:08:41 +01:00
|
|
|
owner = heap_getattr(tup, Anum_owner, RelationGetDescr(rel), &isnull);
|
|
|
|
Assert(!isnull);
|
2010-11-26 23:27:23 +01:00
|
|
|
ownerId = DatumGetObjectId(owner);
|
|
|
|
|
|
|
|
if (!has_privs_of_role(GetUserId(), ownerId))
|
|
|
|
aclcheck_error(ACLCHECK_NOT_OWNER, acl_kind,
|
|
|
|
NameStr(*(DatumGetName(name))));
|
|
|
|
|
2011-02-08 22:08:41 +01:00
|
|
|
/* User must have CREATE privilege on new namespace */
|
|
|
|
aclresult = pg_namespace_aclcheck(nspOid, GetUserId(), ACL_CREATE);
|
2010-11-26 23:27:23 +01:00
|
|
|
if (aclresult != ACLCHECK_OK)
|
|
|
|
aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
|
2011-02-08 22:08:41 +01:00
|
|
|
get_namespace_name(nspOid));
|
2010-11-26 23:27:23 +01:00
|
|
|
}
|
|
|
|
|
2011-02-08 22:08:41 +01:00
|
|
|
/*
|
|
|
|
* Check for duplicate name (more friendly than unique-index failure).
|
|
|
|
* Since this is just a friendliness check, we can just skip it in cases
|
|
|
|
* where there isn't a suitable syscache available.
|
|
|
|
*/
|
|
|
|
if (nameCacheId >= 0 &&
|
|
|
|
SearchSysCacheExists2(nameCacheId, name, ObjectIdGetDatum(nspOid)))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DUPLICATE_OBJECT),
|
|
|
|
errmsg("%s already exists in schema \"%s\"",
|
|
|
|
getObjectDescriptionOids(classId, objid),
|
|
|
|
get_namespace_name(nspOid))));
|
|
|
|
|
|
|
|
/* Build modified tuple */
|
|
|
|
values = palloc0(RelationGetNumberOfAttributes(rel) * sizeof(Datum));
|
|
|
|
nulls = palloc0(RelationGetNumberOfAttributes(rel) * sizeof(bool));
|
|
|
|
replaces = palloc0(RelationGetNumberOfAttributes(rel) * sizeof(bool));
|
|
|
|
values[Anum_namespace - 1] = ObjectIdGetDatum(nspOid);
|
2010-11-26 23:27:23 +01:00
|
|
|
replaces[Anum_namespace - 1] = true;
|
2011-02-08 22:08:41 +01:00
|
|
|
newtup = heap_modify_tuple(tup, RelationGetDescr(rel),
|
|
|
|
values, nulls, replaces);
|
2010-11-26 23:27:23 +01:00
|
|
|
|
|
|
|
/* Perform actual update */
|
|
|
|
simple_heap_update(rel, &tup->t_self, newtup);
|
|
|
|
CatalogUpdateIndexes(rel, newtup);
|
|
|
|
|
|
|
|
/* Release memory */
|
|
|
|
pfree(values);
|
|
|
|
pfree(nulls);
|
|
|
|
pfree(replaces);
|
|
|
|
|
|
|
|
/* update dependencies to point to the new schema */
|
|
|
|
changeDependencyFor(classId, objid,
|
|
|
|
NamespaceRelationId, oldNspOid, nspOid);
|
2011-02-08 22:08:41 +01:00
|
|
|
|
|
|
|
return oldNspOid;
|
2010-11-26 23:27:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-06-25 23:55:59 +02:00
|
|
|
/*
|
|
|
|
* Executes an ALTER OBJECT / OWNER TO statement. Based on the object
|
|
|
|
* type, the function appropriate to that type is executed.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
ExecAlterOwnerStmt(AlterOwnerStmt *stmt)
|
|
|
|
{
|
2010-08-05 16:45:09 +02:00
|
|
|
Oid newowner = get_role_oid(stmt->newowner, false);
|
2004-06-25 23:55:59 +02:00
|
|
|
|
|
|
|
switch (stmt->objectType)
|
|
|
|
{
|
|
|
|
case OBJECT_AGGREGATE:
|
2006-04-15 19:45:46 +02:00
|
|
|
AlterAggregateOwner(stmt->object, stmt->objarg, newowner);
|
2004-06-25 23:55:59 +02:00
|
|
|
break;
|
|
|
|
|
2011-02-12 14:54:13 +01:00
|
|
|
case OBJECT_COLLATION:
|
|
|
|
AlterCollationOwner(stmt->object, newowner);
|
|
|
|
break;
|
|
|
|
|
2004-06-25 23:55:59 +02:00
|
|
|
case OBJECT_CONVERSION:
|
|
|
|
AlterConversionOwner(stmt->object, newowner);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OBJECT_DATABASE:
|
2008-02-07 22:07:55 +01:00
|
|
|
AlterDatabaseOwner(strVal(linitial(stmt->object)), newowner);
|
2004-06-25 23:55:59 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case OBJECT_FUNCTION:
|
|
|
|
AlterFunctionOwner(stmt->object, stmt->objarg, newowner);
|
|
|
|
break;
|
|
|
|
|
2007-03-26 18:58:41 +02:00
|
|
|
case OBJECT_LANGUAGE:
|
2008-02-07 22:07:55 +01:00
|
|
|
AlterLanguageOwner(strVal(linitial(stmt->object)), newowner);
|
2007-03-26 18:58:41 +02:00
|
|
|
break;
|
|
|
|
|
2009-12-11 04:34:57 +01:00
|
|
|
case OBJECT_LARGEOBJECT:
|
2010-06-13 19:43:13 +02:00
|
|
|
LargeObjectAlterOwner(oidparse(linitial(stmt->object)), newowner);
|
2009-12-11 04:34:57 +01:00
|
|
|
break;
|
|
|
|
|
2004-06-25 23:55:59 +02:00
|
|
|
case OBJECT_OPERATOR:
|
2006-04-15 19:45:46 +02:00
|
|
|
Assert(list_length(stmt->objarg) == 2);
|
2004-06-25 23:55:59 +02:00
|
|
|
AlterOperatorOwner(stmt->object,
|
|
|
|
(TypeName *) linitial(stmt->objarg),
|
|
|
|
(TypeName *) lsecond(stmt->objarg),
|
|
|
|
newowner);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OBJECT_OPCLASS:
|
|
|
|
AlterOpClassOwner(stmt->object, stmt->addname, newowner);
|
|
|
|
break;
|
|
|
|
|
2007-01-23 06:07:18 +01:00
|
|
|
case OBJECT_OPFAMILY:
|
|
|
|
AlterOpFamilyOwner(stmt->object, stmt->addname, newowner);
|
|
|
|
break;
|
|
|
|
|
2004-06-25 23:55:59 +02:00
|
|
|
case OBJECT_SCHEMA:
|
2008-02-07 22:07:55 +01:00
|
|
|
AlterSchemaOwner(strVal(linitial(stmt->object)), newowner);
|
2004-06-25 23:55:59 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case OBJECT_TABLESPACE:
|
2008-02-07 22:07:55 +01:00
|
|
|
AlterTableSpaceOwner(strVal(linitial(stmt->object)), newowner);
|
2004-06-25 23:55:59 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case OBJECT_TYPE:
|
|
|
|
case OBJECT_DOMAIN: /* same as TYPE */
|
2012-01-27 20:20:34 +01:00
|
|
|
AlterTypeOwner(stmt->object, newowner, stmt->objectType);
|
2004-06-25 23:55:59 +02:00
|
|
|
break;
|
|
|
|
|
2007-08-21 03:11:32 +02:00
|
|
|
case OBJECT_TSDICTIONARY:
|
|
|
|
AlterTSDictionaryOwner(stmt->object, newowner);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OBJECT_TSCONFIGURATION:
|
|
|
|
AlterTSConfigurationOwner(stmt->object, newowner);
|
|
|
|
break;
|
|
|
|
|
2008-12-19 17:25:19 +01:00
|
|
|
case OBJECT_FDW:
|
|
|
|
AlterForeignDataWrapperOwner(strVal(linitial(stmt->object)),
|
|
|
|
newowner);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OBJECT_FOREIGN_SERVER:
|
|
|
|
AlterForeignServerOwner(strVal(linitial(stmt->object)), newowner);
|
|
|
|
break;
|
|
|
|
|
2004-06-25 23:55:59 +02:00
|
|
|
default:
|
|
|
|
elog(ERROR, "unrecognized AlterOwnerStmt type: %d",
|
|
|
|
(int) stmt->objectType);
|
|
|
|
}
|
|
|
|
}
|