Commit b08dee24 authored by Alvaro Herrera's avatar Alvaro Herrera

Add pg_dump support for ALTER obj DEPENDS ON EXTENSION

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 899a04f5)
Discussion: https://postgr.es/m/20200217225333.GA30974@alvherre.pgsql
parent 085b6b66
...@@ -549,6 +549,7 @@ AssignDumpId(DumpableObject *dobj) ...@@ -549,6 +549,7 @@ AssignDumpId(DumpableObject *dobj)
dobj->namespace = NULL; /* may be set later */ dobj->namespace = NULL; /* may be set later */
dobj->dump = DUMP_COMPONENT_ALL; /* default assumption */ dobj->dump = DUMP_COMPONENT_ALL; /* default assumption */
dobj->ext_member = false; /* default assumption */ dobj->ext_member = false; /* default assumption */
dobj->depends_on_ext = false; /* default assumption */
dobj->dependencies = NULL; dobj->dependencies = NULL;
dobj->nDeps = 0; dobj->nDeps = 0;
dobj->allocDeps = 0; dobj->allocDeps = 0;
......
...@@ -4291,6 +4291,55 @@ dumpSubscription(Archive *fout, SubscriptionInfo *subinfo) ...@@ -4291,6 +4291,55 @@ dumpSubscription(Archive *fout, SubscriptionInfo *subinfo)
free(qsubname); 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 static void
binary_upgrade_set_type_oids_by_type_oid(Archive *fout, binary_upgrade_set_type_oids_by_type_oid(Archive *fout,
PQExpBuffer upgrade_buffer, PQExpBuffer upgrade_buffer,
...@@ -12161,6 +12210,12 @@ dumpFunc(Archive *fout, FuncInfo *finfo) ...@@ -12161,6 +12210,12 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
appendPQExpBuffer(q, "\n %s;\n", asPart->data); 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) if (dopt->binary_upgrade)
binary_upgrade_extension_member(q, &finfo->dobj, binary_upgrade_extension_member(q, &finfo->dobj,
keyword, funcsig, keyword, funcsig,
...@@ -15871,6 +15926,14 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo) ...@@ -15871,6 +15926,14 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
else else
appendPQExpBufferStr(q, ";\n"); 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 * in binary upgrade mode, update the catalog with any missing values
* that might be present. * that might be present.
...@@ -16375,6 +16438,7 @@ dumpIndex(Archive *fout, IndxInfo *indxinfo) ...@@ -16375,6 +16438,7 @@ dumpIndex(Archive *fout, IndxInfo *indxinfo)
PQExpBuffer q; PQExpBuffer q;
PQExpBuffer delq; PQExpBuffer delq;
char *qindxname; char *qindxname;
char *qqindxname;
if (dopt->dataOnly) if (dopt->dataOnly)
return; return;
...@@ -16383,6 +16447,7 @@ dumpIndex(Archive *fout, IndxInfo *indxinfo) ...@@ -16383,6 +16447,7 @@ dumpIndex(Archive *fout, IndxInfo *indxinfo)
delq = createPQExpBuffer(); delq = createPQExpBuffer();
qindxname = pg_strdup(fmtId(indxinfo->dobj.name)); 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 * If there's an associated constraint, don't dump the index per se, but
...@@ -16435,8 +16500,7 @@ dumpIndex(Archive *fout, IndxInfo *indxinfo) ...@@ -16435,8 +16500,7 @@ dumpIndex(Archive *fout, IndxInfo *indxinfo)
for (j = 0; j < nstatcols; j++) for (j = 0; j < nstatcols; j++)
{ {
appendPQExpBuffer(q, "ALTER INDEX %s ", appendPQExpBuffer(q, "ALTER INDEX %s ", qqindxname);
fmtQualifiedDumpable(indxinfo));
/* /*
* Note that this is a column number, so no quotes should be * Note that this is a column number, so no quotes should be
...@@ -16449,6 +16513,11 @@ dumpIndex(Archive *fout, IndxInfo *indxinfo) ...@@ -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 the index defines identity, we need to record that. */
if (indxinfo->indisreplident) if (indxinfo->indisreplident)
{ {
...@@ -16459,8 +16528,7 @@ dumpIndex(Archive *fout, IndxInfo *indxinfo) ...@@ -16459,8 +16528,7 @@ dumpIndex(Archive *fout, IndxInfo *indxinfo)
qindxname); qindxname);
} }
appendPQExpBuffer(delq, "DROP INDEX %s;\n", appendPQExpBuffer(delq, "DROP INDEX %s;\n", qqindxname);
fmtQualifiedDumpable(indxinfo));
if (indxinfo->dobj.dump & DUMP_COMPONENT_DEFINITION) if (indxinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
ArchiveEntry(fout, indxinfo->dobj.catId, indxinfo->dobj.dumpId, ArchiveEntry(fout, indxinfo->dobj.catId, indxinfo->dobj.dumpId,
...@@ -16491,6 +16559,7 @@ dumpIndex(Archive *fout, IndxInfo *indxinfo) ...@@ -16491,6 +16559,7 @@ dumpIndex(Archive *fout, IndxInfo *indxinfo)
destroyPQExpBuffer(q); destroyPQExpBuffer(q);
destroyPQExpBuffer(delq); destroyPQExpBuffer(delq);
free(qindxname); free(qindxname);
free(qqindxname);
} }
/* /*
...@@ -16729,6 +16798,11 @@ dumpConstraint(Archive *fout, ConstraintInfo *coninfo) ...@@ -16729,6 +16798,11 @@ dumpConstraint(Archive *fout, ConstraintInfo *coninfo)
fmtId(indxinfo->dobj.name)); 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 ", appendPQExpBuffer(delq, "ALTER TABLE ONLY %s ",
fmtQualifiedDumpable(tbinfo)); fmtQualifiedDumpable(tbinfo));
appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n", appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
...@@ -17248,6 +17322,7 @@ dumpTrigger(Archive *fout, TriggerInfo *tginfo) ...@@ -17248,6 +17322,7 @@ dumpTrigger(Archive *fout, TriggerInfo *tginfo)
PQExpBuffer query; PQExpBuffer query;
PQExpBuffer delqry; PQExpBuffer delqry;
PQExpBuffer trigprefix; PQExpBuffer trigprefix;
PQExpBuffer trigidentity;
char *qtabname; char *qtabname;
char *tgargs; char *tgargs;
size_t lentgargs; size_t lentgargs;
...@@ -17265,13 +17340,14 @@ dumpTrigger(Archive *fout, TriggerInfo *tginfo) ...@@ -17265,13 +17340,14 @@ dumpTrigger(Archive *fout, TriggerInfo *tginfo)
query = createPQExpBuffer(); query = createPQExpBuffer();
delqry = createPQExpBuffer(); delqry = createPQExpBuffer();
trigprefix = createPQExpBuffer(); trigprefix = createPQExpBuffer();
trigidentity = createPQExpBuffer();
qtabname = pg_strdup(fmtId(tbinfo->dobj.name)); qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
appendPQExpBuffer(delqry, "DROP TRIGGER %s ", appendPQExpBuffer(trigidentity, "%s ", fmtId(tginfo->dobj.name));
fmtId(tginfo->dobj.name)); appendPQExpBuffer(trigidentity, "ON %s", fmtQualifiedDumpable(tbinfo));
appendPQExpBuffer(delqry, "ON %s;\n",
fmtQualifiedDumpable(tbinfo)); appendPQExpBuffer(delqry, "DROP TRIGGER %s;\n", trigidentity->data);
if (tginfo->tgdef) if (tginfo->tgdef)
{ {
...@@ -17390,6 +17466,11 @@ dumpTrigger(Archive *fout, TriggerInfo *tginfo) ...@@ -17390,6 +17466,11 @@ dumpTrigger(Archive *fout, TriggerInfo *tginfo)
appendPQExpBufferStr(query, ");\n"); 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') if (tginfo->tgenabled != 't' && tginfo->tgenabled != 'O')
{ {
appendPQExpBuffer(query, "\nALTER TABLE %s ", appendPQExpBuffer(query, "\nALTER TABLE %s ",
...@@ -17438,6 +17519,7 @@ dumpTrigger(Archive *fout, TriggerInfo *tginfo) ...@@ -17438,6 +17519,7 @@ dumpTrigger(Archive *fout, TriggerInfo *tginfo)
destroyPQExpBuffer(query); destroyPQExpBuffer(query);
destroyPQExpBuffer(delqry); destroyPQExpBuffer(delqry);
destroyPQExpBuffer(trigprefix); destroyPQExpBuffer(trigprefix);
destroyPQExpBuffer(trigidentity);
free(qtabname); free(qtabname);
} }
...@@ -18087,6 +18169,15 @@ getDependencies(Archive *fout) ...@@ -18087,6 +18169,15 @@ getDependencies(Archive *fout)
continue; 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 * Ordinarily, table rowtypes have implicit dependencies on their
* tables. However, for a composite type the implicit dependency goes * tables. However, for a composite type the implicit dependency goes
......
...@@ -132,6 +132,7 @@ typedef struct _dumpableObject ...@@ -132,6 +132,7 @@ typedef struct _dumpableObject
DumpComponents dump; /* bitmask of components to dump */ DumpComponents dump; /* bitmask of components to dump */
DumpComponents dump_contains; /* as above, but for contained objects */ DumpComponents dump_contains; /* as above, but for contained objects */
bool ext_member; /* true if object is member of extension */ 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 */ DumpId *dependencies; /* dumpIds of objects this one depends on */
int nDeps; /* number of valid dependencies */ int nDeps; /* number of valid dependencies */
int allocDeps; /* allocated size of dependencies[] */ int allocDeps; /* allocated size of dependencies[] */
......
...@@ -523,6 +523,38 @@ my %tests = ( ...@@ -523,6 +523,38 @@ my %tests = (
like => { binary_upgrade => 1, }, 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 # Objects not included in extension, part of schema created by extension
'CREATE TABLE regress_pg_dump_schema.external_tab' => { 'CREATE TABLE regress_pg_dump_schema.external_tab' => {
create_order => 4, create_order => 4,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment