Skip to content

Commit d04e342

Browse files
committed
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 899a04f) Discussion: https://postgr.es/m/20200217225333.GA30974@alvherre.pgsql
1 parent 05283dd commit d04e342

File tree

4 files changed

+146
-6
lines changed

4 files changed

+146
-6
lines changed

src/bin/pg_dump/common.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -461,6 +461,7 @@ AssignDumpId(DumpableObject *dobj)
461461
dobj->namespace = NULL; /* may be set later */
462462
dobj->dump = DUMP_COMPONENT_ALL; /* default assumption */
463463
dobj->ext_member = false; /* default assumption */
464+
dobj->depends_on_ext = false; /* default assumption */
464465
dobj->dependencies = NULL;
465466
dobj->nDeps = 0;
466467
dobj->allocDeps = 0;

src/bin/pg_dump/pg_dump.c

Lines changed: 98 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3946,6 +3946,55 @@ dumpSubscription(Archive *fout, SubscriptionInfo *subinfo)
39463946
free(qsubname);
39473947
}
39483948

3949+
/*
3950+
* Given a "create query", append as many ALTER ... DEPENDS ON EXTENSION as
3951+
* the object needs.
3952+
*/
3953+
static void
3954+
append_depends_on_extension(Archive *fout,
3955+
PQExpBuffer create,
3956+
DumpableObject *dobj,
3957+
const char *catalog,
3958+
const char *keyword,
3959+
const char *objname)
3960+
{
3961+
if (dobj->depends_on_ext)
3962+
{
3963+
char *nm;
3964+
PGresult *res;
3965+
PQExpBuffer query;
3966+
int ntups;
3967+
int i_extname;
3968+
int i;
3969+
3970+
/* dodge fmtId() non-reentrancy */
3971+
nm = pg_strdup(objname);
3972+
3973+
query = createPQExpBuffer();
3974+
appendPQExpBuffer(query,
3975+
"SELECT e.extname "
3976+
"FROM pg_catalog.pg_depend d, pg_catalog.pg_extension e "
3977+
"WHERE d.refobjid = e.oid AND classid = '%s'::pg_catalog.regclass "
3978+
"AND objid = '%u'::pg_catalog.oid AND deptype = 'x' "
3979+
"AND refclassid = 'pg_catalog.pg_extension'::pg_catalog.regclass",
3980+
catalog,
3981+
dobj->catId.oid);
3982+
res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3983+
ntups = PQntuples(res);
3984+
i_extname = PQfnumber(res, "extname");
3985+
for (i = 0; i < ntups; i++)
3986+
{
3987+
appendPQExpBuffer(create, "ALTER %s %s DEPENDS ON EXTENSION %s;\n",
3988+
keyword, nm,
3989+
fmtId(PQgetvalue(res, i, i_extname)));
3990+
}
3991+
3992+
PQclear(res);
3993+
pg_free(nm);
3994+
}
3995+
}
3996+
3997+
39493998
static void
39503999
binary_upgrade_set_type_oids_by_type_oid(Archive *fout,
39514000
PQExpBuffer upgrade_buffer,
@@ -11556,6 +11605,12 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
1155611605

1155711606
appendPQExpBuffer(q, "\n %s;\n", asPart->data);
1155811607

11608+
append_depends_on_extension(fout, q, &finfo->dobj,
11609+
"pg_catalog.pg_proc", "FUNCTION",
11610+
psprintf("%s.%s",
11611+
fmtId(finfo->dobj.namespace->dobj.name),
11612+
funcsig));
11613+
1155911614
if (dopt->binary_upgrade)
1156011615
binary_upgrade_extension_member(q, &finfo->dobj,
1156111616
"FUNCTION", funcsig,
@@ -15184,6 +15239,14 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
1518415239
else
1518515240
appendPQExpBufferStr(q, ";\n");
1518615241

15242+
/* Materialized views can depend on extensions */
15243+
if (tbinfo->relkind == RELKIND_MATVIEW)
15244+
append_depends_on_extension(fout, q, &tbinfo->dobj,
15245+
"pg_catalog.pg_class",
15246+
tbinfo->relkind == RELKIND_MATVIEW ?
15247+
"MATERIALIZED VIEW" : "INDEX",
15248+
qualrelname);
15249+
1518715250
/*
1518815251
* To create binary-compatible heap files, we have to ensure the same
1518915252
* physical column order, including dropped columns, as in the
@@ -15661,6 +15724,7 @@ dumpIndex(Archive *fout, IndxInfo *indxinfo)
1566115724
PQExpBuffer q;
1566215725
PQExpBuffer delq;
1566315726
char *qindxname;
15727+
char *qqindxname;
1566415728

1566515729
if (dopt->dataOnly)
1566615730
return;
@@ -15669,6 +15733,7 @@ dumpIndex(Archive *fout, IndxInfo *indxinfo)
1566915733
delq = createPQExpBuffer();
1567015734

1567115735
qindxname = pg_strdup(fmtId(indxinfo->dobj.name));
15736+
qqindxname = pg_strdup(fmtQualifiedDumpable(indxinfo));
1567215737

1567315738
/*
1567415739
* If there's an associated constraint, don't dump the index per se, but
@@ -15702,6 +15767,11 @@ dumpIndex(Archive *fout, IndxInfo *indxinfo)
1570215767
qindxname);
1570315768
}
1570415769

15770+
/* Indexes can depend on extensions */
15771+
append_depends_on_extension(fout, q, &indxinfo->dobj,
15772+
"pg_catalog.pg_class",
15773+
"INDEX", qqindxname);
15774+
1570515775
/* If the index defines identity, we need to record that. */
1570615776
if (indxinfo->indisreplident)
1570715777
{
@@ -15712,8 +15782,7 @@ dumpIndex(Archive *fout, IndxInfo *indxinfo)
1571215782
qindxname);
1571315783
}
1571415784

15715-
appendPQExpBuffer(delq, "DROP INDEX %s;\n",
15716-
fmtQualifiedDumpable(indxinfo));
15785+
appendPQExpBuffer(delq, "DROP INDEX %s;\n", qqindxname);
1571715786

1571815787
if (indxinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
1571915788
ArchiveEntry(fout, indxinfo->dobj.catId, indxinfo->dobj.dumpId,
@@ -15739,6 +15808,7 @@ dumpIndex(Archive *fout, IndxInfo *indxinfo)
1573915808
destroyPQExpBuffer(q);
1574015809
destroyPQExpBuffer(delq);
1574115810
free(qindxname);
15811+
free(qqindxname);
1574215812
}
1574315813

1574415814
/*
@@ -15918,6 +15988,11 @@ dumpConstraint(Archive *fout, ConstraintInfo *coninfo)
1591815988
fmtId(indxinfo->dobj.name));
1591915989
}
1592015990

15991+
/* Indexes can depend on extensions */
15992+
append_depends_on_extension(fout, q, &indxinfo->dobj,
15993+
"pg_catalog.pg_class", "INDEX",
15994+
fmtQualifiedDumpable(indxinfo));
15995+
1592115996
appendPQExpBuffer(delq, "ALTER TABLE ONLY %s ",
1592215997
fmtQualifiedDumpable(tbinfo));
1592315998
appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
@@ -16435,6 +16510,7 @@ dumpTrigger(Archive *fout, TriggerInfo *tginfo)
1643516510
PQExpBuffer query;
1643616511
PQExpBuffer delqry;
1643716512
PQExpBuffer trigprefix;
16513+
PQExpBuffer trigidentity;
1643816514
char *qtabname;
1643916515
char *tgargs;
1644016516
size_t lentgargs;
@@ -16452,13 +16528,14 @@ dumpTrigger(Archive *fout, TriggerInfo *tginfo)
1645216528
query = createPQExpBuffer();
1645316529
delqry = createPQExpBuffer();
1645416530
trigprefix = createPQExpBuffer();
16531+
trigidentity = createPQExpBuffer();
1645516532

1645616533
qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
1645716534

16458-
appendPQExpBuffer(delqry, "DROP TRIGGER %s ",
16459-
fmtId(tginfo->dobj.name));
16460-
appendPQExpBuffer(delqry, "ON %s;\n",
16461-
fmtQualifiedDumpable(tbinfo));
16535+
appendPQExpBuffer(trigidentity, "%s ", fmtId(tginfo->dobj.name));
16536+
appendPQExpBuffer(trigidentity, "ON %s", fmtQualifiedDumpable(tbinfo));
16537+
16538+
appendPQExpBuffer(delqry, "DROP TRIGGER %s;\n", trigidentity->data);
1646216539

1646316540
if (tginfo->tgdef)
1646416541
{
@@ -16577,6 +16654,11 @@ dumpTrigger(Archive *fout, TriggerInfo *tginfo)
1657716654
appendPQExpBufferStr(query, ");\n");
1657816655
}
1657916656

16657+
/* Triggers can depend on extensions */
16658+
append_depends_on_extension(fout, query, &tginfo->dobj,
16659+
"pg_catalog.pg_trigger", "TRIGGER",
16660+
trigidentity->data);
16661+
1658016662
if (tginfo->tgenabled != 't' && tginfo->tgenabled != 'O')
1658116663
{
1658216664
appendPQExpBuffer(query, "\nALTER TABLE %s ",
@@ -16626,6 +16708,7 @@ dumpTrigger(Archive *fout, TriggerInfo *tginfo)
1662616708
destroyPQExpBuffer(query);
1662716709
destroyPQExpBuffer(delqry);
1662816710
destroyPQExpBuffer(trigprefix);
16711+
destroyPQExpBuffer(trigidentity);
1662916712
free(qtabname);
1663016713
}
1663116714

@@ -17282,6 +17365,15 @@ getDependencies(Archive *fout)
1728217365
continue;
1728317366
}
1728417367

17368+
/*
17369+
* For 'x' dependencies, mark the object for later; we still add the
17370+
* normal dependency, for possible ordering purposes. Currently
17371+
* pg_dump_sort.c knows to put extensions ahead of all object types
17372+
* that could possibly depend on them, but this is safer.
17373+
*/
17374+
if (deptype == 'x')
17375+
dobj->depends_on_ext = true;
17376+
1728517377
/*
1728617378
* Ordinarily, table rowtypes have implicit dependencies on their
1728717379
* tables. However, for a composite type the implicit dependency goes

src/bin/pg_dump/pg_dump.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ typedef struct _dumpableObject
135135
DumpComponents dump; /* bitmask of components to dump */
136136
DumpComponents dump_contains; /* as above, but for contained objects */
137137
bool ext_member; /* true if object is member of extension */
138+
bool depends_on_ext; /* true if object depends on an extension */
138139
DumpId *dependencies; /* dumpIds of objects this one depends on */
139140
int nDeps; /* number of valid dependencies */
140141
int allocDeps; /* allocated size of dependencies[] */

src/test/modules/test_pg_dump/t/001_base.pl

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -742,6 +742,52 @@
742742
section_pre_data => 1,
743743
section_post_data => 1, }, },
744744
745+
'ALTER INDEX pkey DEPENDS ON extension' => {
746+
create_order => 11,
747+
create_sql =>
748+
'CREATE TABLE regress_pg_dump_schema.extdependtab (col1 integer primary key, col2 int);
749+
CREATE INDEX ON regress_pg_dump_schema.extdependtab (col2);
750+
ALTER INDEX regress_pg_dump_schema.extdependtab_col2_idx DEPENDS ON EXTENSION test_pg_dump;
751+
ALTER INDEX regress_pg_dump_schema.extdependtab_pkey DEPENDS ON EXTENSION test_pg_dump;',
752+
regexp => qr/^
753+
\QALTER INDEX regress_pg_dump_schema.extdependtab_pkey DEPENDS ON EXTENSION test_pg_dump;\E\n
754+
/xms,
755+
like => {
756+
binary_upgrade => 1,
757+
clean_if_exists => 1,
758+
createdb => 1,
759+
defaults => 1,
760+
no_owner => 1,
761+
no_privs => 1,
762+
section_post_data => 1,
763+
schema_only => 1, },
764+
unlike => {
765+
column_inserts => 1,
766+
data_only => 1,
767+
pg_dumpall_globals => 1,
768+
section_data => 1,
769+
section_pre_data => 1, }, },
770+
771+
'ALTER INDEX idx DEPENDS ON extension' => {
772+
regexp => qr/^
773+
\QALTER INDEX regress_pg_dump_schema.extdependtab_col2_idx DEPENDS ON EXTENSION test_pg_dump;\E\n
774+
/xms,
775+
like => {
776+
binary_upgrade => 1,
777+
clean_if_exists => 1,
778+
createdb => 1,
779+
defaults => 1,
780+
no_owner => 1,
781+
no_privs => 1,
782+
section_post_data => 1,
783+
schema_only => 1, },
784+
unlike => {
785+
column_inserts => 1,
786+
data_only => 1,
787+
pg_dumpall_globals => 1,
788+
section_data => 1,
789+
section_pre_data => 1, }, },
790+
745791
# Objects not included in extension, part of schema created by extension
746792
'CREATE TABLE regress_pg_dump_schema.external_tab' => {
747793
create_order => 4,

0 commit comments

Comments
 (0)