>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.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_operator.sgml b/doc/src/sgml/ref/alter_operator.sgml
index 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.sgml
index 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.sgml
index 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.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/doc/src/sgml/ref/alter_tsconfig.sgml b/doc/src/sgml/ref/alter_tsconfig.sgml
index 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.sgml
index 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.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..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.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..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 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..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.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

