Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 1752e35

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 3c8c55d commit 1752e35

File tree

5 files changed

+82
-5
lines changed

5 files changed

+82
-5
lines changed

src/bin/pg_dump/common.c

+3
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

+40-2
Original file line numberDiff line numberDiff line change
@@ -7115,6 +7115,7 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
71157115
indxinfo[j].indisclustered = (PQgetvalue(res, j, i_indisclustered)[0] == 't');
71167116
indxinfo[j].indisreplident = (PQgetvalue(res, j, i_indisreplident)[0] == 't');
71177117
indxinfo[j].parentidx = atooid(PQgetvalue(res, j, i_parentidx));
7118+
indxinfo[j].partattaches = (SimplePtrList) { NULL, NULL };
71187119
contype = *(PQgetvalue(res, j, i_contype));
71197120

71207121
if (contype == 'p' || contype == 'u' || contype == 'x')
@@ -7256,6 +7257,7 @@ getConstraints(Archive *fout, TableInfo tblinfo[], int numTables)
72567257
i_conoid,
72577258
i_conname,
72587259
i_confrelid,
7260+
i_conindid,
72597261
i_condef;
72607262
int ntups;
72617263

@@ -7281,7 +7283,7 @@ getConstraints(Archive *fout, TableInfo tblinfo[], int numTables)
72817283
resetPQExpBuffer(query);
72827284
if (fout->remoteVersion >= 110000)
72837285
appendPQExpBuffer(query,
7284-
"SELECT tableoid, oid, conname, confrelid, "
7286+
"SELECT tableoid, oid, conname, confrelid, conindid, "
72857287
"pg_catalog.pg_get_constraintdef(oid) AS condef "
72867288
"FROM pg_catalog.pg_constraint "
72877289
"WHERE conrelid = '%u'::pg_catalog.oid "
@@ -7290,7 +7292,7 @@ getConstraints(Archive *fout, TableInfo tblinfo[], int numTables)
72907292
tbinfo->dobj.catId.oid);
72917293
else
72927294
appendPQExpBuffer(query,
7293-
"SELECT tableoid, oid, conname, confrelid, "
7295+
"SELECT tableoid, oid, conname, confrelid, 0 as conindid, "
72947296
"pg_catalog.pg_get_constraintdef(oid) AS condef "
72957297
"FROM pg_catalog.pg_constraint "
72967298
"WHERE conrelid = '%u'::pg_catalog.oid "
@@ -7304,12 +7306,15 @@ getConstraints(Archive *fout, TableInfo tblinfo[], int numTables)
73047306
i_conoid = PQfnumber(res, "oid");
73057307
i_conname = PQfnumber(res, "conname");
73067308
i_confrelid = PQfnumber(res, "confrelid");
7309+
i_conindid = PQfnumber(res, "conindid");
73077310
i_condef = PQfnumber(res, "condef");
73087311

73097312
constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
73107313

73117314
for (j = 0; j < ntups; j++)
73127315
{
7316+
TableInfo *reftable;
7317+
73137318
constrinfo[j].dobj.objType = DO_FK_CONSTRAINT;
73147319
constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
73157320
constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
@@ -7326,6 +7331,39 @@ getConstraints(Archive *fout, TableInfo tblinfo[], int numTables)
73267331
constrinfo[j].condeferred = false;
73277332
constrinfo[j].conislocal = true;
73287333
constrinfo[j].separate = true;
7334+
7335+
/*
7336+
* Restoring an FK that points to a partitioned table requires
7337+
* that all partition indexes have been attached beforehand.
7338+
* Ensure that happens by making the constraint depend on each
7339+
* index partition attach object.
7340+
*/
7341+
reftable = findTableByOid(constrinfo[j].confrelid);
7342+
if (reftable && reftable->relkind == RELKIND_PARTITIONED_TABLE)
7343+
{
7344+
IndxInfo *refidx;
7345+
Oid indexOid = atooid(PQgetvalue(res, j, i_conindid));
7346+
7347+
if (indexOid != InvalidOid)
7348+
{
7349+
for (int k = 0; k < reftable->numIndexes; k++)
7350+
{
7351+
SimplePtrListCell *cell;
7352+
7353+
/* not our index? */
7354+
if (reftable->indexes[k].dobj.catId.oid != indexOid)
7355+
continue;
7356+
7357+
refidx = &reftable->indexes[k];
7358+
for (cell = refidx->partattaches.head; cell;
7359+
cell = cell->next)
7360+
addObjectDependency(&constrinfo[j].dobj,
7361+
((DumpableObject *)
7362+
cell->ptr)->dumpId);
7363+
break;
7364+
}
7365+
}
7366+
}
73297367
}
73307368

73317369
PQclear(res);

src/bin/pg_dump/pg_dump.h

+2
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,8 @@ typedef struct _indxInfo
367367
bool indisclustered;
368368
bool indisreplident;
369369
Oid parentidx; /* if partitioned, parent index OID */
370+
SimplePtrList partattaches; /* if partitioned, partition attach objects */
371+
370372
/* if there is an associated constraint object, its dumpId: */
371373
DumpId indexconstraint;
372374
} IndxInfo;

src/fe_utils/simple_list.c

+21
Original file line numberDiff line numberDiff line change
@@ -152,3 +152,24 @@ simple_string_list_not_touched(SimpleStringList *list)
152152
}
153153
return NULL;
154154
}
155+
156+
/*
157+
* Append a pointer to the list.
158+
*
159+
* Caller must ensure that the pointer remains valid.
160+
*/
161+
void
162+
simple_ptr_list_append(SimplePtrList *list, void *ptr)
163+
{
164+
SimplePtrListCell *cell;
165+
166+
cell = (SimplePtrListCell *) pg_malloc(sizeof(SimplePtrListCell));
167+
cell->next = NULL;
168+
cell->ptr = ptr;
169+
170+
if (list->tail)
171+
list->tail->next = cell;
172+
else
173+
list->head = cell;
174+
list->tail = cell;
175+
}

src/include/fe_utils/simple_list.h

+16-3
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);
@@ -54,4 +65,6 @@ extern void simple_string_list_destroy(SimpleStringList *list);
5465

5566
extern const char *simple_string_list_not_touched(SimpleStringList *list);
5667

68+
extern void simple_ptr_list_append(SimplePtrList *list, void *val);
69+
5770
#endif /* SIMPLE_LIST_H */

0 commit comments

Comments
 (0)