OK, thanks for the clarification. Here's the earlier patch, but with the relevant added docs and tests retained.
-- Abhijit
>From dfb6ded15246ec65cc911864bfcff285eef1c4d4 Mon Sep 17 00:00:00 2001 From: Abhijit Menon-Sen <a...@2ndquadrant.com> Date: Tue, 5 Apr 2016 11:55:09 +0530 Subject: =?UTF-8?q?Implement=20"ALTER=20=E2=80=A6=20DEPENDS=20ON=20EXTENSI?= =?UTF-8?q?ON=20=E2=80=A6"=20for=20functions=20and=20triggers?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A new dependency type, DEPENDENCY_AUTO_EXTENSION, indicates that an object depends on an extension (but doesn't belong to it, so pg_dump should continue to dump it) and should be dropped when the extension itself is dropped. A new statement type, AlterObjectDependsStmt, is used to declare such dependencies. Includes documentation and tests. --- doc/src/sgml/catalogs.sgml | 13 ++++++ doc/src/sgml/ref/alter_function.sgml | 20 +++++++++ doc/src/sgml/ref/alter_trigger.sgml | 16 +++++++ src/backend/catalog/dependency.c | 2 + src/backend/catalog/objectaddress.c | 25 +++++++++++ src/backend/commands/alter.c | 32 ++++++++++++++ src/backend/nodes/copyfuncs.c | 17 ++++++++ src/backend/nodes/equalfuncs.c | 15 +++++++ src/backend/parser/gram.y | 36 +++++++++++++++- src/backend/tcop/utility.c | 27 ++++++++++++ src/include/catalog/dependency.h | 9 +++- src/include/catalog/objectaddress.h | 4 ++ src/include/commands/alter.h | 1 + src/include/nodes/nodes.h | 1 + src/include/nodes/parsenodes.h | 15 +++++++ src/include/parser/kwlist.h | 1 + src/test/modules/test_extensions/Makefile | 2 +- .../test_extensions/expected/test_extdepend.out | 50 ++++++++++++++++++++++ .../modules/test_extensions/sql/test_extdepend.sql | 32 ++++++++++++++ src/tools/pgindent/typedefs.list | 1 + 20 files changed, 315 insertions(+), 4 deletions(-) create mode 100644 src/test/modules/test_extensions/expected/test_extdepend.out create mode 100644 src/test/modules/test_extensions/sql/test_extdepend.sql diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml index bb75229..3c128a0 100644 --- a/doc/src/sgml/catalogs.sgml +++ b/doc/src/sgml/catalogs.sgml @@ -2888,6 +2888,19 @@ </para> </listitem> </varlistentry> + + <varlistentry> + <term><symbol>DEPENDENCY_AUTO_EXTENSION</> (<literal>x</>)</term> + <listitem> + <para> + The dependent object is not a member of the extension that is the + referenced object (and so should not be ignored by pg_dump), but + cannot function without it and should be dropped when the + extension itself is. The dependent object may be dropped on its + own as well. + </para> + </listitem> + </varlistentry> </variablelist> Other dependency flavors might be needed in future. diff --git a/doc/src/sgml/ref/alter_function.sgml b/doc/src/sgml/ref/alter_function.sgml index f40363e..1ef905f 100644 --- a/doc/src/sgml/ref/alter_function.sgml +++ b/doc/src/sgml/ref/alter_function.sgml @@ -29,6 +29,8 @@ ALTER FUNCTION <replaceable>name</replaceable> ( [ [ <replaceable class="paramet OWNER TO { <replaceable>new_owner</replaceable> | CURRENT_USER | SESSION_USER } ALTER FUNCTION <replaceable>name</replaceable> ( [ [ <replaceable class="parameter">argmode</replaceable> ] [ <replaceable class="parameter">argname</replaceable> ] <replaceable class="parameter">argtype</replaceable> [, ...] ] ) SET SCHEMA <replaceable>new_schema</replaceable> +ALTER FUNCTION <replaceable>name</replaceable> ( [ [ <replaceable class="parameter">argmode</replaceable> ] [ <replaceable class="parameter">argname</replaceable> ] <replaceable class="parameter">argtype</replaceable> [, ...] ] ) + DEPENDS ON EXTENSION <replaceable>extension_name</replaceable> <phrase>where <replaceable class="PARAMETER">action</replaceable> is one of:</phrase> @@ -148,6 +150,15 @@ ALTER FUNCTION <replaceable>name</replaceable> ( [ [ <replaceable class="paramet </listitem> </varlistentry> + <varlistentry> + <term><replaceable class="parameter">extension_name</replaceable></term> + <listitem> + <para> + The name of an extension that the function depends on. + </para> + </listitem> + </varlistentry> + <varlistentry> <term><literal>CALLED ON NULL INPUT</literal></term> <term><literal>RETURNS NULL ON NULL INPUT</literal></term> @@ -300,6 +311,15 @@ ALTER FUNCTION sqrt(integer) SET SCHEMA maths; </para> <para> + To mark the function <literal>sqrt</literal> for type + <type>integer</type> as being dependent on the extension + <literal>mathlib</literal>: +<programlisting> +ALTER FUNCTION sqrt(integer) DEPENDS ON EXTENSION mathlib; +</programlisting> + </para> + + <para> To adjust the search path that is automatically set for a function: <programlisting> ALTER FUNCTION check_password(text) SET search_path = admin, pg_temp; diff --git a/doc/src/sgml/ref/alter_trigger.sgml b/doc/src/sgml/ref/alter_trigger.sgml index c63b5df..37c4d03 100644 --- a/doc/src/sgml/ref/alter_trigger.sgml +++ b/doc/src/sgml/ref/alter_trigger.sgml @@ -22,6 +22,7 @@ PostgreSQL documentation <refsynopsisdiv> <synopsis> ALTER TRIGGER <replaceable class="PARAMETER">name</replaceable> ON <replaceable class="PARAMETER">table_name</replaceable> RENAME TO <replaceable class="PARAMETER">new_name</replaceable> +ALTER TRIGGER <replaceable class="PARAMETER">name</replaceable> ON <replaceable class="PARAMETER">table_name</replaceable> DEPENDS ON EXTENSION <replaceable class="PARAMETER">extension_name</replaceable> </synopsis> </refsynopsisdiv> @@ -70,6 +71,15 @@ ALTER TRIGGER <replaceable class="PARAMETER">name</replaceable> ON <replaceable </para> </listitem> </varlistentry> + + <varlistentry> + <term><replaceable class="PARAMETER">extension_name</replaceable></term> + <listitem> + <para> + The name of an extension that the trigger depends on. + </para> + </listitem> + </varlistentry> </variablelist> </refsect1> @@ -93,6 +103,12 @@ ALTER TRIGGER <replaceable class="PARAMETER">name</replaceable> ON <replaceable <programlisting> ALTER TRIGGER emp_stamp ON emp RENAME TO emp_track_chgs; </programlisting></para> + + <para> + To mark a trigger as being dependent on an extension: +<programlisting> +ALTER TRIGGER emp_stamp ON emp DEPENDS ON EXTENSION emplib; +</programlisting></para> </refsect1> <refsect1> diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c index 17f9de1..79595a9 100644 --- a/src/backend/catalog/dependency.c +++ b/src/backend/catalog/dependency.c @@ -589,6 +589,7 @@ findDependentObjects(const ObjectAddress *object, { case DEPENDENCY_NORMAL: case DEPENDENCY_AUTO: + case DEPENDENCY_AUTO_EXTENSION: /* no problem */ break; case DEPENDENCY_INTERNAL: @@ -788,6 +789,7 @@ findDependentObjects(const ObjectAddress *object, subflags = DEPFLAG_NORMAL; break; case DEPENDENCY_AUTO: + case DEPENDENCY_AUTO_EXTENSION: subflags = DEPFLAG_AUTO; break; case DEPENDENCY_INTERNAL: diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index cb3ba85..1324461 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -1016,6 +1016,31 @@ get_object_address(ObjectType objtype, List *objname, List *objargs, } /* + * Return an ObjectAddress based on a RangeVar and an object name. The + * name of the relation identified by the RangeVar is prepended to the + * (possibly empty) list passed in as objname. This is useful to find + * the ObjectAddress of objects that depend on a relation. All other + * considerations are exactly as for get_object_address above. + */ +ObjectAddress +get_object_address_rv(ObjectType objtype, RangeVar *rel, List *objname, + List *objargs, Relation *relp, LOCKMODE lockmode, + bool missing_ok) +{ + if (rel) + { + objname = lcons(makeString(rel->relname), objname); + if (rel->schemaname) + objname = lcons(makeString(rel->schemaname), objname); + if (rel->catalogname) + objname = lcons(makeString(rel->catalogname), objname); + } + + return get_object_address(objtype, objname, objargs, + relp, lockmode, missing_ok); +} + +/* * Find an ObjectAddress for a type of object that is identified by an * unqualified name. */ diff --git a/src/backend/commands/alter.c b/src/backend/commands/alter.c index 5af0f2f..932117a 100644 --- a/src/backend/commands/alter.c +++ b/src/backend/commands/alter.c @@ -391,6 +391,38 @@ ExecRenameStmt(RenameStmt *stmt) } /* + * Executes an ALTER OBJECT / DEPENDS ON EXTENSION statement. + * + * Return value is the address of the altered object. + */ +ObjectAddress +ExecAlterObjectDependsStmt(AlterObjectDependsStmt *stmt) +{ + ObjectAddress address; + ObjectAddress extAddr; + Relation rel = NULL; + + address = + get_object_address_rv(stmt->objectType, stmt->relation, stmt->objname, + stmt->objargs, &rel, AccessExclusiveLock, false); + + /* + * If a relation was involved, it would have been opened and locked. + * We don't need the relation here, but we'll retain the lock until + * commit. + */ + if (rel) + heap_close(rel, NoLock); + + extAddr = get_object_address(OBJECT_EXTENSION, stmt->extname, NULL, + &rel, AccessExclusiveLock, false); + + recordDependencyOn(&address, &extAddr, DEPENDENCY_AUTO_EXTENSION); + + return address; +} + +/* * Executes an ALTER OBJECT / SET SCHEMA statement. Based on the object * type, the function appropriate to that type is executed. * diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index f4e4a91..1e123d8 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -3204,6 +3204,20 @@ _copyRenameStmt(const RenameStmt *from) return newnode; } +static AlterObjectDependsStmt * +_copyAlterObjectDependsStmt(const AlterObjectDependsStmt *from) +{ + AlterObjectDependsStmt *newnode = makeNode(AlterObjectDependsStmt); + + COPY_SCALAR_FIELD(objectType); + COPY_NODE_FIELD(relation); + COPY_NODE_FIELD(objname); + COPY_NODE_FIELD(objargs); + COPY_NODE_FIELD(extname); + + return newnode; +} + static AlterObjectSchemaStmt * _copyAlterObjectSchemaStmt(const AlterObjectSchemaStmt *from) { @@ -4682,6 +4696,9 @@ copyObject(const void *from) case T_RenameStmt: retval = _copyRenameStmt(from); break; + case T_AlterObjectDependsStmt: + retval = _copyAlterObjectDependsStmt(from); + break; case T_AlterObjectSchemaStmt: retval = _copyAlterObjectSchemaStmt(from); break; diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c index 854c062..6c05096 100644 --- a/src/backend/nodes/equalfuncs.c +++ b/src/backend/nodes/equalfuncs.c @@ -1326,6 +1326,18 @@ _equalRenameStmt(const RenameStmt *a, const RenameStmt *b) } static bool +_equalAlterObjectDependsStmt(const AlterObjectDependsStmt *a, const AlterObjectDependsStmt *b) +{ + COMPARE_SCALAR_FIELD(objectType); + COMPARE_NODE_FIELD(relation); + COMPARE_NODE_FIELD(objname); + COMPARE_NODE_FIELD(objargs); + COMPARE_NODE_FIELD(extname); + + return true; +} + +static bool _equalAlterObjectSchemaStmt(const AlterObjectSchemaStmt *a, const AlterObjectSchemaStmt *b) { COMPARE_SCALAR_FIELD(objectType); @@ -3004,6 +3016,9 @@ equal(const void *a, const void *b) case T_RenameStmt: retval = _equalRenameStmt(a, b); break; + case T_AlterObjectDependsStmt: + retval = _equalAlterObjectDependsStmt(a, b); + break; case T_AlterObjectSchemaStmt: retval = _equalAlterObjectSchemaStmt(a, b); break; diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 1273352..3dcebba 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -233,7 +233,8 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); AlterEventTrigStmt AlterDatabaseStmt AlterDatabaseSetStmt AlterDomainStmt AlterEnumStmt AlterFdwStmt AlterForeignServerStmt AlterGroupStmt - AlterObjectSchemaStmt AlterOwnerStmt AlterOperatorStmt AlterSeqStmt AlterSystemStmt AlterTableStmt + AlterObjectDependsStmt AlterObjectSchemaStmt AlterOwnerStmt + AlterOperatorStmt AlterSeqStmt AlterSystemStmt AlterTableStmt AlterTblSpcStmt AlterExtensionStmt AlterExtensionContentsStmt AlterForeignTableStmt AlterCompositeTypeStmt AlterUserStmt AlterUserMappingStmt AlterUserSetStmt AlterRoleStmt AlterRoleSetStmt AlterPolicyStmt @@ -578,7 +579,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); CURRENT_TIME CURRENT_TIMESTAMP CURRENT_USER CURSOR CYCLE DATA_P DATABASE DAY_P DEALLOCATE DEC DECIMAL_P DECLARE DEFAULT DEFAULTS - DEFERRABLE DEFERRED DEFINER DELETE_P DELIMITER DELIMITERS DESC + DEFERRABLE DEFERRED DEFINER DELETE_P DELIMITER DELIMITERS DEPENDS DESC DICTIONARY DISABLE_P DISCARD DISTINCT DO DOCUMENT_P DOMAIN_P DOUBLE_P DROP EACH ELSE ENABLE_P ENCODING ENCRYPTED END_P ENUM_P ESCAPE EVENT EXCEPT @@ -767,6 +768,7 @@ stmt : | AlterForeignTableStmt | AlterFunctionStmt | AlterGroupStmt + | AlterObjectDependsStmt | AlterObjectSchemaStmt | AlterOwnerStmt | AlterOperatorStmt @@ -8027,6 +8029,35 @@ opt_set_data: SET DATA_P { $$ = 1; } /***************************************************************************** * + * ALTER THING name DEPENDS ON EXTENSION name + * + *****************************************************************************/ + +AlterObjectDependsStmt: + ALTER FUNCTION function_with_argtypes DEPENDS ON EXTENSION name + { + AlterObjectDependsStmt *n = makeNode(AlterObjectDependsStmt); + n->objectType = OBJECT_FUNCTION; + n->relation = NULL; + n->objname = $3->funcname; + n->objargs = $3->funcargs; + n->extname = list_make1(makeString($7)); + $$ = (Node *)n; + } + | ALTER TRIGGER name ON qualified_name DEPENDS ON EXTENSION name + { + AlterObjectDependsStmt *n = makeNode(AlterObjectDependsStmt); + n->objectType = OBJECT_TRIGGER; + n->relation = $5; + n->objname = list_make1(makeString($3)); + n->objargs = NIL; + n->extname = list_make1(makeString($9)); + $$ = (Node *)n; + } + ; + +/***************************************************************************** + * * ALTER THING name SET SCHEMA name * *****************************************************************************/ @@ -13726,6 +13757,7 @@ unreserved_keyword: | DELETE_P | DELIMITER | DELIMITERS + | DEPENDS | DICTIONARY | DISABLE_P | DISCARD diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c index 4d0aac9..321db87 100644 --- a/src/backend/tcop/utility.c +++ b/src/backend/tcop/utility.c @@ -147,6 +147,7 @@ check_xact_readonly(Node *parsetree) case T_AlterFunctionStmt: case T_AlterRoleStmt: case T_AlterRoleSetStmt: + case T_AlterObjectDependsStmt: case T_AlterObjectSchemaStmt: case T_AlterOwnerStmt: case T_AlterOperatorStmt: @@ -836,6 +837,19 @@ standard_ProcessUtility(Node *parsetree, } break; + case T_AlterObjectDependsStmt: + { + AlterObjectDependsStmt *stmt = (AlterObjectDependsStmt *) parsetree; + + if (EventTriggerSupportsObjectType(stmt->objectType)) + ProcessUtilitySlow(parsetree, queryString, + context, params, + dest, completionTag); + else + ExecAlterObjectDependsStmt(stmt); + } + break; + case T_AlterObjectSchemaStmt: { AlterObjectSchemaStmt *stmt = (AlterObjectSchemaStmt *) parsetree; @@ -1472,6 +1486,11 @@ ProcessUtilitySlow(Node *parsetree, address = ExecRenameStmt((RenameStmt *) parsetree); break; + case T_AlterObjectDependsStmt: + address = + ExecAlterObjectDependsStmt((AlterObjectDependsStmt *) parsetree); + break; + case T_AlterObjectSchemaStmt: address = ExecAlterObjectSchemaStmt((AlterObjectSchemaStmt *) parsetree, @@ -2192,6 +2211,10 @@ CreateCommandTag(Node *parsetree) tag = AlterObjectTypeCommandTag(((RenameStmt *) parsetree)->renameType); break; + case T_AlterObjectDependsStmt: + tag = AlterObjectTypeCommandTag(((AlterObjectDependsStmt *) parsetree)->objectType); + break; + case T_AlterObjectSchemaStmt: tag = AlterObjectTypeCommandTag(((AlterObjectSchemaStmt *) parsetree)->objectType); break; @@ -2822,6 +2845,10 @@ GetCommandLogLevel(Node *parsetree) lev = LOGSTMT_DDL; break; + case T_AlterObjectDependsStmt: + lev = LOGSTMT_DDL; + break; + case T_AlterObjectSchemaStmt: lev = LOGSTMT_DDL; break; diff --git a/src/include/catalog/dependency.h b/src/include/catalog/dependency.h index d41abc4..107c859 100644 --- a/src/include/catalog/dependency.h +++ b/src/include/catalog/dependency.h @@ -61,6 +61,12 @@ * created only during initdb. The fields for the dependent object * contain zeroes. * + * DEPENDENCY_AUTO_EXTENSION ('x'): the dependent object is not a member + * of the extension that is the referenced object (and so should not be + * ignored by pg_dump), but cannot function without it and should be + * dropped when the extension itself is. The dependent object may be + * dropped on its own as well. + * * Other dependency flavors may be needed in future. */ @@ -70,7 +76,8 @@ typedef enum DependencyType DEPENDENCY_AUTO = 'a', DEPENDENCY_INTERNAL = 'i', DEPENDENCY_EXTENSION = 'e', - DEPENDENCY_PIN = 'p' + DEPENDENCY_PIN = 'p', + DEPENDENCY_AUTO_EXTENSION = 'x' } DependencyType; /* diff --git a/src/include/catalog/objectaddress.h b/src/include/catalog/objectaddress.h index 640f7ff..87aa414 100644 --- a/src/include/catalog/objectaddress.h +++ b/src/include/catalog/objectaddress.h @@ -44,6 +44,10 @@ extern ObjectAddress get_object_address(ObjectType objtype, List *objname, List *objargs, Relation *relp, LOCKMODE lockmode, bool missing_ok); +extern ObjectAddress get_object_address_rv(ObjectType objtype, RangeVar *rel, + List *objname, List *objargs, Relation *relp, + LOCKMODE lockmode, bool missing_ok); + extern void check_object_ownership(Oid roleid, ObjectType objtype, ObjectAddress address, List *objname, List *objargs, Relation relation); diff --git a/src/include/commands/alter.h b/src/include/commands/alter.h index cf92e3e..6cd1bca 100644 --- a/src/include/commands/alter.h +++ b/src/include/commands/alter.h @@ -21,6 +21,7 @@ extern ObjectAddress ExecRenameStmt(RenameStmt *stmt); +extern ObjectAddress ExecAlterObjectDependsStmt(AlterObjectDependsStmt *stmt); extern ObjectAddress ExecAlterObjectSchemaStmt(AlterObjectSchemaStmt *stmt, ObjectAddress *oldSchemaAddr); extern Oid AlterObjectNamespace_oid(Oid classId, Oid objid, Oid nspOid, diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h index 734df77..d888b41 100644 --- a/src/include/nodes/nodes.h +++ b/src/include/nodes/nodes.h @@ -368,6 +368,7 @@ typedef enum NodeTag T_DeclareCursorStmt, T_CreateTableSpaceStmt, T_DropTableSpaceStmt, + T_AlterObjectDependsStmt, T_AlterObjectSchemaStmt, T_AlterOwnerStmt, T_AlterOperatorStmt, diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index 8b958b4..744bea6 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -2536,6 +2536,21 @@ typedef struct RenameStmt } RenameStmt; /* ---------------------- + * ALTER object DEPENDS ON EXTENSION extname + * ---------------------- + */ + +typedef struct AlterObjectDependsStmt +{ + NodeTag type; + ObjectType objectType; /* OBJECT_TABLE, OBJECT_TYPE, etc */ + RangeVar *relation; /* in case a table is involved */ + List *objname; /* name of the object */ + List *objargs; /* argument types, if applicable */ + List *extname; /* target extension's name */ +} AlterObjectDependsStmt; + +/* ---------------------- * ALTER object SET SCHEMA Statement * ---------------------- */ diff --git a/src/include/parser/kwlist.h b/src/include/parser/kwlist.h index 7de3404..17ffef5 100644 --- a/src/include/parser/kwlist.h +++ b/src/include/parser/kwlist.h @@ -125,6 +125,7 @@ PG_KEYWORD("definer", DEFINER, UNRESERVED_KEYWORD) PG_KEYWORD("delete", DELETE_P, UNRESERVED_KEYWORD) PG_KEYWORD("delimiter", DELIMITER, UNRESERVED_KEYWORD) PG_KEYWORD("delimiters", DELIMITERS, UNRESERVED_KEYWORD) +PG_KEYWORD("depends", DEPENDS, UNRESERVED_KEYWORD) PG_KEYWORD("desc", DESC, RESERVED_KEYWORD) PG_KEYWORD("dictionary", DICTIONARY, UNRESERVED_KEYWORD) PG_KEYWORD("disable", DISABLE_P, UNRESERVED_KEYWORD) diff --git a/src/test/modules/test_extensions/Makefile b/src/test/modules/test_extensions/Makefile index 5691357..2832337 100644 --- a/src/test/modules/test_extensions/Makefile +++ b/src/test/modules/test_extensions/Makefile @@ -9,7 +9,7 @@ DATA = test_ext1--1.0.sql test_ext2--1.0.sql test_ext3--1.0.sql \ test_ext4--1.0.sql test_ext5--1.0.sql test_ext_cyclic1--1.0.sql \ test_ext_cyclic2--1.0.sql -REGRESS = test_extensions +REGRESS = test_extensions test_extdepend ifdef USE_PGXS PG_CONFIG = pg_config diff --git a/src/test/modules/test_extensions/expected/test_extdepend.out b/src/test/modules/test_extensions/expected/test_extdepend.out new file mode 100644 index 0000000..33e9145 --- /dev/null +++ b/src/test/modules/test_extensions/expected/test_extdepend.out @@ -0,0 +1,50 @@ +CREATE SCHEMA test_ext; +CREATE EXTENSION test_ext5 SCHEMA test_ext; +-- create various objects +SET search_path=test_ext; +CREATE TABLE a(a1 int); +CREATE FUNCTION b() RETURNS TRIGGER LANGUAGE plpgsql AS $$BEGIN NEW.a1:=NEW.a1+42; RETURN NEW; END;$$; +CREATE TRIGGER c BEFORE INSERT ON a FOR EACH ROW EXECUTE PROCEDURE b(); +-- add 'x' dependencies on test_ext5 +ALTER FUNCTION b() DEPENDS ON EXTENSION test_ext5; +ALTER TRIGGER c ON a DEPENDS ON EXTENSION test_ext5; +-- make sure we have the right number of dependencies on the extension +SELECT COUNT(*) FROM pg_catalog.pg_depend + WHERE deptype='x' AND refclassid='pg_extension'::regclass AND + refobjid=(SELECT oid FROM pg_extension WHERE extname='test_ext5'); + count +------- + 2 +(1 row) + +-- enumerate the dependent objects we created +SELECT * FROM pg_catalog.pg_proc p JOIN pg_catalog.pg_namespace n ON (p.pronamespace=n.oid) + WHERE proname='b' AND n.nspname='test_ext'; + proname | pronamespace | proowner | prolang | procost | prorows | provariadic | protransform | proisagg | proiswindow | prosecdef | proleakproof | proisstrict | proretset | provolatile | proparallel | pronargs | pronargdefaults | prorettype | proargtypes | proallargtypes | proargmodes | proargnames | proargdefaults | protrftypes | prosrc | probin | proconfig | proacl | nspname | nspowner | nspacl +---------+--------------+----------+---------+---------+---------+-------------+--------------+----------+-------------+-----------+--------------+-------------+-----------+-------------+-------------+----------+-----------------+------------+-------------+----------------+-------------+-------------+----------------+-------------+-------------------------------------------+--------+-----------+--------+----------+----------+-------- + b | 16393 | 10 | 12396 | 100 | 0 | 0 | - | f | f | f | f | f | f | v | u | 0 | 0 | 2279 | | | | | | | BEGIN NEW.a1:=NEW.a1+42; RETURN NEW; END; | | | | test_ext | 10 | +(1 row) + +SELECT * FROM pg_catalog.pg_trigger + WHERE tgname='c' AND tgrelid='a'::regclass; + tgrelid | tgname | tgfoid | tgtype | tgenabled | tgisinternal | tgconstrrelid | tgconstrindid | tgconstraint | tgdeferrable | tginitdeferred | tgnargs | tgattr | tgargs | tgqual +---------+--------+--------+--------+-----------+--------------+---------------+---------------+--------------+--------------+----------------+---------+--------+--------+-------- + 16395 | c | 16398 | 7 | O | f | 0 | 0 | 0 | f | f | 0 | | \x | +(1 row) + +-- they should all disappear when the extension is dropped +DROP EXTENSION test_ext5; +SELECT * FROM pg_catalog.pg_proc p JOIN pg_catalog.pg_namespace n ON (p.pronamespace=n.oid) + WHERE proname='b' AND n.nspname='test_ext'; + proname | pronamespace | proowner | prolang | procost | prorows | provariadic | protransform | proisagg | proiswindow | prosecdef | proleakproof | proisstrict | proretset | provolatile | proparallel | pronargs | pronargdefaults | prorettype | proargtypes | proallargtypes | proargmodes | proargnames | proargdefaults | protrftypes | prosrc | probin | proconfig | proacl | nspname | nspowner | nspacl +---------+--------------+----------+---------+---------+---------+-------------+--------------+----------+-------------+-----------+--------------+-------------+-----------+-------------+-------------+----------+-----------------+------------+-------------+----------------+-------------+-------------+----------------+-------------+--------+--------+-----------+--------+---------+----------+-------- +(0 rows) + +SELECT * FROM pg_catalog.pg_trigger + WHERE tgname='c' AND tgrelid='a'::regclass; + tgrelid | tgname | tgfoid | tgtype | tgenabled | tgisinternal | tgconstrrelid | tgconstrindid | tgconstraint | tgdeferrable | tginitdeferred | tgnargs | tgattr | tgargs | tgqual +---------+--------+--------+--------+-----------+--------------+---------------+---------------+--------------+--------------+----------------+---------+--------+--------+-------- +(0 rows) + +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 new file mode 100644 index 0000000..d688b2e --- /dev/null +++ b/src/test/modules/test_extensions/sql/test_extdepend.sql @@ -0,0 +1,32 @@ +CREATE SCHEMA test_ext; +CREATE EXTENSION test_ext5 SCHEMA test_ext; + +-- create various objects +SET search_path=test_ext; +CREATE TABLE a(a1 int); +CREATE FUNCTION b() RETURNS TRIGGER LANGUAGE plpgsql AS $$BEGIN NEW.a1:=NEW.a1+42; RETURN NEW; END;$$; +CREATE TRIGGER c BEFORE INSERT ON a FOR EACH ROW EXECUTE PROCEDURE b(); + +-- add 'x' dependencies on test_ext5 +ALTER FUNCTION b() DEPENDS ON EXTENSION test_ext5; +ALTER TRIGGER c ON a DEPENDS ON EXTENSION test_ext5; + +-- make sure we have the right number of dependencies on the extension +SELECT COUNT(*) FROM pg_catalog.pg_depend + WHERE deptype='x' AND refclassid='pg_extension'::regclass AND + refobjid=(SELECT oid FROM pg_extension WHERE extname='test_ext5'); + +-- enumerate the dependent objects we created +SELECT * FROM pg_catalog.pg_proc p JOIN pg_catalog.pg_namespace n ON (p.pronamespace=n.oid) + WHERE proname='b' AND n.nspname='test_ext'; +SELECT * FROM pg_catalog.pg_trigger + WHERE tgname='c' AND tgrelid='a'::regclass; + +-- they should all disappear when the extension is dropped +DROP EXTENSION test_ext5; +SELECT * FROM pg_catalog.pg_proc p JOIN pg_catalog.pg_namespace n ON (p.pronamespace=n.oid) + WHERE proname='b' AND n.nspname='test_ext'; +SELECT * FROM pg_catalog.pg_trigger + WHERE tgname='c' AND tgrelid='a'::regclass; + +DROP SCHEMA test_ext CASCADE; diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list index c2511de..e293fc0 100644 --- a/src/tools/pgindent/typedefs.list +++ b/src/tools/pgindent/typedefs.list @@ -67,6 +67,7 @@ AlterExtensionStmt AlterFdwStmt AlterForeignServerStmt AlterFunctionStmt +AlterObjectDependsStmt AlterObjectSchemaStmt AlterOpFamilyStmt AlterOwnerStmt -- 2.1.4
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers