From 55109313f96fb5c7d671fe8954b6f7fc0cca9631 Mon Sep 17 00:00:00 2001 From: Robert Haas Date: Fri, 26 Nov 2010 17:27:23 -0500 Subject: [PATCH] Add more ALTER .. SET SCHEMA commands. This adds support for changing the schema of a conversion, operator, operator class, operator family, text search configuration, text search dictionary, text search parser, or text search template. Dimitri Fontaine, with assorted corrections and other kibitzing. --- doc/src/sgml/ref/alter_conversion.sgml | 10 ++ doc/src/sgml/ref/alter_opclass.sgml | 10 ++ doc/src/sgml/ref/alter_operator.sgml | 10 ++ doc/src/sgml/ref/alter_opfamily.sgml | 10 ++ doc/src/sgml/ref/alter_tsconfig.sgml | 10 ++ doc/src/sgml/ref/alter_tsdictionary.sgml | 10 ++ doc/src/sgml/ref/alter_tsparser.sgml | 10 ++ doc/src/sgml/ref/alter_tstemplate.sgml | 10 ++ src/backend/commands/alter.c | 134 ++++++++++++++++++++++ src/backend/commands/conversioncmds.c | 28 +++++ src/backend/commands/opclasscmds.c | 70 +++++++++++ src/backend/commands/operatorcmds.c | 34 ++++++ src/backend/commands/tsearchcmds.c | 102 ++++++++++++++++ src/backend/parser/gram.y | 67 +++++++++++ src/backend/tcop/utility.c | 12 ++ src/bin/psql/tab-complete.c | 38 ++++-- src/include/commands/alter.h | 7 ++ src/include/commands/conversioncmds.h | 1 + src/include/commands/defrem.h | 7 ++ src/test/regress/expected/alter_table.out | 29 ++++- src/test/regress/sql/alter_table.sql | 24 ++++ 21 files changed, 620 insertions(+), 13 deletions(-) diff --git a/doc/src/sgml/ref/alter_conversion.sgml b/doc/src/sgml/ref/alter_conversion.sgml index 0ad8fff182..4f2269b849 100644 --- a/doc/src/sgml/ref/alter_conversion.sgml +++ b/doc/src/sgml/ref/alter_conversion.sgml @@ -23,6 +23,7 @@ PostgreSQL documentation ALTER CONVERSION name RENAME TO new_name ALTER CONVERSION name OWNER TO new_owner +ALTER CONVERSION name SET SCHEMA new_schema @@ -75,6 +76,15 @@ ALTER CONVERSION name OWNER TO new_owner + + + new_schema + + + The new schema for the conversion. + + + diff --git a/doc/src/sgml/ref/alter_opclass.sgml b/doc/src/sgml/ref/alter_opclass.sgml index 90c53c6c05..c70f6cd6a2 100644 --- a/doc/src/sgml/ref/alter_opclass.sgml +++ b/doc/src/sgml/ref/alter_opclass.sgml @@ -23,6 +23,7 @@ PostgreSQL documentation ALTER OPERATOR CLASS name USING index_method RENAME TO new_name ALTER OPERATOR CLASS name USING index_method OWNER TO new_owner +ALTER OPERATOR CLASS name USING index_method SET SCHEMA new_schema @@ -85,6 +86,15 @@ ALTER OPERATOR CLASS name USING new_schema + + + The new schema for the operator class. + + + diff --git a/doc/src/sgml/ref/alter_operator.sgml b/doc/src/sgml/ref/alter_operator.sgml index 615a1a66d3..a52f9f9cb4 100644 --- a/doc/src/sgml/ref/alter_operator.sgml +++ b/doc/src/sgml/ref/alter_operator.sgml @@ -22,6 +22,7 @@ PostgreSQL documentation ALTER OPERATOR name ( { left_type | NONE } , { right_type | NONE } ) OWNER TO new_owner +ALTER OPERATOR name ( { left_type | NONE } , { right_type | NONE } ) SET SCHEMA new_schema @@ -85,6 +86,15 @@ ALTER OPERATOR name ( { left_type + + + new_schema + + + The new schema for the operator. + + + diff --git a/doc/src/sgml/ref/alter_opfamily.sgml b/doc/src/sgml/ref/alter_opfamily.sgml index 3c8ca21f61..e22b4728d9 100644 --- a/doc/src/sgml/ref/alter_opfamily.sgml +++ b/doc/src/sgml/ref/alter_opfamily.sgml @@ -31,6 +31,7 @@ ALTER OPERATOR FAMILY name USING index_method RENAME TO new_name ALTER OPERATOR FAMILY name USING index_method OWNER TO new_owner +ALTER OPERATOR FAMILY name USING index_method SET SCHEMA new_schema @@ -216,6 +217,15 @@ ALTER OPERATOR FAMILY name USING new_schema + + + The new schema for the operator family. + + + diff --git a/doc/src/sgml/ref/alter_tsconfig.sgml b/doc/src/sgml/ref/alter_tsconfig.sgml index 95843ac93e..deef329b29 100644 --- a/doc/src/sgml/ref/alter_tsconfig.sgml +++ b/doc/src/sgml/ref/alter_tsconfig.sgml @@ -33,6 +33,7 @@ ALTER TEXT SEARCH CONFIGURATION name DROP MAPPING [ IF EXISTS ] FOR token_type [, ... ] ALTER TEXT SEARCH CONFIGURATION name RENAME TO new_name ALTER TEXT SEARCH CONFIGURATION name OWNER TO new_owner +ALTER TEXT SEARCH CONFIGURATION name SET SCHEMA new_schema @@ -123,6 +124,15 @@ ALTER TEXT SEARCH CONFIGURATION name OWNER TO + + + new_schema + + + The new schema for the text search configuration. + + + diff --git a/doc/src/sgml/ref/alter_tsdictionary.sgml b/doc/src/sgml/ref/alter_tsdictionary.sgml index 6858b9143a..7c12037041 100644 --- a/doc/src/sgml/ref/alter_tsdictionary.sgml +++ b/doc/src/sgml/ref/alter_tsdictionary.sgml @@ -26,6 +26,7 @@ ALTER TEXT SEARCH DICTIONARY name ( ) ALTER TEXT SEARCH DICTIONARY name RENAME TO new_name ALTER TEXT SEARCH DICTIONARY name OWNER TO new_owner +ALTER TEXT SEARCH DICTIONARY name SET SCHEMA new_schema @@ -96,6 +97,15 @@ ALTER TEXT SEARCH DICTIONARY name OWNER TO + + + new_schema + + + The new schema for the text search dictionary. + + + diff --git a/doc/src/sgml/ref/alter_tsparser.sgml b/doc/src/sgml/ref/alter_tsparser.sgml index 2de260a7ab..8c082433b0 100644 --- a/doc/src/sgml/ref/alter_tsparser.sgml +++ b/doc/src/sgml/ref/alter_tsparser.sgml @@ -22,6 +22,7 @@ PostgreSQL documentation ALTER TEXT SEARCH PARSER name RENAME TO new_name +ALTER TEXT SEARCH PARSER name SET SCHEMA new_schema @@ -60,6 +61,15 @@ ALTER TEXT SEARCH PARSER name RENAME TO + + + new_schema + + + The new schema for the text search parser. + + + diff --git a/doc/src/sgml/ref/alter_tstemplate.sgml b/doc/src/sgml/ref/alter_tstemplate.sgml index b729fdee91..e4f0ff3b1e 100644 --- a/doc/src/sgml/ref/alter_tstemplate.sgml +++ b/doc/src/sgml/ref/alter_tstemplate.sgml @@ -22,6 +22,7 @@ PostgreSQL documentation ALTER TEXT SEARCH TEMPLATE name RENAME TO new_name +ALTER TEXT SEARCH TEMPLATE name SET SCHEMA new_schema @@ -60,6 +61,15 @@ ALTER TEXT SEARCH TEMPLATE name RENAME TO + + + new_schema + + + The new schema for the text search template. + + + diff --git a/src/backend/commands/alter.c b/src/backend/commands/alter.c index 0d0227d04a..6c9ba1eb35 100644 --- a/src/backend/commands/alter.c +++ b/src/backend/commands/alter.c @@ -14,8 +14,11 @@ */ #include "postgres.h" +#include "catalog/dependency.h" +#include "catalog/indexing.h" #include "catalog/namespace.h" #include "catalog/pg_largeobject.h" +#include "catalog/pg_namespace.h" #include "commands/alter.h" #include "commands/conversioncmds.h" #include "commands/dbcommands.h" @@ -33,6 +36,7 @@ #include "utils/acl.h" #include "utils/builtins.h" #include "utils/lsyscache.h" +#include "utils/syscache.h" /* @@ -178,11 +182,27 @@ ExecAlterObjectSchemaStmt(AlterObjectSchemaStmt *stmt) stmt->newschema); break; + case OBJECT_CONVERSION: + AlterConversionNamespace(stmt->object, stmt->newschema); + break; + case OBJECT_FUNCTION: AlterFunctionNamespace(stmt->object, stmt->objarg, false, stmt->newschema); break; + case OBJECT_OPERATOR: + AlterOperatorNamespace(stmt->object, stmt->objarg, stmt->newschema); + break; + + case OBJECT_OPCLASS: + AlterOpClassNamespace(stmt->object, stmt->objarg, stmt->newschema); + break; + + case OBJECT_OPFAMILY: + AlterOpFamilyNamespace(stmt->object, stmt->objarg, stmt->newschema); + break; + case OBJECT_SEQUENCE: case OBJECT_TABLE: case OBJECT_VIEW: @@ -191,6 +211,22 @@ ExecAlterObjectSchemaStmt(AlterObjectSchemaStmt *stmt) stmt->objectType, AccessExclusiveLock); break; + 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; + case OBJECT_TYPE: case OBJECT_DOMAIN: AlterTypeNamespace(stmt->object, stmt->newschema); @@ -202,6 +238,104 @@ ExecAlterObjectSchemaStmt(AlterObjectSchemaStmt *stmt) } } +/* + * Generic function to change the namespace of a given object, for simple + * cases (won't work for tables or functions, objects which have more than 2 + * key-attributes to use when searching for their syscache entries --- we + * don't want nor need to get this generic here). + * + * The AlterFooNamespace() calls just above will call a function whose job + * is to lookup the arguments for the generic function here. + * + * Relation must already by open, it's the responsibility of the caller to + * close it. + */ +void +AlterObjectNamespace(Relation rel, int cacheId, + Oid classId, Oid objid, Oid nspOid, + int Anum_name, int Anum_namespace, int Anum_owner, + AclObjectKind acl_kind, + bool superuser_only) +{ + Oid oldNspOid; + Datum name, namespace; + bool isnull; + HeapTuple tup, newtup = NULL; + Datum *values; + bool *nulls; + bool *replaces; + + tup = SearchSysCacheCopy1(cacheId, ObjectIdGetDatum(objid)); + if (!HeapTupleIsValid(tup)) /* should not happen */ + elog(ERROR, "cache lookup failed for object %u: %s", + objid, getObjectDescriptionOids(classId, objid)); + + name = heap_getattr(tup, Anum_name, rel->rd_att, &isnull); + namespace = heap_getattr(tup, Anum_namespace, rel->rd_att, &isnull); + oldNspOid = DatumGetObjectId(namespace); + + /* Check basic namespace related issues */ + CheckSetNamespace(oldNspOid, nspOid, classId, objid); + + /* check for duplicate name (more friendly than unique-index failure) */ + if (SearchSysCacheExists2(cacheId, name, ObjectIdGetDatum(nspOid))) + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_OBJECT), + errmsg("%s already exists in schema \"%s\"", + getObjectDescriptionOids(classId, objid), + get_namespace_name(nspOid)))); + + /* Superusers can always do it */ + if (!superuser()) + { + Datum owner; + Oid ownerId; + AclResult aclresult; + + if (superuser_only) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + (errmsg("must be superuser to SET SCHEMA of %s", + getObjectDescriptionOids(classId, objid))))); + + /* Otherwise, must be owner of the existing object */ + owner = heap_getattr(tup, Anum_owner, rel->rd_att, &isnull); + ownerId = DatumGetObjectId(owner); + + if (!has_privs_of_role(GetUserId(), ownerId)) + aclcheck_error(ACLCHECK_NOT_OWNER, acl_kind, + NameStr(*(DatumGetName(name)))); + + /* owner must have CREATE privilege on namespace */ + aclresult = pg_namespace_aclcheck(oldNspOid, GetUserId(), ACL_CREATE); + if (aclresult != ACLCHECK_OK) + aclcheck_error(aclresult, ACL_KIND_NAMESPACE, + get_namespace_name(oldNspOid)); + } + + /* Prepare to update tuple */ + values = palloc0(rel->rd_att->natts * sizeof(Datum)); + nulls = palloc0(rel->rd_att->natts * sizeof(bool)); + replaces = palloc0(rel->rd_att->natts * sizeof(bool)); + values[Anum_namespace - 1] = nspOid; + replaces[Anum_namespace - 1] = true; + newtup = heap_modify_tuple(tup, rel->rd_att, values, nulls, replaces); + + /* 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); +} + + /* * Executes an ALTER OBJECT / OWNER TO statement. Based on the object * type, the function appropriate to that type is executed. diff --git a/src/backend/commands/conversioncmds.c b/src/backend/commands/conversioncmds.c index 73a3d026e1..521132a5e5 100644 --- a/src/backend/commands/conversioncmds.c +++ b/src/backend/commands/conversioncmds.c @@ -19,7 +19,9 @@ #include "catalog/indexing.h" #include "catalog/pg_conversion.h" #include "catalog/pg_conversion_fn.h" +#include "catalog/pg_namespace.h" #include "catalog/pg_type.h" +#include "commands/alter.h" #include "commands/conversioncmds.h" #include "mb/pg_wchar.h" #include "miscadmin.h" @@ -326,3 +328,29 @@ AlterConversionOwner_internal(Relation rel, Oid conversionOid, Oid newOwnerId) heap_freetuple(tup); } + +/* + * Execute ALTER CONVERSION SET SCHEMA + */ +void +AlterConversionNamespace(List *name, const char *newschema) +{ + Oid convOid, nspOid; + Relation rel; + + rel = heap_open(ConversionRelationId, RowExclusiveLock); + + convOid = get_conversion_oid(name, false); + + /* get schema OID */ + nspOid = LookupCreationNamespace(newschema); + + AlterObjectNamespace(rel, CONVOID, ConversionRelationId, convOid, nspOid, + Anum_pg_conversion_conname, + Anum_pg_conversion_connamespace, + Anum_pg_conversion_conowner, + ACL_KIND_CONVERSION, + false); + + heap_close(rel, NoLock); +} diff --git a/src/backend/commands/opclasscmds.c b/src/backend/commands/opclasscmds.c index 5055fb17cd..5598d82270 100644 --- a/src/backend/commands/opclasscmds.c +++ b/src/backend/commands/opclasscmds.c @@ -31,6 +31,7 @@ #include "catalog/pg_opfamily.h" #include "catalog/pg_proc.h" #include "catalog/pg_type.h" +#include "commands/alter.h" #include "commands/defrem.h" #include "miscadmin.h" #include "parser/parse_func.h" @@ -1988,6 +1989,41 @@ AlterOpClassOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId) } } +/* + * ALTER OPERATOR CLASS any_name USING access_method SET SCHEMA name + */ +void +AlterOpClassNamespace(List *name, List *argam, const char *newschema) +{ + Oid amOid; + char *access_method = linitial(argam); + Relation rel; + Oid oid; + Oid nspOid; + + Assert(list_length(argam) == 1); + + amOid = get_am_oid(access_method, false); + + rel = heap_open(OperatorClassRelationId, RowExclusiveLock); + + /* Look up the opclass. */ + oid = get_opclass_oid(amOid, name, false); + + /* get schema OID */ + nspOid = LookupCreationNamespace(newschema); + + AlterObjectNamespace(rel, CLAOID, OperatorClassRelationId, + oid, nspOid, + Anum_pg_opfamily_opfname, + Anum_pg_opfamily_opfnamespace, + Anum_pg_opfamily_opfowner, + ACL_KIND_OPCLASS, + false); + + heap_close(rel, NoLock); +} + /* * Change opfamily owner by name */ @@ -2144,3 +2180,37 @@ get_am_oid(const char *amname, bool missing_ok) errmsg("access method \"%s\" does not exist", amname))); return oid; } + +/* + * ALTER OPERATOR FAMILY any_name USING access_method SET SCHEMA name + */ +void +AlterOpFamilyNamespace(List *name, List *argam, const char *newschema) +{ + Oid amOid; + char *access_method = linitial(argam); + Relation rel; + Oid nspOid; + Oid oid; + + Assert(list_length(argam) == 1); + amOid = get_am_oid(access_method, false); + + rel = heap_open(OperatorFamilyRelationId, RowExclusiveLock); + + /* Look up the opfamily */ + oid = get_opfamily_oid(amOid, name, false); + + /* get schema OID */ + nspOid = LookupCreationNamespace(newschema); + + AlterObjectNamespace(rel, OPFAMILYOID, OperatorFamilyRelationId, + oid, nspOid, + Anum_pg_opfamily_opfname, + Anum_pg_opfamily_opfnamespace, + Anum_pg_opfamily_opfowner, + ACL_KIND_OPFAMILY, + false); + + heap_close(rel, NoLock); +} diff --git a/src/backend/commands/operatorcmds.c b/src/backend/commands/operatorcmds.c index 503cf0f23d..2578eaf4f8 100644 --- a/src/backend/commands/operatorcmds.c +++ b/src/backend/commands/operatorcmds.c @@ -39,7 +39,9 @@ #include "catalog/indexing.h" #include "catalog/namespace.h" #include "catalog/pg_operator.h" +#include "catalog/pg_namespace.h" #include "catalog/pg_type.h" +#include "commands/alter.h" #include "commands/defrem.h" #include "miscadmin.h" #include "parser/parse_func.h" @@ -452,3 +454,35 @@ AlterOperatorOwner_internal(Relation rel, Oid operOid, Oid newOwnerId) heap_freetuple(tup); } + +/* + * Execute ALTER OPERATOR SET SCHEMA + */ +void +AlterOperatorNamespace(List *names, List *argtypes, const char *newschema) +{ + List *operatorName = names; + TypeName *typeName1 = (TypeName *) linitial(argtypes); + TypeName *typeName2 = (TypeName *) lsecond(argtypes); + Oid operOid, nspOid; + Relation rel; + + rel = heap_open(OperatorRelationId, RowExclusiveLock); + + Assert(list_length(argtypes) == 2); + operOid = LookupOperNameTypeNames(NULL, operatorName, + typeName1, typeName2, + false, -1); + + /* get schema OID */ + nspOid = LookupCreationNamespace(newschema); + + AlterObjectNamespace(rel, OPEROID, OperatorRelationId, operOid, nspOid, + Anum_pg_operator_oprname, + Anum_pg_operator_oprnamespace, + Anum_pg_operator_oprowner, + ACL_KIND_OPER, + false); + + heap_close(rel, NoLock); +} diff --git a/src/backend/commands/tsearchcmds.c b/src/backend/commands/tsearchcmds.c index 412b1d278d..6746ac0c62 100644 --- a/src/backend/commands/tsearchcmds.c +++ b/src/backend/commands/tsearchcmds.c @@ -32,6 +32,7 @@ #include "catalog/pg_ts_parser.h" #include "catalog/pg_ts_template.h" #include "catalog/pg_type.h" +#include "commands/alter.h" #include "commands/defrem.h" #include "miscadmin.h" #include "nodes/makefuncs.h" @@ -397,6 +398,30 @@ RenameTSParser(List *oldname, const char *newname) heap_freetuple(tup); } +/* + * ALTER TEXT SEARCH PARSER any_name SET SCHEMA name + */ +void +AlterTSParserNamespace(List *name, const char *newschema) +{ + Oid prsId, nspOid; + Relation rel; + + rel = heap_open(TSParserRelationId, RowExclusiveLock); + + prsId = get_ts_parser_oid(name, false); + + /* get schema OID */ + nspOid = LookupCreationNamespace(newschema); + + AlterObjectNamespace(rel, TSPARSEROID, TSParserRelationId, prsId, nspOid, + Anum_pg_ts_parser_prsname, + Anum_pg_ts_parser_prsnamespace, + -1, -1, true); + + heap_close(rel, NoLock); +} + /* ---------------------- TS Dictionary commands -----------------------*/ /* @@ -627,6 +652,32 @@ RenameTSDictionary(List *oldname, const char *newname) heap_freetuple(tup); } +/* + * ALTER TEXT SEARCH DICTIONARY any_name SET SCHEMA name + */ +void +AlterTSDictionaryNamespace(List *name, const char *newschema) +{ + Oid dictId, nspOid; + Relation rel; + + rel = heap_open(TSDictionaryRelationId, RowExclusiveLock); + + dictId = get_ts_dict_oid(name, false); + + /* get schema OID */ + nspOid = LookupCreationNamespace(newschema); + + AlterObjectNamespace(rel, TSDICTOID, TSDictionaryRelationId, dictId, nspOid, + Anum_pg_ts_dict_dictname, + Anum_pg_ts_dict_dictnamespace, + Anum_pg_ts_dict_dictowner, + ACL_KIND_TSDICTIONARY, + true); + + heap_close(rel, NoLock); +} + /* * DROP TEXT SEARCH DICTIONARY */ @@ -1110,6 +1161,31 @@ RenameTSTemplate(List *oldname, const char *newname) heap_freetuple(tup); } +/* + * ALTER TEXT SEARCH TEMPLATE any_name SET SCHEMA name + */ +void +AlterTSTemplateNamespace(List *name, const char *newschema) +{ + Oid tmplId, nspOid; + Relation rel; + + rel = heap_open(TSTemplateRelationId, RowExclusiveLock); + + tmplId = get_ts_template_oid(name, false); + + /* get schema OID */ + nspOid = LookupCreationNamespace(newschema); + + AlterObjectNamespace(rel, TSTEMPLATEOID, TSTemplateRelationId, + tmplId, nspOid, + Anum_pg_ts_template_tmplname, + Anum_pg_ts_template_tmplnamespace, + -1, -1, true); + + heap_close(rel, NoLock); +} + /* * DROP TEXT SEARCH TEMPLATE */ @@ -1511,6 +1587,32 @@ RenameTSConfiguration(List *oldname, const char *newname) heap_freetuple(tup); } +/* + * ALTER TEXT SEARCH CONFIGURATION any_name SET SCHEMA name + */ +void +AlterTSConfigurationNamespace(List *name, const char *newschema) +{ + Oid cfgId, nspOid; + Relation rel; + + rel = heap_open(TSConfigRelationId, RowExclusiveLock); + + cfgId = get_ts_config_oid(name, false); + + /* get schema OID */ + nspOid = LookupCreationNamespace(newschema); + + AlterObjectNamespace(rel, TSCONFIGOID, TSConfigRelationId, cfgId, nspOid, + Anum_pg_ts_config_cfgname, + Anum_pg_ts_config_cfgnamespace, + Anum_pg_ts_config_cfgowner, + ACL_KIND_TSCONFIGURATION, + false); + + heap_close(rel, NoLock); +} + /* * DROP TEXT SEARCH CONFIGURATION */ diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 1c17be8921..9ec75f776c 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -6051,6 +6051,14 @@ AlterObjectSchemaStmt: n->newschema = $7; $$ = (Node *)n; } + | ALTER CONVERSION_P any_name SET SCHEMA name + { + AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt); + n->objectType = OBJECT_CONVERSION; + n->object = $3; + n->newschema = $6; + $$ = (Node *)n; + } | ALTER DOMAIN_P any_name SET SCHEMA name { AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt); @@ -6068,6 +6076,33 @@ AlterObjectSchemaStmt: n->newschema = $6; $$ = (Node *)n; } + | ALTER OPERATOR any_operator oper_argtypes SET SCHEMA name + { + AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt); + n->objectType = OBJECT_OPERATOR; + n->object = $3; + n->objarg = $4; + n->newschema = $7; + $$ = (Node *)n; + } + | ALTER OPERATOR CLASS any_name USING access_method SET SCHEMA name + { + AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt); + n->objectType = OBJECT_OPCLASS; + n->object = $4; + n->objarg = list_make1($6); + n->newschema = $9; + $$ = (Node *)n; + } + | ALTER OPERATOR FAMILY any_name USING access_method SET SCHEMA name + { + AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt); + n->objectType = OBJECT_OPFAMILY; + n->object = $4; + n->objarg = list_make1($6); + n->newschema = $9; + $$ = (Node *)n; + } | ALTER TABLE relation_expr SET SCHEMA name { AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt); @@ -6076,6 +6111,38 @@ AlterObjectSchemaStmt: n->newschema = $6; $$ = (Node *)n; } + | ALTER TEXT_P SEARCH PARSER any_name SET SCHEMA name + { + AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt); + n->objectType = OBJECT_TSPARSER; + n->object = $5; + n->newschema = $8; + $$ = (Node *)n; + } + | ALTER TEXT_P SEARCH DICTIONARY any_name SET SCHEMA name + { + AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt); + n->objectType = OBJECT_TSDICTIONARY; + n->object = $5; + n->newschema = $8; + $$ = (Node *)n; + } + | ALTER TEXT_P SEARCH TEMPLATE any_name SET SCHEMA name + { + AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt); + n->objectType = OBJECT_TSTEMPLATE; + n->object = $5; + n->newschema = $8; + $$ = (Node *)n; + } + | ALTER TEXT_P SEARCH CONFIGURATION any_name SET SCHEMA name + { + AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt); + n->objectType = OBJECT_TSCONFIGURATION; + n->object = $5; + n->newschema = $8; + $$ = (Node *)n; + } | ALTER SEQUENCE qualified_name SET SCHEMA name { AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt); diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c index 2300e88249..803c6036ab 100644 --- a/src/backend/tcop/utility.c +++ b/src/backend/tcop/utility.c @@ -1694,9 +1694,21 @@ CreateCommandTag(Node *parsetree) case OBJECT_AGGREGATE: tag = "ALTER AGGREGATE"; break; + case OBJECT_CONVERSION: + tag = "ALTER CONVERSION"; + break; case OBJECT_DOMAIN: tag = "ALTER DOMAIN"; break; + case OBJECT_OPERATOR: + tag = "ALTER OPERATOR"; + break; + case OBJECT_OPCLASS: + tag = "ALTER OPERATOR CLASS"; + break; + case OBJECT_OPFAMILY: + tag = "ALTER OPERATOR FAMILY"; + break; case OBJECT_FUNCTION: tag = "ALTER FUNCTION"; break; diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c index 2c368504ec..4c468a858c 100644 --- a/src/bin/psql/tab-complete.c +++ b/src/bin/psql/tab-complete.c @@ -741,10 +741,9 @@ psql_completion(char *text, int start, int end) } } - /* ALTER CONVERSION,SCHEMA */ + /* ALTER SCHEMA */ else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 && - (pg_strcasecmp(prev2_wd, "CONVERSION") == 0 || - pg_strcasecmp(prev2_wd, "SCHEMA") == 0)) + pg_strcasecmp(prev2_wd, "SCHEMA") == 0) { static const char *const list_ALTERGEN[] = {"OWNER TO", "RENAME TO", NULL}; @@ -752,6 +751,16 @@ psql_completion(char *text, int start, int end) COMPLETE_WITH_LIST(list_ALTERGEN); } + /* ALTER CONVERSION */ + else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 && + pg_strcasecmp(prev2_wd, "CONVERSION") == 0) + { + static const char *const list_ALTERGEN[] = + {"OWNER TO", "RENAME TO", "SET SCHEMA", NULL}; + + COMPLETE_WITH_LIST(list_ALTERGEN); + } + /* ALTER DATABASE */ else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 && pg_strcasecmp(prev2_wd, "DATABASE") == 0) @@ -1237,15 +1246,9 @@ psql_completion(char *text, int start, int end) pg_strcasecmp(prev3_wd, "SEARCH") == 0 && (pg_strcasecmp(prev2_wd, "TEMPLATE") == 0 || pg_strcasecmp(prev2_wd, "PARSER") == 0)) - COMPLETE_WITH_CONST("RENAME TO"); - - else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 && - pg_strcasecmp(prev4_wd, "TEXT") == 0 && - pg_strcasecmp(prev3_wd, "SEARCH") == 0 && - pg_strcasecmp(prev2_wd, "DICTIONARY") == 0) { static const char *const list_ALTERTEXTSEARCH2[] = - {"OWNER TO", "RENAME TO", NULL}; + {"RENAME TO", "SET SCHEMA", NULL}; COMPLETE_WITH_LIST(list_ALTERTEXTSEARCH2); } @@ -1253,14 +1256,25 @@ psql_completion(char *text, int start, int end) else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 && pg_strcasecmp(prev4_wd, "TEXT") == 0 && pg_strcasecmp(prev3_wd, "SEARCH") == 0 && - pg_strcasecmp(prev2_wd, "CONFIGURATION") == 0) + pg_strcasecmp(prev2_wd, "DICTIONARY") == 0) { static const char *const list_ALTERTEXTSEARCH3[] = - {"ADD MAPPING FOR", "ALTER MAPPING", "DROP MAPPING FOR", "OWNER TO", "RENAME TO", NULL}; + {"OWNER TO", "RENAME TO", "SET SCHEMA", NULL}; COMPLETE_WITH_LIST(list_ALTERTEXTSEARCH3); } + else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 && + pg_strcasecmp(prev4_wd, "TEXT") == 0 && + pg_strcasecmp(prev3_wd, "SEARCH") == 0 && + pg_strcasecmp(prev2_wd, "CONFIGURATION") == 0) + { + static const char *const list_ALTERTEXTSEARCH4[] = + {"ADD MAPPING FOR", "ALTER MAPPING", "DROP MAPPING FOR", "OWNER TO", "RENAME TO", "SET SCHEMA", NULL}; + + COMPLETE_WITH_LIST(list_ALTERTEXTSEARCH4); + } + /* complete ALTER TYPE with actions */ else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 && pg_strcasecmp(prev2_wd, "TYPE") == 0) diff --git a/src/include/commands/alter.h b/src/include/commands/alter.h index 5cee895f6c..a833f19a73 100644 --- a/src/include/commands/alter.h +++ b/src/include/commands/alter.h @@ -15,9 +15,16 @@ #define ALTER_H #include "nodes/parsenodes.h" +#include "utils/acl.h" +#include "utils/relcache.h" extern void ExecRenameStmt(RenameStmt *stmt); extern void ExecAlterObjectSchemaStmt(AlterObjectSchemaStmt *stmt); +extern void AlterObjectNamespace(Relation rel, int cacheId, + Oid classId, Oid objid, Oid nspId, + int Anum_name, int Anum_namespace, int Anum_owner, + AclObjectKind acl_kind, + bool superuser_only); extern void ExecAlterOwnerStmt(AlterOwnerStmt *stmt); #endif /* ALTER_H */ diff --git a/src/include/commands/conversioncmds.h b/src/include/commands/conversioncmds.h index 049e8c49ac..41056ea320 100644 --- a/src/include/commands/conversioncmds.h +++ b/src/include/commands/conversioncmds.h @@ -22,5 +22,6 @@ extern void DropConversionsCommand(DropStmt *drop); extern void RenameConversion(List *name, const char *newname); extern void AlterConversionOwner(List *name, Oid newOwnerId); extern void AlterConversionOwner_oid(Oid conversionOid, Oid newOwnerId); +extern void AlterConversionNamespace(List *name, const char *newschema); #endif /* CONVERSIONCMDS_H */ diff --git a/src/include/commands/defrem.h b/src/include/commands/defrem.h index 1dc1a7d194..86d62af9ed 100644 --- a/src/include/commands/defrem.h +++ b/src/include/commands/defrem.h @@ -76,6 +76,7 @@ extern void RemoveOperatorById(Oid operOid); extern void AlterOperatorOwner(List *name, TypeName *typeName1, TypeName *typename2, Oid newOwnerId); extern void AlterOperatorOwner_oid(Oid operOid, Oid newOwnerId); +extern void AlterOperatorNamespace(List *names, List *argtypes, const char *newschema); extern Oid get_opclass_oid(Oid amID, List *opclassname, bool missing_ok); extern Oid get_opfamily_oid(Oid amID, List *opfamilyname, bool missing_ok); @@ -100,13 +101,16 @@ extern void RenameOpClass(List *name, const char *access_method, const char *new extern void RenameOpFamily(List *name, const char *access_method, const char *newname); extern void AlterOpClassOwner(List *name, const char *access_method, Oid newOwnerId); extern void AlterOpClassOwner_oid(Oid opclassOid, Oid newOwnerId); +extern void AlterOpClassNamespace(List *name, List *argam, const char *newschema); extern void AlterOpFamilyOwner(List *name, const char *access_method, Oid newOwnerId); extern void AlterOpFamilyOwner_oid(Oid opfamilyOid, Oid newOwnerId); extern Oid get_am_oid(const char *amname, bool missing_ok); +extern void AlterOpFamilyNamespace(List *name, List *argam, const char *newschema); /* commands/tsearchcmds.c */ extern void DefineTSParser(List *names, List *parameters); extern void RenameTSParser(List *oldname, const char *newname); +extern void AlterTSParserNamespace(List *name, const char *newschema); extern void RemoveTSParsers(DropStmt *drop); extern void RemoveTSParserById(Oid prsId); @@ -116,9 +120,11 @@ extern void RemoveTSDictionaries(DropStmt *drop); extern void RemoveTSDictionaryById(Oid dictId); extern void AlterTSDictionary(AlterTSDictionaryStmt *stmt); extern void AlterTSDictionaryOwner(List *name, Oid newOwnerId); +extern void AlterTSDictionaryNamespace(List *name, const char *newschema); extern void DefineTSTemplate(List *names, List *parameters); extern void RenameTSTemplate(List *oldname, const char *newname); +extern void AlterTSTemplateNamespace(List *name, const char *newschema); extern void RemoveTSTemplates(DropStmt *stmt); extern void RemoveTSTemplateById(Oid tmplId); @@ -128,6 +134,7 @@ extern void RemoveTSConfigurations(DropStmt *stmt); extern void RemoveTSConfigurationById(Oid cfgId); extern void AlterTSConfiguration(AlterTSConfigurationStmt *stmt); extern void AlterTSConfigurationOwner(List *name, Oid newOwnerId); +extern void AlterTSConfigurationNamespace(List *name, const char *newschema); extern text *serialize_deflist(List *deflist); extern List *deserialize_deflist(Datum txt); diff --git a/src/test/regress/expected/alter_table.out b/src/test/regress/expected/alter_table.out index b68dfd4fc2..e415730bd0 100644 --- a/src/test/regress/expected/alter_table.out +++ b/src/test/regress/expected/alter_table.out @@ -1645,13 +1645,32 @@ create view alter1.v1 as select * from alter1.t1; create function alter1.plus1(int) returns int as 'select $1+1' language sql; create domain alter1.posint integer check (value > 0); create type alter1.ctype as (f1 int, f2 text); +create function alter1.same(alter1.ctype, alter1.ctype) returns boolean language sql +as 'select $1.f1 is not distinct from $2.f1 and $1.f2 is not distinct from $2.f2'; +create operator alter1.=(procedure = alter1.same, leftarg = alter1.ctype, rightarg = alter1.ctype); +create operator class alter1.ctype_hash_ops default for type alter1.ctype using hash as + operator 1 alter1.=(alter1.ctype, alter1.ctype); +create conversion alter1.ascii_to_utf8 for 'sql_ascii' to 'utf8' from ascii_to_utf8; +create text search parser alter1.prs(start = prsd_start, gettoken = prsd_nexttoken, end = prsd_end, lextypes = prsd_lextype); +create text search configuration alter1.cfg(parser = alter1.prs); +create text search template alter1.tmpl(init = dsimple_init, lexize = dsimple_lexize); +create text search dictionary alter1.dict(template = alter1.tmpl); insert into alter1.t1(f2) values(11); insert into alter1.t1(f2) values(12); alter table alter1.t1 set schema alter2; alter table alter1.v1 set schema alter2; alter function alter1.plus1(int) set schema alter2; alter domain alter1.posint set schema alter2; +alter operator class alter1.ctype_hash_ops using hash set schema alter2; +alter operator family alter1.ctype_hash_ops using hash set schema alter2; +alter operator alter1.=(alter1.ctype, alter1.ctype) set schema alter2; +alter function alter1.same(alter1.ctype, alter1.ctype) set schema alter2; alter type alter1.ctype set schema alter2; +alter conversion alter1.ascii_to_utf8 set schema alter2; +alter text search parser alter1.prs set schema alter2; +alter text search configuration alter1.cfg set schema alter2; +alter text search template alter1.tmpl set schema alter2; +alter text search dictionary alter1.dict set schema alter2; -- this should succeed because nothing is left in alter1 drop schema alter1; insert into alter2.t1(f2) values(13); @@ -1682,12 +1701,20 @@ select alter2.plus1(41); -- clean up drop schema alter2 cascade; -NOTICE: drop cascades to 5 other objects +NOTICE: drop cascades to 13 other objects DETAIL: drop cascades to table alter2.t1 drop cascades to view alter2.v1 drop cascades to function alter2.plus1(integer) drop cascades to type alter2.posint +drop cascades to operator family alter2.ctype_hash_ops for access method hash drop cascades to type alter2.ctype +drop cascades to function alter2.same(alter2.ctype,alter2.ctype) +drop cascades to operator alter2.=(alter2.ctype,alter2.ctype) +drop cascades to conversion ascii_to_utf8 +drop cascades to text search parser prs +drop cascades to text search configuration cfg +drop cascades to text search template tmpl +drop cascades to text search dictionary dict -- -- composite types -- diff --git a/src/test/regress/sql/alter_table.sql b/src/test/regress/sql/alter_table.sql index 98a68d5877..4895768d7f 100644 --- a/src/test/regress/sql/alter_table.sql +++ b/src/test/regress/sql/alter_table.sql @@ -1206,6 +1206,21 @@ create domain alter1.posint integer check (value > 0); create type alter1.ctype as (f1 int, f2 text); +create function alter1.same(alter1.ctype, alter1.ctype) returns boolean language sql +as 'select $1.f1 is not distinct from $2.f1 and $1.f2 is not distinct from $2.f2'; + +create operator alter1.=(procedure = alter1.same, leftarg = alter1.ctype, rightarg = alter1.ctype); + +create operator class alter1.ctype_hash_ops default for type alter1.ctype using hash as + operator 1 alter1.=(alter1.ctype, alter1.ctype); + +create conversion alter1.ascii_to_utf8 for 'sql_ascii' to 'utf8' from ascii_to_utf8; + +create text search parser alter1.prs(start = prsd_start, gettoken = prsd_nexttoken, end = prsd_end, lextypes = prsd_lextype); +create text search configuration alter1.cfg(parser = alter1.prs); +create text search template alter1.tmpl(init = dsimple_init, lexize = dsimple_lexize); +create text search dictionary alter1.dict(template = alter1.tmpl); + insert into alter1.t1(f2) values(11); insert into alter1.t1(f2) values(12); @@ -1213,7 +1228,16 @@ alter table alter1.t1 set schema alter2; alter table alter1.v1 set schema alter2; alter function alter1.plus1(int) set schema alter2; alter domain alter1.posint set schema alter2; +alter operator class alter1.ctype_hash_ops using hash set schema alter2; +alter operator family alter1.ctype_hash_ops using hash set schema alter2; +alter operator alter1.=(alter1.ctype, alter1.ctype) set schema alter2; +alter function alter1.same(alter1.ctype, alter1.ctype) set schema alter2; alter type alter1.ctype set schema alter2; +alter conversion alter1.ascii_to_utf8 set schema alter2; +alter text search parser alter1.prs set schema alter2; +alter text search configuration alter1.cfg set schema alter2; +alter text search template alter1.tmpl set schema alter2; +alter text search dictionary alter1.dict set schema alter2; -- this should succeed because nothing is left in alter1 drop schema alter1;