mirror of
https://github.com/postgres/postgres.git
synced 2025-05-01 01:04:50 +03:00
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 899a04f5ed61) Discussion: https://postgr.es/m/20200217225333.GA30974@alvherre.pgsql
This commit is contained in:
parent
63b51dfec1
commit
e70187c9b4
@ -587,6 +587,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;
|
||||||
|
@ -4252,6 +4252,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,
|
||||||
@ -12070,6 +12119,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,
|
||||||
@ -15780,6 +15835,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.
|
||||||
@ -16280,6 +16343,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;
|
||||||
@ -16288,6 +16352,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
|
||||||
@ -16340,8 +16405,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
|
||||||
@ -16354,6 +16418,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)
|
||||||
{
|
{
|
||||||
@ -16364,8 +16433,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,
|
||||||
@ -16396,6 +16464,7 @@ dumpIndex(Archive *fout, IndxInfo *indxinfo)
|
|||||||
destroyPQExpBuffer(q);
|
destroyPQExpBuffer(q);
|
||||||
destroyPQExpBuffer(delq);
|
destroyPQExpBuffer(delq);
|
||||||
free(qindxname);
|
free(qindxname);
|
||||||
|
free(qqindxname);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -16625,6 +16694,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",
|
||||||
@ -17148,6 +17222,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;
|
||||||
@ -17165,13 +17240,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)
|
||||||
{
|
{
|
||||||
@ -17290,6 +17366,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 ",
|
||||||
@ -17339,6 +17420,7 @@ dumpTrigger(Archive *fout, TriggerInfo *tginfo)
|
|||||||
destroyPQExpBuffer(query);
|
destroyPQExpBuffer(query);
|
||||||
destroyPQExpBuffer(delqry);
|
destroyPQExpBuffer(delqry);
|
||||||
destroyPQExpBuffer(trigprefix);
|
destroyPQExpBuffer(trigprefix);
|
||||||
|
destroyPQExpBuffer(trigidentity);
|
||||||
free(qtabname);
|
free(qtabname);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -17995,6 +18077,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
|
||||||
|
@ -136,6 +136,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 = (
|
|||||||
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,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user