Hi,

>  Yeah, but I think we need to take that chance.  At the very least, we
>> need to support the equivalent of a non-inherited CHECK (false) on
>> parent tables.
>>
>
> Indeed. I usually enforce that with a trigger that raises an exception, but
> of course that doesn't help at all with constraint exclusion, and I saw a
> result just a few weeks ago (I forget the exact details) where it appeared
> that the plan chosen was significantly worse because the parent table wasn't
> excluded, so there's a  non-trivial downside from having this restriction.
>
>
The downside appears to be non-trivial indeed! I cooked up the attached
patch to try to allow ALTER...ONLY...CHECK(false) on parent tables.

If this approach looks acceptable, I can provide a complete patch later with
some documentation changes (I think we ought to tell about this special case
in the documentation) and a minor test case along with it (if the need be
felt for the test case).

Although partitioning ought to be looked at from a different angle
completely, maybe this small patch can help out a bit in the current scheme
of things, although this is indeed a unusual special casing... Thoughts?

Regards,
Nikhils
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 82bb756..5340402 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -5433,6 +5433,7 @@ ATAddCheckConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel,
 	ListCell   *lcon;
 	List	   *children;
 	ListCell   *child;
+	bool		skip_children = false;
 
 	/* At top level, permission check was done in ATPrepCmd, else do it */
 	if (recursing)
@@ -5502,9 +5503,31 @@ ATAddCheckConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel,
 	 * tables; else the addition would put them out of step.
 	 */
 	if (children && !recurse)
-		ereport(ERROR,
+	{
+		/*
+		 * Try a bit harder and check if this is a CHECK(FALSE) kinda
+		 * constraint. Allow if so, otherwise error out
+		 */
+		if (list_length(newcons) == 1)
+		{
+			CookedConstraint *cooked = linitial(newcons);
+
+			if (cooked->contype == CONSTR_CHECK && cooked->expr)
+			{
+				Node *expr = cooked->expr;
+				if (IsA(expr, Const) && ((Const *)expr)->consttype == BOOLOID &&
+					 ((Const *)expr)->constvalue == 0)
+				{
+					skip_children = true;
+				}
+			}
+		}
+
+		if (!skip_children)
+			ereport(ERROR,
 				(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
 				 errmsg("constraint must be added to child tables too")));
+	}
 
 	foreach(child, children)
 	{
@@ -5512,6 +5535,13 @@ ATAddCheckConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel,
 		Relation	childrel;
 		AlteredTableInfo *childtab;
 
+		/*
+		 * Skipping the constraint should be good enough for the special case.
+		 * No need to even release the locks on the children immediately..
+		 */
+		if (skip_children)
+			break;
+
 		/* find_inheritance_children already got lock */
 		childrel = heap_open(childrelid, NoLock);
 		CheckTableNotInUse(childrel, "ALTER TABLE");
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to