diff --git a/src/backend/catalog/pg_inherits.c b/src/backend/catalog/pg_inherits.c index bb8b2249b1..ed75468a56 100644 --- a/src/backend/catalog/pg_inherits.c +++ b/src/backend/catalog/pg_inherits.c @@ -54,11 +54,12 @@ typedef struct SeenRelsEntry * * include_detached says to include all partitions, even if they're marked * detached. Passing it as false means they might or might not be included, - * depending on the visibility of the pg_inherits row for the active snapshot. + * depending on the visibility of the pg_inherits row for the active snapshot; + * whether actually included or not is returned in *detached_included. */ List * find_inheritance_children(Oid parentrelId, bool include_detached, - LOCKMODE lockmode) + bool *detached_included, LOCKMODE lockmode) { List *list = NIL; Relation relation; @@ -71,6 +72,9 @@ find_inheritance_children(Oid parentrelId, bool include_detached, numoids, i; + if (detached_included) + *detached_included = false; + /* * Can skip the scan if pg_class shows the relation has never had a * subclass. @@ -104,11 +108,12 @@ find_inheritance_children(Oid parentrelId, bool include_detached, * if its pg_inherits tuple's xmin is still visible to the active * snapshot. * - * The reason for this check is that we want to avoid seeing the - * partition as alive in RI queries during REPEATABLE READ or - * SERIALIZABLE transactions. (If there's no active snapshot set, - * that means we're not running a user query, so it's OK to always - * include detached partitions in that case.) + * The reason for this check is that we want the RI queries running in + * REPEATABLE READ or SERIALIZABLE transactions to not see detach- + * pending partitions that were detached after a given transaction + * started. (If there's no active snapshot set, that means we're not + * running a user query, so it's OK to always include detached + * partitions in that case.) */ if (((Form_pg_inherits) GETSTRUCT(inheritsTuple))->inhdetachpending && !include_detached && @@ -122,6 +127,9 @@ find_inheritance_children(Oid parentrelId, bool include_detached, if (!XidInMVCCSnapshot(xmin, snap)) continue; + + if (detached_included) + *detached_included = true; } inhrelid = ((Form_pg_inherits) GETSTRUCT(inheritsTuple))->inhrelid; @@ -236,7 +244,7 @@ find_all_inheritors(Oid parentrelId, LOCKMODE lockmode, List **numparents) /* Get the direct children of this rel */ currentchildren = find_inheritance_children(currentrel, false, - lockmode); + NULL, lockmode); /* * Add to the queue only those children not already seen. This avoids diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 096a6f2891..291ebbd3be 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -3507,7 +3507,7 @@ renameatt_internal(Oid myrelid, * expected_parents will only be 0 if we are not already recursing. */ if (expected_parents == 0 && - find_inheritance_children(myrelid, false, NoLock) != NIL) + find_inheritance_children(myrelid, false, NULL, NoLock) != NIL) ereport(ERROR, (errcode(ERRCODE_INVALID_TABLE_DEFINITION), errmsg("inherited column \"%s\" must be renamed in child tables too", @@ -3706,7 +3706,7 @@ rename_constraint_internal(Oid myrelid, else { if (expected_parents == 0 && - find_inheritance_children(myrelid, false, NoLock) != NIL) + find_inheritance_children(myrelid, false, NULL, NoLock) != NIL) ereport(ERROR, (errcode(ERRCODE_INVALID_TABLE_DEFINITION), errmsg("inherited constraint \"%s\" must be renamed in child tables too", @@ -6580,7 +6580,7 @@ ATExecAddColumn(List **wqueue, AlteredTableInfo *tab, Relation rel, */ if (colDef->identity && recurse && - find_inheritance_children(myrelid, false, NoLock) != NIL) + find_inheritance_children(myrelid, false, NULL, NoLock) != NIL) ereport(ERROR, (errcode(ERRCODE_INVALID_TABLE_DEFINITION), errmsg("cannot recursively add identity column to table that has child tables"))); @@ -6826,7 +6826,7 @@ ATExecAddColumn(List **wqueue, AlteredTableInfo *tab, Relation rel, * use find_all_inheritors to do it in one pass. */ children = - find_inheritance_children(RelationGetRelid(rel), false, lockmode); + find_inheritance_children(RelationGetRelid(rel), false, NULL, lockmode); /* * If we are told not to recurse, there had better not be any child @@ -7689,7 +7689,7 @@ ATPrepDropExpression(Relation rel, AlterTableCmd *cmd, bool recurse, bool recurs * resulting state can be properly dumped and restored. */ if (!recurse && - find_inheritance_children(RelationGetRelid(rel), false, lockmode)) + find_inheritance_children(RelationGetRelid(rel), false, NULL, lockmode)) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("ALTER TABLE / DROP EXPRESSION must be applied to child tables too"))); @@ -8297,7 +8297,7 @@ ATExecDropColumn(List **wqueue, Relation rel, const char *colName, * use find_all_inheritors to do it in one pass. */ children = - find_inheritance_children(RelationGetRelid(rel), false, lockmode); + find_inheritance_children(RelationGetRelid(rel), false, NULL, lockmode); if (children) { @@ -8785,7 +8785,7 @@ ATAddCheckConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel, * use find_all_inheritors to do it in one pass. */ children = - find_inheritance_children(RelationGetRelid(rel), false, lockmode); + find_inheritance_children(RelationGetRelid(rel), false, NULL, lockmode); /* * Check if ONLY was specified with ALTER TABLE. If so, allow the @@ -11319,7 +11319,7 @@ ATExecDropConstraint(Relation rel, const char *constrName, */ if (!is_no_inherit_constraint) children = - find_inheritance_children(RelationGetRelid(rel), false, lockmode); + find_inheritance_children(RelationGetRelid(rel), false, NULL, lockmode); else children = NIL; @@ -11704,7 +11704,7 @@ ATPrepAlterColumnType(List **wqueue, } else if (!recursing && find_inheritance_children(RelationGetRelid(rel), false, - NoLock) != NIL) + NULL, NoLock) != NIL) ereport(ERROR, (errcode(ERRCODE_INVALID_TABLE_DEFINITION), errmsg("type of inherited column \"%s\" must be changed in child tables too", diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c index 3421014e47..b216a0a9a9 100644 --- a/src/backend/commands/trigger.c +++ b/src/backend/commands/trigger.c @@ -1141,7 +1141,7 @@ CreateTrigger(CreateTrigStmt *stmt, const char *queryString, ListCell *l; List *idxs = NIL; - idxs = find_inheritance_children(indexOid, false, + idxs = find_inheritance_children(indexOid, false, NULL, ShareRowExclusiveLock); foreach(l, idxs) childTbls = lappend_oid(childTbls, diff --git a/src/backend/partitioning/partdesc.c b/src/backend/partitioning/partdesc.c index 58570fecfd..35dd10c6b2 100644 --- a/src/backend/partitioning/partdesc.c +++ b/src/backend/partitioning/partdesc.c @@ -105,6 +105,7 @@ RelationBuildPartitionDesc(Relation rel, bool include_detached) MemoryContext new_pdcxt; MemoryContext oldcxt; int *mapping; + bool includes_detached; /* * Get partition oids from pg_inherits. This uses a single snapshot to @@ -113,7 +114,7 @@ RelationBuildPartitionDesc(Relation rel, bool include_detached) * some well-defined point in time. */ inhoids = find_inheritance_children(RelationGetRelid(rel), include_detached, - NoLock); + &includes_detached, NoLock); nparts = list_length(inhoids); /* Allocate working arrays for OIDs, leaf flags, and boundspecs. */ @@ -241,7 +242,7 @@ RelationBuildPartitionDesc(Relation rel, bool include_detached) partdesc->boundinfo = partition_bounds_copy(boundinfo, key); partdesc->oids = (Oid *) palloc(nparts * sizeof(Oid)); partdesc->is_leaf = (bool *) palloc(nparts * sizeof(bool)); - partdesc->includes_detached = include_detached; + partdesc->includes_detached = includes_detached; /* * Assign OIDs from the original array into mapped indexes of the diff --git a/src/include/catalog/pg_inherits.h b/src/include/catalog/pg_inherits.h index 6d07e1b302..26f5489ac8 100644 --- a/src/include/catalog/pg_inherits.h +++ b/src/include/catalog/pg_inherits.h @@ -51,7 +51,7 @@ DECLARE_INDEX(pg_inherits_parent_index, 2187, on pg_inherits using btree(inhpare extern List *find_inheritance_children(Oid parentrelId, bool include_detached, - LOCKMODE lockmode); + bool *detached_included, LOCKMODE lockmode); extern List *find_all_inheritors(Oid parentrelId, LOCKMODE lockmode, List **parents); extern bool has_subclass(Oid relationId); diff --git a/src/test/isolation/expected/detach-partition-concurrently-4.out b/src/test/isolation/expected/detach-partition-concurrently-4.out index 90a75cb077..2167675374 100644 --- a/src/test/isolation/expected/detach-partition-concurrently-4.out +++ b/src/test/isolation/expected/detach-partition-concurrently-4.out @@ -324,6 +324,7 @@ a 1 2 step s1insert: insert into d4_fk values (1); +ERROR: insert or update on table "d4_fk" violates foreign key constraint "d4_fk_a_fkey" step s1c: commit; starting permutation: s2snitch s1b s1s s2detach s1cancel s3vacfreeze s1s s1insert s1c