From 5bc178b89f3ab93fb3845a941769c212f5eeaf1a Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Wed, 9 Feb 2011 11:55:32 -0500 Subject: [PATCH] Implement "ALTER EXTENSION ADD object". This is an essential component of making the extension feature usable; first because it's needed in the process of converting an existing installation containing "loose" objects of an old contrib module into the extension-based world, and second because we'll have to use it in pg_dump --binary-upgrade, as per recent discussion. Loosely based on part of Dimitri Fontaine's ALTER EXTENSION UPGRADE patch. --- doc/src/sgml/extend.sgml | 12 ++ doc/src/sgml/ref/alter_extension.sgml | 194 +++++++++++++++--- src/backend/commands/extension.c | 59 +++++- src/backend/nodes/copyfuncs.c | 16 ++ src/backend/nodes/equalfuncs.c | 14 ++ src/backend/parser/gram.y | 186 +++++++++++++++++- src/backend/tcop/utility.c | 357 +++++++++++++--------------------- src/include/commands/extension.h | 2 + src/include/nodes/nodes.h | 1 + src/include/nodes/parsenodes.h | 15 +- 10 files changed, 601 insertions(+), 255 deletions(-) diff --git a/doc/src/sgml/extend.sgml b/doc/src/sgml/extend.sgml index 206eb6b901..31ea0487f1 100644 --- a/doc/src/sgml/extend.sgml +++ b/doc/src/sgml/extend.sgml @@ -331,6 +331,18 @@ data; see below.) + + The kinds of SQL objects that can be members of an extension are shown in + the description of . Notably, objects + that are database-cluster-wide, such as databases, roles, and tablespaces, + cannot be extension members since an extension is only known within one + database. (Although an extension script is not prohibited from creating + such objects, if it does so they will not be tracked as part of the + extension.) Also notice that while a table can be a member of an + extension, its subsidiary objects such as indexes are not directly + considered members of the extension. + + Extension Files diff --git a/doc/src/sgml/ref/alter_extension.sgml b/doc/src/sgml/ref/alter_extension.sgml index 1b29d274cd..6613418fd2 100644 --- a/doc/src/sgml/ref/alter_extension.sgml +++ b/doc/src/sgml/ref/alter_extension.sgml @@ -23,7 +23,32 @@ PostgreSQL documentation -ALTER EXTENSION name SET SCHEMA new_schema +ALTER EXTENSION extension_name SET SCHEMA new_schema +ALTER EXTENSION extension_name ADD member_object + +where member_object is: + + AGGREGATE agg_name (agg_type [, ...] ) | + CAST (source_type AS target_type) | + CONVERSION object_name | + DOMAIN object_name | + FOREIGN DATA WRAPPER object_name | + FOREIGN TABLE object_name | + FUNCTION function_name ( [ [ argmode ] [ argname ] argtype [, ...] ] ) | + OPERATOR operator_name (left_type, right_type) | + OPERATOR CLASS object_name USING index_method | + OPERATOR FAMILY object_name USING index_method | + [ PROCEDURAL ] LANGUAGE object_name | + SCHEMA object_name | + SEQUENCE object_name | + SERVER object_name | + TABLE object_name | + TEXT SEARCH CONFIGURATION object_name | + TEXT SEARCH DICTIONARY object_name | + TEXT SEARCH PARSER object_name | + TEXT SEARCH TEMPLATE object_name | + TYPE object_name | + VIEW object_name @@ -31,8 +56,8 @@ ALTER EXTENSION name SET SCHEMA Description - ALTER EXTENSION changes the definition of an existing extension. - Currently there is only one subform: + ALTER EXTENSION changes the definition of an installed + extension. There are several subforms: @@ -41,37 +66,151 @@ ALTER EXTENSION name SET SCHEMA This form moves the extension's objects into another schema. The extension has to be relocatable for this command to - succeed. See for details. + succeed. + + + + + + ADD member_object + + + This form adds an existing object to the extension. This is mainly + useful in extension upgrade scripts. The object will subsequently + be treated as a member of the extension; notably, it can only be + dropped by dropping the extension. + + See for more information about these + operations. + + + + Only superusers can execute ALTER EXTENSION. Parameters - - - - name - - - The name of an installed extension. - - - - - - new_schema - - - The new schema for the extension. - - - - + + + + extension_name + + + The name of an installed extension. + + + + + + new_schema + + + The new schema for the extension. + + + + + + object_name + agg_name + function_name + operator_name + + + The name of an object to be added to the extension. Names of tables, + aggregates, domains, foreign tables, functions, operators, + operator classes, operator families, sequences, text search objects, + types, and views can be schema-qualified. + + + + + + agg_type + + + An input data type on which the aggregate function operates. + To reference a zero-argument aggregate function, write * + in place of the list of input data types. + + + + + + source_type + + + The name of the source data type of the cast. + + + + + + target_type + + + The name of the target data type of the cast. + + + + + + argmode + + + + The mode of a function argument: IN, OUT, + INOUT, or VARIADIC. + If omitted, the default is IN. + Note that ALTER EXTENSION does not actually pay + any attention to OUT arguments, since only the input + arguments are needed to determine the function's identity. + So it is sufficient to list the IN, INOUT, + and VARIADIC arguments. + + + + + + argname + + + + The name of a function argument. + Note that ALTER EXTENSION does not actually pay + any attention to argument names, since only the argument data + types are needed to determine the function's identity. + + + + + + argtype + + + + The data type(s) of the function's arguments (optionally + schema-qualified), if any. + + + + + + PROCEDURAL + + + + This is a noise word. + + + + @@ -85,6 +224,13 @@ ALTER EXTENSION name SET SCHEMA + + + To add an existing function to the hstore extension: + +ALTER EXTENSION hstore ADD FUNCTION populate_record(anyelement, hstore); + + diff --git a/src/backend/commands/extension.c b/src/backend/commands/extension.c index ee42d2e13d..41667fb3af 100644 --- a/src/backend/commands/extension.c +++ b/src/backend/commands/extension.c @@ -1134,7 +1134,7 @@ pg_extension_config_dump(PG_FUNCTION_ARGS) if (getExtensionOfObject(RelationRelationId, tableoid) != CurrentExtensionObject) ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), errmsg("table \"%s\" is not a member of the extension being created", tablename))); @@ -1392,3 +1392,60 @@ AlterExtensionNamespace(List *names, const char *newschema) changeDependencyFor(ExtensionRelationId, extensionOid, NamespaceRelationId, oldNspOid, nspOid); } + +/* + * Execute ALTER EXTENSION ADD + */ +void +ExecAlterExtensionAddStmt(AlterExtensionAddStmt *stmt) +{ + ObjectAddress extension; + ObjectAddress object; + Relation relation; + + /* + * For now, insist on superuser privilege. Later we might want to + * relax this to ownership of the target object and the extension. + */ + if (!superuser()) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + (errmsg("must be superuser to use ALTER EXTENSION")))); + + /* Do this next to fail on nonexistent extension */ + extension.classId = ExtensionRelationId; + extension.objectId = get_extension_oid(stmt->extname, false); + extension.objectSubId = 0; + + /* + * Translate the parser representation that identifies the object into + * an ObjectAddress. get_object_address() will throw an error if the + * object does not exist, and will also acquire a lock on the object + * to guard against concurrent DROP and ALTER EXTENSION ADD operations. + */ + object = get_object_address(stmt->objtype, stmt->objname, stmt->objargs, + &relation, ShareUpdateExclusiveLock); + + /* + * Complain if object is already attached to some extension. + */ + if (getExtensionOfObject(object.classId, object.objectId) != InvalidOid) + ereport(ERROR, + (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), + errmsg("%s is already a member of an extension", + getObjectDescription(&object)))); + + /* + * OK, add the dependency. + */ + recordDependencyOn(&object, &extension, DEPENDENCY_EXTENSION); + + /* + * If get_object_address() opened the relation for us, we close it to keep + * the reference count correct - but we retain any locks acquired by + * get_object_address() until commit time, to guard against concurrent + * activity. + */ + if (relation != NULL) + relation_close(relation, NoLock); +} diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index 851186146d..3d898326d7 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -3250,6 +3250,19 @@ _copyCreateExtensionStmt(CreateExtensionStmt *from) return newnode; } +static AlterExtensionAddStmt * +_copyAlterExtensionAddStmt(AlterExtensionAddStmt *from) +{ + AlterExtensionAddStmt *newnode = makeNode(AlterExtensionAddStmt); + + COPY_STRING_FIELD(extname); + COPY_SCALAR_FIELD(objtype); + COPY_NODE_FIELD(objname); + COPY_NODE_FIELD(objargs); + + return newnode; +} + static CreateFdwStmt * _copyCreateFdwStmt(CreateFdwStmt *from) { @@ -4252,6 +4265,9 @@ copyObject(void *from) case T_CreateExtensionStmt: retval = _copyCreateExtensionStmt(from); break; + case T_AlterExtensionAddStmt: + retval = _copyAlterExtensionAddStmt(from); + break; case T_CreateFdwStmt: retval = _copyCreateFdwStmt(from); break; diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c index 00d23ccfa5..9baa7862e6 100644 --- a/src/backend/nodes/equalfuncs.c +++ b/src/backend/nodes/equalfuncs.c @@ -1655,6 +1655,17 @@ _equalCreateExtensionStmt(CreateExtensionStmt *a, CreateExtensionStmt *b) } static bool +_equalAlterExtensionAddStmt(AlterExtensionAddStmt *a, AlterExtensionAddStmt *b) +{ + COMPARE_STRING_FIELD(extname); + COMPARE_SCALAR_FIELD(objtype); + COMPARE_NODE_FIELD(objname); + COMPARE_NODE_FIELD(objargs); + + return true; +} + +static bool _equalCreateFdwStmt(CreateFdwStmt *a, CreateFdwStmt *b) { COMPARE_STRING_FIELD(fdwname); @@ -2857,6 +2868,9 @@ equal(void *a, void *b) case T_CreateExtensionStmt: retval = _equalCreateExtensionStmt(a, b); break; + case T_AlterExtensionAddStmt: + retval = _equalAlterExtensionAddStmt(a, b); + break; case T_CreateFdwStmt: retval = _equalCreateFdwStmt(a, b); break; diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 4c4536b9be..a61f3dc7ba 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -185,7 +185,7 @@ static RangeVar *makeRangeVarFromAnyName(List *names, int position, core_yyscan_ AlterDatabaseStmt AlterDatabaseSetStmt AlterDomainStmt AlterEnumStmt AlterFdwStmt AlterForeignServerStmt AlterGroupStmt AlterObjectSchemaStmt AlterOwnerStmt AlterSeqStmt AlterTableStmt - AlterForeignTableStmt + AlterExtensionAddStmt AlterForeignTableStmt AlterCompositeTypeStmt AlterUserStmt AlterUserMappingStmt AlterUserSetStmt AlterRoleStmt AlterRoleSetStmt AlterDefaultPrivilegesStmt DefACLAction @@ -664,6 +664,7 @@ stmt : | AlterDefaultPrivilegesStmt | AlterDomainStmt | AlterEnumStmt + | AlterExtensionAddStmt | AlterFdwStmt | AlterForeignServerStmt | AlterForeignTableStmt @@ -3250,6 +3251,189 @@ create_extension_opt_item: /***************************************************************************** * + * ALTER EXTENSION name ADD object-identifier + * + *****************************************************************************/ + +AlterExtensionAddStmt: + ALTER EXTENSION name ADD_P AGGREGATE func_name aggr_args + { + AlterExtensionAddStmt *n = makeNode(AlterExtensionAddStmt); + n->extname = $3; + n->objtype = OBJECT_AGGREGATE; + n->objname = $6; + n->objargs = $7; + $$ = (Node *)n; + } + | ALTER EXTENSION name ADD_P CAST '(' Typename AS Typename ')' + { + AlterExtensionAddStmt *n = makeNode(AlterExtensionAddStmt); + n->extname = $3; + n->objtype = OBJECT_CAST; + n->objname = list_make1($7); + n->objargs = list_make1($9); + $$ = (Node *) n; + } + | ALTER EXTENSION name ADD_P CONVERSION_P any_name + { + AlterExtensionAddStmt *n = makeNode(AlterExtensionAddStmt); + n->extname = $3; + n->objtype = OBJECT_CONVERSION; + n->objname = $6; + $$ = (Node *)n; + } + | ALTER EXTENSION name ADD_P DOMAIN_P any_name + { + AlterExtensionAddStmt *n = makeNode(AlterExtensionAddStmt); + n->extname = $3; + n->objtype = OBJECT_DOMAIN; + n->objname = $6; + $$ = (Node *)n; + } + | ALTER EXTENSION name ADD_P FUNCTION function_with_argtypes + { + AlterExtensionAddStmt *n = makeNode(AlterExtensionAddStmt); + n->extname = $3; + n->objtype = OBJECT_FUNCTION; + n->objname = $6->funcname; + n->objargs = $6->funcargs; + $$ = (Node *)n; + } + | ALTER EXTENSION name ADD_P opt_procedural LANGUAGE name + { + AlterExtensionAddStmt *n = makeNode(AlterExtensionAddStmt); + n->extname = $3; + n->objtype = OBJECT_LANGUAGE; + n->objname = list_make1(makeString($7)); + $$ = (Node *)n; + } + | ALTER EXTENSION name ADD_P OPERATOR any_operator oper_argtypes + { + AlterExtensionAddStmt *n = makeNode(AlterExtensionAddStmt); + n->extname = $3; + n->objtype = OBJECT_OPERATOR; + n->objname = $6; + n->objargs = $7; + $$ = (Node *)n; + } + | ALTER EXTENSION name ADD_P OPERATOR CLASS any_name USING access_method + { + AlterExtensionAddStmt *n = makeNode(AlterExtensionAddStmt); + n->extname = $3; + n->objtype = OBJECT_OPCLASS; + n->objname = $7; + n->objargs = list_make1(makeString($9)); + $$ = (Node *)n; + } + | ALTER EXTENSION name ADD_P OPERATOR FAMILY any_name USING access_method + { + AlterExtensionAddStmt *n = makeNode(AlterExtensionAddStmt); + n->extname = $3; + n->objtype = OBJECT_OPFAMILY; + n->objname = $7; + n->objargs = list_make1(makeString($9)); + $$ = (Node *)n; + } + | ALTER EXTENSION name ADD_P SCHEMA name + { + AlterExtensionAddStmt *n = makeNode(AlterExtensionAddStmt); + n->extname = $3; + n->objtype = OBJECT_SCHEMA; + n->objname = list_make1(makeString($6)); + $$ = (Node *)n; + } + | ALTER EXTENSION name ADD_P TABLE any_name + { + AlterExtensionAddStmt *n = makeNode(AlterExtensionAddStmt); + n->extname = $3; + n->objtype = OBJECT_TABLE; + n->objname = $6; + $$ = (Node *)n; + } + | ALTER EXTENSION name ADD_P TEXT_P SEARCH PARSER any_name + { + AlterExtensionAddStmt *n = makeNode(AlterExtensionAddStmt); + n->extname = $3; + n->objtype = OBJECT_TSPARSER; + n->objname = $8; + $$ = (Node *)n; + } + | ALTER EXTENSION name ADD_P TEXT_P SEARCH DICTIONARY any_name + { + AlterExtensionAddStmt *n = makeNode(AlterExtensionAddStmt); + n->extname = $3; + n->objtype = OBJECT_TSDICTIONARY; + n->objname = $8; + $$ = (Node *)n; + } + | ALTER EXTENSION name ADD_P TEXT_P SEARCH TEMPLATE any_name + { + AlterExtensionAddStmt *n = makeNode(AlterExtensionAddStmt); + n->extname = $3; + n->objtype = OBJECT_TSTEMPLATE; + n->objname = $8; + $$ = (Node *)n; + } + | ALTER EXTENSION name ADD_P TEXT_P SEARCH CONFIGURATION any_name + { + AlterExtensionAddStmt *n = makeNode(AlterExtensionAddStmt); + n->extname = $3; + n->objtype = OBJECT_TSCONFIGURATION; + n->objname = $8; + $$ = (Node *)n; + } + | ALTER EXTENSION name ADD_P SEQUENCE any_name + { + AlterExtensionAddStmt *n = makeNode(AlterExtensionAddStmt); + n->extname = $3; + n->objtype = OBJECT_SEQUENCE; + n->objname = $6; + $$ = (Node *)n; + } + | ALTER EXTENSION name ADD_P VIEW any_name + { + AlterExtensionAddStmt *n = makeNode(AlterExtensionAddStmt); + n->extname = $3; + n->objtype = OBJECT_VIEW; + n->objname = $6; + $$ = (Node *)n; + } + | ALTER EXTENSION name ADD_P FOREIGN TABLE any_name + { + AlterExtensionAddStmt *n = makeNode(AlterExtensionAddStmt); + n->extname = $3; + n->objtype = OBJECT_FOREIGN_TABLE; + n->objname = $7; + $$ = (Node *)n; + } + | ALTER EXTENSION name ADD_P FOREIGN DATA_P WRAPPER name + { + AlterExtensionAddStmt *n = makeNode(AlterExtensionAddStmt); + n->extname = $3; + n->objtype = OBJECT_FDW; + n->objname = list_make1(makeString($8)); + $$ = (Node *)n; + } + | ALTER EXTENSION name ADD_P SERVER name + { + AlterExtensionAddStmt *n = makeNode(AlterExtensionAddStmt); + n->extname = $3; + n->objtype = OBJECT_FOREIGN_SERVER; + n->objname = list_make1(makeString($6)); + $$ = (Node *)n; + } + | ALTER EXTENSION name ADD_P TYPE_P any_name + { + AlterExtensionAddStmt *n = makeNode(AlterExtensionAddStmt); + n->extname = $3; + n->objtype = OBJECT_TYPE; + n->objname = $6; + $$ = (Node *)n; + } + ; + +/***************************************************************************** + * * QUERY: * CREATE FOREIGN DATA WRAPPER name [ VALIDATOR name ] * diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c index 10a4438995..9d1562af7d 100644 --- a/src/backend/tcop/utility.c +++ b/src/backend/tcop/utility.c @@ -212,6 +212,7 @@ check_xact_readonly(Node *parsetree) case T_AlterTSDictionaryStmt: case T_AlterTSConfigurationStmt: case T_CreateExtensionStmt: + case T_AlterExtensionAddStmt: case T_CreateFdwStmt: case T_AlterFdwStmt: case T_DropFdwStmt: @@ -600,6 +601,10 @@ standard_ProcessUtility(Node *parsetree, CreateExtension((CreateExtensionStmt *) parsetree); break; + case T_AlterExtensionAddStmt: + ExecAlterExtensionAddStmt((AlterExtensionAddStmt *) parsetree); + break; + case T_CreateFdwStmt: CreateForeignDataWrapper((CreateFdwStmt *) parsetree); break; @@ -1422,6 +1427,123 @@ QueryReturnsTuples(Query *parsetree) /* + * AlterObjectTypeCommandTag + * helper function for CreateCommandTag + * + * This covers most cases where ALTER is used with an ObjectType enum. + */ +static const char * +AlterObjectTypeCommandTag(ObjectType objtype) +{ + const char *tag; + + switch (objtype) + { + case OBJECT_AGGREGATE: + tag = "ALTER AGGREGATE"; + break; + case OBJECT_ATTRIBUTE: + tag = "ALTER TYPE"; + break; + case OBJECT_CAST: + tag = "ALTER CAST"; + break; + case OBJECT_COLUMN: + tag = "ALTER TABLE"; + break; + case OBJECT_CONSTRAINT: + tag = "ALTER TABLE"; + break; + case OBJECT_CONVERSION: + tag = "ALTER CONVERSION"; + break; + case OBJECT_DATABASE: + tag = "ALTER DATABASE"; + break; + case OBJECT_DOMAIN: + tag = "ALTER DOMAIN"; + break; + case OBJECT_EXTENSION: + tag = "ALTER EXTENSION"; + break; + case OBJECT_FDW: + tag = "ALTER FOREIGN DATA WRAPPER"; + break; + case OBJECT_FOREIGN_SERVER: + tag = "ALTER SERVER"; + break; + case OBJECT_FOREIGN_TABLE: + tag = "ALTER FOREIGN TABLE"; + break; + case OBJECT_FUNCTION: + tag = "ALTER FUNCTION"; + break; + case OBJECT_INDEX: + tag = "ALTER INDEX"; + break; + case OBJECT_LANGUAGE: + tag = "ALTER LANGUAGE"; + break; + case OBJECT_LARGEOBJECT: + tag = "ALTER LARGE OBJECT"; + break; + case OBJECT_OPCLASS: + tag = "ALTER OPERATOR CLASS"; + break; + case OBJECT_OPERATOR: + tag = "ALTER OPERATOR"; + break; + case OBJECT_OPFAMILY: + tag = "ALTER OPERATOR FAMILY"; + break; + case OBJECT_ROLE: + tag = "ALTER ROLE"; + break; + case OBJECT_RULE: + tag = "ALTER RULE"; + break; + case OBJECT_SCHEMA: + tag = "ALTER SCHEMA"; + break; + case OBJECT_SEQUENCE: + tag = "ALTER SEQUENCE"; + break; + case OBJECT_TABLE: + tag = "ALTER TABLE"; + break; + case OBJECT_TABLESPACE: + tag = "ALTER TABLESPACE"; + break; + case OBJECT_TRIGGER: + tag = "ALTER TRIGGER"; + break; + case OBJECT_TSCONFIGURATION: + tag = "ALTER TEXT SEARCH CONFIGURATION"; + break; + case OBJECT_TSDICTIONARY: + tag = "ALTER TEXT SEARCH DICTIONARY"; + break; + case OBJECT_TSPARSER: + tag = "ALTER TEXT SEARCH PARSER"; + break; + case OBJECT_TSTEMPLATE: + tag = "ALTER TEXT SEARCH TEMPLATE"; + break; + case OBJECT_TYPE: + tag = "ALTER TYPE"; + break; + case OBJECT_VIEW: + tag = "ALTER VIEW"; + break; + default: + tag = "???"; + break; + } + + return tag; +} + +/* * CreateCommandTag * utility to get a string representation of the command operation, * given either a raw (un-analyzed) parsetree or a planned query. @@ -1558,6 +1680,10 @@ CreateCommandTag(Node *parsetree) tag = "CREATE EXTENSION"; break; + case T_AlterExtensionAddStmt: + tag = "ALTER EXTENSION"; + break; + case T_CreateFdwStmt: tag = "CREATE FOREIGN DATA WRAPPER"; break; @@ -1665,235 +1791,19 @@ CreateCommandTag(Node *parsetree) break; case T_RenameStmt: - switch (((RenameStmt *) parsetree)->renameType) - { - case OBJECT_AGGREGATE: - tag = "ALTER AGGREGATE"; - break; - case OBJECT_CONVERSION: - tag = "ALTER CONVERSION"; - break; - case OBJECT_DATABASE: - tag = "ALTER DATABASE"; - break; - case OBJECT_FUNCTION: - tag = "ALTER FUNCTION"; - break; - case OBJECT_INDEX: - tag = "ALTER INDEX"; - break; - case OBJECT_LANGUAGE: - tag = "ALTER LANGUAGE"; - break; - case OBJECT_OPCLASS: - tag = "ALTER OPERATOR CLASS"; - break; - case OBJECT_OPFAMILY: - tag = "ALTER OPERATOR FAMILY"; - break; - case OBJECT_ROLE: - tag = "ALTER ROLE"; - break; - case OBJECT_SCHEMA: - tag = "ALTER SCHEMA"; - break; - case OBJECT_SEQUENCE: - tag = "ALTER SEQUENCE"; - break; - case OBJECT_COLUMN: - { - RenameStmt *stmt = (RenameStmt *) parsetree; - if (stmt->relationType == OBJECT_FOREIGN_TABLE) - tag = "ALTER FOREIGN TABLE"; - else - tag = "ALTER TABLE"; - } - break; - case OBJECT_TABLE: - tag = "ALTER TABLE"; - break; - case OBJECT_TABLESPACE: - tag = "ALTER TABLESPACE"; - break; - case OBJECT_TRIGGER: - tag = "ALTER TRIGGER"; - break; - case OBJECT_VIEW: - tag = "ALTER VIEW"; - break; - case OBJECT_FOREIGN_TABLE: - tag = "ALTER FOREIGN TABLE"; - break; - case OBJECT_TSPARSER: - tag = "ALTER TEXT SEARCH PARSER"; - break; - case OBJECT_TSDICTIONARY: - tag = "ALTER TEXT SEARCH DICTIONARY"; - break; - case OBJECT_TSTEMPLATE: - tag = "ALTER TEXT SEARCH TEMPLATE"; - break; - case OBJECT_TSCONFIGURATION: - tag = "ALTER TEXT SEARCH CONFIGURATION"; - break; - case OBJECT_ATTRIBUTE: - case OBJECT_TYPE: - tag = "ALTER TYPE"; - break; - default: - tag = "???"; - break; - } + tag = AlterObjectTypeCommandTag(((RenameStmt *) parsetree)->renameType); break; case T_AlterObjectSchemaStmt: - switch (((AlterObjectSchemaStmt *) parsetree)->objectType) - { - case OBJECT_AGGREGATE: - tag = "ALTER AGGREGATE"; - break; - case OBJECT_CONVERSION: - tag = "ALTER CONVERSION"; - break; - case OBJECT_DOMAIN: - tag = "ALTER DOMAIN"; - break; - case OBJECT_EXTENSION: - tag = "ALTER EXTENSION"; - 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; - case OBJECT_SEQUENCE: - tag = "ALTER SEQUENCE"; - break; - case OBJECT_TABLE: - tag = "ALTER TABLE"; - break; - case OBJECT_TYPE: - tag = "ALTER TYPE"; - break; - case OBJECT_TSPARSER: - tag = "ALTER TEXT SEARCH PARSER"; - break; - case OBJECT_TSDICTIONARY: - tag = "ALTER TEXT SEARCH DICTIONARY"; - break; - case OBJECT_TSTEMPLATE: - tag = "ALTER TEXT SEARCH TEMPLATE"; - break; - case OBJECT_TSCONFIGURATION: - tag = "ALTER TEXT SEARCH CONFIGURATION"; - break; - case OBJECT_VIEW: - tag = "ALTER VIEW"; - break; - case OBJECT_FOREIGN_TABLE: - tag = "ALTER FOREIGN TABLE"; - break; - default: - tag = "???"; - break; - } + tag = AlterObjectTypeCommandTag(((AlterObjectSchemaStmt *) parsetree)->objectType); break; case T_AlterOwnerStmt: - switch (((AlterOwnerStmt *) parsetree)->objectType) - { - case OBJECT_AGGREGATE: - tag = "ALTER AGGREGATE"; - break; - case OBJECT_CONVERSION: - tag = "ALTER CONVERSION"; - break; - case OBJECT_DATABASE: - tag = "ALTER DATABASE"; - break; - case OBJECT_DOMAIN: - tag = "ALTER DOMAIN"; - break; - case OBJECT_FUNCTION: - tag = "ALTER FUNCTION"; - break; - case OBJECT_LANGUAGE: - tag = "ALTER LANGUAGE"; - break; - case OBJECT_LARGEOBJECT: - tag = "ALTER LARGE OBJECT"; - 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_SCHEMA: - tag = "ALTER SCHEMA"; - break; - case OBJECT_TABLESPACE: - tag = "ALTER TABLESPACE"; - break; - case OBJECT_TYPE: - tag = "ALTER TYPE"; - break; - case OBJECT_TSCONFIGURATION: - tag = "ALTER TEXT SEARCH CONFIGURATION"; - break; - case OBJECT_TSDICTIONARY: - tag = "ALTER TEXT SEARCH DICTIONARY"; - break; - case OBJECT_FDW: - tag = "ALTER FOREIGN DATA WRAPPER"; - break; - case OBJECT_FOREIGN_SERVER: - tag = "ALTER SERVER"; - break; - case OBJECT_FOREIGN_TABLE: - tag = "ALTER FOREIGN TABLE"; - break; - default: - tag = "???"; - break; - } + tag = AlterObjectTypeCommandTag(((AlterOwnerStmt *) parsetree)->objectType); break; case T_AlterTableStmt: - switch (((AlterTableStmt *) parsetree)->relkind) - { - case OBJECT_TABLE: - tag = "ALTER TABLE"; - break; - case OBJECT_INDEX: - tag = "ALTER INDEX"; - break; - case OBJECT_SEQUENCE: - tag = "ALTER SEQUENCE"; - break; - case OBJECT_TYPE: - tag = "ALTER TYPE"; - break; - case OBJECT_VIEW: - tag = "ALTER VIEW"; - break; - case OBJECT_FOREIGN_TABLE: - tag = "ALTER FOREIGN TABLE"; - break; - default: - tag = "???"; - break; - } + tag = AlterObjectTypeCommandTag(((AlterTableStmt *) parsetree)->relkind); break; case T_AlterDomainStmt: @@ -2391,18 +2301,13 @@ GetCommandLogLevel(Node *parsetree) break; case T_CreateTableSpaceStmt: - lev = LOGSTMT_DDL; - break; - case T_DropTableSpaceStmt: - lev = LOGSTMT_DDL; - break; - case T_AlterTableSpaceOptionsStmt: lev = LOGSTMT_DDL; break; case T_CreateExtensionStmt: + case T_AlterExtensionAddStmt: lev = LOGSTMT_DDL; break; diff --git a/src/include/commands/extension.h b/src/include/commands/extension.h index 10d08935a0..d0e94556f5 100644 --- a/src/include/commands/extension.h +++ b/src/include/commands/extension.h @@ -32,6 +32,8 @@ extern void CreateExtension(CreateExtensionStmt *stmt); extern void RemoveExtensions(DropStmt *stmt); extern void RemoveExtensionById(Oid extId); +extern void ExecAlterExtensionAddStmt(AlterExtensionAddStmt *stmt); + extern Oid get_extension_oid(const char *extname, bool missing_ok); extern char *get_extension_name(Oid ext_oid); diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h index 1ca5f1ef9a..1ce9738631 100644 --- a/src/include/nodes/nodes.h +++ b/src/include/nodes/nodes.h @@ -356,6 +356,7 @@ typedef enum NodeTag T_SecLabelStmt, T_CreateForeignTableStmt, T_CreateExtensionStmt, + T_AlterExtensionAddStmt, /* * TAGS FOR PARSE TREE NODES (parsenodes.h) diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index 5de4dbd5ec..2116c94d0d 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -1060,13 +1060,13 @@ typedef struct SetOperationStmt /* * When a command can act on several kinds of objects with only one * parse structure required, use these constants to designate the - * object type. + * object type. Note that commands typically don't support all the types. */ typedef enum ObjectType { OBJECT_AGGREGATE, - OBJECT_ATTRIBUTE, /* type's attribute, when distinct from column */ + OBJECT_ATTRIBUTE, /* type's attribute, when distinct from column */ OBJECT_CAST, OBJECT_COLUMN, OBJECT_CONSTRAINT, @@ -1535,7 +1535,7 @@ typedef struct AlterTableSpaceOptionsStmt } AlterTableSpaceOptionsStmt; /* ---------------------- - * Create Extension Statement + * Create/Alter Extension Statements * ---------------------- */ @@ -1546,6 +1546,15 @@ typedef struct CreateExtensionStmt List *options; /* List of DefElem nodes */ } CreateExtensionStmt; +typedef struct AlterExtensionAddStmt +{ + NodeTag type; + char *extname; /* Extension's name */ + ObjectType objtype; /* Object's type */ + List *objname; /* Qualified name of the object */ + List *objargs; /* Arguments if needed (eg, for functions) */ +} AlterExtensionAddStmt; + /* ---------------------- * Create/Drop FOREIGN DATA WRAPPER Statements * ---------------------- -- 2.11.0