diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 5f6fe41..d23dcdc 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -96,6 +96,17 @@ typedef struct OnCommitItem SubTransactionId deleting_subid; } OnCommitItem; +/* + * Visit information needed to prevent redundant constraint merges. This + * structure is needed to prevent faulty increments of coninhcount in the case + * of a multiple inheritance tree that has multiple paths to a parent. + */ +typedef struct ParentVisit +{ + Oid parent; + Oid child; +} ParentVisit; + static List *on_commits = NIL; @@ -300,7 +311,7 @@ static void ATExecAddConstraint(List **wqueue, static void ATAddCheckConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel, Constraint *constr, - bool recurse, bool recursing); + bool recurse, bool recursing, List *visited); static void ATAddForeignKeyConstraint(AlteredTableInfo *tab, Relation rel, Constraint *fkconstraint); static void ATExecDropConstraint(Relation rel, const char *constrName, @@ -4584,7 +4595,7 @@ ATExecAddConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel, { case CONSTR_CHECK: ATAddCheckConstraint(wqueue, tab, rel, - newConstraint, recurse, false); + newConstraint, recurse, false, NIL); break; case CONSTR_FOREIGN: @@ -4639,7 +4650,7 @@ ATExecAddConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel, */ static void ATAddCheckConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel, - Constraint *constr, bool recurse, bool recursing) + Constraint *constr, bool recurse, bool recursing, List *visited) { List *newcons; ListCell *lcon; @@ -4711,6 +4722,30 @@ ATAddCheckConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel, Oid childrelid = lfirst_oid(child); Relation childrel; AlteredTableInfo *childtab; + ListCell *lv; + bool skip = false; + ParentVisit *visit; + + /* Skip children that were visited from the same direct parent. */ + foreach(lv, visited) + { + visit = lfirst(lv); + + if ((visit->parent == RelationGetRelid(rel)) && + (visit->child == childrelid)) + { + skip = true; + break; + } + } + + if (skip) + continue; + + visit = (ParentVisit *) palloc(sizeof(ParentVisit)); + visit->parent = RelationGetRelid(rel); + visit->child = childrelid; + visited = lappend(visited, visit); /* find_inheritance_children already got lock */ childrel = heap_open(childrelid, NoLock); @@ -4721,7 +4756,7 @@ ATAddCheckConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel, /* Recurse to child */ ATAddCheckConstraint(wqueue, childtab, childrel, - constr, recurse, true); + constr, recurse, true, visited); heap_close(childrel, NoLock); }