pgsql-v9.2-ddl-refactoring-part-2.v1.groundworks.patch
application/octet-stream
Filename: pgsql-v9.2-ddl-refactoring-part-2.v1.groundworks.patch
Type: application/octet-stream
Part: 2
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: unified
Series: patch v9
| File | + | − |
|---|---|---|
| src/backend/catalog/objectaddress.c | 493 | 84 |
| src/backend/commands/comment.c | 1 | 2 |
| src/backend/commands/dropcmds.c | 1 | 2 |
| src/backend/commands/extension.c | 1 | 2 |
| src/backend/commands/seclabel.c | 1 | 2 |
| src/include/catalog/objectaddress.h | 9 | 2 |
| src/test/regress/expected/alter_rename.out | 282 | 0 |
| src/test/regress/expected/privileges.out | 1 | 1 |
| src/test/regress/parallel_schedule | 1 | 1 |
| src/test/regress/serial_schedule | 1 | 0 |
| src/test/regress/sql/alter_rename.sql | 240 | 0 |
src/backend/catalog/objectaddress.c | 577 ++++++++++++++++++++++++----
src/backend/commands/comment.c | 3 +-
src/backend/commands/dropcmds.c | 3 +-
src/backend/commands/extension.c | 3 +-
src/backend/commands/seclabel.c | 3 +-
src/include/catalog/objectaddress.h | 11 +-
src/test/regress/expected/alter_rename.out | 282 ++++++++++++++
src/test/regress/expected/privileges.out | 2 +-
src/test/regress/parallel_schedule | 2 +-
src/test/regress/serial_schedule | 1 +
src/test/regress/sql/alter_rename.sql | 240 ++++++++++++
11 files changed, 1031 insertions(+), 96 deletions(-)
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index ec4c987..bcf5259 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -53,6 +53,7 @@
#include "foreign/foreign.h"
#include "libpq/be-fsstubs.h"
#include "miscadmin.h"
+#include "mb/pg_wchar.h"
#include "nodes/makefuncs.h"
#include "parser/parse_func.h"
#include "parser/parse_oper.h"
@@ -76,8 +77,11 @@ typedef struct
{
Oid class_oid; /* oid of catalog */
Oid oid_index_oid; /* oid of index on system oid column */
+ Oid name_index_oid; /* oid of index on name/schema column */
int oid_catcache_id; /* id of catcache on system oid column */
+ int name_catcache_id; /* id of catcache on name/schema column */
AttrNumber attnum_namespace; /* attnum of namespace field */
+ AttrNumber attnum_name; /* attnum of name field */
} ObjectPropertyType;
static ObjectPropertyType ObjectProperty[] =
@@ -85,152 +89,227 @@ static ObjectPropertyType ObjectProperty[] =
{
CastRelationId,
CastOidIndexId,
+ InvalidOid,
-1,
- InvalidAttrNumber
+ -1,
+ InvalidAttrNumber,
+ InvalidAttrNumber,
},
{
CollationRelationId,
CollationOidIndexId,
+ InvalidOid, /* No suitable index on pg_collation */
COLLOID,
- Anum_pg_collation_collnamespace
+ -1, /* COLLNAMEENCNSP also takes oid of encoding */
+ Anum_pg_collation_collnamespace,
+ Anum_pg_collation_collname,
},
{
ConstraintRelationId,
ConstraintOidIndexId,
+ ConstraintNameNspIndexId,
CONSTROID,
- Anum_pg_constraint_connamespace
+ -1,
+ Anum_pg_constraint_connamespace,
+ Anum_pg_constraint_conname,
},
{
ConversionRelationId,
ConversionOidIndexId,
+ ConversionNameNspIndexId,
CONVOID,
- Anum_pg_conversion_connamespace
+ -1,
+ Anum_pg_conversion_connamespace,
+ Anum_pg_conversion_conname,
},
{
DatabaseRelationId,
DatabaseOidIndexId,
+ DatabaseNameIndexId,
DATABASEOID,
- InvalidAttrNumber
+ -1,
+ InvalidAttrNumber,
+ Anum_pg_database_datname,
},
{
ExtensionRelationId,
ExtensionOidIndexId,
+ InvalidOid,
+ -1,
-1,
- InvalidAttrNumber /* extension doesn't belong to extnamespace */
+ InvalidAttrNumber, /* extension doesn't belong to extnamespace */
+ InvalidAttrNumber, /* extension name is unavailable to change */
},
{
ForeignDataWrapperRelationId,
ForeignDataWrapperOidIndexId,
+ ForeignDataWrapperNameIndexId,
FOREIGNDATAWRAPPEROID,
- InvalidAttrNumber
+ FOREIGNDATAWRAPPERNAME,
+ InvalidAttrNumber,
+ Anum_pg_foreign_data_wrapper_fdwname,
},
{
ForeignServerRelationId,
ForeignServerOidIndexId,
+ ForeignServerNameIndexId,
FOREIGNSERVEROID,
- InvalidAttrNumber
+ FOREIGNSERVERNAME,
+ InvalidAttrNumber,
+ Anum_pg_foreign_server_srvname,
},
{
ProcedureRelationId,
ProcedureOidIndexId,
+ InvalidOid, /* No suitable index on pg_proc */
PROCOID,
- Anum_pg_proc_pronamespace
+ -1, /* PROCNAMEARGSNSP takes argument types too */
+ Anum_pg_proc_pronamespace,
+ Anum_pg_proc_proname,
},
{
LanguageRelationId,
LanguageOidIndexId,
+ LanguageNameIndexId,
LANGOID,
+ LANGNAME,
InvalidAttrNumber,
+ Anum_pg_language_lanname,
},
{
LargeObjectMetadataRelationId,
LargeObjectMetadataOidIndexId,
+ InvalidOid,
+ -1,
-1,
- InvalidAttrNumber
+ InvalidAttrNumber,
+ InvalidAttrNumber,
},
{
OperatorClassRelationId,
OpclassOidIndexId,
+ InvalidOid, /* No suitable index on pg_opclass */
CLAOID,
+ -1, /* CLANAME takes oid of access method too */
Anum_pg_opclass_opcnamespace,
+ Anum_pg_opclass_opcname,
},
{
OperatorRelationId,
OperatorOidIndexId,
+ OperatorNameNspIndexId,
OPEROID,
- Anum_pg_operator_oprnamespace
+ -1, /* OPERNAMENSP takes oid of left/right types too */
+ Anum_pg_operator_oprnamespace,
+ Anum_pg_operator_oprname,
},
{
OperatorFamilyRelationId,
OpfamilyOidIndexId,
+ InvalidOid, /* No suitable index on op_opfamily */
OPFAMILYOID,
- Anum_pg_opfamily_opfnamespace
+ -1, /* OPFAMILYAMNAMENSP takes oid of access method too */
+ Anum_pg_opfamily_opfnamespace,
+ Anum_pg_opfamily_opfname,
},
{
AuthIdRelationId,
AuthIdOidIndexId,
+ AuthIdRolnameIndexId,
AUTHOID,
- InvalidAttrNumber
+ AUTHNAME,
+ InvalidAttrNumber,
+ AuthIdRelationId,
},
{
RewriteRelationId,
RewriteOidIndexId,
+ InvalidOid, /* No suitable index on pg_rewrite */
-1,
- InvalidAttrNumber
+ -1, /* RULERELNAME takes oid of relation too */
+ InvalidAttrNumber,
+ Anum_pg_rewrite_rulename,
},
{
NamespaceRelationId,
NamespaceOidIndexId,
+ NamespaceNameIndexId,
NAMESPACEOID,
- InvalidAttrNumber
+ NAMESPACENAME,
+ InvalidAttrNumber,
+ Anum_pg_namespace_nspname,
},
{
RelationRelationId,
ClassOidIndexId,
+ ClassNameNspIndexId,
RELOID,
- Anum_pg_class_relnamespace
+ RELNAMENSP,
+ Anum_pg_class_relnamespace,
+ Anum_pg_class_relname,
},
{
TableSpaceRelationId,
TablespaceOidIndexId,
+ TablespaceNameIndexId,
TABLESPACEOID,
- InvalidAttrNumber
+ -1,
+ InvalidAttrNumber,
+ Anum_pg_tablespace_spcname,
},
{
TriggerRelationId,
TriggerOidIndexId,
+ InvalidOid, /* No suitable index on pg_trigegr */
+ -1,
-1,
- InvalidAttrNumber
+ InvalidAttrNumber,
+ Anum_pg_trigger_tgname,
},
{
TSConfigRelationId,
TSConfigOidIndexId,
+ TSConfigNameNspIndexId,
TSCONFIGOID,
- Anum_pg_ts_config_cfgnamespace
+ TSCONFIGNAMENSP,
+ Anum_pg_ts_config_cfgnamespace,
+ Anum_pg_ts_config_cfgname,
},
{
TSDictionaryRelationId,
TSDictionaryOidIndexId,
+ TSDictionaryNameNspIndexId,
TSDICTOID,
- Anum_pg_ts_dict_dictnamespace
+ TSDICTNAMENSP,
+ Anum_pg_ts_dict_dictnamespace,
+ Anum_pg_ts_dict_dictname,
},
{
TSParserRelationId,
TSParserOidIndexId,
+ TSParserNameNspIndexId,
TSPARSEROID,
- Anum_pg_ts_parser_prsnamespace
+ TSPARSERNAMENSP,
+ Anum_pg_ts_parser_prsnamespace,
+ Anum_pg_ts_parser_prsname,
},
{
TSTemplateRelationId,
TSTemplateOidIndexId,
+ TSTemplateNameNspIndexId,
TSTEMPLATEOID,
+ TSTEMPLATENAMENSP,
Anum_pg_ts_template_tmplnamespace,
+ Anum_pg_ts_template_tmplname,
},
{
TypeRelationId,
TypeOidIndexId,
+ TypeNameNspIndexId,
TYPEOID,
- Anum_pg_type_typnamespace
+ TYPENAMENSP,
+ Anum_pg_type_typnamespace,
+ Anum_pg_type_typname,
}
};
@@ -914,93 +993,129 @@ object_exists(ObjectAddress address)
* Check ownership of an object previously identified by get_object_address.
*/
void
-check_object_ownership(Oid roleid, ObjectType objtype, ObjectAddress address,
- List *objname, List *objargs, Relation relation)
+check_object_ownership(Oid roleid, ObjectAddress address, Relation relation)
{
- switch (objtype)
+ switch (address.classId)
{
- case OBJECT_INDEX:
- case OBJECT_SEQUENCE:
- case OBJECT_TABLE:
- case OBJECT_VIEW:
- case OBJECT_FOREIGN_TABLE:
- case OBJECT_COLUMN:
- case OBJECT_RULE:
- case OBJECT_TRIGGER:
- case OBJECT_CONSTRAINT:
+ case RelationRelationId:
+ case RewriteRelationId:
+ case TriggerRelationId:
+ case ConstraintRelationId:
if (!pg_class_ownercheck(RelationGetRelid(relation), roleid))
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
RelationGetRelationName(relation));
break;
- case OBJECT_DATABASE:
+ case DatabaseRelationId:
if (!pg_database_ownercheck(address.objectId, roleid))
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE,
- NameListToString(objname));
+ get_database_name(address.objectId));
break;
- case OBJECT_TYPE:
- case OBJECT_DOMAIN:
- case OBJECT_ATTRIBUTE:
+ case TypeRelationId:
if (!pg_type_ownercheck(address.objectId, roleid))
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
format_type_be(address.objectId));
break;
- case OBJECT_AGGREGATE:
- case OBJECT_FUNCTION:
+ case ProcedureRelationId:
if (!pg_proc_ownercheck(address.objectId, roleid))
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
- NameListToString(objname));
+ format_procedure(address.objectId));
break;
- case OBJECT_OPERATOR:
+ case OperatorRelationId:
if (!pg_oper_ownercheck(address.objectId, roleid))
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPER,
- NameListToString(objname));
+ format_operator(address.objectId));
break;
- case OBJECT_SCHEMA:
+ case NamespaceRelationId:
if (!pg_namespace_ownercheck(address.objectId, roleid))
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_NAMESPACE,
- NameListToString(objname));
+ get_namespace_name(address.objectId));
break;
- case OBJECT_COLLATION:
+ case CollationRelationId:
if (!pg_collation_ownercheck(address.objectId, roleid))
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_COLLATION,
- NameListToString(objname));
+ get_collation_name(address.objectId));
break;
- case OBJECT_CONVERSION:
+ case ConversionRelationId:
if (!pg_conversion_ownercheck(address.objectId, roleid))
+ {
+ char *convname = NULL;
+ HeapTuple tup = SearchSysCache1(CONVOID,
+ ObjectIdGetDatum(address.objectId));
+ if (HeapTupleIsValid(tup))
+ {
+ Form_pg_conversion conversion
+ = (Form_pg_conversion) GETSTRUCT(tup);
+ convname = pstrdup(NameStr(conversion->conname));
+ ReleaseSysCache(tup);
+ }
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CONVERSION,
- NameListToString(objname));
+ convname);
+ }
break;
- case OBJECT_EXTENSION:
+ case ExtensionRelationId:
if (!pg_extension_ownercheck(address.objectId, roleid))
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_EXTENSION,
- NameListToString(objname));
+ get_extension_name(address.objectId));
break;
- case OBJECT_FDW:
+ case ForeignDataWrapperRelationId:
if (!pg_foreign_data_wrapper_ownercheck(address.objectId, roleid))
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_FDW,
- NameListToString(objname));
+ GetForeignDataWrapper(address.objectId)->fdwname);
break;
- case OBJECT_FOREIGN_SERVER:
+ case ForeignServerRelationId:
if (!pg_foreign_server_ownercheck(address.objectId, roleid))
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_FOREIGN_SERVER,
- NameListToString(objname));
+ GetForeignServer(address.objectId)->servername);
break;
- case OBJECT_LANGUAGE:
+ case LanguageRelationId:
if (!pg_language_ownercheck(address.objectId, roleid))
- aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_LANGUAGE,
- NameListToString(objname));
+ {
+ char *lanname = NULL;
+ HeapTuple tup = SearchSysCache1(LANGOID,
+ ObjectIdGetDatum(address.objectId));
+ if (HeapTupleIsValid(tup))
+ {
+ Form_pg_language lang
+ = (Form_pg_language) GETSTRUCT(tup);
+ lanname = pstrdup(NameStr(lang->lanname));
+ ReleaseSysCache(tup);
+ }
+ aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_LANGUAGE, lanname);
+ }
break;
- case OBJECT_OPCLASS:
+ case OperatorClassRelationId:
if (!pg_opclass_ownercheck(address.objectId, roleid))
- aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPCLASS,
- NameListToString(objname));
+ {
+ char *opcname = NULL;
+ HeapTuple tup = SearchSysCache1(CLAOID,
+ ObjectIdGetDatum(address.objectId));
+ if (HeapTupleIsValid(tup))
+ {
+ Form_pg_opclass opclass
+ = (Form_pg_opclass) GETSTRUCT(tup);
+ opcname = pstrdup(NameStr(opclass->opcname));
+ ReleaseSysCache(tup);
+ }
+ aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPCLASS, opcname);
+ }
break;
- case OBJECT_OPFAMILY:
+ case OperatorFamilyRelationId:
if (!pg_opfamily_ownercheck(address.objectId, roleid))
- aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPFAMILY,
- NameListToString(objname));
+ {
+ char *opfname = NULL;
+ HeapTuple tup = SearchSysCache1(OPFAMILYOID,
+ ObjectIdGetDatum(address.objectId));
+ if (HeapTupleIsValid(tup))
+ {
+ Form_pg_opfamily opfamily
+ = (Form_pg_opfamily) GETSTRUCT(tup);
+ opfname = pstrdup(NameStr(opfamily->opfname));
+ ReleaseSysCache(tup);
+ }
+ aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPFAMILY, opfname);
+ }
break;
- case OBJECT_LARGEOBJECT:
+ case LargeObjectRelationId:
if (!lo_compat_privileges &&
!pg_largeobject_ownercheck(address.objectId, roleid))
ereport(ERROR,
@@ -1008,14 +1123,36 @@ check_object_ownership(Oid roleid, ObjectType objtype, ObjectAddress address,
errmsg("must be owner of large object %u",
address.objectId)));
break;
- case OBJECT_CAST:
+ case CastRelationId:
{
- /* We can only check permissions on the source/target types */
- TypeName *sourcetype = (TypeName *) linitial(objname);
- TypeName *targettype = (TypeName *) linitial(objargs);
- Oid sourcetypeid = typenameTypeId(NULL, sourcetype);
- Oid targettypeid = typenameTypeId(NULL, targettype);
+ Relation catalog;
+ ScanKeyData skey[1];
+ SysScanDesc scan;
+ HeapTuple tup;
+ Oid sourcetypeid;
+ Oid targettypeid;
+
+ catalog = heap_open(CastRelationId, AccessShareLock);
+
+ ScanKeyInit(&skey[0],
+ ObjectIdAttributeNumber,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(address.objectId));
+
+ scan = systable_beginscan(catalog, CastOidIndexId, true,
+ SnapshotNow, 1, skey);
+ tup = systable_getnext(scan);
+ if (!HeapTupleIsValid(tup))
+ elog(ERROR, "could not find tuple for cast %u",
+ address.objectId);
+
+ sourcetypeid = ((Form_pg_cast) GETSTRUCT(tup))->castsource;
+ targettypeid = ((Form_pg_cast) GETSTRUCT(tup))->casttarget;
+
+ systable_endscan(scan);
+ heap_close(catalog, AccessShareLock);
+ /* We can only check permissions on the source/target types */
if (!pg_type_ownercheck(sourcetypeid, roleid)
&& !pg_type_ownercheck(targettypeid, roleid))
ereport(ERROR,
@@ -1025,23 +1162,46 @@ check_object_ownership(Oid roleid, ObjectType objtype, ObjectAddress address,
format_type_be(targettypeid))));
}
break;
- case OBJECT_TABLESPACE:
+ case TableSpaceRelationId:
if (!pg_tablespace_ownercheck(address.objectId, roleid))
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TABLESPACE,
- NameListToString(objname));
+ get_tablespace_name(address.objectId));
break;
- case OBJECT_TSDICTIONARY:
+ case TSDictionaryRelationId:
if (!pg_ts_dict_ownercheck(address.objectId, roleid))
+ {
+ char *dictname = NULL;
+ HeapTuple tup = SearchSysCache1(TSDICTOID,
+ ObjectIdGetDatum(address.objectId));
+ if (HeapTupleIsValid(tup))
+ {
+ Form_pg_ts_dict tsdict
+ = (Form_pg_ts_dict) GETSTRUCT(tup);
+ dictname = pstrdup(NameStr(tsdict->dictname));
+ ReleaseSysCache(tup);
+ }
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TSDICTIONARY,
- NameListToString(objname));
+ dictname);
+ }
break;
- case OBJECT_TSCONFIGURATION:
+ case TSConfigRelationId:
if (!pg_ts_config_ownercheck(address.objectId, roleid))
+ {
+ char *confname = NULL;
+ HeapTuple tup = SearchSysCache1(TSCONFIGOID,
+ ObjectIdGetDatum(address.objectId));
+ if (HeapTupleIsValid(tup))
+ {
+ Form_pg_ts_config tsconf
+ = (Form_pg_ts_config) GETSTRUCT(tup);
+ confname = pstrdup(NameStr(tsconf->cfgname));
+ ReleaseSysCache(tup);
+ }
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TSCONFIGURATION,
- NameListToString(objname));
+ confname);
+ }
break;
- case OBJECT_ROLE:
-
+ case AuthIdRelationId:
/*
* We treat roles as being "owned" by those with CREATEROLE priv,
* except that superusers are only owned by superusers.
@@ -1061,8 +1221,8 @@ check_object_ownership(Oid roleid, ObjectType objtype, ObjectAddress address,
errmsg("must have CREATEROLE privilege")));
}
break;
- case OBJECT_TSPARSER:
- case OBJECT_TSTEMPLATE:
+ case TSParserRelationId:
+ case TSTemplateRelationId:
/* We treat these object types as being owned by superusers */
if (!superuser_arg(roleid))
ereport(ERROR,
@@ -1070,9 +1230,258 @@ check_object_ownership(Oid roleid, ObjectType objtype, ObjectAddress address,
errmsg("must be superuser")));
break;
default:
- elog(ERROR, "unrecognized object type: %d",
- (int) objtype);
+ elog(ERROR, "unrecognized class-id of the object: %u",
+ address.classId);
+ }
+}
+
+/*
+ * check_exists_namespace
+ *
+ * check name or/and namespace conflict of the supplied object, if and
+ * when its name or namespace would be switched to.
+ */
+bool
+object_exists_namespace(ObjectAddress address,
+ Oid new_namespace, const char *new_name)
+{
+ ObjectPropertyType *property;
+ HeapTuple tuple;
+ Datum datum;
+ bool isnull;
+ bool found = false;
+
+ /*
+ * Right now, we have no code path to invoke this routine toward
+ * pg_attribute, pg_trigger or pg_rewrite; that takes special
+ * treatments.
+ */
+ Assert(address.objectSubId == 0);
+ Assert(address.classId != TriggerRelationId);
+ Assert(address.classId != RewriteRelationId);
+
+ /*
+ * Weird backward compatibility hack: ObjectAddress notation uses
+ * LargeObjectRelationId for large objects, but since PostgreSQL
+ * 9.0, the relevant catalog is actually LargeObjectMetadataRelationId.
+ */
+ if (address.classId == LargeObjectRelationId)
+ address.classId = LargeObjectMetadataRelationId;
+
+ property = get_object_property_data(address.classId);
+
+ /* This routine must be called towards object classes with its name. */
+ Assert(property->attnum_name != InvalidAttrNumber);
+
+ /* We have catcache by oid for named object types */
+ Assert(property->oid_catcache_id != -1);
+
+ tuple = SearchSysCache1(property->oid_catcache_id,
+ ObjectIdGetDatum(address.objectId));
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "cache lookup failed for class %u object %u subobj %d",
+ address.classId, address.objectId, address.objectSubId);
+
+ /*
+ * if namespace is preserved, the current one shall be used as
+ * a key to look up system catalog.
+ */
+ if (!OidIsValid(new_namespace) &&
+ property->attnum_namespace != InvalidAttrNumber)
+ {
+
+ datum = SysCacheGetAttr(property->oid_catcache_id,
+ tuple,
+ property->attnum_namespace,
+ &isnull);
+ Assert(!isnull);
+ new_namespace = DatumGetObjectId(datum);
+ }
+
+ /*
+ * if name is preserved, the current one shall be used as
+ * a key to look up system catalog.
+ */
+ if (!new_name)
+ {
+ datum = SysCacheGetAttr(property->oid_catcache_id,
+ tuple,
+ property->attnum_name,
+ &isnull);
+ Assert(!isnull);
+ new_name = pstrdup(NameStr(*(DatumGetName(datum))));
+ }
+ Assert(new_name != NULL);
+
+ /* COLLNAMEENCNSP cache takes encoding type, so special treatment too */
+ if (address.classId == CollationRelationId)
+ {
+ if (SearchSysCacheExists3(COLLNAMEENCNSP,
+ CStringGetDatum(new_name),
+ Int32GetDatum(GetDatabaseEncoding()),
+ ObjectIdGetDatum(new_namespace)))
+ found = true;
+ /* mustn't match an any-encoding entry, either */
+ if (SearchSysCacheExists3(COLLNAMEENCNSP,
+ CStringGetDatum(new_name),
+ Int32GetDatum(-1),
+ ObjectIdGetDatum(new_namespace)))
+ found = true;
}
+ /* PROCNAMEARGSNSP cache takes argument types too */
+ else if (address.classId == ProcedureRelationId)
+ {
+ Form_pg_proc procForm = (Form_pg_proc) GETSTRUCT(tuple);
+
+ if (SearchSysCacheExists3(PROCNAMEARGSNSP,
+ CStringGetDatum(new_name),
+ PointerGetDatum(&procForm->proargtypes),
+ ObjectIdGetDatum(new_namespace)))
+ found = true;
+ }
+ /* OPERNAMENSP cache takes oid of left/right types too */
+ else if (address.classId == OperatorRelationId)
+ {
+ Oid oprleft = ((Form_pg_operator) GETSTRUCT(tuple))->oprleft;
+ Oid oprright = ((Form_pg_operator) GETSTRUCT(tuple))->oprright;
+
+ if (SearchSysCacheExists4(OPERNAMENSP,
+ CStringGetDatum(new_name),
+ ObjectIdGetDatum(oprleft),
+ ObjectIdGetDatum(oprright),
+ ObjectIdGetDatum(new_namespace)))
+ found = true;
+ }
+ /* CLAAMNAMENSP cache takes oid of access method too */
+ else if (address.classId == OperatorClassRelationId)
+ {
+ Oid amoid = ((Form_pg_opclass) GETSTRUCT(tuple))->opcmethod;
+
+ if (SearchSysCacheExists3(CLAAMNAMENSP,
+ ObjectIdGetDatum(amoid),
+ CStringGetDatum(new_name),
+ ObjectIdGetDatum(new_namespace)))
+ found = true;
+ }
+ /* OPFAMILYAMNAMENSP cache takes oid of access method too */
+ else if (address.classId == OperatorFamilyRelationId)
+ {
+ Oid amoid = ((Form_pg_opfamily) GETSTRUCT(tuple))->opfmethod;
+
+ if (SearchSysCacheExists3(OPFAMILYAMNAMENSP,
+ ObjectIdGetDatum(amoid),
+ CStringGetDatum(new_name),
+ ObjectIdGetDatum(new_namespace)))
+ found = true;
+ }
+ else if (property->name_catcache_id != -1)
+ {
+ found = SearchSysCacheExists2(property->name_catcache_id,
+ CStringGetDatum(new_name),
+ ObjectIdGetDatum(new_namespace));
+ }
+ else
+ {
+ Relation rel;
+ ScanKeyData skey[2];
+ SysScanDesc scan;
+ int nkeys;
+
+ /* No syscache, so examine the table directly. */
+ Assert(OidIsValid(property->name_index_oid));
+
+ ScanKeyInit(&skey[0],
+ property->attnum_name,
+ BTEqualStrategyNumber, F_NAMEEQ,
+ CStringGetDatum(new_name));
+ if (property->attnum_namespace == InvalidAttrNumber)
+ nkeys = 1;
+ else
+ {
+ ScanKeyInit(&skey[1],
+ property->attnum_namespace,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(new_namespace));
+ nkeys = 2;
+ }
+
+ rel = heap_open(address.classId, AccessShareLock);
+ scan = systable_beginscan(rel, property->name_index_oid, true,
+ SnapshotNow, nkeys, skey);
+ found = HeapTupleIsValid(systable_getnext(scan));
+ systable_endscan(scan);
+ heap_close(rel, AccessShareLock);
+ }
+ ReleaseSysCache(tuple);
+
+ return found;
+}
+
+/*
+ * get_object_tuple
+ *
+ * It returns a copy of heaptuple data within system catalog.
+ */
+HeapTuple
+get_object_tuple(ObjectAddress address)
+{
+ int cache = -1;
+ Oid indexoid = InvalidOid;
+ Relation rel;
+ ScanKeyData skey[1];
+ SysScanDesc sd;
+ HeapTuple tuple = NULL;
+ ObjectPropertyType *property;
+
+ /* Sub-objects require special treatment. */
+ if (address.objectSubId != 0)
+ {
+ /* Currently, attributes are the only sub-objects. */
+ Assert(address.classId == RelationRelationId);
+ tuple = SearchSysCacheCopy2(ATTNUM,
+ ObjectIdGetDatum(address.objectId),
+ Int16GetDatum(address.objectSubId));
+ if (((Form_pg_attribute) GETSTRUCT(tuple))->attisdropped)
+ {
+ heap_freetuple(tuple);
+ return NULL;
+ }
+ return tuple;
+ }
+
+ /*
+ * Weird backward compatibility hack: ObjectAddress notation uses
+ * LargeObjectRelationId for large objects, but since PostgreSQL
+ * 9.0, the relevant catalog is actually LargeObjectMetadataRelationId.
+ */
+ if (address.classId == LargeObjectRelationId)
+ address.classId = LargeObjectMetadataRelationId;
+
+ /*
+ * For object types that have a relevant syscache, we use it; for
+ * everything else, we'll have to do an index-scan.
+ */
+ property = get_object_property_data(address.classId);
+ cache = property->oid_catcache_id;
+ indexoid = property->oid_index_oid;
+
+ /* Found a syscache? */
+ if (cache != -1)
+ return SearchSysCacheCopy1(cache, ObjectIdGetDatum(address.objectId));
+
+ /* No syscache, so examine the table directly. */
+ Assert(OidIsValid(indexoid));
+ ScanKeyInit(&skey[0],
+ ObjectIdAttributeNumber,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(address.objectId));
+ rel = heap_open(address.classId, AccessShareLock);
+ sd = systable_beginscan(rel, indexoid, true, SnapshotNow, 1, skey);
+ tuple = heap_copytuple(systable_getnext(sd));
+ systable_endscan(sd);
+ heap_close(rel, AccessShareLock);
+
+ return tuple;
}
/*
diff --git a/src/backend/commands/comment.c b/src/backend/commands/comment.c
index 200b6a2..34705e5 100644
--- a/src/backend/commands/comment.c
+++ b/src/backend/commands/comment.c
@@ -73,8 +73,7 @@ CommentObject(CommentStmt *stmt)
&relation, ShareUpdateExclusiveLock, false);
/* Require ownership of the target object. */
- check_object_ownership(GetUserId(), stmt->objtype, address,
- stmt->objname, stmt->objargs, relation);
+ check_object_ownership(GetUserId(), address, relation);
/* Perform other integrity checks as needed. */
switch (stmt->objtype)
diff --git a/src/backend/commands/dropcmds.c b/src/backend/commands/dropcmds.c
index ef70168..2cd8232 100644
--- a/src/backend/commands/dropcmds.c
+++ b/src/backend/commands/dropcmds.c
@@ -98,8 +98,7 @@ RemoveObjects(DropStmt *stmt)
namespaceId = get_object_namespace(&address);
if (!OidIsValid(namespaceId) ||
!pg_namespace_ownercheck(namespaceId, GetUserId()))
- check_object_ownership(GetUserId(), stmt->removeType, address,
- objname, objargs, relation);
+ check_object_ownership(GetUserId(), address, relation);
}
/* Release any relcache reference count, but keep lock until commit. */
diff --git a/src/backend/commands/extension.c b/src/backend/commands/extension.c
index c334ca9..5a2cc09 100644
--- a/src/backend/commands/extension.c
+++ b/src/backend/commands/extension.c
@@ -2652,8 +2652,7 @@ ExecAlterExtensionContentsStmt(AlterExtensionContentsStmt *stmt)
&relation, ShareUpdateExclusiveLock, false);
/* Permission check: must own target object, too */
- check_object_ownership(GetUserId(), stmt->objtype, object,
- stmt->objname, stmt->objargs, relation);
+ check_object_ownership(GetUserId(), object, relation);
/*
* Check existing extension membership.
diff --git a/src/backend/commands/seclabel.c b/src/backend/commands/seclabel.c
index e0fd7ac..118f467 100644
--- a/src/backend/commands/seclabel.c
+++ b/src/backend/commands/seclabel.c
@@ -90,8 +90,7 @@ ExecSecLabelStmt(SecLabelStmt *stmt)
&relation, ShareUpdateExclusiveLock, false);
/* Require ownership of the target object. */
- check_object_ownership(GetUserId(), stmt->objtype, address,
- stmt->objname, stmt->objargs, relation);
+ check_object_ownership(GetUserId(), address, relation);
/* Perform other integrity checks as needed. */
switch (stmt->objtype)
diff --git a/src/include/catalog/objectaddress.h b/src/include/catalog/objectaddress.h
index eddccb8..ff7b957 100644
--- a/src/include/catalog/objectaddress.h
+++ b/src/include/catalog/objectaddress.h
@@ -13,6 +13,7 @@
#ifndef OBJECTADDRESS_H
#define OBJECTADDRESS_H
+#include "access/htup.h"
#include "nodes/parsenodes.h"
#include "storage/lock.h"
#include "utils/relcache.h"
@@ -32,8 +33,14 @@ extern ObjectAddress get_object_address(ObjectType objtype, List *objname,
LOCKMODE lockmode, bool missing_ok);
extern void check_object_ownership(Oid roleid,
- ObjectType objtype, ObjectAddress address,
- List *objname, List *objargs, Relation relation);
+ ObjectAddress address,
+ Relation relation);
+
+extern bool object_exists_namespace(ObjectAddress address,
+ Oid new_namespace,
+ const char *new_name);
+
+extern HeapTuple get_object_tuple(ObjectAddress address);
extern Oid get_object_namespace(const ObjectAddress *address);
diff --git a/src/test/regress/expected/alter_rename.out b/src/test/regress/expected/alter_rename.out
new file mode 100644
index 0000000..6688d50
--- /dev/null
+++ b/src/test/regress/expected/alter_rename.out
@@ -0,0 +1,282 @@
+--
+-- ALTER xxx RENAME TO/SET SCHEMA statement
+--
+CREATE SCHEMA testschema_1;
+CREATE SCHEMA testschema_2;
+SET search_path = testschema_1, public;
+--
+-- ROLE
+--
+CREATE ROLE testrole_1;
+CREATE ROLE testrole_2;
+ALTER ROLE testrole_1 RENAME TO testrole_2; -- fail
+ERROR: role "testrole_2" already exists
+ALTER ROLE testrole_1 RENAME TO testrole_3; -- OK
+DROP ROLE testrole_2, testrole_3;
+--
+-- LANGUAGE
+--
+CREATE LANGUAGE testlang_1 HANDLER plpgsql_call_handler;
+CREATE LANGUAGE testlang_2 HANDLER plpgsql_call_handler;
+ALTER LANGUAGE testlang_1 RENAME TO testlang_2; -- fail
+ERROR: language "testlang_2" already exists
+ALTER LANGUAGE testlang_1 RENAME TO testlang_3; -- OK
+DROP LANGUAGE testlang_2;
+DROP LANGUAGE testlang_3;
+--
+-- TABLE
+--
+CREATE TABLE testtable_a(a int, b int);
+CREATE TABLE testtable_b(x int, y int);
+ALTER TABLE testtable_a RENAME TO testtable_b; -- fail
+ERROR: relation "testtable_b" already exists
+ALTER TABLE testtable_b SET SCHEMA testschema_2; -- OK
+ALTER TABLE testtable_a RENAME TO testtable_b; -- OK
+ALTER TABLE testtable_b SET SCHEMA testschema_2; -- fail
+ERROR: relation "testtable_b" already exists in schema "testschema_2"
+--
+-- VIEW
+--
+CREATE VIEW testview_a AS SELECT * FROM pg_class WHERE relname like 'pg_%';
+CREATE VIEW testview_b AS SELECT * FROM pg_class WHERE relname like 'pg_%';
+ALTER VIEW testview_a RENAME TO testview_b; -- fail
+ERROR: relation "testview_b" already exists
+ALTER VIEW testview_b SET SCHEMA testschema_2; -- OK
+ALTER VIEW testview_a RENAME TO testview_b; -- OK
+ALTER VIEW testview_b SET SCHEMA testschema_2; -- fail
+ERROR: relation "testview_b" already exists in schema "testschema_2"
+ALTER VIEW testtable_b SET SCHEMA public; -- fail
+ERROR: "testtable_b" is not a view
+ALTER VIEW testtable_b RENAME TO testtable_c; -- fail
+ERROR: "testtable_b" is not a view
+--
+-- SEQUENCE
+--
+CREATE SEQUENCE testseq_a;
+CREATE SEQUENCE testseq_b;
+ALTER SEQUENCE testseq_a RENAME TO testseq_b; -- fail
+ERROR: relation "testseq_b" already exists
+ALTER SEQUENCE testseq_b SET SCHEMA testschema_2; -- OK
+ALTER SEQUENCE testseq_a RENAME TO testseq_b; -- OK
+ALTER SEQUENCE testseq_b SET SCHEMA testschema_2; -- fail
+ERROR: relation "testseq_b" already exists in schema "testschema_2"
+ALTER SEQUENCE testview_b SET SCHEMA public; -- fail
+ERROR: "testview_b" is not a sequence
+ALTER SEQUENCE testview_b RENAME TO testview_c; -- fail
+ERROR: "testview_b" is not a sequence
+--
+-- COMPOSITE TYPE
+--
+CREATE TYPE testcomptype_a AS (a int, b int);
+CREATE TYPE testcomptype_b AS (a int, b int);
+ALTER TYPE testcomptype_a RENAME TO testcomptype_b; -- fail
+ERROR: relation "testcomptype_b" already exists
+ALTER TYPE testcomptype_b SET SCHEMA testschema_2; -- OK
+ALTER TYPE testcomptype_a RENAME TO testcomptype_b; -- OK
+ALTER TYPE testcomptype_b SET SCHEMA testschema_2; -- fail
+ERROR: type "testcomptype_b" already exists in schema "testschema_2"
+ALTER TYPE testseq_b SET SCHEMA public; -- fail
+ERROR: testseq_b is a table's row type
+HINT: Use ALTER TABLE instead.
+ALTER TYPE testseq_b RENAME TO testseq_c; -- fail
+ERROR: testseq_b is a table's row type
+HINT: Use ALTER TABLE instead.
+--
+-- INDEX
+--
+CREATE INDEX testindex_a ON testtable_b (a);
+CREATE INDEX testindex_b ON testtable_b (b);
+ALTER INDEX testindex_a RENAME TO testindex_b; -- fail
+ERROR: relation "testindex_b" already exists
+ALTER INDEX testindex_a RENAME TO testindex_c; -- OK
+--
+-- COLUMN
+--
+ALTER TABLE testtable_b RENAME a TO b; -- fail
+ERROR: column "b" of relation "testtable_b" already exists
+ALTER TABLE testtable_b RENAME a TO x; -- OK
+CREATE TABLE testtable_c (z int) INHERITS (testtable_b);
+ALTER TABLE ONLY testtable_b RENAME b TO y; -- fail
+ERROR: inherited column "b" must be renamed in child tables too
+ALTER TABLE testtable_b RENAME b TO y; -- OK
+ALTER TABLE testtable_c RENAME z TO zz; -- OK
+ALTER TABLE testtable_c RENAME x TO xx; -- fail
+ERROR: cannot rename inherited column "x"
+--
+-- TRIGGER
+--
+CREATE TRIGGER testtrigger_a
+ BEFORE UPDATE ON testtable_b
+ FOR EACH ROW EXECUTE PROCEDURE suppress_redundant_updates_trigger();
+CREATE TRIGGER testtrigger_b
+ BEFORE UPDATE ON testtable_b
+ FOR EACH ROW EXECUTE PROCEDURE suppress_redundant_updates_trigger();
+ALTER TRIGGER testtrigger_a ON testtable_b RENAME TO testtrigger_b; -- fail
+ERROR: trigger "testtrigger_b" for relation "testtable_b" already exists
+ALTER TRIGGER testtrigger_a ON testtable_b RENAME TO testtrigger_c; -- OK
+--
+-- FUNCTION, AGGREGATE
+--
+CREATE FUNCTION testfunc_a(int)
+ RETURNS int LANGUAGE sql
+ AS 'SELECT $1 + $1';
+CREATE FUNCTION testfunc_b(int)
+ RETURNS int LANGUAGE sql
+ AS 'SELECT $1 + $1';
+ALTER FUNCTION testfunc_a(int) RENAME TO testfunc_b; -- fail
+ERROR: function testfunc_b(integer) already exists in schema "testschema_1"
+ALTER FUNCTION testfunc_b(int) SET SCHEMA testschema_2; -- OK
+ALTER FUNCTION testfunc_a(int) RENAME TO testfunc_b; -- OK
+ALTER FUNCTION testfunc_b(int) SET SCHEMA testschema_2; -- fail
+ERROR: function "testfunc_b" already exists in schema "testschema_2"
+CREATE AGGREGATE testagg_a(
+ sfunc1 = int4pl, basetype = int4, stype1 = int4,
+ initcond1 = '0'
+);
+CREATE AGGREGATE testagg_b(
+ sfunc1 = int4pl, basetype = int4, stype1 = int4,
+ initcond1 = '0'
+);
+ALTER AGGREGATE testagg_a(int) RENAME TO testagg_b; -- fail
+ERROR: function testagg_b(integer) already exists in schema "testschema_1"
+ALTER AGGREGATE testagg_b(int) SET SCHEMA testschema_2; -- OK
+ALTER AGGREGATE testagg_a(int) RENAME TO testagg_b; -- OK
+ALTER AGGREGATE testagg_b(int) SET SCHEMA testschema_2; -- fail
+ERROR: function "testagg_b" already exists in schema "testschema_2"
+--
+-- TYPE
+--
+CREATE TYPE testtype_a;
+CREATE TYPE testtype_b;
+CREATE FUNCTION testtype_a_in (cstring) RETURNS testtype_a LANGUAGE 'internal' AS 'int4in';
+NOTICE: return type testtype_a is only a shell
+CREATE FUNCTION testtype_b_in (cstring) RETURNS testtype_b LANGUAGE 'internal' AS 'int4in';
+NOTICE: return type testtype_b is only a shell
+CREATE FUNCTION testtype_a_out (testtype_a) RETURNS cstring LANGUAGE 'internal' AS 'int4out';
+NOTICE: argument type testtype_a is only a shell
+CREATE FUNCTION testtype_b_out (testtype_b) RETURNS cstring LANGUAGE 'internal' AS 'int4out';
+NOTICE: argument type testtype_b is only a shell
+CREATE TYPE testtype_a (internallength = 4, input = testtype_a_in, output = testtype_a_out);
+CREATE TYPE testtype_b (internallength = 4, input = testtype_b_in, output = testtype_b_out);
+ALTER TYPE testtype_a RENAME TO testtype_b; -- fail
+ERROR: type "testtype_b" already exists
+ALTER TYPE testtype_b SET SCHEMA testschema_2; -- OK
+ALTER TYPE testtype_a RENAME TO testtype_b; -- OK
+ALTER TYPE testtype_b SET SCHEMA testschema_2; -- fail
+ERROR: type "testtype_b" already exists in schema "testschema_2"
+--
+-- OPERATOR, OPERATOR FAMILY and OPERATOR CLASS
+--
+CREATE OPERATOR @#@
+ (leftarg = int8, rightarg = int8, procedure = int8xor);
+ALTER OPERATOR @#@(int8,int8) SET SCHEMA testschema_2; -- OK
+CREATE OPERATOR @#@
+ (leftarg = int8, rightarg = int8, procedure = int8xor);
+-- XXX - comment out due to error message with oid determinded at runtime
+-- ALTER OPERATOR @#@(int8,int8) SET SCHEMA testschema_2; -- fail
+CREATE OPERATOR FAMILY testopfamily_a USING btree;
+CREATE OPERATOR FAMILY testopfamily_b USING btree;
+ALTER OPERATOR FAMILY testopfamily_a USING btree RENAME TO testopfamily_b; -- fail
+ERROR: operator family "testopfamily_b" for access method "btree" already exists in schema "testschema_1"
+ALTER OPERATOR FAMILY testopfamily_b USING btree SET SCHEMA testschema_2; -- OK
+ALTER OPERATOR FAMILY testopfamily_a USING btree RENAME TO testopfamily_b; -- OK
+-- XXX - comment out due to error message with oid determinded at runtime
+-- ALTER OPERATOR FAMILY testopfamily_b USING btree SET SCHEMA testschema_2; -- fail
+CREATE OPERATOR CLASS testopclass_a
+ FOR TYPE box USING btree FAMILY testopfamily_b AS OPERATOR 1 =;
+CREATE OPERATOR CLASS testopclass_b
+ FOR TYPE circle USING btree FAMILY testopfamily_b AS OPERATOR 1 =;
+ALTER OPERATOR CLASS testopclass_a USING btree RENAME TO testopclass_b; -- fail
+ERROR: operator class "testopclass_b" for access method "btree" already exists in schema "testschema_1"
+ALTER OPERATOR CLASS testopclass_b USING btree SET SCHEMA testschema_2; -- OK
+ALTER OPERATOR CLASS testopclass_a USING btree RENAME TO testopclass_b; -- OK
+-- XXX - comment out due to error message with oid determinded at runtime
+-- ALTER OPERATOR CLASS testopclass_b USING btree SET SCHEMA testschema_2; -- fail
+--
+-- TEXT SEARCH
+--
+CREATE TEXT SEARCH DICTIONARY testtsdict_a (
+ Template=ispell,
+ DictFile=ispell_sample,
+ AffFile=ispell_sample
+);
+CREATE TEXT SEARCH DICTIONARY testtsdict_b (
+ Template=ispell,
+ DictFile=ispell_sample,
+ AffFile=ispell_sample
+);
+ALTER TEXT SEARCH DICTIONARY testtsdict_a RENAME TO testtsdict_b; -- fail
+ERROR: text search dictionary "testtsdict_b" already exists
+ALTER TEXT SEARCH DICTIONARY testtsdict_b SET SCHEMA testschema_2; -- OK
+ALTER TEXT SEARCH DICTIONARY testtsdict_a RENAME TO testtsdict_b; -- OK
+ALTER TEXT SEARCH DICTIONARY testtsdict_b SET SCHEMA testschema_2; -- fail
+ERROR: text search dictionary testtsdict_b already exists in schema "testschema_2"
+CREATE TEXT SEARCH CONFIGURATION testtsconf_a (COPY=english);
+CREATE TEXT SEARCH CONFIGURATION testtsconf_b (COPY=english);
+ALTER TEXT SEARCH CONFIGURATION testtsconf_a RENAME TO testtsconf_b; -- fail
+ERROR: text search configuration "testtsconf_b" already exists
+ALTER TEXT SEARCH CONFIGURATION testtsconf_b SET SCHEMA testschema_2; -- OK
+ALTER TEXT SEARCH CONFIGURATION testtsconf_a RENAME TO testtsconf_b; -- OK
+ALTER TEXT SEARCH CONFIGURATION testtsconf_b SET SCHEMA testschema_2; -- fail
+ERROR: text search configuration testtsconf_b already exists in schema "testschema_2"
+--
+-- COLLATION
+--
+CREATE COLLATION testcollation_a FROM "C";
+CREATE COLLATION testcollation_b FROM "C";
+ALTER COLLATION testcollation_a RENAME TO testcollation_b; -- fail
+ERROR: collation "testcollation_b" for encoding "UTF8" already exists in schema "testschema_1"
+ALTER COLLATION testcollation_b SET SCHEMA testschema_2; -- OK
+ALTER COLLATION testcollation_a RENAME TO testcollation_b; -- OK
+ALTER COLLATION testcollation_b SET SCHEMA testschema_2; -- fail
+ERROR: collation "testcollation_b" for encoding "UTF8" already exists in schema "testschema_2"
+--
+-- CONVERSION
+--
+CREATE CONVERSION testconv_a FOR 'LATIN1' TO 'UTF8' FROM iso8859_1_to_utf8;
+CREATE CONVERSION testconv_b FOR 'LATIN1' TO 'UTF8' FROM iso8859_1_to_utf8;
+ALTER CONVERSION testconv_a RENAME TO testconv_b; -- fail
+ERROR: conversion "testconv_b" already exists in schema "testschema_1"
+ALTER CONVERSION testconv_b SET SCHEMA testschema_2; -- OK
+ALTER CONVERSION testconv_a RENAME TO testconv_b; -- OK
+ALTER CONVERSION testconv_b SET SCHEMA testschema_2; -- fail
+ERROR: conversion testconv_b already exists in schema "testschema_2"
+--
+-- SCHEMA
+--
+ALTER SCHEMA testschema_1 RENAME TO testschema_2; -- fail
+ERROR: schema "testschema_2" already exists
+ALTER SCHEMA testschema_1 RENAME TO testschema_3; -- OK
+DROP SCHEMA testschema_2, testschema_3 CASCADE;
+NOTICE: drop cascades to 31 other objects
+DETAIL: drop cascades to table testschema_3.testtable_b
+drop cascades to view testschema_3.testview_b
+drop cascades to sequence testschema_3.testseq_b
+drop cascades to type testschema_3.testcomptype_b
+drop cascades to table testschema_3.testtable_c
+drop cascades to function testschema_3.testfunc_b(integer)
+drop cascades to function testschema_3.testagg_b(integer)
+drop cascades to type testschema_3.testtype_b
+drop cascades to function testschema_3.testtype_a_in(cstring)
+drop cascades to function testschema_3.testtype_a_out(testschema_3.testtype_b)
+drop cascades to operator testschema_3.@#@(bigint,bigint)
+drop cascades to operator family testschema_3.testopfamily_b for access method btree
+drop cascades to text search dictionary testtsdict_b
+drop cascades to text search configuration testtsconf_b
+drop cascades to collation testcollation_b
+drop cascades to conversion testconv_b
+drop cascades to table testschema_2.testtable_b
+drop cascades to view testschema_2.testview_b
+drop cascades to sequence testschema_2.testseq_b
+drop cascades to type testschema_2.testcomptype_b
+drop cascades to function testschema_2.testfunc_b(integer)
+drop cascades to function testschema_2.testagg_b(integer)
+drop cascades to type testschema_2.testtype_b
+drop cascades to function testschema_3.testtype_b_in(cstring)
+drop cascades to function testschema_3.testtype_b_out(testschema_2.testtype_b)
+drop cascades to operator testschema_2.@#@(bigint,bigint)
+drop cascades to operator family testschema_2.testopfamily_b for access method btree
+drop cascades to text search dictionary testtsdict_b
+drop cascades to text search configuration testtsconf_b
+drop cascades to collation testcollation_b
+drop cascades to conversion testconv_b
diff --git a/src/test/regress/expected/privileges.out b/src/test/regress/expected/privileges.out
index 5cda230..8aec0a4 100644
--- a/src/test/regress/expected/privileges.out
+++ b/src/test/regress/expected/privileges.out
@@ -504,7 +504,7 @@ SELECT testfunc1(5); -- ok
(1 row)
DROP FUNCTION testfunc1(int); -- fail
-ERROR: must be owner of function testfunc1
+ERROR: must be owner of function testfunc1(integer)
\c -
DROP FUNCTION testfunc1(int); -- ok
-- restore to sanity
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index b47b08b..7f590fc 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -99,7 +99,7 @@ test: select_views portals_p2 foreign_key cluster dependency guc bitmapops combo
# NB: temp.sql does a reconnect which transiently uses 2 connections,
# so keep this parallel group to at most 19 tests
# ----------
-test: plancache limit plpgsql copy2 temp domain rangefuncs prepare without_oid conversion truncate alter_table sequence polymorphism rowtypes returning largeobject with xml
+test: plancache limit plpgsql copy2 temp domain rangefuncs prepare without_oid conversion truncate alter_rename alter_table sequence polymorphism rowtypes returning largeobject with xml
# run stats by itself because its delay may be insufficient under heavy load
test: stats
diff --git a/src/test/regress/serial_schedule b/src/test/regress/serial_schedule
index 57806b5..78f63e3 100644
--- a/src/test/regress/serial_schedule
+++ b/src/test/regress/serial_schedule
@@ -119,6 +119,7 @@ test: prepare
test: without_oid
test: conversion
test: truncate
+test: alter_rename
test: alter_table
test: sequence
test: polymorphism
diff --git a/src/test/regress/sql/alter_rename.sql b/src/test/regress/sql/alter_rename.sql
new file mode 100644
index 0000000..9b2bdf1
--- /dev/null
+++ b/src/test/regress/sql/alter_rename.sql
@@ -0,0 +1,240 @@
+--
+-- ALTER xxx RENAME TO/SET SCHEMA statement
+--
+
+CREATE SCHEMA testschema_1;
+CREATE SCHEMA testschema_2;
+
+SET search_path = testschema_1, public;
+
+--
+-- ROLE
+--
+CREATE ROLE testrole_1;
+CREATE ROLE testrole_2;
+
+ALTER ROLE testrole_1 RENAME TO testrole_2; -- fail
+ALTER ROLE testrole_1 RENAME TO testrole_3; -- OK
+
+DROP ROLE testrole_2, testrole_3;
+
+--
+-- LANGUAGE
+--
+CREATE LANGUAGE testlang_1 HANDLER plpgsql_call_handler;
+CREATE LANGUAGE testlang_2 HANDLER plpgsql_call_handler;
+
+ALTER LANGUAGE testlang_1 RENAME TO testlang_2; -- fail
+ALTER LANGUAGE testlang_1 RENAME TO testlang_3; -- OK
+
+DROP LANGUAGE testlang_2;
+DROP LANGUAGE testlang_3;
+
+--
+-- TABLE
+--
+CREATE TABLE testtable_a(a int, b int);
+CREATE TABLE testtable_b(x int, y int);
+ALTER TABLE testtable_a RENAME TO testtable_b; -- fail
+ALTER TABLE testtable_b SET SCHEMA testschema_2; -- OK
+ALTER TABLE testtable_a RENAME TO testtable_b; -- OK
+ALTER TABLE testtable_b SET SCHEMA testschema_2; -- fail
+
+--
+-- VIEW
+--
+CREATE VIEW testview_a AS SELECT * FROM pg_class WHERE relname like 'pg_%';
+CREATE VIEW testview_b AS SELECT * FROM pg_class WHERE relname like 'pg_%';
+ALTER VIEW testview_a RENAME TO testview_b; -- fail
+ALTER VIEW testview_b SET SCHEMA testschema_2; -- OK
+ALTER VIEW testview_a RENAME TO testview_b; -- OK
+ALTER VIEW testview_b SET SCHEMA testschema_2; -- fail
+ALTER VIEW testtable_b SET SCHEMA public; -- fail
+ALTER VIEW testtable_b RENAME TO testtable_c; -- fail
+
+--
+-- SEQUENCE
+--
+CREATE SEQUENCE testseq_a;
+CREATE SEQUENCE testseq_b;
+ALTER SEQUENCE testseq_a RENAME TO testseq_b; -- fail
+ALTER SEQUENCE testseq_b SET SCHEMA testschema_2; -- OK
+ALTER SEQUENCE testseq_a RENAME TO testseq_b; -- OK
+ALTER SEQUENCE testseq_b SET SCHEMA testschema_2; -- fail
+ALTER SEQUENCE testview_b SET SCHEMA public; -- fail
+ALTER SEQUENCE testview_b RENAME TO testview_c; -- fail
+
+--
+-- COMPOSITE TYPE
+--
+CREATE TYPE testcomptype_a AS (a int, b int);
+CREATE TYPE testcomptype_b AS (a int, b int);
+ALTER TYPE testcomptype_a RENAME TO testcomptype_b; -- fail
+ALTER TYPE testcomptype_b SET SCHEMA testschema_2; -- OK
+ALTER TYPE testcomptype_a RENAME TO testcomptype_b; -- OK
+ALTER TYPE testcomptype_b SET SCHEMA testschema_2; -- fail
+ALTER TYPE testseq_b SET SCHEMA public; -- fail
+ALTER TYPE testseq_b RENAME TO testseq_c; -- fail
+
+--
+-- INDEX
+--
+CREATE INDEX testindex_a ON testtable_b (a);
+CREATE INDEX testindex_b ON testtable_b (b);
+ALTER INDEX testindex_a RENAME TO testindex_b; -- fail
+ALTER INDEX testindex_a RENAME TO testindex_c; -- OK
+
+--
+-- COLUMN
+--
+ALTER TABLE testtable_b RENAME a TO b; -- fail
+ALTER TABLE testtable_b RENAME a TO x; -- OK
+CREATE TABLE testtable_c (z int) INHERITS (testtable_b);
+ALTER TABLE ONLY testtable_b RENAME b TO y; -- fail
+ALTER TABLE testtable_b RENAME b TO y; -- OK
+ALTER TABLE testtable_c RENAME z TO zz; -- OK
+ALTER TABLE testtable_c RENAME x TO xx; -- fail
+
+--
+-- TRIGGER
+--
+CREATE TRIGGER testtrigger_a
+ BEFORE UPDATE ON testtable_b
+ FOR EACH ROW EXECUTE PROCEDURE suppress_redundant_updates_trigger();
+CREATE TRIGGER testtrigger_b
+ BEFORE UPDATE ON testtable_b
+ FOR EACH ROW EXECUTE PROCEDURE suppress_redundant_updates_trigger();
+ALTER TRIGGER testtrigger_a ON testtable_b RENAME TO testtrigger_b; -- fail
+ALTER TRIGGER testtrigger_a ON testtable_b RENAME TO testtrigger_c; -- OK
+
+
+--
+-- FUNCTION, AGGREGATE
+--
+CREATE FUNCTION testfunc_a(int)
+ RETURNS int LANGUAGE sql
+ AS 'SELECT $1 + $1';
+CREATE FUNCTION testfunc_b(int)
+ RETURNS int LANGUAGE sql
+ AS 'SELECT $1 + $1';
+ALTER FUNCTION testfunc_a(int) RENAME TO testfunc_b; -- fail
+ALTER FUNCTION testfunc_b(int) SET SCHEMA testschema_2; -- OK
+ALTER FUNCTION testfunc_a(int) RENAME TO testfunc_b; -- OK
+ALTER FUNCTION testfunc_b(int) SET SCHEMA testschema_2; -- fail
+
+
+CREATE AGGREGATE testagg_a(
+ sfunc1 = int4pl, basetype = int4, stype1 = int4,
+ initcond1 = '0'
+);
+CREATE AGGREGATE testagg_b(
+ sfunc1 = int4pl, basetype = int4, stype1 = int4,
+ initcond1 = '0'
+);
+ALTER AGGREGATE testagg_a(int) RENAME TO testagg_b; -- fail
+ALTER AGGREGATE testagg_b(int) SET SCHEMA testschema_2; -- OK
+ALTER AGGREGATE testagg_a(int) RENAME TO testagg_b; -- OK
+ALTER AGGREGATE testagg_b(int) SET SCHEMA testschema_2; -- fail
+
+--
+-- TYPE
+--
+CREATE TYPE testtype_a;
+CREATE TYPE testtype_b;
+CREATE FUNCTION testtype_a_in (cstring) RETURNS testtype_a LANGUAGE 'internal' AS 'int4in';
+CREATE FUNCTION testtype_b_in (cstring) RETURNS testtype_b LANGUAGE 'internal' AS 'int4in';
+CREATE FUNCTION testtype_a_out (testtype_a) RETURNS cstring LANGUAGE 'internal' AS 'int4out';
+CREATE FUNCTION testtype_b_out (testtype_b) RETURNS cstring LANGUAGE 'internal' AS 'int4out';
+CREATE TYPE testtype_a (internallength = 4, input = testtype_a_in, output = testtype_a_out);
+CREATE TYPE testtype_b (internallength = 4, input = testtype_b_in, output = testtype_b_out);
+
+ALTER TYPE testtype_a RENAME TO testtype_b; -- fail
+ALTER TYPE testtype_b SET SCHEMA testschema_2; -- OK
+ALTER TYPE testtype_a RENAME TO testtype_b; -- OK
+ALTER TYPE testtype_b SET SCHEMA testschema_2; -- fail
+
+--
+-- OPERATOR, OPERATOR FAMILY and OPERATOR CLASS
+--
+
+CREATE OPERATOR @#@
+ (leftarg = int8, rightarg = int8, procedure = int8xor);
+ALTER OPERATOR @#@(int8,int8) SET SCHEMA testschema_2; -- OK
+CREATE OPERATOR @#@
+ (leftarg = int8, rightarg = int8, procedure = int8xor);
+-- XXX - comment out due to error message with oid determinded at runtime
+-- ALTER OPERATOR @#@(int8,int8) SET SCHEMA testschema_2; -- fail
+
+CREATE OPERATOR FAMILY testopfamily_a USING btree;
+CREATE OPERATOR FAMILY testopfamily_b USING btree;
+ALTER OPERATOR FAMILY testopfamily_a USING btree RENAME TO testopfamily_b; -- fail
+ALTER OPERATOR FAMILY testopfamily_b USING btree SET SCHEMA testschema_2; -- OK
+ALTER OPERATOR FAMILY testopfamily_a USING btree RENAME TO testopfamily_b; -- OK
+-- XXX - comment out due to error message with oid determinded at runtime
+-- ALTER OPERATOR FAMILY testopfamily_b USING btree SET SCHEMA testschema_2; -- fail
+
+
+CREATE OPERATOR CLASS testopclass_a
+ FOR TYPE box USING btree FAMILY testopfamily_b AS OPERATOR 1 =;
+CREATE OPERATOR CLASS testopclass_b
+ FOR TYPE circle USING btree FAMILY testopfamily_b AS OPERATOR 1 =;
+ALTER OPERATOR CLASS testopclass_a USING btree RENAME TO testopclass_b; -- fail
+ALTER OPERATOR CLASS testopclass_b USING btree SET SCHEMA testschema_2; -- OK
+ALTER OPERATOR CLASS testopclass_a USING btree RENAME TO testopclass_b; -- OK
+-- XXX - comment out due to error message with oid determinded at runtime
+-- ALTER OPERATOR CLASS testopclass_b USING btree SET SCHEMA testschema_2; -- fail
+
+--
+-- TEXT SEARCH
+--
+CREATE TEXT SEARCH DICTIONARY testtsdict_a (
+ Template=ispell,
+ DictFile=ispell_sample,
+ AffFile=ispell_sample
+);
+CREATE TEXT SEARCH DICTIONARY testtsdict_b (
+ Template=ispell,
+ DictFile=ispell_sample,
+ AffFile=ispell_sample
+);
+ALTER TEXT SEARCH DICTIONARY testtsdict_a RENAME TO testtsdict_b; -- fail
+ALTER TEXT SEARCH DICTIONARY testtsdict_b SET SCHEMA testschema_2; -- OK
+ALTER TEXT SEARCH DICTIONARY testtsdict_a RENAME TO testtsdict_b; -- OK
+ALTER TEXT SEARCH DICTIONARY testtsdict_b SET SCHEMA testschema_2; -- fail
+
+CREATE TEXT SEARCH CONFIGURATION testtsconf_a (COPY=english);
+CREATE TEXT SEARCH CONFIGURATION testtsconf_b (COPY=english);
+ALTER TEXT SEARCH CONFIGURATION testtsconf_a RENAME TO testtsconf_b; -- fail
+ALTER TEXT SEARCH CONFIGURATION testtsconf_b SET SCHEMA testschema_2; -- OK
+ALTER TEXT SEARCH CONFIGURATION testtsconf_a RENAME TO testtsconf_b; -- OK
+ALTER TEXT SEARCH CONFIGURATION testtsconf_b SET SCHEMA testschema_2; -- fail
+
+--
+-- COLLATION
+--
+CREATE COLLATION testcollation_a FROM "C";
+CREATE COLLATION testcollation_b FROM "C";
+
+ALTER COLLATION testcollation_a RENAME TO testcollation_b; -- fail
+ALTER COLLATION testcollation_b SET SCHEMA testschema_2; -- OK
+ALTER COLLATION testcollation_a RENAME TO testcollation_b; -- OK
+ALTER COLLATION testcollation_b SET SCHEMA testschema_2; -- fail
+
+--
+-- CONVERSION
+--
+CREATE CONVERSION testconv_a FOR 'LATIN1' TO 'UTF8' FROM iso8859_1_to_utf8;
+CREATE CONVERSION testconv_b FOR 'LATIN1' TO 'UTF8' FROM iso8859_1_to_utf8;
+
+ALTER CONVERSION testconv_a RENAME TO testconv_b; -- fail
+ALTER CONVERSION testconv_b SET SCHEMA testschema_2; -- OK
+ALTER CONVERSION testconv_a RENAME TO testconv_b; -- OK
+ALTER CONVERSION testconv_b SET SCHEMA testschema_2; -- fail
+
+--
+-- SCHEMA
+--
+ALTER SCHEMA testschema_1 RENAME TO testschema_2; -- fail
+ALTER SCHEMA testschema_1 RENAME TO testschema_3; -- OK
+
+DROP SCHEMA testschema_2, testschema_3 CASCADE;