On 2020-Aug-12, Alvaro Herrera wrote: > Hmm, we do make the FK constraint depend on the ATTACH for the direct > children; what I think we're lacking is dependencies on descendants > twice-removed (?) or higher. This mock patch seems to fix this problem > by adding dependencies recursively on all children of the index; I no > longer see this problem with it.
After going over this some more, this analysis seems correct. Here's a better version of the patch which seems final to me. I'm not yet clear on whether the noisy DROP INDEX is an actual bug that needs to be fixed, or instead it needs to be left alone. -- Álvaro Herrera https://www.2ndQuadrant.com/ PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
>From 07d8af1885edafbd670efc52faa15824787a1dc2 Mon Sep 17 00:00:00 2001 From: Alvaro Herrera <[email protected]> Date: Fri, 14 Aug 2020 13:26:20 -0400 Subject: [PATCH v2] pg_dump: fix dependencies on FKs to multi-level partitioned tables MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Parallel-restoring a foreign key that references a partitioned table with several levels of partitions can fail: pg_restore: while PROCESSING TOC: pg_restore: from TOC entry 6684; 2606 29166 FK CONSTRAINT fk fk_a_fkey postgres pg_restore: error: could not execute query: ERROR: there is no unique constraint matching given keys for referenced table "pk" Command was: ALTER TABLE fkpart3.fk ADD CONSTRAINT fk_a_fkey FOREIGN KEY (a) REFERENCES fkpart3.pk(a); This happens in parallel restore mode because some index partitions aren't yet attached to the topmost partitioned index that the FK uses, and so the index is still invalid. The current code marks the FK as dependent on the first level of index-attach dump objects; the bug is fixed by recursively marking the FK on their children. Reported-by: Tom Lane <[email protected]> Author: Álvaro Herrera <[email protected]> Discussion: https://postgr.es/m/[email protected] --- src/bin/pg_dump/pg_dump.c | 39 ++++++++++++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 7 deletions(-) diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index 9c8436dde6..2cb3f9b083 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -235,6 +235,7 @@ static DumpableObject *createBoundaryObjects(void); static void addBoundaryDependencies(DumpableObject **dobjs, int numObjs, DumpableObject *boundaryObjs); +static void addConstrChildIdxDeps(DumpableObject *dobj, IndxInfo *refidx); static void getDomainConstraints(Archive *fout, TypeInfo *tyinfo); static void getTableData(DumpOptions *dopt, TableInfo *tblinfo, int numTables, char relkind); static void makeTableDataInfo(DumpOptions *dopt, TableInfo *tbinfo); @@ -7517,25 +7518,20 @@ getConstraints(Archive *fout, TableInfo tblinfo[], int numTables) reftable = findTableByOid(constrinfo[j].confrelid); if (reftable && reftable->relkind == RELKIND_PARTITIONED_TABLE) { - IndxInfo *refidx; Oid indexOid = atooid(PQgetvalue(res, j, i_conindid)); if (indexOid != InvalidOid) { for (int k = 0; k < reftable->numIndexes; k++) { - SimplePtrListCell *cell; + IndxInfo *refidx; /* not our index? */ if (reftable->indexes[k].dobj.catId.oid != indexOid) continue; refidx = &reftable->indexes[k]; - for (cell = refidx->partattaches.head; cell; - cell = cell->next) - addObjectDependency(&constrinfo[j].dobj, - ((DumpableObject *) - cell->ptr)->dumpId); + addConstrChildIdxDeps(&constrinfo[j].dobj, refidx); break; } } @@ -7548,6 +7544,35 @@ getConstraints(Archive *fout, TableInfo tblinfo[], int numTables) destroyPQExpBuffer(query); } +/* + * addConstrChildIdxDeps + * + * Recursive subroutine for getConstraints + * + * Given an object representing a foreign key constraint and an index on the + * partitioned table it references, mark the constraint object as dependent + * on the DO_INDEX_ATTACH object of each index partition, recursively + * drilling down to their partitions if any. This ensures that the FK is not + * restored until the index is fully marked valid. + */ +static void +addConstrChildIdxDeps(DumpableObject *dobj, IndxInfo *refidx) +{ + SimplePtrListCell *cell; + + Assert(dobj->objType == DO_FK_CONSTRAINT); + + for (cell = refidx->partattaches.head; cell; cell = cell->next) + { + IndexAttachInfo *attach = (IndexAttachInfo *) cell->ptr; + + addObjectDependency(dobj, attach->dobj.dumpId); + + if (attach->partitionIdx->partattaches.head != NULL) + addConstrChildIdxDeps(dobj, attach->partitionIdx); + } +} + /* * getDomainConstraints * -- 2.20.1
