Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.89) (envelope-from ) id 1j3qFK-0004Mf-1n for pgsql-hackers@arkaria.postgresql.org; Mon, 17 Feb 2020 23:56:14 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.89) (envelope-from ) id 1j3qFI-0003wX-Fl for pgsql-hackers@arkaria.postgresql.org; Mon, 17 Feb 2020 23:56:12 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.89) (envelope-from ) id 1j3qFI-0003wP-4z for pgsql-hackers@lists.postgresql.org; Mon, 17 Feb 2020 23:56:12 +0000 Received: from mail-qk1-x742.google.com ([2607:f8b0:4864:20::742]) by magus.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.92) (envelope-from ) id 1j3qFE-0004K6-PI for pgsql-hackers@lists.postgresql.org; Mon, 17 Feb 2020 23:56:11 +0000 Received: by mail-qk1-x742.google.com with SMTP id p7so17891422qkh.10 for ; Mon, 17 Feb 2020 15:56:08 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=2ndquadrant-com.20150623.gappssmtp.com; s=20150623; h=date:from:to:subject:message-id:mime-version:content-disposition :content-transfer-encoding:in-reply-to:user-agent; bh=J1Iod3MkK2mV0Yqsn/uG+9BVoN9ExFnj+/FpxqYJrjg=; b=VMXMwHUNaD0pT85+rmDu5eNQfvi6mGNmppW3Ilua9QXHGHLd+sR1RW8uOzL3vo5au/ mtPUM/PdiPaiCuOl4lEXjqTmYxvVpd/kV7IV7SGxv8W980kIOAtOG35elZQEHOf9TNRc nFYEYPb0xF7Hjj0RvzLNYvwx755Gmahfb7RBEGtw82ztFbCJdYPzINXr9nFuoqnu1rjU PqoP/x3XYfxbwcIpy/ahhiJzveiSvMZk8w27d+pG9q2hMXea2Hvs9/Oy2fRAyfJdN6h7 X7ZHv0u2mac2y/sSu0z+6ebPWI74K9BSMaKZ7YhNhtGgPPkw2eXLxuI/Likh594dc9sB /hEA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:from:to:subject:message-id:mime-version :content-disposition:content-transfer-encoding:in-reply-to :user-agent; bh=J1Iod3MkK2mV0Yqsn/uG+9BVoN9ExFnj+/FpxqYJrjg=; b=YouQqjjiXSNsi5H6r8ouCtZxokAgqYWxtQzwwUYfT7hVT6KWEHocJ0Tii1dgmhzkTa AqPKlYwQPOKlF69iz9Fa5DoewACsDLvQ0H5nUK9hk9rrmfSTvhsRmWENHWnbuzMZsjdf dCtJBE0/8rxDWuvRfgtoHU8EuOhTiQlGzH6eliJV54sAxzUgqlLQ8Ge86ng3tMWftX9e 42aWZUtgEzp8rluon/giRpEBH1o9drNGGdoxmGutpbPvWTbtizQKqHxpMAIJrJcqZ/cP SQas0J161sKw18bF7+0du3yiKAIo9cwWo4rkkBYe5FHyeJWh9/0XpHG1DYHZfSe2+7DH ynOw== X-Gm-Message-State: APjAAAVmOkvstvVX7NhHIbKTpjyVA+7MPiUzSy6tatnXA57NRzARU/2M b5tOxtXbD3qcFAF5BIIXWYHypLtQNSVfwp4x5YK7KTXScTWQO1Y0p3ZO4mwSvQFOJcYJy0JlN2n ECSqY1praDGhVLM1hlaG+xyRS70ZoWhfW+8GJiUWP2obN2BykgqPCkb5+PmvQiBixLATyBZIeSu QhAEzeQIPpZirGr6Hb X-Google-Smtp-Source: APXvYqxD7bkn3O1ahxOmYDqhwjXZgafzFxN75bWrqzqZQIhhyePp/U0icsSgoJLbBfhpBa2A0OLzHA== X-Received: by 2002:ae9:dc85:: with SMTP id q127mr16336299qkf.460.1581983766211; Mon, 17 Feb 2020 15:56:06 -0800 (PST) Received: from nimloth.alvh.no-ip.org ([201.186.208.119]) by smtp.gmail.com with ESMTPSA id t55sm1077229qte.24.2020.02.17.15.56.05 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 17 Feb 2020 15:56:05 -0800 (PST) Received: by nimloth.alvh.no-ip.org (Postfix, from userid 1000) id 5D2CC300760; Mon, 17 Feb 2020 20:56:03 -0300 (-03) Date: Mon, 17 Feb 2020 20:56:03 -0300 From: Alvaro Herrera To: Pg Hackers Subject: Re: more ALTER .. DEPENDS ON EXTENSION fixes Message-ID: <20200217235603.GA32740@alvherre.pgsql> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="azLHFNyN32YCQGCU" Content-Disposition: inline Content-Transfer-Encoding: 8bit In-Reply-To: <20200217225333.GA30974@alvherre.pgsql> User-Agent: Mutt/1.10.1 (2018-07-13) List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Precedence: bulk --azLHFNyN32YCQGCU Content-Type: text/plain; charset=iso-8859-1 Content-Disposition: inline Content-Transfer-Encoding: 8bit On 2020-Feb-17, Alvaro Herrera wrote: > * More than one 'x' dependencies are allowed for the same object on the > same extension. That's useless and polluting, so should be prevented. > > * There's no way to remove an 'x' dependency. Here's these two patches. There's an "if (true)" in 0002 which is a little weird -- that's there just to avoid reindenting those lines in 0003. In principle, I would think that these are all backpatchable bugfixes. Maybe 0002 could pass as not backpatchable since it disallows a command that works today. OTOH the feature is rarely used, so maybe a backpatch is not welcome anyhow. -- Álvaro Herrera https://www.2ndQuadrant.com/ PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services --azLHFNyN32YCQGCU Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0002-Avoid-duplicates-in-ALTER-.-DEPENDS-ON-EXTENSION.patch" From 586899b994e45a2b2bf217a25198ba4bdbc6ee82 Mon Sep 17 00:00:00 2001 From: Alvaro Herrera Date: Mon, 17 Feb 2020 19:42:57 -0300 Subject: [PATCH 2/3] Avoid duplicates in ALTER ... DEPENDS ON EXTENSION If the command is attempted on an extension that the object already depends on, raise an error. --- src/backend/catalog/pg_depend.c | 43 ++++++++++++++++++++++++++++++++ src/backend/commands/alter.c | 17 ++++++++++++- src/include/catalog/dependency.h | 1 + 3 files changed, 60 insertions(+), 1 deletion(-) diff --git a/src/backend/catalog/pg_depend.c b/src/backend/catalog/pg_depend.c index f9af245eec..596dafe19c 100644 --- a/src/backend/catalog/pg_depend.c +++ b/src/backend/catalog/pg_depend.c @@ -648,6 +648,49 @@ getExtensionOfObject(Oid classId, Oid objectId) return result; } +/* + * Return (possibly NIL) list of extensions that the given object depends on + * in DEPENDENCY_AUTO_EXTENSION mode. + */ +List * +getAutoExtensionsOfObject(Oid classId, Oid objectId) +{ + List *result = NIL; + Relation depRel; + ScanKeyData key[2]; + SysScanDesc scan; + HeapTuple tup; + + depRel = table_open(DependRelationId, AccessShareLock); + + 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, + NULL, 2, key); + + while (HeapTupleIsValid((tup = systable_getnext(scan)))) + { + Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup); + + if (depform->refclassid == ExtensionRelationId && + depform->deptype == DEPENDENCY_AUTO_EXTENSION) + result = lappend_oid(result, depform->refobjid); + } + + systable_endscan(scan); + + table_close(depRel, AccessShareLock); + + return result; +} + /* * Detect whether a sequence is marked as "owned" by a column * diff --git a/src/backend/commands/alter.c b/src/backend/commands/alter.c index 1cb84182b0..28e32f2fb5 100644 --- a/src/backend/commands/alter.c +++ b/src/backend/commands/alter.c @@ -462,7 +462,22 @@ ExecAlterObjectDependsStmt(AlterObjectDependsStmt *stmt, ObjectAddress *refAddre if (refAddress) *refAddress = refAddr; - recordDependencyOn(&address, &refAddr, DEPENDENCY_AUTO_EXTENSION); + if (true) + { + List *currexts; + + /* Avoid duplicates */ + currexts = getAutoExtensionsOfObject(address.classId, + address.objectId); + if (list_member_oid(currexts, refAddr.objectId)) + ereport(ERROR, + (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), + errmsg("%s already depends on extension \"%s\"", + getObjectDescription(&address), + get_extension_name(refAddr.objectId)))); + + recordDependencyOn(&address, &refAddr, DEPENDENCY_AUTO_EXTENSION); + } return address; } diff --git a/src/include/catalog/dependency.h b/src/include/catalog/dependency.h index 0cd6fcf027..ab5e92bdc6 100644 --- a/src/include/catalog/dependency.h +++ b/src/include/catalog/dependency.h @@ -207,6 +207,7 @@ extern long changeDependenciesOn(Oid refClassId, Oid oldRefObjectId, Oid newRefObjectId); extern Oid getExtensionOfObject(Oid classId, Oid objectId); +extern List *getAutoExtensionsOfObject(Oid classId, Oid objectId); extern bool sequenceIsOwned(Oid seqId, char deptype, Oid *tableId, int32 *colId); extern List *getOwnedSequences(Oid relid); -- 2.20.1 --azLHFNyN32YCQGCU Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0003-Add-ALTER-.-NO-DEPENDS-ON.patch" From 540941aa2d8a3bd84518dbd49600dc013771c275 Mon Sep 17 00:00:00 2001 From: Alvaro Herrera Date: Wed, 30 Oct 2019 16:57:29 -0300 Subject: [PATCH 3/3] Add ALTER .. NO DEPENDS ON This new command removes any previously added dependency mark; necessary for completeness. --- doc/src/sgml/ref/alter_function.sgml | 10 ++-- doc/src/sgml/ref/alter_index.sgml | 9 ++-- doc/src/sgml/ref/alter_materialized_view.sgml | 11 ++--- doc/src/sgml/ref/alter_trigger.sgml | 7 ++- src/backend/catalog/pg_depend.c | 49 +++++++++++++++++++ src/backend/commands/alter.c | 17 ++++++- src/backend/nodes/copyfuncs.c | 1 + src/backend/nodes/equalfuncs.c | 1 + src/backend/parser/gram.y | 36 +++++++++----- src/include/catalog/dependency.h | 4 ++ src/include/nodes/parsenodes.h | 1 + .../expected/test_extdepend.out | 39 ++++++++++++++- .../test_extensions/sql/test_extdepend.sql | 18 ++++++- 13 files changed, 169 insertions(+), 34 deletions(-) diff --git a/doc/src/sgml/ref/alter_function.sgml b/doc/src/sgml/ref/alter_function.sgml index 03ffa5945a..70b1f24bc0 100644 --- a/doc/src/sgml/ref/alter_function.sgml +++ b/doc/src/sgml/ref/alter_function.sgml @@ -30,7 +30,7 @@ ALTER FUNCTION name [ ( [ [ argmode ] [ argname ] argtype [, ...] ] ) ] SET SCHEMA new_schema ALTER FUNCTION name [ ( [ [ argmode ] [ argname ] argtype [, ...] ] ) ] - DEPENDS ON EXTENSION extension_name + [ NO ] DEPENDS ON EXTENSION extension_name where action is one of: @@ -153,10 +153,14 @@ ALTER FUNCTION name [ ( [ [ extension_name + DEPENDS ON EXTENSION extension_name + NO DEPENDS ON EXTENSION extension_name - The name of the extension that the function is to depend on. + This form marks the function as dependent on the extension, or no longer + dependent on that extension if NO is specified. + A function that's marked as dependent on an extension is automatically + dropped when the extension is dropped. diff --git a/doc/src/sgml/ref/alter_index.sgml b/doc/src/sgml/ref/alter_index.sgml index 6d34dbb74e..de6f89d458 100644 --- a/doc/src/sgml/ref/alter_index.sgml +++ b/doc/src/sgml/ref/alter_index.sgml @@ -100,11 +100,14 @@ ALTER INDEX ALL IN TABLESPACE name - DEPENDS ON EXTENSION + DEPENDS ON EXTENSION extension_name + NO DEPENDS ON EXTENSION extension_name - This form marks the index as dependent on the extension, such that if the - extension is dropped, the index will automatically be dropped as well. + This form marks the index as dependent on the extension, or no longer + dependent on that extension if NO is specified. + An index that's marked as dependent on an extension is automatically + dropped when the extension is dropped. diff --git a/doc/src/sgml/ref/alter_materialized_view.sgml b/doc/src/sgml/ref/alter_materialized_view.sgml index 03e3df1ffd..9df8a79977 100644 --- a/doc/src/sgml/ref/alter_materialized_view.sgml +++ b/doc/src/sgml/ref/alter_materialized_view.sgml @@ -68,12 +68,6 @@ ALTER MATERIALIZED VIEW ALL IN TABLESPACE name - - The DEPENDS ON EXTENSION form marks the materialized view - as dependent on an extension, such that the materialized view will - automatically be dropped if the extension is dropped. - - The statement subforms and actions available for ALTER MATERIALIZED VIEW are a subset of those available @@ -110,7 +104,10 @@ ALTER MATERIALIZED VIEW ALL IN TABLESPACE nameextension_name - The name of the extension that the materialized view is to depend on. + The name of the extension that the materialized view is to depend on (or no longer + dependent on, if NO is specified). A materialized view + that's marked as dependent on an extension is automatically dropped when + the extension is dropped. diff --git a/doc/src/sgml/ref/alter_trigger.sgml b/doc/src/sgml/ref/alter_trigger.sgml index 6cf789a67a..6d4784c82f 100644 --- a/doc/src/sgml/ref/alter_trigger.sgml +++ b/doc/src/sgml/ref/alter_trigger.sgml @@ -22,7 +22,7 @@ PostgreSQL documentation ALTER TRIGGER name ON table_name RENAME TO new_name -ALTER TRIGGER name ON table_name DEPENDS ON EXTENSION extension_name +ALTER TRIGGER name ON table_name [ NO ] DEPENDS ON EXTENSION extension_name @@ -78,7 +78,10 @@ ALTER TRIGGER name ON extension_name - The name of the extension that the trigger is to depend on. + The name of the extension that the trigger is to depend on (or no longer + dependent on, if NO is specified). A trigger + that's marked as dependent on an extension is automatically dropped when + the extension is dropped. diff --git a/src/backend/catalog/pg_depend.c b/src/backend/catalog/pg_depend.c index 596dafe19c..fa38ee9477 100644 --- a/src/backend/catalog/pg_depend.c +++ b/src/backend/catalog/pg_depend.c @@ -278,6 +278,55 @@ deleteDependencyRecordsForClass(Oid classId, Oid objectId, return count; } +/* + * deleteDependencyRecordsForSpecific -- delete all records with given depender + * classId/objectId, dependee classId/objectId, of the given deptype. + * Returns the number of records deleted. + */ +long +deleteDependencyRecordsForSpecific(Oid classId, Oid objectId, char deptype, + Oid refclassId, Oid refobjectId) +{ + long count = 0; + Relation depRel; + ScanKeyData key[2]; + SysScanDesc scan; + HeapTuple tup; + + depRel = table_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, + NULL, 2, key); + + while (HeapTupleIsValid(tup = systable_getnext(scan))) + { + Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup); + + if (depform->refclassid == refclassId && + depform->refobjid == refobjectId && + depform->deptype == deptype) + { + CatalogTupleDelete(depRel, &tup->t_self); + count++; + } + } + + systable_endscan(scan); + + table_close(depRel, RowExclusiveLock); + + return count; +} + /* * Adjust dependency record(s) to point to a different object of the same type * diff --git a/src/backend/commands/alter.c b/src/backend/commands/alter.c index 28e32f2fb5..4a98e11efe 100644 --- a/src/backend/commands/alter.c +++ b/src/backend/commands/alter.c @@ -421,7 +421,7 @@ ExecRenameStmt(RenameStmt *stmt) } /* - * Executes an ALTER OBJECT / DEPENDS ON [EXTENSION] statement. + * Executes an ALTER OBJECT / [NO] DEPENDS ON EXTENSION statement. * * Return value is the address of the altered object. refAddress is an output * argument which, if not null, receives the address of the object that the @@ -462,10 +462,23 @@ ExecAlterObjectDependsStmt(AlterObjectDependsStmt *stmt, ObjectAddress *refAddre if (refAddress) *refAddress = refAddr; - if (true) + if (stmt->remove) + deleteDependencyRecordsForSpecific(address.classId, address.objectId, + DEPENDENCY_AUTO_EXTENSION, + refAddr.classId, refAddr.objectId); + else { + Oid currextoid; List *currexts; + /* Fail if object is part of an extension */ + currextoid = getExtensionOfObject(address.classId, address.objectId); + if (OidIsValid(currextoid)) + ereport(ERROR, + (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), + errmsg("%s is already part of extension \"%s\"", + getObjectDescription(&address), + get_extension_name(currextoid)))); /* Avoid duplicates */ currexts = getAutoExtensionsOfObject(address.classId, address.objectId); diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index 54ad62bb7f..851e0b0c4a 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -3593,6 +3593,7 @@ _copyAlterObjectDependsStmt(const AlterObjectDependsStmt *from) COPY_NODE_FIELD(relation); COPY_NODE_FIELD(object); COPY_NODE_FIELD(extname); + COPY_SCALAR_FIELD(remove); return newnode; } diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c index 5b1ba143b1..8c734045a8 100644 --- a/src/backend/nodes/equalfuncs.c +++ b/src/backend/nodes/equalfuncs.c @@ -1445,6 +1445,7 @@ _equalAlterObjectDependsStmt(const AlterObjectDependsStmt *a, const AlterObjectD COMPARE_NODE_FIELD(relation); COMPARE_NODE_FIELD(object); COMPARE_NODE_FIELD(extname); + COMPARE_SCALAR_FIELD(remove); return true; } diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 1b0edf5d3d..d99156194d 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -311,7 +311,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); %type vac_analyze_option_list %type vac_analyze_option_arg %type drop_option -%type opt_or_replace +%type opt_or_replace opt_no opt_grant_grant_option opt_grant_admin_option opt_nowait opt_if_exists opt_with_data opt_transaction_chain @@ -9024,57 +9024,67 @@ opt_set_data: SET DATA_P { $$ = 1; } *****************************************************************************/ AlterObjectDependsStmt: - ALTER FUNCTION function_with_argtypes DEPENDS ON EXTENSION name + ALTER FUNCTION function_with_argtypes opt_no DEPENDS ON EXTENSION name { AlterObjectDependsStmt *n = makeNode(AlterObjectDependsStmt); n->objectType = OBJECT_FUNCTION; n->object = (Node *) $3; - n->extname = makeString($7); + n->extname = makeString($8); + n->remove = $4; $$ = (Node *)n; } - | ALTER PROCEDURE function_with_argtypes DEPENDS ON EXTENSION name + | ALTER PROCEDURE function_with_argtypes opt_no DEPENDS ON EXTENSION name { AlterObjectDependsStmt *n = makeNode(AlterObjectDependsStmt); n->objectType = OBJECT_PROCEDURE; n->object = (Node *) $3; - n->extname = makeString($7); + n->extname = makeString($8); + n->remove = $4; $$ = (Node *)n; } - | ALTER ROUTINE function_with_argtypes DEPENDS ON EXTENSION name + | ALTER ROUTINE function_with_argtypes opt_no DEPENDS ON EXTENSION name { AlterObjectDependsStmt *n = makeNode(AlterObjectDependsStmt); n->objectType = OBJECT_ROUTINE; n->object = (Node *) $3; - n->extname = makeString($7); + n->extname = makeString($8); + n->remove = $4; $$ = (Node *)n; } - | ALTER TRIGGER name ON qualified_name DEPENDS ON EXTENSION name + | ALTER TRIGGER name ON qualified_name opt_no DEPENDS ON EXTENSION name { AlterObjectDependsStmt *n = makeNode(AlterObjectDependsStmt); n->objectType = OBJECT_TRIGGER; n->relation = $5; n->object = (Node *) list_make1(makeString($3)); - n->extname = makeString($9); + n->extname = makeString($10); + n->remove = $6; $$ = (Node *)n; } - | ALTER MATERIALIZED VIEW qualified_name DEPENDS ON EXTENSION name + | ALTER MATERIALIZED VIEW qualified_name opt_no DEPENDS ON EXTENSION name { AlterObjectDependsStmt *n = makeNode(AlterObjectDependsStmt); n->objectType = OBJECT_MATVIEW; n->relation = $4; - n->extname = makeString($8); + n->extname = makeString($9); + n->remove = $5; $$ = (Node *)n; } - | ALTER INDEX qualified_name DEPENDS ON EXTENSION name + | ALTER INDEX qualified_name opt_no DEPENDS ON EXTENSION name { AlterObjectDependsStmt *n = makeNode(AlterObjectDependsStmt); n->objectType = OBJECT_INDEX; n->relation = $3; - n->extname = makeString($7); + n->extname = makeString($8); + n->remove = $4; $$ = (Node *)n; } ; +opt_no: NO { $$ = true; } + | /* EMPTY */ { $$ = false; } + ; + /***************************************************************************** * * ALTER THING name SET SCHEMA name diff --git a/src/include/catalog/dependency.h b/src/include/catalog/dependency.h index ab5e92bdc6..2c6abe26a5 100644 --- a/src/include/catalog/dependency.h +++ b/src/include/catalog/dependency.h @@ -196,6 +196,10 @@ extern long deleteDependencyRecordsFor(Oid classId, Oid objectId, extern long deleteDependencyRecordsForClass(Oid classId, Oid objectId, Oid refclassId, char deptype); +extern long deleteDependencyRecordsForSpecific(Oid classId, Oid objectId, + char deptype, + Oid refclassId, Oid refobjectId); + extern long changeDependencyFor(Oid classId, Oid objectId, Oid refClassId, Oid oldRefObjectId, Oid newRefObjectId); diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index da0706add5..dad344f137 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -2930,6 +2930,7 @@ typedef struct AlterObjectDependsStmt RangeVar *relation; /* in case a table is involved */ Node *object; /* name of the object */ Value *extname; /* extension name */ + bool remove; /* set true to remove dep rather than add */ } AlterObjectDependsStmt; /* ---------------------- diff --git a/src/test/modules/test_extensions/expected/test_extdepend.out b/src/test/modules/test_extensions/expected/test_extdepend.out index 11e441ddd3..7bb1d8f362 100644 --- a/src/test/modules/test_extensions/expected/test_extdepend.out +++ b/src/test/modules/test_extensions/expected/test_extdepend.out @@ -147,6 +147,41 @@ SELECT deptype, i.* ---------+------+--------+------+---------- (0 rows) -DROP TABLE a; +RESET search_path; DROP SCHEMA test_ext CASCADE; -NOTICE: drop cascades to extension test_ext5 +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to extension test_ext5 +drop cascades to table test_ext.a +-- Fourth test: we can mark the objects as dependent, then unmark; then the +-- drop of the extension does nothing +SELECT * FROM test_extdep_commands \gexec + CREATE SCHEMA test_ext + CREATE EXTENSION test_ext5 SCHEMA test_ext + SET search_path TO test_ext + CREATE TABLE a (a1 int) + + CREATE FUNCTION b() RETURNS TRIGGER LANGUAGE plpgsql AS + $$ BEGIN NEW.a1 := NEW.a1 + 42; RETURN NEW; END; $$ + ALTER FUNCTION b() DEPENDS ON EXTENSION test_ext5 + + CREATE TRIGGER c BEFORE INSERT ON a FOR EACH ROW EXECUTE PROCEDURE b() + ALTER TRIGGER c ON a DEPENDS ON EXTENSION test_ext5 + + CREATE MATERIALIZED VIEW d AS SELECT * FROM a + ALTER MATERIALIZED VIEW d DEPENDS ON EXTENSION test_ext5 + + CREATE INDEX e ON a (a1) + ALTER INDEX e DEPENDS ON EXTENSION test_ext5 + RESET search_path +SET search_path TO test_ext; +ALTER FUNCTION b() NO DEPENDS ON EXTENSION test_ext5; +ALTER TRIGGER c ON a NO DEPENDS ON EXTENSION test_ext5; +ALTER MATERIALIZED VIEW d NO DEPENDS ON EXTENSION test_ext5; +ALTER INDEX e NO DEPENDS ON EXTENSION test_ext5; +DROP EXTENSION test_ext5; +DROP TRIGGER c ON a; +DROP FUNCTION b(); +DROP MATERIALIZED VIEW d; +DROP INDEX e; +DROP SCHEMA test_ext CASCADE; +NOTICE: drop cascades to table a diff --git a/src/test/modules/test_extensions/sql/test_extdepend.sql b/src/test/modules/test_extensions/sql/test_extdepend.sql index cf44145dcb..b709d71e96 100644 --- a/src/test/modules/test_extensions/sql/test_extdepend.sql +++ b/src/test/modules/test_extensions/sql/test_extdepend.sql @@ -68,6 +68,20 @@ SELECT deptype, i.* refobjid=(SELECT oid FROM pg_extension WHERE extname='test_ext5')) OR (refclassid='pg_class'::regclass AND refobjid='test_ext.a'::regclass) AND NOT deptype IN ('i', 'a'); - -DROP TABLE a; +RESET search_path; +DROP SCHEMA test_ext CASCADE; + +-- Fourth test: we can mark the objects as dependent, then unmark; then the +-- drop of the extension does nothing +SELECT * FROM test_extdep_commands \gexec +SET search_path TO test_ext; +ALTER FUNCTION b() NO DEPENDS ON EXTENSION test_ext5; +ALTER TRIGGER c ON a NO DEPENDS ON EXTENSION test_ext5; +ALTER MATERIALIZED VIEW d NO DEPENDS ON EXTENSION test_ext5; +ALTER INDEX e NO DEPENDS ON EXTENSION test_ext5; +DROP EXTENSION test_ext5; +DROP TRIGGER c ON a; +DROP FUNCTION b(); +DROP MATERIALIZED VIEW d; +DROP INDEX e; DROP SCHEMA test_ext CASCADE; -- 2.20.1 --azLHFNyN32YCQGCU--