diff --git a/doc/src/sgml/extend.sgml b/doc/src/sgml/extend.sgml
index 206eb6b9017..31ea0487f1e 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 1b29d274cd6..6613418fd23 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.
-
-
-
+
+
+
+ extension_name
+
+
+ The name of an installed extension.
+
+
+
-
- new_schema
-
-
- The new schema for the 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.
+
+
+
+
@@ -83,6 +222,13 @@ ALTER EXTENSION name SET SCHEMA utils:
ALTER EXTENSION hstore SET SCHEMA utils;
+
+
+
+
+ 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 ee42d2e13df..41667fb3afc 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 851186146dd..3d898326d7a 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 00d23ccfa56..9baa7862e6c 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -1654,6 +1654,17 @@ _equalCreateExtensionStmt(CreateExtensionStmt *a, CreateExtensionStmt *b)
return true;
}
+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)
{
@@ -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 4c4536b9be3..a61f3dc7ba4 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
@@ -3248,6 +3249,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:
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index 10a4438995f..9d1562af7dc 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;
@@ -1421,6 +1426,123 @@ QueryReturnsTuples(Query *parsetree)
#endif
+/*
+ * 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,
@@ -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 10d08935a00..d0e94556f50 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 1ca5f1ef9a1..1ce97386315 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 5de4dbd5ec1..2116c94d0d3 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
* ----------------------