From 04226b640493a206b9927b8160fb48b864efcce6 Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Sun, 14 Mar 2004 23:41:27 +0000
Subject: [PATCH] Tweak planner so that index expressions and predicates are
 matched to queries without regard to whether coercions are stated explicitly
 or implicitly.  Per suggestion from Stephan Szabo.

---
 src/backend/nodes/equalfuncs.c       |  8 +++---
 src/backend/optimizer/util/clauses.c | 38 ++++++++++++++++++++++++++--
 src/backend/utils/cache/relcache.c   | 14 +++++++++-
 src/include/nodes/primnodes.h        |  4 +--
 src/include/optimizer/clauses.h      |  4 ++-
 5 files changed, 58 insertions(+), 10 deletions(-)

diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index b23002ff947..fadd02c9357 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -18,7 +18,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.216 2004/03/11 01:47:35 ishii Exp $
+ *	  $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.217 2004/03/14 23:41:26 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -231,7 +231,7 @@ _equalFuncExpr(FuncExpr *a, FuncExpr *b)
 	COMPARE_SCALAR_FIELD(funcretset);
 
 	/*
-	 * Special-case COERCE_DONTCARE, so that pathkeys can build coercion
+	 * Special-case COERCE_DONTCARE, so that planner can build coercion
 	 * nodes that are equal() to both explicit and implicit coercions.
 	 */
 	if (a->funcformat != b->funcformat &&
@@ -372,7 +372,7 @@ _equalRelabelType(RelabelType *a, RelabelType *b)
 	COMPARE_SCALAR_FIELD(resulttypmod);
 
 	/*
-	 * Special-case COERCE_DONTCARE, so that pathkeys can build coercion
+	 * Special-case COERCE_DONTCARE, so that planner can build coercion
 	 * nodes that are equal() to both explicit and implicit coercions.
 	 */
 	if (a->relabelformat != b->relabelformat &&
@@ -472,7 +472,7 @@ _equalCoerceToDomain(CoerceToDomain *a, CoerceToDomain *b)
 	COMPARE_SCALAR_FIELD(resulttypmod);
 
 	/*
-	 * Special-case COERCE_DONTCARE, so that pathkeys can build coercion
+	 * Special-case COERCE_DONTCARE, so that planner can build coercion
 	 * nodes that are equal() to both explicit and implicit coercions.
 	 */
 	if (a->coercionformat != b->coercionformat &&
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index a767eda803c..1f3a8afc7f4 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.163 2004/01/28 00:05:04 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.164 2004/03/14 23:41:27 tgl Exp $
  *
  * HISTORY
  *	  AUTHOR			DATE			MAJOR EVENT
@@ -60,6 +60,7 @@ static bool contain_subplans_walker(Node *node, void *context);
 static bool contain_mutable_functions_walker(Node *node, void *context);
 static bool contain_volatile_functions_walker(Node *node, void *context);
 static bool contain_nonstrict_functions_walker(Node *node, void *context);
+static bool set_coercionform_dontcare_walker(Node *node, void *context);
 static Node *eval_const_expressions_mutator(Node *node, List *active_fns);
 static List *simplify_or_arguments(List *args,
 								   bool *haveNull, bool *forceTrue);
@@ -1002,6 +1003,39 @@ CommuteClause(OpExpr *clause)
 	lsecond(clause->args) = temp;
 }
 
+/*
+ * set_coercionform_dontcare: set all CoercionForm fields to COERCE_DONTCARE
+ *
+ * This is used to make index expressions and index predicates more easily
+ * comparable to clauses of queries.  CoercionForm is not semantically
+ * significant (for cases where it does matter, the significant info is
+ * coded into the coercion function arguments) so we can ignore it during
+ * comparisons.  Thus, for example, an index on "foo::int4" can match an
+ * implicit coercion to int4.
+ *
+ * Caution: the passed expression tree is modified in-place.
+ */
+void
+set_coercionform_dontcare(Node *node)
+{
+	(void) set_coercionform_dontcare_walker(node, NULL);
+}
+
+static bool
+set_coercionform_dontcare_walker(Node *node, void *context)
+{
+	if (node == NULL)
+		return false;
+	if (IsA(node, FuncExpr))
+		((FuncExpr *) node)->funcformat = COERCE_DONTCARE;
+	if (IsA(node, RelabelType))
+		((RelabelType *) node)->relabelformat = COERCE_DONTCARE;
+	if (IsA(node, CoerceToDomain))
+		((CoerceToDomain *) node)->coercionformat = COERCE_DONTCARE;
+	return expression_tree_walker(node, set_coercionform_dontcare_walker,
+								  context);
+}
+
 
 /*--------------------
  * eval_const_expressions
@@ -1766,7 +1800,7 @@ evaluate_function(Oid funcid, Oid result_type, List *args,
 	newexpr->funcid = funcid;
 	newexpr->funcresulttype = result_type;
 	newexpr->funcretset = false;
-	newexpr->funcformat = COERCE_EXPLICIT_CALL; /* doesn't matter */
+	newexpr->funcformat = COERCE_DONTCARE;		/* doesn't matter */
 	newexpr->args = args;
 
 	return evaluate_expr((Expr *) newexpr, result_type);
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
index ac0ee1a5e51..4900cfa5276 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/utils/cache/relcache.c,v 1.198 2004/02/25 19:41:23 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/utils/cache/relcache.c,v 1.199 2004/03/14 23:41:27 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -2687,6 +2687,12 @@ RelationGetIndexExpressions(Relation relation)
 
 	result = (List *) eval_const_expressions((Node *) result);
 
+	/*
+	 * Also mark any coercion format fields as "don't care", so that the
+	 * planner can match to both explicit and implicit coercions.
+	 */
+	set_coercionform_dontcare((Node *) result);
+
 	/* May as well fix opfuncids too */
 	fix_opfuncids((Node *) result);
 
@@ -2755,6 +2761,12 @@ RelationGetIndexPredicate(Relation relation)
 
 	result = (List *) eval_const_expressions((Node *) result);
 
+	/*
+	 * Also mark any coercion format fields as "don't care", so that the
+	 * planner can match to both explicit and implicit coercions.
+	 */
+	set_coercionform_dontcare((Node *) result);
+
 	/* Also convert to implicit-AND format */
 	result = make_ands_implicit((Expr *) result);
 
diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h
index 6a9312b73fe..065ca656a7f 100644
--- a/src/include/nodes/primnodes.h
+++ b/src/include/nodes/primnodes.h
@@ -10,7 +10,7 @@
  * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/nodes/primnodes.h,v 1.94 2004/01/07 18:43:36 neilc Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/primnodes.h,v 1.95 2004/03/14 23:41:27 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -307,7 +307,7 @@ typedef enum CoercionForm
 	COERCE_EXPLICIT_CALL,		/* display as a function call */
 	COERCE_EXPLICIT_CAST,		/* display as an explicit cast */
 	COERCE_IMPLICIT_CAST,		/* implicit cast, so hide it */
-	COERCE_DONTCARE				/* special case for pathkeys */
+	COERCE_DONTCARE				/* special case for planner */
 } CoercionForm;
 
 /*
diff --git a/src/include/optimizer/clauses.h b/src/include/optimizer/clauses.h
index 947c4467e7b..09f0822f468 100644
--- a/src/include/optimizer/clauses.h
+++ b/src/include/optimizer/clauses.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/optimizer/clauses.h,v 1.72 2004/01/05 18:04:39 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/optimizer/clauses.h,v 1.73 2004/03/14 23:41:27 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -63,6 +63,8 @@ extern bool has_distinct_on_clause(Query *query);
 extern int	NumRelids(Node *clause);
 extern void CommuteClause(OpExpr *clause);
 
+extern void set_coercionform_dontcare(Node *node);
+
 extern Node *eval_const_expressions(Node *node);
 
 extern bool expression_tree_walker(Node *node, bool (*walker) (),
-- 
GitLab