diff --git a/doc/src/sgml/ref/alter_extension.sgml b/doc/src/sgml/ref/alter_extension.sgml index 6613418fd235c6e3697e27a40ff6897af0056542..e9eb1aafbb6f3552a096f3c872bcf0d3f1ad7f3f 100644 --- a/doc/src/sgml/ref/alter_extension.sgml +++ b/doc/src/sgml/ref/alter_extension.sgml @@ -25,6 +25,7 @@ PostgreSQL documentation <synopsis> ALTER EXTENSION <replaceable class="PARAMETER">extension_name</replaceable> SET SCHEMA <replaceable class="PARAMETER">new_schema</replaceable> ALTER EXTENSION <replaceable class="PARAMETER">extension_name</replaceable> ADD <replaceable class="PARAMETER">member_object</replaceable> +ALTER EXTENSION <replaceable class="PARAMETER">extension_name</replaceable> DROP <replaceable class="PARAMETER">member_object</replaceable> <phrase>where <replaceable class="PARAMETER">member_object</replaceable> is:</phrase> @@ -82,6 +83,17 @@ ALTER EXTENSION <replaceable class="PARAMETER">extension_name</replaceable> ADD </para> </listitem> </varlistentry> + + <varlistentry> + <term><literal>DROP <replaceable class="PARAMETER">member_object</replaceable></literal></term> + <listitem> + <para> + This form removes a member object from the extension. This is mainly + useful in extension upgrade scripts. The object is not dropped, only + disassociated from the extension. + </para> + </listitem> + </varlistentry> </variablelist> See <xref linkend="extend-extensions"> for more information about these @@ -123,7 +135,8 @@ ALTER EXTENSION <replaceable class="PARAMETER">extension_name</replaceable> ADD <term><replaceable class="parameter">operator_name</replaceable></term> <listitem> <para> - The name of an object to be added to the extension. Names of tables, + The name of an object to be added to or removed from 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. diff --git a/src/backend/catalog/pg_depend.c b/src/backend/catalog/pg_depend.c index b2ce148d625ae151ef4fb69863a203bee5ce6dba..2bb7bb3d5fa920b7690959d37126589b0ef9147d 100644 --- a/src/backend/catalog/pg_depend.c +++ b/src/backend/catalog/pg_depend.c @@ -199,6 +199,57 @@ deleteDependencyRecordsFor(Oid classId, Oid objectId, return count; } +/* + * deleteDependencyRecordsForClass -- delete all records with given depender + * classId/objectId, dependee classId, and deptype. + * Returns the number of records deleted. + * + * This is a variant of deleteDependencyRecordsFor, useful when revoking + * an object property that is expressed by a dependency record (such as + * extension membership). + */ +long +deleteDependencyRecordsForClass(Oid classId, Oid objectId, + Oid refclassId, char deptype) +{ + long count = 0; + Relation depRel; + ScanKeyData key[2]; + SysScanDesc scan; + HeapTuple tup; + + depRel = heap_open(DependRelationId, RowExclusiveLock); + + ScanKeyInit(&key[0], + Anum_pg_depend_classid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(classId)); + ScanKeyInit(&key[1], + Anum_pg_depend_objid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(objectId)); + + scan = systable_beginscan(depRel, DependDependerIndexId, true, + SnapshotNow, 2, key); + + while (HeapTupleIsValid(tup = systable_getnext(scan))) + { + Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup); + + if (depform->refclassid == refclassId && depform->deptype == deptype) + { + simple_heap_delete(depRel, &tup->t_self); + count++; + } + } + + systable_endscan(scan); + + heap_close(depRel, RowExclusiveLock); + + return count; +} + /* * Adjust dependency record(s) to point to a different object of the same type * @@ -470,39 +521,8 @@ sequenceIsOwned(Oid seqId, Oid *tableId, int32 *colId) void markSequenceUnowned(Oid seqId) { - Relation depRel; - ScanKeyData key[2]; - SysScanDesc scan; - HeapTuple tup; - - depRel = heap_open(DependRelationId, RowExclusiveLock); - - ScanKeyInit(&key[0], - Anum_pg_depend_classid, - BTEqualStrategyNumber, F_OIDEQ, - ObjectIdGetDatum(RelationRelationId)); - ScanKeyInit(&key[1], - Anum_pg_depend_objid, - BTEqualStrategyNumber, F_OIDEQ, - ObjectIdGetDatum(seqId)); - - scan = systable_beginscan(depRel, DependDependerIndexId, true, - SnapshotNow, 2, key); - - while (HeapTupleIsValid((tup = systable_getnext(scan)))) - { - Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup); - - if (depform->refclassid == RelationRelationId && - depform->deptype == DEPENDENCY_AUTO) - { - simple_heap_delete(depRel, &tup->t_self); - } - } - - systable_endscan(scan); - - heap_close(depRel, RowExclusiveLock); + deleteDependencyRecordsForClass(RelationRelationId, seqId, + RelationRelationId, DEPENDENCY_AUTO); } /* diff --git a/src/backend/commands/extension.c b/src/backend/commands/extension.c index 1da76aca10fac6c47571ee5287d43bd29f4d4892..bc121808bec094299bdd17faf752f6db018bd6b1 100644 --- a/src/backend/commands/extension.c +++ b/src/backend/commands/extension.c @@ -1436,14 +1436,15 @@ AlterExtensionNamespace(List *names, const char *newschema) } /* - * Execute ALTER EXTENSION ADD + * Execute ALTER EXTENSION ADD/DROP */ void -ExecAlterExtensionAddStmt(AlterExtensionAddStmt *stmt) +ExecAlterExtensionContentsStmt(AlterExtensionContentsStmt *stmt) { ObjectAddress extension; ObjectAddress object; Relation relation; + Oid oldExtension; /* * For now, insist on superuser privilege. Later we might want to @@ -1462,25 +1463,54 @@ ExecAlterExtensionAddStmt(AlterExtensionAddStmt *stmt) /* * 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 does not exist, and will also acquire a lock on the object to + * guard against concurrent DROP and ALTER EXTENSION ADD/DROP operations. */ object = get_object_address(stmt->objtype, stmt->objname, stmt->objargs, &relation, ShareUpdateExclusiveLock); /* - * Complain if object is already attached to some extension. + * Check existing extension membership. */ - 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)))); + oldExtension = getExtensionOfObject(object.classId, object.objectId); - /* - * OK, add the dependency. - */ - recordDependencyOn(&object, &extension, DEPENDENCY_EXTENSION); + if (stmt->action > 0) + { + /* + * ADD, so complain if object is already attached to some extension. + */ + if (OidIsValid(oldExtension)) + ereport(ERROR, + (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), + errmsg("%s is already a member of extension \"%s\"", + getObjectDescription(&object), + get_extension_name(oldExtension)))); + + /* + * OK, add the dependency. + */ + recordDependencyOn(&object, &extension, DEPENDENCY_EXTENSION); + } + else + { + /* + * DROP, so complain if it's not a member. + */ + if (oldExtension != extension.objectId) + ereport(ERROR, + (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), + errmsg("%s is not a member of extension \"%s\"", + getObjectDescription(&object), + stmt->extname))); + + /* + * OK, drop the dependency. + */ + if (deleteDependencyRecordsForClass(object.classId, object.objectId, + ExtensionRelationId, + DEPENDENCY_EXTENSION) != 1) + elog(ERROR, "unexpected number of extension dependency records"); + } /* * If get_object_address() opened the relation for us, we close it to keep diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index 83630924f6386ad89021854c96f499d47cb56d59..46acaf8d701abc6be9b8683f30a3f04d066f596c 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -3251,12 +3251,13 @@ _copyCreateExtensionStmt(CreateExtensionStmt *from) return newnode; } -static AlterExtensionAddStmt * -_copyAlterExtensionAddStmt(AlterExtensionAddStmt *from) +static AlterExtensionContentsStmt * +_copyAlterExtensionContentsStmt(AlterExtensionContentsStmt *from) { - AlterExtensionAddStmt *newnode = makeNode(AlterExtensionAddStmt); + AlterExtensionContentsStmt *newnode = makeNode(AlterExtensionContentsStmt); COPY_STRING_FIELD(extname); + COPY_SCALAR_FIELD(action); COPY_SCALAR_FIELD(objtype); COPY_NODE_FIELD(objname); COPY_NODE_FIELD(objargs); @@ -4266,8 +4267,8 @@ copyObject(void *from) case T_CreateExtensionStmt: retval = _copyCreateExtensionStmt(from); break; - case T_AlterExtensionAddStmt: - retval = _copyAlterExtensionAddStmt(from); + case T_AlterExtensionContentsStmt: + retval = _copyAlterExtensionContentsStmt(from); break; case T_CreateFdwStmt: retval = _copyCreateFdwStmt(from); diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c index 9baa7862e6cca36d4e06fa9268a8de0ec3ef9896..2fbe99937d2e49d901058e43118a978d99201ffc 100644 --- a/src/backend/nodes/equalfuncs.c +++ b/src/backend/nodes/equalfuncs.c @@ -1655,9 +1655,10 @@ _equalCreateExtensionStmt(CreateExtensionStmt *a, CreateExtensionStmt *b) } static bool -_equalAlterExtensionAddStmt(AlterExtensionAddStmt *a, AlterExtensionAddStmt *b) +_equalAlterExtensionContentsStmt(AlterExtensionContentsStmt *a, AlterExtensionContentsStmt *b) { COMPARE_STRING_FIELD(extname); + COMPARE_SCALAR_FIELD(action); COMPARE_SCALAR_FIELD(objtype); COMPARE_NODE_FIELD(objname); COMPARE_NODE_FIELD(objargs); @@ -2868,8 +2869,8 @@ equal(void *a, void *b) case T_CreateExtensionStmt: retval = _equalCreateExtensionStmt(a, b); break; - case T_AlterExtensionAddStmt: - retval = _equalAlterExtensionAddStmt(a, b); + case T_AlterExtensionContentsStmt: + retval = _equalAlterExtensionContentsStmt(a, b); break; case T_CreateFdwStmt: retval = _equalCreateFdwStmt(a, b); diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index e2d7d6a02f311e8b9f0eff71431c938166edda45..82ff9accc72761c83afa5b6d7e6fc9cb2e1d8e9a 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 - AlterExtensionAddStmt AlterForeignTableStmt + AlterExtensionContentsStmt AlterForeignTableStmt AlterCompositeTypeStmt AlterUserStmt AlterUserMappingStmt AlterUserSetStmt AlterRoleStmt AlterRoleSetStmt AlterDefaultPrivilegesStmt DefACLAction @@ -664,7 +664,7 @@ stmt : | AlterDefaultPrivilegesStmt | AlterDomainStmt | AlterEnumStmt - | AlterExtensionAddStmt + | AlterExtensionContentsStmt | AlterFdwStmt | AlterForeignServerStmt | AlterForeignTableStmt @@ -3251,181 +3251,202 @@ create_extension_opt_item: /***************************************************************************** * - * ALTER EXTENSION name ADD object-identifier + * ALTER EXTENSION name ADD/DROP object-identifier * *****************************************************************************/ -AlterExtensionAddStmt: - ALTER EXTENSION name ADD_P AGGREGATE func_name aggr_args +AlterExtensionContentsStmt: + ALTER EXTENSION name add_drop AGGREGATE func_name aggr_args { - AlterExtensionAddStmt *n = makeNode(AlterExtensionAddStmt); + AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt); n->extname = $3; + n->action = $4; n->objtype = OBJECT_AGGREGATE; n->objname = $6; n->objargs = $7; $$ = (Node *)n; } - | ALTER EXTENSION name ADD_P CAST '(' Typename AS Typename ')' + | ALTER EXTENSION name add_drop CAST '(' Typename AS Typename ')' { - AlterExtensionAddStmt *n = makeNode(AlterExtensionAddStmt); + AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt); n->extname = $3; + n->action = $4; 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 + | ALTER EXTENSION name add_drop CONVERSION_P any_name { - AlterExtensionAddStmt *n = makeNode(AlterExtensionAddStmt); + AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt); n->extname = $3; + n->action = $4; n->objtype = OBJECT_CONVERSION; n->objname = $6; $$ = (Node *)n; } - | ALTER EXTENSION name ADD_P DOMAIN_P any_name + | ALTER EXTENSION name add_drop DOMAIN_P any_name { - AlterExtensionAddStmt *n = makeNode(AlterExtensionAddStmt); + AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt); n->extname = $3; + n->action = $4; n->objtype = OBJECT_DOMAIN; n->objname = $6; $$ = (Node *)n; } - | ALTER EXTENSION name ADD_P FUNCTION function_with_argtypes + | ALTER EXTENSION name add_drop FUNCTION function_with_argtypes { - AlterExtensionAddStmt *n = makeNode(AlterExtensionAddStmt); + AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt); n->extname = $3; + n->action = $4; n->objtype = OBJECT_FUNCTION; n->objname = $6->funcname; n->objargs = $6->funcargs; $$ = (Node *)n; } - | ALTER EXTENSION name ADD_P opt_procedural LANGUAGE name + | ALTER EXTENSION name add_drop opt_procedural LANGUAGE name { - AlterExtensionAddStmt *n = makeNode(AlterExtensionAddStmt); + AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt); n->extname = $3; + n->action = $4; n->objtype = OBJECT_LANGUAGE; n->objname = list_make1(makeString($7)); $$ = (Node *)n; } - | ALTER EXTENSION name ADD_P OPERATOR any_operator oper_argtypes + | ALTER EXTENSION name add_drop OPERATOR any_operator oper_argtypes { - AlterExtensionAddStmt *n = makeNode(AlterExtensionAddStmt); + AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt); n->extname = $3; + n->action = $4; n->objtype = OBJECT_OPERATOR; n->objname = $6; n->objargs = $7; $$ = (Node *)n; } - | ALTER EXTENSION name ADD_P OPERATOR CLASS any_name USING access_method + | ALTER EXTENSION name add_drop OPERATOR CLASS any_name USING access_method { - AlterExtensionAddStmt *n = makeNode(AlterExtensionAddStmt); + AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt); n->extname = $3; + n->action = $4; 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 + | ALTER EXTENSION name add_drop OPERATOR FAMILY any_name USING access_method { - AlterExtensionAddStmt *n = makeNode(AlterExtensionAddStmt); + AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt); n->extname = $3; + n->action = $4; n->objtype = OBJECT_OPFAMILY; n->objname = $7; n->objargs = list_make1(makeString($9)); $$ = (Node *)n; } - | ALTER EXTENSION name ADD_P SCHEMA name + | ALTER EXTENSION name add_drop SCHEMA name { - AlterExtensionAddStmt *n = makeNode(AlterExtensionAddStmt); + AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt); n->extname = $3; + n->action = $4; n->objtype = OBJECT_SCHEMA; n->objname = list_make1(makeString($6)); $$ = (Node *)n; } - | ALTER EXTENSION name ADD_P TABLE any_name + | ALTER EXTENSION name add_drop TABLE any_name { - AlterExtensionAddStmt *n = makeNode(AlterExtensionAddStmt); + AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt); n->extname = $3; + n->action = $4; n->objtype = OBJECT_TABLE; n->objname = $6; $$ = (Node *)n; } - | ALTER EXTENSION name ADD_P TEXT_P SEARCH PARSER any_name + | ALTER EXTENSION name add_drop TEXT_P SEARCH PARSER any_name { - AlterExtensionAddStmt *n = makeNode(AlterExtensionAddStmt); + AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt); n->extname = $3; + n->action = $4; n->objtype = OBJECT_TSPARSER; n->objname = $8; $$ = (Node *)n; } - | ALTER EXTENSION name ADD_P TEXT_P SEARCH DICTIONARY any_name + | ALTER EXTENSION name add_drop TEXT_P SEARCH DICTIONARY any_name { - AlterExtensionAddStmt *n = makeNode(AlterExtensionAddStmt); + AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt); n->extname = $3; + n->action = $4; n->objtype = OBJECT_TSDICTIONARY; n->objname = $8; $$ = (Node *)n; } - | ALTER EXTENSION name ADD_P TEXT_P SEARCH TEMPLATE any_name + | ALTER EXTENSION name add_drop TEXT_P SEARCH TEMPLATE any_name { - AlterExtensionAddStmt *n = makeNode(AlterExtensionAddStmt); + AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt); n->extname = $3; + n->action = $4; n->objtype = OBJECT_TSTEMPLATE; n->objname = $8; $$ = (Node *)n; } - | ALTER EXTENSION name ADD_P TEXT_P SEARCH CONFIGURATION any_name + | ALTER EXTENSION name add_drop TEXT_P SEARCH CONFIGURATION any_name { - AlterExtensionAddStmt *n = makeNode(AlterExtensionAddStmt); + AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt); n->extname = $3; + n->action = $4; n->objtype = OBJECT_TSCONFIGURATION; n->objname = $8; $$ = (Node *)n; } - | ALTER EXTENSION name ADD_P SEQUENCE any_name + | ALTER EXTENSION name add_drop SEQUENCE any_name { - AlterExtensionAddStmt *n = makeNode(AlterExtensionAddStmt); + AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt); n->extname = $3; + n->action = $4; n->objtype = OBJECT_SEQUENCE; n->objname = $6; $$ = (Node *)n; } - | ALTER EXTENSION name ADD_P VIEW any_name + | ALTER EXTENSION name add_drop VIEW any_name { - AlterExtensionAddStmt *n = makeNode(AlterExtensionAddStmt); + AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt); n->extname = $3; + n->action = $4; n->objtype = OBJECT_VIEW; n->objname = $6; $$ = (Node *)n; } - | ALTER EXTENSION name ADD_P FOREIGN TABLE any_name + | ALTER EXTENSION name add_drop FOREIGN TABLE any_name { - AlterExtensionAddStmt *n = makeNode(AlterExtensionAddStmt); + AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt); n->extname = $3; + n->action = $4; n->objtype = OBJECT_FOREIGN_TABLE; n->objname = $7; $$ = (Node *)n; } - | ALTER EXTENSION name ADD_P FOREIGN DATA_P WRAPPER name + | ALTER EXTENSION name add_drop FOREIGN DATA_P WRAPPER name { - AlterExtensionAddStmt *n = makeNode(AlterExtensionAddStmt); + AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt); n->extname = $3; + n->action = $4; n->objtype = OBJECT_FDW; n->objname = list_make1(makeString($8)); $$ = (Node *)n; } - | ALTER EXTENSION name ADD_P SERVER name + | ALTER EXTENSION name add_drop SERVER name { - AlterExtensionAddStmt *n = makeNode(AlterExtensionAddStmt); + AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt); n->extname = $3; + n->action = $4; n->objtype = OBJECT_FOREIGN_SERVER; n->objname = list_make1(makeString($6)); $$ = (Node *)n; } - | ALTER EXTENSION name ADD_P TYPE_P any_name + | ALTER EXTENSION name add_drop TYPE_P any_name { - AlterExtensionAddStmt *n = makeNode(AlterExtensionAddStmt); + AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt); n->extname = $3; + n->action = $4; n->objtype = OBJECT_TYPE; n->objname = $6; $$ = (Node *)n; diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c index 9d1562af7dc6e7b4090097452f84f3cf29c3d773..c942de3bf62cb7b47ab26c1e2b62ff78d808945a 100644 --- a/src/backend/tcop/utility.c +++ b/src/backend/tcop/utility.c @@ -212,7 +212,7 @@ check_xact_readonly(Node *parsetree) case T_AlterTSDictionaryStmt: case T_AlterTSConfigurationStmt: case T_CreateExtensionStmt: - case T_AlterExtensionAddStmt: + case T_AlterExtensionContentsStmt: case T_CreateFdwStmt: case T_AlterFdwStmt: case T_DropFdwStmt: @@ -601,8 +601,8 @@ standard_ProcessUtility(Node *parsetree, CreateExtension((CreateExtensionStmt *) parsetree); break; - case T_AlterExtensionAddStmt: - ExecAlterExtensionAddStmt((AlterExtensionAddStmt *) parsetree); + case T_AlterExtensionContentsStmt: + ExecAlterExtensionContentsStmt((AlterExtensionContentsStmt *) parsetree); break; case T_CreateFdwStmt: @@ -1680,7 +1680,7 @@ CreateCommandTag(Node *parsetree) tag = "CREATE EXTENSION"; break; - case T_AlterExtensionAddStmt: + case T_AlterExtensionContentsStmt: tag = "ALTER EXTENSION"; break; @@ -2307,7 +2307,7 @@ GetCommandLogLevel(Node *parsetree) break; case T_CreateExtensionStmt: - case T_AlterExtensionAddStmt: + case T_AlterExtensionContentsStmt: lev = LOGSTMT_DDL; break; diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c index 1c9623de1e56440540c96f4d3fd2692c805f2abb..c01b02ae3a11fab9f9590ddcef7d36be00df0639 100644 --- a/src/bin/psql/tab-complete.c +++ b/src/bin/psql/tab-complete.c @@ -855,7 +855,12 @@ psql_completion(char *text, int start, int end) /* ALTER EXTENSION <name> */ else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 && pg_strcasecmp(prev2_wd, "EXTENSION") == 0) - COMPLETE_WITH_CONST("SET SCHEMA"); + { + static const char *const list_ALTEREXTENSION[] = + {"ADD", "DROP", "SET SCHEMA", NULL}; + + COMPLETE_WITH_LIST(list_ALTEREXTENSION); + } /* ALTER FOREIGN */ else if (pg_strcasecmp(prev2_wd, "ALTER") == 0 && diff --git a/src/include/catalog/dependency.h b/src/include/catalog/dependency.h index 4d7ff8853d1c0c26c61d4aa0eff5bfb204e11869..eda41d69216dcafdc565cd465c20776b5fe6449e 100644 --- a/src/include/catalog/dependency.h +++ b/src/include/catalog/dependency.h @@ -205,6 +205,9 @@ extern void recordDependencyOnCurrentExtension(const ObjectAddress *object); extern long deleteDependencyRecordsFor(Oid classId, Oid objectId, bool skipExtensionDeps); +extern long deleteDependencyRecordsForClass(Oid classId, Oid objectId, + Oid refclassId, char deptype); + extern long changeDependencyFor(Oid classId, Oid objectId, Oid refClassId, Oid oldRefObjectId, Oid newRefObjectId); diff --git a/src/include/commands/extension.h b/src/include/commands/extension.h index 8c07c3aaeffad931421a71e633cf8ec873bfc980..7c94449a6cb0f5e853fe70bd79ae7ce0c87b5069 100644 --- a/src/include/commands/extension.h +++ b/src/include/commands/extension.h @@ -37,7 +37,7 @@ extern Oid InsertExtensionTuple(const char *extName, Oid extOwner, Datum extConfig, Datum extCondition, List *requiredExtensions); -extern void ExecAlterExtensionAddStmt(AlterExtensionAddStmt *stmt); +extern void ExecAlterExtensionContentsStmt(AlterExtensionContentsStmt *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 1ce97386315119f0260eb1122a524f7bebf6ddda..15bf0631e44c50fb2a94014fd02edf997adcb2b7 100644 --- a/src/include/nodes/nodes.h +++ b/src/include/nodes/nodes.h @@ -356,7 +356,7 @@ typedef enum NodeTag T_SecLabelStmt, T_CreateForeignTableStmt, T_CreateExtensionStmt, - T_AlterExtensionAddStmt, + T_AlterExtensionContentsStmt, /* * TAGS FOR PARSE TREE NODES (parsenodes.h) diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index 2116c94d0d39b3679f6bc97bca3f26d63434c318..b54f0cfe02f7bb5d47d4c37171d12e0543cdbe1e 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -1546,14 +1546,15 @@ typedef struct CreateExtensionStmt List *options; /* List of DefElem nodes */ } CreateExtensionStmt; -typedef struct AlterExtensionAddStmt +typedef struct AlterExtensionContentsStmt { NodeTag type; char *extname; /* Extension's name */ + int action; /* +1 = add object, -1 = drop object */ ObjectType objtype; /* Object's type */ List *objname; /* Qualified name of the object */ List *objargs; /* Arguments if needed (eg, for functions) */ -} AlterExtensionAddStmt; +} AlterExtensionContentsStmt; /* ---------------------- * Create/Drop FOREIGN DATA WRAPPER Statements