Skip to content

Commit b304b2b

Browse files
committed
Fix parallel restore of FKs to partitioned tables
When an FK constraint is created, it needs the index on the referenced table to exist and be valid. When doing parallel pg_restore and the referenced table was partitioned, this condition can sometimes not be met, because pg_dump didn't emit sufficient object dependencies to ensure so; this means that parallel pg_restore would fail in certain conditions. Fix by having pg_dump make the FK constraint object dependent on the partition attachment objects for the constraint's referenced index. This has been broken since f56f8f8, so backpatch to Postgres 12. Discussion: https://postgr.es/m/20191005224333.GA9738@alvherre.pgsql
1 parent 3af7c64 commit b304b2b

File tree

5 files changed

+82
-5
lines changed

5 files changed

+82
-5
lines changed

src/bin/pg_dump/common.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,9 @@ flagInhIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
412412
addObjectDependency(&attachinfo[k].dobj,
413413
parentidx->indextable->dobj.dumpId);
414414

415+
/* keep track of the list of partitions in the parent index */
416+
simple_ptr_list_append(&parentidx->partattaches, &attachinfo[k].dobj);
417+
415418
k++;
416419
}
417420
}

src/bin/pg_dump/pg_dump.c

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7109,6 +7109,7 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
71097109
indxinfo[j].indisclustered = (PQgetvalue(res, j, i_indisclustered)[0] == 't');
71107110
indxinfo[j].indisreplident = (PQgetvalue(res, j, i_indisreplident)[0] == 't');
71117111
indxinfo[j].parentidx = atooid(PQgetvalue(res, j, i_parentidx));
7112+
indxinfo[j].partattaches = (SimplePtrList) { NULL, NULL };
71127113
contype = *(PQgetvalue(res, j, i_contype));
71137114

71147115
if (contype == 'p' || contype == 'u' || contype == 'x')
@@ -7241,6 +7242,7 @@ getConstraints(Archive *fout, TableInfo tblinfo[], int numTables)
72417242
i_conoid,
72427243
i_conname,
72437244
i_confrelid,
7245+
i_conindid,
72447246
i_condef;
72457247
int ntups;
72467248

@@ -7266,7 +7268,7 @@ getConstraints(Archive *fout, TableInfo tblinfo[], int numTables)
72667268
resetPQExpBuffer(query);
72677269
if (fout->remoteVersion >= 110000)
72687270
appendPQExpBuffer(query,
7269-
"SELECT tableoid, oid, conname, confrelid, "
7271+
"SELECT tableoid, oid, conname, confrelid, conindid, "
72707272
"pg_catalog.pg_get_constraintdef(oid) AS condef "
72717273
"FROM pg_catalog.pg_constraint "
72727274
"WHERE conrelid = '%u'::pg_catalog.oid "
@@ -7275,7 +7277,7 @@ getConstraints(Archive *fout, TableInfo tblinfo[], int numTables)
72757277
tbinfo->dobj.catId.oid);
72767278
else
72777279
appendPQExpBuffer(query,
7278-
"SELECT tableoid, oid, conname, confrelid, "
7280+
"SELECT tableoid, oid, conname, confrelid, 0 as conindid, "
72797281
"pg_catalog.pg_get_constraintdef(oid) AS condef "
72807282
"FROM pg_catalog.pg_constraint "
72817283
"WHERE conrelid = '%u'::pg_catalog.oid "
@@ -7289,12 +7291,15 @@ getConstraints(Archive *fout, TableInfo tblinfo[], int numTables)
72897291
i_conoid = PQfnumber(res, "oid");
72907292
i_conname = PQfnumber(res, "conname");
72917293
i_confrelid = PQfnumber(res, "confrelid");
7294+
i_conindid = PQfnumber(res, "conindid");
72927295
i_condef = PQfnumber(res, "condef");
72937296

72947297
constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
72957298

72967299
for (j = 0; j < ntups; j++)
72977300
{
7301+
TableInfo *reftable;
7302+
72987303
constrinfo[j].dobj.objType = DO_FK_CONSTRAINT;
72997304
constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
73007305
constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
@@ -7311,6 +7316,39 @@ getConstraints(Archive *fout, TableInfo tblinfo[], int numTables)
73117316
constrinfo[j].condeferred = false;
73127317
constrinfo[j].conislocal = true;
73137318
constrinfo[j].separate = true;
7319+
7320+
/*
7321+
* Restoring an FK that points to a partitioned table requires
7322+
* that all partition indexes have been attached beforehand.
7323+
* Ensure that happens by making the constraint depend on each
7324+
* index partition attach object.
7325+
*/
7326+
reftable = findTableByOid(constrinfo[j].confrelid);
7327+
if (reftable && reftable->relkind == RELKIND_PARTITIONED_TABLE)
7328+
{
7329+
IndxInfo *refidx;
7330+
Oid indexOid = atooid(PQgetvalue(res, j, i_conindid));
7331+
7332+
if (indexOid != InvalidOid)
7333+
{
7334+
for (int k = 0; k < reftable->numIndexes; k++)
7335+
{
7336+
SimplePtrListCell *cell;
7337+
7338+
/* not our index? */
7339+
if (reftable->indexes[k].dobj.catId.oid != indexOid)
7340+
continue;
7341+
7342+
refidx = &reftable->indexes[k];
7343+
for (cell = refidx->partattaches.head; cell;
7344+
cell = cell->next)
7345+
addObjectDependency(&constrinfo[j].dobj,
7346+
((DumpableObject *)
7347+
cell->ptr)->dumpId);
7348+
break;
7349+
}
7350+
}
7351+
}
73147352
}
73157353

73167354
PQclear(res);

src/bin/pg_dump/pg_dump.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,8 @@ typedef struct _indxInfo
371371
bool indisclustered;
372372
bool indisreplident;
373373
Oid parentidx; /* if partitioned, parent index OID */
374+
SimplePtrList partattaches; /* if partitioned, partition attach objects */
375+
374376
/* if there is an associated constraint object, its dumpId: */
375377
DumpId indexconstraint;
376378
} IndxInfo;

src/fe_utils/simple_list.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,3 +114,24 @@ simple_string_list_not_touched(SimpleStringList *list)
114114
}
115115
return NULL;
116116
}
117+
118+
/*
119+
* Append a pointer to the list.
120+
*
121+
* Caller must ensure that the pointer remains valid.
122+
*/
123+
void
124+
simple_ptr_list_append(SimplePtrList *list, void *ptr)
125+
{
126+
SimplePtrListCell *cell;
127+
128+
cell = (SimplePtrListCell *) pg_malloc(sizeof(SimplePtrListCell));
129+
cell->next = NULL;
130+
cell->ptr = ptr;
131+
132+
if (list->tail)
133+
list->tail->next = cell;
134+
else
135+
list->head = cell;
136+
list->tail = cell;
137+
}

src/include/fe_utils/simple_list.h

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22
*
33
* Simple list facilities for frontend code
44
*
5-
* Data structures for simple lists of OIDs and strings. The support for
6-
* these is very primitive compared to the backend's List facilities, but
7-
* it's all we need in, eg, pg_dump.
5+
* Data structures for simple lists of OIDs, strings, and pointers. The
6+
* support for these is very primitive compared to the backend's List
7+
* facilities, but it's all we need in, eg, pg_dump.
88
*
99
*
1010
* Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
@@ -43,6 +43,17 @@ typedef struct SimpleStringList
4343
SimpleStringListCell *tail;
4444
} SimpleStringList;
4545

46+
typedef struct SimplePtrListCell
47+
{
48+
struct SimplePtrListCell *next;
49+
void *ptr;
50+
} SimplePtrListCell;
51+
52+
typedef struct SimplePtrList
53+
{
54+
SimplePtrListCell *head;
55+
SimplePtrListCell *tail;
56+
} SimplePtrList;
4657

4758
extern void simple_oid_list_append(SimpleOidList *list, Oid val);
4859
extern bool simple_oid_list_member(SimpleOidList *list, Oid val);
@@ -52,4 +63,6 @@ extern bool simple_string_list_member(SimpleStringList *list, const char *val);
5263

5364
extern const char *simple_string_list_not_touched(SimpleStringList *list);
5465

66+
extern void simple_ptr_list_append(SimplePtrList *list, void *val);
67+
5568
#endif /* SIMPLE_LIST_H */

0 commit comments

Comments
 (0)