From: Abhijit Menon-Sen <ams@2ndQuadrant.com>
To: Alvaro Herrera <alvherre@2ndquadrant.com>
Cc: David Steele <david@pgmasters.net>
Cc: Robert Haas <robertmhaas@gmail.com>
Cc: pgsql-hackers@postgresql.org, Alexander Korotkov <a.korotkov@postgrespro.ru>
Subject: Re: dealing with extension dependencies that aren't quite 'e'
Date: Tue, 5 Apr 2016 12:05:32 +0530
Message-ID: <20160405063532.GA20712@toroid.org> (raw)
In-Reply-To: <20160405022530.GA3078@toroid.org>
References: <20160401123136.GA6379@toroid.org>
<20160404215503.GA237481@alvherre.pgsql>
<20160405022530.GA3078@toroid.org>
List-Unsubscribe: <mailto:majordomo@postgresql.org?body=unsub%20pgsql-hackers>
Hi.
Here's the updated patch. It fixes a couple of small problems, and
includes documentation and tests (which I placed in a new file in
src/test/modules/test_extensions, on Petr's advice).
I wanted to post this before I went on to attempt any more grammar
cleanups. Please let me know if there's anything else you'd like to
see here.
Thanks again for your review and suggestions.
-- Abhijit
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackersAttachments:0001-Implement-ALTER-DEPENDS-ON-EXTENSION-for-various-obj-20160405.patch (text/x-diff, 48.5K) download
From d4882446de50c49c6563dac6dbdd386c01f9477a Mon Sep 17 00:00:00 2001
From: Abhijit Menon-Sen <ams@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=20various=20object=20types?=
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_operator.sgml | 18 ++++
doc/src/sgml/ref/alter_rule.sgml | 18 +++-
doc/src/sgml/ref/alter_table.sgml | 25 +++++
doc/src/sgml/ref/alter_trigger.sgml | 16 +++
doc/src/sgml/ref/alter_tsconfig.sgml | 23 ++++-
doc/src/sgml/ref/alter_type.sgml | 27 +++++
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 | 86 +++++++++++++++-
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 | 110 +++++++++++++++++++++
.../modules/test_extensions/sql/test_extdepend.sql | 56 +++++++++++
src/tools/pgindent/typedefs.list | 1 +
25 files changed, 558 insertions(+), 6 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.sgmlindex 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.sgmlindex 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_operator.sgml b/doc/src/sgml/ref/alter_operator.sgmlindex b2eaa7a..456243f 100644--- a/doc/src/sgml/ref/alter_operator.sgml+++ b/doc/src/sgml/ref/alter_operator.sgml@@ -28,6 +28,9 @@ ALTER OPERATOR <replaceable>name</replaceable> ( { <replaceable>left_type</repla
SET SCHEMA <replaceable>new_schema</replaceable>
ALTER OPERATOR <replaceable>name</replaceable> ( { <replaceable>left_type</replaceable> | NONE } , { <replaceable>right_type</replaceable> | NONE } )
+ DEPENDS ON EXTENSION <replaceable>extension_name</replaceable>++ALTER OPERATOR <replaceable>name</replaceable> ( { <replaceable>left_type</replaceable> | NONE } , { <replaceable>right_type</replaceable> | NONE } )
SET ( { RESTRICT = { <replaceable class="parameter">res_proc</replaceable> | NONE }
| JOIN = { <replaceable class="parameter">join_proc</replaceable> | NONE }
} [, ... ] )
@@ -104,6 +107,15 @@ ALTER OPERATOR <replaceable>name</replaceable> ( { <replaceable>left_type</repla
</varlistentry>
<varlistentry>
+ <term><replaceable class="parameter">extension_name</replaceable></term>+ <listitem>+ <para>+ The name of an extension that the operator depends on.+ </para>+ </listitem>+ </varlistentry>++ <varlistentry>
<term><replaceable class="parameter">res_proc</replaceable></term>
<listitem>
<para>
@@ -134,6 +146,12 @@ ALTER OPERATOR @@ (text, text) OWNER TO joe;
</programlisting></para>
<para>
+ Mark a custom operator <literal>a @@ b</literal> for type <type>text</type> as being dependent on the extension <literal>geolib</literal>:+<programlisting>+ALTER OPERATOR @@ (text, text) DEPENDS ON EXTENSION geolib;+</programlisting></para>++ <para>
Change the restriction and join selectivity estimator functions of a custom operator <literal>a && b</literal> for type <type>int[]</type>:
<programlisting>
ALTER OPERATOR && (_int4, _int4) SET (RESTRICT = _int_contsel, JOIN = _int_contjoinsel);
diff --git a/doc/src/sgml/ref/alter_rule.sgml b/doc/src/sgml/ref/alter_rule.sgmlindex 993a0ce..bdf041f 100644--- a/doc/src/sgml/ref/alter_rule.sgml+++ b/doc/src/sgml/ref/alter_rule.sgml@@ -22,6 +22,7 @@ PostgreSQL documentation
<refsynopsisdiv>
<synopsis>
ALTER RULE <replaceable class="PARAMETER">name</replaceable> ON <replaceable class="PARAMETER">table_name</replaceable> RENAME TO <replaceable class="PARAMETER">new_name</replaceable>
+ALTER RULE <replaceable class="PARAMETER">name</replaceable> ON <replaceable class="PARAMETER">table_name</replaceable> DEPENDS ON EXTENSION <replaceable class="PARAMETER">extension_name</replaceable>
</synopsis>
</refsynopsisdiv>
@@ -30,7 +31,7 @@ ALTER RULE <replaceable class="PARAMETER">name</replaceable> ON <replaceable cla
<para>
<command>ALTER RULE</command> changes properties of an existing
- rule. Currently, the only available action is to change the rule's name.+ rule, including its name and extension dependencies.
</para>
<para>
@@ -70,6 +71,15 @@ ALTER RULE <replaceable class="PARAMETER">name</replaceable> ON <replaceable cla
</para>
</listitem>
</varlistentry>
++ <varlistentry>+ <term><replaceable class="PARAMETER">extension_name</replaceable></term>+ <listitem>+ <para>+ The name of an extension that the rule depends on.+ </para>+ </listitem>+ </varlistentry>
</variablelist>
</refsect1>
@@ -81,6 +91,12 @@ ALTER RULE <replaceable class="PARAMETER">name</replaceable> ON <replaceable cla
<programlisting>
ALTER RULE notify_all ON emp RENAME TO notify_me;
</programlisting></para>
++ <para>+ To mark an existing rule as being dependent on an extension:+<programlisting>+ALTER RULE notify_all ON emp DEPENDS ON EXTENSION notifylib;+</programlisting></para>
</refsect1>
<refsect1>
diff --git a/doc/src/sgml/ref/alter_table.sgml b/doc/src/sgml/ref/alter_table.sgmlindex 5ca211e..86de6a2 100644--- a/doc/src/sgml/ref/alter_table.sgml+++ b/doc/src/sgml/ref/alter_table.sgml@@ -31,6 +31,8 @@ ALTER TABLE [ IF EXISTS ] <replaceable class="PARAMETER">name</replaceable>
RENAME TO <replaceable class="PARAMETER">new_name</replaceable>
ALTER TABLE [ IF EXISTS ] <replaceable class="PARAMETER">name</replaceable>
SET SCHEMA <replaceable class="PARAMETER">new_schema</replaceable>
+ALTER TABLE [ IF EXISTS ] <replaceable class="PARAMETER">name</replaceable>+ DEPENDS ON EXTENSION <replaceable class="PARAMETER">extension_name</replaceable>
ALTER TABLE ALL IN TABLESPACE <replaceable class="PARAMETER">name</replaceable> [ OWNED BY <replaceable class="PARAMETER">role_name</replaceable> [, ... ] ]
SET TABLESPACE <replaceable class="PARAMETER">new_tablespace</replaceable> [ NOWAIT ]
@@ -704,6 +706,14 @@ ALTER TABLE ALL IN TABLESPACE <replaceable class="PARAMETER">name</replaceable>
</listitem>
</varlistentry>
+ <varlistentry>+ <term><literal>DEPENDS ON EXTENSION</literal></term>+ <listitem>+ <para>+ This form marks the table as being dependent on an extension.+ </para>+ </listitem>+ </varlistentry>
</variablelist>
</para>
@@ -936,6 +946,14 @@ ALTER TABLE ALL IN TABLESPACE <replaceable class="PARAMETER">name</replaceable>
</listitem>
</varlistentry>
+ <varlistentry>+ <term><replaceable class="PARAMETER">extension_name</replaceable></term>+ <listitem>+ <para>+ The name of an extension that the table depends on.+ </para>+ </listitem>+ </varlistentry>
</variablelist>
</refsect1>
@@ -1219,6 +1237,13 @@ ALTER TABLE myschema.distributors SET SCHEMA yourschema;
</para>
<para>
+ To mark a table as being dependent on an extension:+<programlisting>+ALTER TABLE myschema.distributors DEPENDS ON EXTENSION yourext;+</programlisting>+ </para>++ <para>
To recreate a primary key constraint, without blocking updates while the
index is rebuilt:
<programlisting>
diff --git a/doc/src/sgml/ref/alter_trigger.sgml b/doc/src/sgml/ref/alter_trigger.sgmlindex 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/doc/src/sgml/ref/alter_tsconfig.sgml b/doc/src/sgml/ref/alter_tsconfig.sgmlindex 72a719b..3233093 100644--- a/doc/src/sgml/ref/alter_tsconfig.sgml+++ b/doc/src/sgml/ref/alter_tsconfig.sgml@@ -34,6 +34,7 @@ ALTER TEXT SEARCH CONFIGURATION <replaceable>name</replaceable>
ALTER TEXT SEARCH CONFIGURATION <replaceable>name</replaceable> RENAME TO <replaceable>new_name</replaceable>
ALTER TEXT SEARCH CONFIGURATION <replaceable>name</replaceable> OWNER TO { <replaceable>new_owner</replaceable> | CURRENT_USER | SESSION_USER }
ALTER TEXT SEARCH CONFIGURATION <replaceable>name</replaceable> SET SCHEMA <replaceable>new_schema</replaceable>
+ALTER TEXT SEARCH CONFIGURATION <replaceable>name</replaceable> DEPENDS ON EXTENSION <replaceable>extension_name</replaceable>
</synopsis>
</refsynopsisdiv>
@@ -44,7 +45,8 @@ ALTER TEXT SEARCH CONFIGURATION <replaceable>name</replaceable> SET SCHEMA <repl
<command>ALTER TEXT SEARCH CONFIGURATION</command> changes the definition of
a text search configuration. You can modify
its mappings from token types to dictionaries,
- or change the configuration's name or owner.+ or change the configuration's name or owner, or+ its extension dependencies.
</para>
<para>
@@ -133,6 +135,15 @@ ALTER TEXT SEARCH CONFIGURATION <replaceable>name</replaceable> SET SCHEMA <repl
</para>
</listitem>
</varlistentry>
++ <varlistentry>+ <term><replaceable class="parameter">extension_name</replaceable></term>+ <listitem>+ <para>+ The name of an extension that the text search configuration depends on.+ </para>+ </listitem>+ </varlistentry>
</variablelist>
<para>
@@ -167,6 +178,16 @@ ALTER TEXT SEARCH CONFIGURATION <replaceable>name</replaceable> SET SCHEMA <repl
ALTER TEXT SEARCH CONFIGURATION my_config
ALTER MAPPING REPLACE english WITH swedish;
</programlisting>
++ <para>+ The following example marks <literal>my_config</> as being dependent on+ the extension tslib:+ </para>++<programlisting>+ALTER TEXT SEARCH CONFIGURATION my_config+ DEPENDS ON EXTENSION tslib;+</programlisting>
</refsect1>
<refsect1>
diff --git a/doc/src/sgml/ref/alter_type.sgml b/doc/src/sgml/ref/alter_type.sgmlindex 9789881..d17bbd9 100644--- a/doc/src/sgml/ref/alter_type.sgml+++ b/doc/src/sgml/ref/alter_type.sgml@@ -28,6 +28,7 @@ ALTER TYPE <replaceable class="PARAMETER">name</replaceable> OWNER TO { <replace
ALTER TYPE <replaceable class="PARAMETER">name</replaceable> RENAME ATTRIBUTE <replaceable class="PARAMETER">attribute_name</replaceable> TO <replaceable class="PARAMETER">new_attribute_name</replaceable> [ CASCADE | RESTRICT ]
ALTER TYPE <replaceable class="PARAMETER">name</replaceable> RENAME TO <replaceable class="PARAMETER">new_name</replaceable>
ALTER TYPE <replaceable class="PARAMETER">name</replaceable> SET SCHEMA <replaceable class="PARAMETER">new_schema</replaceable>
+ALTER TYPE <replaceable class="PARAMETER">name</replaceable> DEPENDS ON EXTENSION <replaceable class="PARAMETER">extension_name</replaceable>
ALTER TYPE <replaceable class="PARAMETER">name</replaceable> ADD VALUE [ IF NOT EXISTS ] <replaceable class="PARAMETER">new_enum_value</replaceable> [ { BEFORE | AFTER } <replaceable class="PARAMETER">existing_enum_value</replaceable> ]
<phrase>where <replaceable class="PARAMETER">action</replaceable> is one of:</phrase>
@@ -106,6 +107,15 @@ ALTER TYPE <replaceable class="PARAMETER">name</replaceable> ADD VALUE [ IF NOT
</varlistentry>
<varlistentry>
+ <term><literal>DEPENDS ON EXTENSION</literal></term>+ <listitem>+ <para>+ This form marks the type as being dependent on an extension.+ </para>+ </listitem>+ </varlistentry>++ <varlistentry>
<term><literal>ADD VALUE [ IF NOT EXISTS ] [ BEFORE | AFTER ]</literal></term>
<listitem>
<para>
@@ -210,6 +220,15 @@ ALTER TYPE <replaceable class="PARAMETER">name</replaceable> ADD VALUE [ IF NOT
</varlistentry>
<varlistentry>
+ <term><replaceable class="PARAMETER">extension_name</replaceable></term>+ <listitem>+ <para>+ The name of an extension that the type depends on.+ </para>+ </listitem>+ </varlistentry>++ <varlistentry>
<term><replaceable class="PARAMETER">attribute_name</replaceable></term>
<listitem>
<para>
@@ -311,6 +330,14 @@ ALTER TYPE email SET SCHEMA customers;
</para>
<para>
+ To mark the type <literal>email</literal> as being dependent+ on the extension <literal>mimelib</literal>:+<programlisting>+ALTER TYPE email DEPENDS ON EXTENSION mimelib;+</programlisting>+ </para>++ <para>
To add a new attribute to a type:
<programlisting>
ALTER TYPE compfoo ADD ATTRIBUTE f3 int;
diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.cindex 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.cindex 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.cindex 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.cindex 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.cindex 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.yindex 1273352..9d071f9 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,85 @@ 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 RULE name ON qualified_name DEPENDS ON EXTENSION name+ {+ AlterObjectDependsStmt *n = makeNode(AlterObjectDependsStmt);+ n->objectType = OBJECT_RULE;+ n->relation = $5;+ n->objname = list_make1(makeString($3));+ n->objargs = NIL;+ n->extname = list_make1(makeString($9));+ $$ = (Node *)n;+ }+ | ALTER TABLE qualified_name DEPENDS ON EXTENSION name+ {+ AlterObjectDependsStmt *n = makeNode(AlterObjectDependsStmt);+ n->objectType = OBJECT_TABLE;+ n->relation = $3;+ n->objname = NIL;+ n->objargs = NIL;+ n->extname = list_make1(makeString($7));+ $$ = (Node *)n;+ }+ | ALTER TEXT_P SEARCH CONFIGURATION any_name DEPENDS ON EXTENSION name+ {+ AlterObjectDependsStmt *n = makeNode(AlterObjectDependsStmt);+ n->objectType = OBJECT_TSCONFIGURATION;+ n->relation = NULL;+ n->objname = $5;+ n->objargs = NIL;+ n->extname = list_make1(makeString($9));+ $$ = (Node *)n;+ }+ | ALTER TYPE_P any_name DEPENDS ON EXTENSION name+ {+ AlterObjectDependsStmt *n = makeNode(AlterObjectDependsStmt);+ n->objectType = OBJECT_TYPE;+ n->relation = NULL;+ n->objname = list_make1(makeTypeNameFromNameList($3));+ n->objargs = NIL;+ n->extname = list_make1(makeString($7));+ $$ = (Node *)n;+ }+ | ALTER OPERATOR any_operator oper_argtypes DEPENDS ON EXTENSION name+ {+ AlterObjectDependsStmt *n = makeNode(AlterObjectDependsStmt);+ n->objectType = OBJECT_OPERATOR;+ n->relation = NULL;+ n->objname = $3;+ n->objargs = $4;+ n->extname = list_make1(makeString($8));+ $$ = (Node *)n;+ }+ ;++/*****************************************************************************+ *
* ALTER THING name SET SCHEMA name
*
*****************************************************************************/
@@ -13726,6 +13807,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.cindex 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.hindex 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.hindex 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.hindex 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.hindex 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.hindex 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.hindex 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/Makefileindex 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.outnew file mode 100644index 0000000..76ba066--- /dev/null+++ b/src/test/modules/test_extensions/expected/test_extdepend.out@@ -0,0 +1,110 @@+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();+CREATE TABLE d(d1 int);+CREATE TYPE e;+CREATE OPERATOR ### (rightarg = int8, procedure = numeric_fac);+CREATE TEXT SEARCH CONFIGURATION g (copy=english);+-- add 'x' dependencies on test_ext5+ALTER FUNCTION b() DEPENDS ON EXTENSION test_ext5;+ALTER TRIGGER c ON a DEPENDS ON EXTENSION test_ext5;+ALTER TABLE d DEPENDS ON EXTENSION test_ext5;+ALTER TYPE e DEPENDS ON EXTENSION test_ext5;+ALTER OPERATOR ### (NONE, int8) DEPENDS ON EXTENSION test_ext5;+ALTER TEXT SEARCH CONFIGURATION g 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 +-------+ 6+(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)++SELECT * FROM pg_catalog.pg_class c JOIN pg_catalog.pg_namespace n ON (c.relnamespace=n.oid)+ WHERE relname='d' AND n.nspname='test_ext';+ relname | relnamespace | reltype | reloftype | relowner | relam | relfilenode | reltablespace | relpages | reltuples | relallvisible | reltoastrelid | relhasindex | relisshared | relpersistence | relkind | relnatts | relchecks | relhasoids | relhaspkey | relhasrules | relhastriggers | relhassubclass | relrowsecurity | relforcerowsecurity | relispopulated | relreplident | relfrozenxid | relminmxid | relacl | reloptions | nspname | nspowner | nspacl +---------+--------------+---------+-----------+----------+-------+-------------+---------------+----------+-----------+---------------+---------------+-------------+-------------+----------------+---------+----------+-----------+------------+------------+-------------+----------------+----------------+----------------+---------------------+----------------+--------------+--------------+------------+--------+------------+----------+----------+--------+ d | 16393 | 16402 | 0 | 10 | 0 | 16400 | 0 | 0 | 0 | 0 | 0 | f | f | p | r | 1 | 0 | f | f | f | f | f | f | f | t | d | 558 | 1 | | | test_ext | 10 | +(1 row)++SELECT * FROM pg_catalog.pg_type t JOIN pg_catalog.pg_namespace n ON (t.typnamespace=n.oid)+ WHERE typname='e' AND n.nspname='test_ext';+ typname | typnamespace | typowner | typlen | typbyval | typtype | typcategory | typispreferred | typisdefined | typdelim | typrelid | typelem | typarray | typinput | typoutput | typreceive | typsend | typmodin | typmodout | typanalyze | typalign | typstorage | typnotnull | typbasetype | typtypmod | typndims | typcollation | typdefaultbin | typdefault | typacl | nspname | nspowner | nspacl +---------+--------------+----------+--------+----------+---------+-------------+----------------+--------------+----------+----------+---------+----------+----------+-----------+------------+---------+----------+-----------+------------+----------+------------+------------+-------------+-----------+----------+--------------+---------------+------------+--------+----------+----------+--------+ e | 16393 | 10 | 4 | t | p | P | f | f | , | 0 | 0 | 0 | shell_in | shell_out | - | - | - | - | - | i | p | f | 0 | -1 | 0 | 0 | | | | test_ext | 10 | +(1 row)++SELECT * FROM pg_catalog.pg_operator o JOIN pg_catalog.pg_namespace n ON (o.oprnamespace=n.oid)+ WHERE oprname='###' AND n.nspname='test_ext';+ oprname | oprnamespace | oprowner | oprkind | oprcanmerge | oprcanhash | oprleft | oprright | oprresult | oprcom | oprnegate | oprcode | oprrest | oprjoin | nspname | nspowner | nspacl +---------+--------------+----------+---------+-------------+------------+---------+----------+-----------+--------+-----------+-------------+---------+---------+----------+----------+--------+ ### | 16393 | 10 | l | f | f | 0 | 20 | 1700 | 0 | 0 | numeric_fac | - | - | test_ext | 10 | +(1 row)++SELECT * FROM pg_catalog.pg_ts_config t JOIN pg_catalog.pg_namespace n ON (t.cfgnamespace=n.oid)+ WHERE cfgname='g' AND n.nspname='test_ext';+ cfgname | cfgnamespace | cfgowner | cfgparser | nspname | nspowner | nspacl +---------+--------------+----------+-----------+----------+----------+--------+ g | 16393 | 10 | 3722 | test_ext | 10 | +(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)++SELECT * FROM pg_catalog.pg_class c JOIN pg_catalog.pg_namespace n ON (c.relnamespace=n.oid)+ WHERE relname='d' AND n.nspname='test_ext';+ relname | relnamespace | reltype | reloftype | relowner | relam | relfilenode | reltablespace | relpages | reltuples | relallvisible | reltoastrelid | relhasindex | relisshared | relpersistence | relkind | relnatts | relchecks | relhasoids | relhaspkey | relhasrules | relhastriggers | relhassubclass | relrowsecurity | relforcerowsecurity | relispopulated | relreplident | relfrozenxid | relminmxid | relacl | reloptions | nspname | nspowner | nspacl +---------+--------------+---------+-----------+----------+-------+-------------+---------------+----------+-----------+---------------+---------------+-------------+-------------+----------------+---------+----------+-----------+------------+------------+-------------+----------------+----------------+----------------+---------------------+----------------+--------------+--------------+------------+--------+------------+---------+----------+--------+(0 rows)++SELECT * FROM pg_catalog.pg_type t JOIN pg_catalog.pg_namespace n ON (t.typnamespace=n.oid)+ WHERE typname='e' AND n.nspname='test_ext';+ typname | typnamespace | typowner | typlen | typbyval | typtype | typcategory | typispreferred | typisdefined | typdelim | typrelid | typelem | typarray | typinput | typoutput | typreceive | typsend | typmodin | typmodout | typanalyze | typalign | typstorage | typnotnull | typbasetype | typtypmod | typndims | typcollation | typdefaultbin | typdefault | typacl | nspname | nspowner | nspacl +---------+--------------+----------+--------+----------+---------+-------------+----------------+--------------+----------+----------+---------+----------+----------+-----------+------------+---------+----------+-----------+------------+----------+------------+------------+-------------+-----------+----------+--------------+---------------+------------+--------+---------+----------+--------+(0 rows)++SELECT * FROM pg_catalog.pg_operator o JOIN pg_catalog.pg_namespace n ON (o.oprnamespace=n.oid)+ WHERE oprname='###' AND n.nspname='test_ext';+ oprname | oprnamespace | oprowner | oprkind | oprcanmerge | oprcanhash | oprleft | oprright | oprresult | oprcom | oprnegate | oprcode | oprrest | oprjoin | nspname | nspowner | nspacl +---------+--------------+----------+---------+-------------+------------+---------+----------+-----------+--------+-----------+---------+---------+---------+---------+----------+--------+(0 rows)++SELECT * FROM pg_catalog.pg_ts_config t JOIN pg_catalog.pg_namespace n ON (t.cfgnamespace=n.oid)+ WHERE cfgname='g' AND n.nspname='test_ext';+ cfgname | cfgnamespace | cfgowner | cfgparser | nspname | nspowner | nspacl +---------+--------------+----------+-----------+---------+----------+--------+(0 rows)++DROP SCHEMA test_ext CASCADE;+NOTICE: drop cascades to table adiff --git a/src/test/modules/test_extensions/sql/test_extdepend.sql b/src/test/modules/test_extensions/sql/test_extdepend.sqlnew file mode 100644index 0000000..ce50cb9--- /dev/null+++ b/src/test/modules/test_extensions/sql/test_extdepend.sql@@ -0,0 +1,56 @@+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();+CREATE TABLE d(d1 int);+CREATE TYPE e;+CREATE OPERATOR ### (rightarg = int8, procedure = numeric_fac);+CREATE TEXT SEARCH CONFIGURATION g (copy=english);++-- add 'x' dependencies on test_ext5+ALTER FUNCTION b() DEPENDS ON EXTENSION test_ext5;+ALTER TRIGGER c ON a DEPENDS ON EXTENSION test_ext5;+ALTER TABLE d DEPENDS ON EXTENSION test_ext5;+ALTER TYPE e DEPENDS ON EXTENSION test_ext5;+ALTER OPERATOR ### (NONE, int8) DEPENDS ON EXTENSION test_ext5;+ALTER TEXT SEARCH CONFIGURATION g 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;+SELECT * FROM pg_catalog.pg_class c JOIN pg_catalog.pg_namespace n ON (c.relnamespace=n.oid)+ WHERE relname='d' AND n.nspname='test_ext';+SELECT * FROM pg_catalog.pg_type t JOIN pg_catalog.pg_namespace n ON (t.typnamespace=n.oid)+ WHERE typname='e' AND n.nspname='test_ext';+SELECT * FROM pg_catalog.pg_operator o JOIN pg_catalog.pg_namespace n ON (o.oprnamespace=n.oid)+ WHERE oprname='###' AND n.nspname='test_ext';+SELECT * FROM pg_catalog.pg_ts_config t JOIN pg_catalog.pg_namespace n ON (t.cfgnamespace=n.oid)+ WHERE cfgname='g' AND n.nspname='test_ext';++-- 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;+SELECT * FROM pg_catalog.pg_class c JOIN pg_catalog.pg_namespace n ON (c.relnamespace=n.oid)+ WHERE relname='d' AND n.nspname='test_ext';+SELECT * FROM pg_catalog.pg_type t JOIN pg_catalog.pg_namespace n ON (t.typnamespace=n.oid)+ WHERE typname='e' AND n.nspname='test_ext';+SELECT * FROM pg_catalog.pg_operator o JOIN pg_catalog.pg_namespace n ON (o.oprnamespace=n.oid)+ WHERE oprname='###' AND n.nspname='test_ext';+SELECT * FROM pg_catalog.pg_ts_config t JOIN pg_catalog.pg_namespace n ON (t.cfgnamespace=n.oid)+ WHERE cfgname='g' AND n.nspname='test_ext';++DROP SCHEMA test_ext CASCADE;diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.listindex 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
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Reply to all the recipients using the --to and --cc options:
reply via email
To: pgsql-hackers@postgresql.org
Cc: ams@2ndQuadrant.com, alvherre@2ndquadrant.com, david@pgmasters.net, robertmhaas@gmail.com, a.korotkov@postgrespro.ru
Subject: Re: dealing with extension dependencies that aren't quite 'e'
In-Reply-To: <20160405063532.GA20712@toroid.org>
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
This inbox is served by DDX for PostgreSQL; see mirroring instructions
for how to clone and mirror all data and code used for this inbox