From 507b53c8338c176edb27804573e5747874b171f2 Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Tue, 24 Jul 2007 17:22:07 +0000
Subject: [PATCH] Fix predicate-proving logic to cope with binary-compatibility
 cases when checking whether an IS NULL/IS NOT NULL clause is implied or
 refuted by a strict function.  Per example from Dawid Kuroczko. Backpatch to
 8.2 since this is arguably a performance bug.

---
 src/backend/optimizer/util/predtest.c | 41 +++++++++++++++++++++++----
 1 file changed, 36 insertions(+), 5 deletions(-)

diff --git a/src/backend/optimizer/util/predtest.c b/src/backend/optimizer/util/predtest.c
index 9bdef7a319c..3280612dfd5 100644
--- a/src/backend/optimizer/util/predtest.c
+++ b/src/backend/optimizer/util/predtest.c
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/optimizer/util/predtest.c,v 1.15 2007/05/12 19:22:35 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/optimizer/util/predtest.c,v 1.16 2007/07/24 17:22:07 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -84,6 +84,7 @@ static bool predicate_implied_by_simple_clause(Expr *predicate, Node *clause);
 static bool predicate_refuted_by_simple_clause(Expr *predicate, Node *clause);
 static bool is_null_contradicts(NullTest *ntest, Node *clause);
 static Node *extract_not_arg(Node *clause);
+static bool list_member_strip(List *list, Expr *datum);
 static bool btree_predicate_proof(Expr *predicate, Node *clause,
 					  bool refute_it);
 
@@ -961,11 +962,11 @@ predicate_implied_by_simple_clause(Expr *predicate, Node *clause)
 		if (!type_is_rowtype(exprType((Node *) nonnullarg)))
 		{
 			if (is_opclause(clause) &&
-				list_member(((OpExpr *) clause)->args, nonnullarg) &&
+				list_member_strip(((OpExpr *) clause)->args, nonnullarg) &&
 				op_strict(((OpExpr *) clause)->opno))
 				return true;
 			if (is_funcclause(clause) &&
-				list_member(((FuncExpr *) clause)->args, nonnullarg) &&
+				list_member_strip(((FuncExpr *) clause)->args, nonnullarg) &&
 				func_strict(((FuncExpr *) clause)->funcid))
 				return true;
 		}
@@ -1044,11 +1045,11 @@ is_null_contradicts(NullTest *ntest, Node *clause)
 
 	/* foo IS NULL contradicts any strict op/func on foo */
 	if (is_opclause(clause) &&
-		list_member(((OpExpr *) clause)->args, isnullarg) &&
+		list_member_strip(((OpExpr *) clause)->args, isnullarg) &&
 		op_strict(((OpExpr *) clause)->opno))
 		return true;
 	if (is_funcclause(clause) &&
-		list_member(((FuncExpr *) clause)->args, isnullarg) &&
+		list_member_strip(((FuncExpr *) clause)->args, isnullarg) &&
 		func_strict(((FuncExpr *) clause)->funcid))
 		return true;
 
@@ -1091,6 +1092,36 @@ extract_not_arg(Node *clause)
 }
 
 
+/*
+ * Check whether an Expr is equal() to any member of a list, ignoring
+ * any top-level RelabelType nodes.  This is legitimate for the purposes
+ * we use it for (matching IS [NOT] NULL arguments to arguments of strict
+ * functions) because RelabelType doesn't change null-ness.  It's helpful
+ * for cases such as a varchar argument of a strict function on text.
+ */
+static bool
+list_member_strip(List *list, Expr *datum)
+{
+	ListCell   *cell;
+
+	if (datum && IsA(datum, RelabelType))
+		datum = ((RelabelType *) datum)->arg;
+
+	foreach(cell, list)
+	{
+		Expr *elem = (Expr *) lfirst(cell);
+
+		if (elem && IsA(elem, RelabelType))
+			elem = ((RelabelType *) elem)->arg;
+
+		if (equal(elem, datum))
+			return true;
+	}
+
+	return false;
+}
+
+
 /*
  * Define an "operator implication table" for btree operators ("strategies"),
  * and a similar table for refutation.
-- 
GitLab