]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Add pg_dump support for ALTER obj DEPENDS ON EXTENSION
authorAlvaro Herrera <alvherre@alvh.no-ip.org>
Wed, 11 Mar 2020 19:54:54 +0000 (16:54 -0300)
committerAlvaro Herrera <alvherre@alvh.no-ip.org>
Wed, 11 Mar 2020 19:54:54 +0000 (16:54 -0300)
pg_dump is oblivious to this kind of dependency, so they're lost on
dump/restores (and pg_upgrade).  Have pg_dump emit ALTER lines so that
they're preserved.  Add some pg_dump tests for the whole thing, also.

Reviewed-by: Tom Lane (offlist)
Reviewed-by: Ibrar Ahmed
Reviewed-by: Ahsan Hadi (who also reviewed commit 899a04f5ed61)
Discussion: https://postgr.es/m/20200217225333.GA30974@alvherre.pgsql

src/bin/pg_dump/common.c
src/bin/pg_dump/pg_dump.c
src/bin/pg_dump/pg_dump.h
src/test/modules/test_pg_dump/t/001_base.pl

index 099d57eef265c6d235ea24b8897feab8935d9228..54eaa5ef539e77575095113c6e75a94d713d7a54 100644 (file)
@@ -461,6 +461,7 @@ AssignDumpId(DumpableObject *dobj)
        dobj->namespace = NULL;         /* may be set later */
        dobj->dump = DUMP_COMPONENT_ALL;        /* default assumption */
        dobj->ext_member = false;       /* default assumption */
+       dobj->depends_on_ext = false;   /* default assumption */
        dobj->dependencies = NULL;
        dobj->nDeps = 0;
        dobj->allocDeps = 0;
index 894cb919556e56510ae13789e7efa07ce06175a0..1efc22559d95915a375fa6549076ce44d6cb68f9 100644 (file)
@@ -3946,6 +3946,55 @@ dumpSubscription(Archive *fout, SubscriptionInfo *subinfo)
        free(qsubname);
 }
 
+/*
+ * Given a "create query", append as many ALTER ... DEPENDS ON EXTENSION as
+ * the object needs.
+ */
+static void
+append_depends_on_extension(Archive *fout,
+                                                       PQExpBuffer create,
+                                                       DumpableObject *dobj,
+                                                       const char *catalog,
+                                                       const char *keyword,
+                                                       const char *objname)
+{
+       if (dobj->depends_on_ext)
+       {
+               char   *nm;
+               PGresult   *res;
+               PQExpBuffer     query;
+               int             ntups;
+               int             i_extname;
+               int             i;
+
+               /* dodge fmtId() non-reentrancy */
+               nm = pg_strdup(objname);
+
+               query = createPQExpBuffer();
+               appendPQExpBuffer(query,
+                                                 "SELECT e.extname "
+                                                 "FROM pg_catalog.pg_depend d, pg_catalog.pg_extension e "
+                                                 "WHERE d.refobjid = e.oid AND classid = '%s'::pg_catalog.regclass "
+                                                 "AND objid = '%u'::pg_catalog.oid AND deptype = 'x' "
+                                                 "AND refclassid = 'pg_catalog.pg_extension'::pg_catalog.regclass",
+                                                 catalog,
+                                                 dobj->catId.oid);
+               res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
+               ntups = PQntuples(res);
+               i_extname = PQfnumber(res, "extname");
+               for (i = 0; i < ntups; i++)
+               {
+                       appendPQExpBuffer(create, "ALTER %s %s DEPENDS ON EXTENSION %s;\n",
+                                                         keyword, nm,
+                                                         fmtId(PQgetvalue(res, i, i_extname)));
+               }
+
+               PQclear(res);
+               pg_free(nm);
+       }
+}
+
+
 static void
 binary_upgrade_set_type_oids_by_type_oid(Archive *fout,
                                                                                 PQExpBuffer upgrade_buffer,
@@ -11556,6 +11605,12 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
 
        appendPQExpBuffer(q, "\n    %s;\n", asPart->data);
 
+       append_depends_on_extension(fout, q, &finfo->dobj,
+                                                               "pg_catalog.pg_proc", "FUNCTION",
+                                                               psprintf("%s.%s",
+                                                                                fmtId(finfo->dobj.namespace->dobj.name),
+                                                                                funcsig));
+
        if (dopt->binary_upgrade)
                binary_upgrade_extension_member(q, &finfo->dobj,
                                                                                "FUNCTION", funcsig,
@@ -15184,6 +15239,14 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
                else
                        appendPQExpBufferStr(q, ";\n");
 
+               /* Materialized views can depend on extensions */
+               if (tbinfo->relkind == RELKIND_MATVIEW)
+                       append_depends_on_extension(fout, q, &tbinfo->dobj,
+                                                                               "pg_catalog.pg_class",
+                                                                               tbinfo->relkind == RELKIND_MATVIEW ?
+                                                                               "MATERIALIZED VIEW" : "INDEX",
+                                                                               qualrelname);
+
                /*
                 * To create binary-compatible heap files, we have to ensure the same
                 * physical column order, including dropped columns, as in the
@@ -15661,6 +15724,7 @@ dumpIndex(Archive *fout, IndxInfo *indxinfo)
        PQExpBuffer q;
        PQExpBuffer delq;
        char       *qindxname;
+       char       *qqindxname;
 
        if (dopt->dataOnly)
                return;
@@ -15669,6 +15733,7 @@ dumpIndex(Archive *fout, IndxInfo *indxinfo)
        delq = createPQExpBuffer();
 
        qindxname = pg_strdup(fmtId(indxinfo->dobj.name));
+       qqindxname = pg_strdup(fmtQualifiedDumpable(indxinfo));
 
        /*
         * If there's an associated constraint, don't dump the index per se, but
@@ -15702,6 +15767,11 @@ dumpIndex(Archive *fout, IndxInfo *indxinfo)
                                                          qindxname);
                }
 
+               /* Indexes can depend on extensions */
+               append_depends_on_extension(fout, q, &indxinfo->dobj,
+                                                                       "pg_catalog.pg_class",
+                                                                       "INDEX", qqindxname);
+
                /* If the index defines identity, we need to record that. */
                if (indxinfo->indisreplident)
                {
@@ -15712,8 +15782,7 @@ dumpIndex(Archive *fout, IndxInfo *indxinfo)
                                                          qindxname);
                }
 
-               appendPQExpBuffer(delq, "DROP INDEX %s;\n",
-                                                 fmtQualifiedDumpable(indxinfo));
+               appendPQExpBuffer(delq, "DROP INDEX %s;\n", qqindxname);
 
                if (indxinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
                        ArchiveEntry(fout, indxinfo->dobj.catId, indxinfo->dobj.dumpId,
@@ -15739,6 +15808,7 @@ dumpIndex(Archive *fout, IndxInfo *indxinfo)
        destroyPQExpBuffer(q);
        destroyPQExpBuffer(delq);
        free(qindxname);
+       free(qqindxname);
 }
 
 /*
@@ -15918,6 +15988,11 @@ dumpConstraint(Archive *fout, ConstraintInfo *coninfo)
                                                          fmtId(indxinfo->dobj.name));
                }
 
+               /* Indexes can depend on extensions */
+               append_depends_on_extension(fout, q, &indxinfo->dobj,
+                                                                       "pg_catalog.pg_class", "INDEX",
+                                                                       fmtQualifiedDumpable(indxinfo));
+
                appendPQExpBuffer(delq, "ALTER TABLE ONLY %s ",
                                                  fmtQualifiedDumpable(tbinfo));
                appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
@@ -16435,6 +16510,7 @@ dumpTrigger(Archive *fout, TriggerInfo *tginfo)
        PQExpBuffer query;
        PQExpBuffer delqry;
        PQExpBuffer trigprefix;
+       PQExpBuffer trigidentity;
        char       *qtabname;
        char       *tgargs;
        size_t          lentgargs;
@@ -16452,13 +16528,14 @@ dumpTrigger(Archive *fout, TriggerInfo *tginfo)
        query = createPQExpBuffer();
        delqry = createPQExpBuffer();
        trigprefix = createPQExpBuffer();
+       trigidentity = createPQExpBuffer();
 
        qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
 
-       appendPQExpBuffer(delqry, "DROP TRIGGER %s ",
-                                         fmtId(tginfo->dobj.name));
-       appendPQExpBuffer(delqry, "ON %s;\n",
-                                         fmtQualifiedDumpable(tbinfo));
+       appendPQExpBuffer(trigidentity, "%s ", fmtId(tginfo->dobj.name));
+       appendPQExpBuffer(trigidentity, "ON %s", fmtQualifiedDumpable(tbinfo));
+
+       appendPQExpBuffer(delqry, "DROP TRIGGER %s;\n", trigidentity->data);
 
        if (tginfo->tgdef)
        {
@@ -16577,6 +16654,11 @@ dumpTrigger(Archive *fout, TriggerInfo *tginfo)
                appendPQExpBufferStr(query, ");\n");
        }
 
+       /* Triggers can depend on extensions */
+       append_depends_on_extension(fout, query, &tginfo->dobj,
+                                                               "pg_catalog.pg_trigger", "TRIGGER",
+                                                               trigidentity->data);
+
        if (tginfo->tgenabled != 't' && tginfo->tgenabled != 'O')
        {
                appendPQExpBuffer(query, "\nALTER TABLE %s ",
@@ -16626,6 +16708,7 @@ dumpTrigger(Archive *fout, TriggerInfo *tginfo)
        destroyPQExpBuffer(query);
        destroyPQExpBuffer(delqry);
        destroyPQExpBuffer(trigprefix);
+       destroyPQExpBuffer(trigidentity);
        free(qtabname);
 }
 
@@ -17282,6 +17365,15 @@ getDependencies(Archive *fout)
                        continue;
                }
 
+               /*
+                * For 'x' dependencies, mark the object for later; we still add the
+                * normal dependency, for possible ordering purposes.  Currently
+                * pg_dump_sort.c knows to put extensions ahead of all object types
+                * that could possibly depend on them, but this is safer.
+                */
+               if (deptype == 'x')
+                       dobj->depends_on_ext = true;
+
                /*
                 * Ordinarily, table rowtypes have implicit dependencies on their
                 * tables.  However, for a composite type the implicit dependency goes
index 941080cc753331dd99cb4ca7c454edeeb043de7b..c5cb935c2d088be90e5b8163939e0f5bad63f87e 100644 (file)
@@ -135,6 +135,7 @@ typedef struct _dumpableObject
        DumpComponents dump;            /* bitmask of components to dump */
        DumpComponents dump_contains;   /* as above, but for contained objects */
        bool            ext_member;             /* true if object is member of extension */
+       bool            depends_on_ext; /* true if object depends on an extension */
        DumpId     *dependencies;       /* dumpIds of objects this one depends on */
        int                     nDeps;                  /* number of valid dependencies */
        int                     allocDeps;              /* allocated size of dependencies[] */
index fca00c64787ab5b88b39aeaf6d5d019fbb821114..f1d8981120292a668af9e69e8bde94decf320daf 100644 (file)
@@ -742,6 +742,52 @@ my %tests = (
                        section_pre_data   => 1,
                        section_post_data  => 1, }, },
 
+       'ALTER INDEX pkey DEPENDS ON extension' => {
+               create_order => 11,
+               create_sql =>
+'CREATE TABLE regress_pg_dump_schema.extdependtab (col1 integer primary key, col2 int);
+               CREATE INDEX ON regress_pg_dump_schema.extdependtab (col2);
+               ALTER INDEX regress_pg_dump_schema.extdependtab_col2_idx DEPENDS ON EXTENSION test_pg_dump;
+               ALTER INDEX regress_pg_dump_schema.extdependtab_pkey DEPENDS ON EXTENSION test_pg_dump;',
+               regexp => qr/^
+               \QALTER INDEX regress_pg_dump_schema.extdependtab_pkey DEPENDS ON EXTENSION test_pg_dump;\E\n
+               /xms,
+               like => {
+                       binary_upgrade    => 1,
+                       clean_if_exists   => 1,
+                       createdb          => 1,
+                       defaults          => 1,
+                       no_owner          => 1,
+                       no_privs          => 1,
+                       section_post_data => 1,
+                       schema_only       => 1, },
+               unlike => {
+                       column_inserts     => 1,
+                       data_only          => 1,
+                       pg_dumpall_globals => 1,
+                       section_data       => 1,
+                       section_pre_data   => 1, }, },
+
+       'ALTER INDEX idx DEPENDS ON extension' => {
+               regexp => qr/^
+                       \QALTER INDEX regress_pg_dump_schema.extdependtab_col2_idx DEPENDS ON EXTENSION test_pg_dump;\E\n
+                       /xms,
+               like => {
+                       binary_upgrade    => 1,
+                       clean_if_exists   => 1,
+                       createdb          => 1,
+                       defaults          => 1,
+                       no_owner          => 1,
+                       no_privs          => 1,
+                       section_post_data => 1,
+                       schema_only       => 1, },
+               unlike => {
+                       column_inserts     => 1,
+                       data_only          => 1,
+                       pg_dumpall_globals => 1,
+                       section_data       => 1,
+                       section_pre_data   => 1, }, },
+
        # Objects not included in extension, part of schema created by extension
        'CREATE TABLE regress_pg_dump_schema.external_tab' => {
                create_order => 4,