diff --git a/src/bin/pg_dump/common.c b/src/bin/pg_dump/common.c index 69508ec9b3..4ea59f5494 100644 --- a/src/bin/pg_dump/common.c +++ b/src/bin/pg_dump/common.c @@ -549,6 +549,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; diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index ad039e97a5..28312e14ef 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -4291,6 +4291,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, @@ -12161,6 +12210,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", keyword, + psprintf("%s.%s", + fmtId(finfo->dobj.namespace->dobj.name), + funcsig)); + if (dopt->binary_upgrade) binary_upgrade_extension_member(q, &finfo->dobj, keyword, funcsig, @@ -15871,6 +15926,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); + /* * in binary upgrade mode, update the catalog with any missing values * that might be present. @@ -16375,6 +16438,7 @@ dumpIndex(Archive *fout, IndxInfo *indxinfo) PQExpBuffer q; PQExpBuffer delq; char *qindxname; + char *qqindxname; if (dopt->dataOnly) return; @@ -16383,6 +16447,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 @@ -16435,8 +16500,7 @@ dumpIndex(Archive *fout, IndxInfo *indxinfo) for (j = 0; j < nstatcols; j++) { - appendPQExpBuffer(q, "ALTER INDEX %s ", - fmtQualifiedDumpable(indxinfo)); + appendPQExpBuffer(q, "ALTER INDEX %s ", qqindxname); /* * Note that this is a column number, so no quotes should be @@ -16449,6 +16513,11 @@ dumpIndex(Archive *fout, IndxInfo *indxinfo) } } + /* 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) { @@ -16459,8 +16528,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, @@ -16491,6 +16559,7 @@ dumpIndex(Archive *fout, IndxInfo *indxinfo) destroyPQExpBuffer(q); destroyPQExpBuffer(delq); free(qindxname); + free(qqindxname); } /* @@ -16729,6 +16798,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", @@ -17248,6 +17322,7 @@ dumpTrigger(Archive *fout, TriggerInfo *tginfo) PQExpBuffer query; PQExpBuffer delqry; PQExpBuffer trigprefix; + PQExpBuffer trigidentity; char *qtabname; char *tgargs; size_t lentgargs; @@ -17265,13 +17340,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) { @@ -17390,6 +17466,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 ", @@ -17438,6 +17519,7 @@ dumpTrigger(Archive *fout, TriggerInfo *tginfo) destroyPQExpBuffer(query); destroyPQExpBuffer(delqry); destroyPQExpBuffer(trigprefix); + destroyPQExpBuffer(trigidentity); free(qtabname); } @@ -18087,6 +18169,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 diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.h index 852020b66c..e0c6444ef6 100644 --- a/src/bin/pg_dump/pg_dump.h +++ b/src/bin/pg_dump/pg_dump.h @@ -132,6 +132,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[] */ diff --git a/src/test/modules/test_pg_dump/t/001_base.pl b/src/test/modules/test_pg_dump/t/001_base.pl index fb4ecf8aca..ae120a5ee3 100644 --- a/src/test/modules/test_pg_dump/t/001_base.pl +++ b/src/test/modules/test_pg_dump/t/001_base.pl @@ -523,6 +523,38 @@ my %tests = ( like => { binary_upgrade => 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 => {%pgdump_runs}, + unlike => { + 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 => {%pgdump_runs}, + unlike => { + 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,