From a1feb90ef32999f188f150795f896bd4ec839223 Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Mon, 1 Dec 2008 21:06:13 +0000
Subject: [PATCH] Fix an oversight in the code that makes transitive-equality
 deductions from outer join clauses.  Given, say, 	... from a left join b
 on a.a1 = b.b1 where a.a1 = 42; we'll deduce a clause b.b1 = 42 and then mark
 the original join clause redundant (we can't remove it completely for reasons
 I don't feel like squeezing into this log entry).  However the original
 implementation of that wasn't bulletproof, because clause_selectivity()
 wouldn't honor this_selec if given nonzero varRelid --- which in practice
 meant that it worked as desired *except* when considering index scan quals. 
 Which resulted in bogus underestimation of the size of the indexscan result
 for an inner indexscan in an outer join, and consequently a possibly bad
 choice of indexscan vs. bitmap scan.  Fix by introducing an explicit test
 into clause_selectivity().  Also, to make sure we don't trigger that test in
 corner cases, change the convention to be that this_selec > 1, not this_selec
 = 1, means it's been marked redundant.  Per trouble report from Scara Maccai.

Back-patch to 8.2, where the problem was introduced.
---
 src/backend/nodes/outfuncs.c            | 3 ++-
 src/backend/optimizer/path/clausesel.c  | 8 +++++++-
 src/backend/optimizer/path/equivclass.c | 8 ++++----
 src/include/nodes/relation.h            | 5 +++--
 4 files changed, 16 insertions(+), 8 deletions(-)

diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index f64553bbf87..2477a17cfa3 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.345 2008/11/15 19:43:46 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.346 2008/12/01 21:06:12 tgl Exp $
  *
  * NOTES
  *	  Every node type that can appear in stored rules' parsetrees *must*
@@ -1563,6 +1563,7 @@ _outRestrictInfo(StringInfo str, RestrictInfo *node)
 	WRITE_BITMAPSET_FIELD(right_relids);
 	WRITE_NODE_FIELD(orclause);
 	/* don't write parent_ec, leads to infinite recursion in plan tree dump */
+	WRITE_FLOAT_FIELD(this_selec, "%.4f");
 	WRITE_NODE_FIELD(mergeopfamilies);
 	/* don't write left_ec, leads to infinite recursion in plan tree dump */
 	/* don't write right_ec, leads to infinite recursion in plan tree dump */
diff --git a/src/backend/optimizer/path/clausesel.c b/src/backend/optimizer/path/clausesel.c
index e3e4e9f02c0..0ecdec10be2 100644
--- a/src/backend/optimizer/path/clausesel.c
+++ b/src/backend/optimizer/path/clausesel.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/optimizer/path/clausesel.c,v 1.94 2008/10/04 21:56:53 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/optimizer/path/clausesel.c,v 1.95 2008/12/01 21:06:13 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -513,6 +513,12 @@ clause_selectivity(PlannerInfo *root,
 				return (Selectivity) 1.0;
 		}
 
+		/*
+		 * If the clause is marked redundant, always return 1.0.
+		 */
+		if (rinfo->this_selec > 1)
+			return (Selectivity) 1.0;
+
 		/*
 		 * If possible, cache the result of the selectivity calculation for
 		 * the clause.	We can cache if varRelid is zero or the clause
diff --git a/src/backend/optimizer/path/equivclass.c b/src/backend/optimizer/path/equivclass.c
index c0351008750..3d35eb605d9 100644
--- a/src/backend/optimizer/path/equivclass.c
+++ b/src/backend/optimizer/path/equivclass.c
@@ -10,7 +10,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/optimizer/path/equivclass.c,v 1.13 2008/10/21 20:42:52 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/optimizer/path/equivclass.c,v 1.14 2008/12/01 21:06:13 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1198,7 +1198,7 @@ reconsider_outer_join_clauses(PlannerInfo *root)
 					list_delete_cell(root->left_join_clauses, cell, prev);
 				/* we throw it back anyway (see notes above) */
 				/* but the thrown-back clause has no extra selectivity */
-				rinfo->this_selec = 1.0;
+				rinfo->this_selec = 2.0;
 				distribute_restrictinfo_to_rels(root, rinfo);
 			}
 			else
@@ -1220,7 +1220,7 @@ reconsider_outer_join_clauses(PlannerInfo *root)
 					list_delete_cell(root->right_join_clauses, cell, prev);
 				/* we throw it back anyway (see notes above) */
 				/* but the thrown-back clause has no extra selectivity */
-				rinfo->this_selec = 1.0;
+				rinfo->this_selec = 2.0;
 				distribute_restrictinfo_to_rels(root, rinfo);
 			}
 			else
@@ -1242,7 +1242,7 @@ reconsider_outer_join_clauses(PlannerInfo *root)
 					list_delete_cell(root->full_join_clauses, cell, prev);
 				/* we throw it back anyway (see notes above) */
 				/* but the thrown-back clause has no extra selectivity */
-				rinfo->this_selec = 1.0;
+				rinfo->this_selec = 2.0;
 				distribute_restrictinfo_to_rels(root, rinfo);
 			}
 			else
diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h
index 56074a469dc..7b67d94700e 100644
--- a/src/include/nodes/relation.h
+++ b/src/include/nodes/relation.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/nodes/relation.h,v 1.164 2008/11/11 18:13:32 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/relation.h,v 1.165 2008/12/01 21:06:13 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -991,7 +991,8 @@ typedef struct RestrictInfo
 
 	/* cache space for cost and selectivity */
 	QualCost	eval_cost;		/* eval cost of clause; -1 if not yet set */
-	Selectivity this_selec;		/* selectivity; -1 if not yet set */
+	Selectivity this_selec;		/* selectivity; -1 if not yet set; >1 means
+								 * a redundant clause */
 
 	/* valid if clause is mergejoinable, else NIL */
 	List	   *mergeopfamilies;	/* opfamilies containing clause operator */
-- 
GitLab