multiple_inheritance-v2.patch

text/plain

Filename: multiple_inheritance-v2.patch
Type: text/plain
Part: 0
Message: Re: patch for check constraints using multiple inheritance

Patch

Same data as JSON: GET /api/v1/attachments/:id/patch the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes. API reference →
Format: unified
Series: patch v2
File+
src/backend/commands/tablecmds.c 27 4
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 49a6f73..08efffc 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -99,6 +99,10 @@ typedef struct OnCommitItem
 
 static List *on_commits = NIL;
 
+/*
+ * Per subcommand history of relids visited in an inheritance hierarchy.
+ */
+static List *visited_relids = NIL;
 
 /*
  * State information for ALTER TABLE
@@ -2584,6 +2588,7 @@ ATController(Relation rel, List *cmds, bool recurse, LOCKMODE lockmode)
 		AlterTableCmd *cmd = (AlterTableCmd *) lfirst(lcmd);
 
 		ATPrepCmd(&wqueue, rel, cmd, recurse, false, lockmode);
+		visited_relids = NIL;
 	}
 
 	/* Close the relation, but keep lock until commit */
@@ -3618,10 +3623,11 @@ ATSimpleRecursion(List **wqueue, Relation rel,
 /*
  * ATOneLevelRecursion
  *
- * Here, we visit only direct inheritance children.  It is expected that
- * the command's prep routine will recurse again to find indirect children.
- * When using this technique, a multiply-inheriting child will be visited
- * multiple times.
+ * Here, we visit only direct inheritance children.  It is expected that the
+ * command's prep routine will recurse again to find indirect children.  When
+ * using this technique, a multiple-inheriting child will be visited multiple
+ * times. Childs of multiple-inheriting childs however are only visited once
+ * for each parent.
  */
 static void
 ATOneLevelRecursion(List **wqueue, Relation rel,
@@ -3631,6 +3637,14 @@ ATOneLevelRecursion(List **wqueue, Relation rel,
 	ListCell   *child;
 	List	   *children;
 
+	/* If we already visited the current multiple-inheriting relation, we
+	 * mustn't recurse to it's child tables, because they've already been
+	 * visited. Visiting them would lead to an incorrect value for
+	 * attinhcount. */
+	if (list_member_oid(visited_relids, relid))
+		return;
+	visited_relids = lappend_oid(visited_relids, relid);
+
 	children = find_inheritance_children(relid, lockmode);
 
 	foreach(child, children)
@@ -4891,6 +4905,15 @@ ATAddCheckConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel,
 	CommandCounterIncrement();
 
 	/*
+	 * If the constraint got merged with an existing constraint, we're done.
+	 * We mustn't recurse to child tables in this case, because they've already
+	 * got the constraint, and visiting them again would lead to an incorrect
+	 * value for coninhcount.
+	 */
+	if (newcons == NIL)
+		return;
+
+	/*
 	 * Propagate to children as appropriate.  Unlike most other ALTER
 	 * routines, we have to do this one level of recursion at a time; we can't
 	 * use find_all_inheritors to do it in one pass.