v7-0002-Simplify-relation_has_unique_index_for.patch

application/octet-stream

Filename: v7-0002-Simplify-relation_has_unique_index_for.patch
Type: application/octet-stream
Part: 1
Message: Re: Pathify RHS unique-ification for semijoin planning

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: format-patch
Series: patch v7-0002
Subject: Simplify relation_has_unique_index_for()
File+
src/backend/optimizer/path/indxpath.c 14 71
src/backend/optimizer/plan/analyzejoins.c 2 3
src/include/optimizer/paths.h 1 4
From 5d75301d1cc042b2043e3a4a4fe3070087134bd8 Mon Sep 17 00:00:00 2001
From: Richard Guo <guofenglinux@gmail.com>
Date: Fri, 1 Aug 2025 18:12:30 +0900
Subject: [PATCH v7 2/2] Simplify relation_has_unique_index_for()

Now that the only call to relation_has_unique_index_for() that
supplied an exprlist and oprlist has been removed, the loop handling
those lists is effectively dead code.  This patch removes that loop
and simplifies the function accordingly.

Author: Richard Guo <guofenglinux@gmail.com>
Discussion: https://postgr.es/m/CAMbWs4-EBnaRvEs7frTLbsXiweSTUXifsteF-d3rvv01FKO86w@mail.gmail.com
---
 src/backend/optimizer/path/indxpath.c     | 85 ++++-------------------
 src/backend/optimizer/plan/analyzejoins.c |  5 +-
 src/include/optimizer/paths.h             |  5 +-
 3 files changed, 17 insertions(+), 78 deletions(-)

diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c
index 601354ea3e0..4f5c98f0091 100644
--- a/src/backend/optimizer/path/indxpath.c
+++ b/src/backend/optimizer/path/indxpath.c
@@ -4142,47 +4142,26 @@ ec_member_matches_indexcol(PlannerInfo *root, RelOptInfo *rel,
  *	  a set of equality conditions, because the conditions constrain all
  *	  columns of some unique index.
  *
- * The conditions can be represented in either or both of two ways:
- * 1. A list of RestrictInfo nodes, where the caller has already determined
- * that each condition is a mergejoinable equality with an expression in
- * this relation on one side, and an expression not involving this relation
- * on the other.  The transient outer_is_left flag is used to identify which
- * side we should look at: left side if outer_is_left is false, right side
- * if it is true.
- * 2. A list of expressions in this relation, and a corresponding list of
- * equality operators. The caller must have already checked that the operators
- * represent equality.  (Note: the operators could be cross-type; the
- * expressions should correspond to their RHS inputs.)
+ * The conditions are provided as a list of RestrictInfo nodes, where the
+ * caller has already determined that each condition is a mergejoinable
+ * equality with an expression in this relation on one side, and an
+ * expression not involving this relation on the other.  The transient
+ * outer_is_left flag is used to identify which side we should look at:
+ * left side if outer_is_left is false, right side if it is true.
  *
  * The caller need only supply equality conditions arising from joins;
  * this routine automatically adds in any usable baserestrictinfo clauses.
  * (Note that the passed-in restrictlist will be destructively modified!)
+ *
+ * If extra_clauses isn't NULL, return baserestrictinfo clauses which were used
+ * to derive uniqueness.
  */
 bool
 relation_has_unique_index_for(PlannerInfo *root, RelOptInfo *rel,
-							  List *restrictlist,
-							  List *exprlist, List *oprlist)
-{
-	return relation_has_unique_index_ext(root, rel, restrictlist,
-										 exprlist, oprlist, NULL);
-}
-
-/*
- * relation_has_unique_index_ext
- *	  Same as relation_has_unique_index_for(), but supports extra_clauses
- *	  parameter.  If extra_clauses isn't NULL, return baserestrictinfo clauses
- *	  which were used to derive uniqueness.
- */
-bool
-relation_has_unique_index_ext(PlannerInfo *root, RelOptInfo *rel,
-							  List *restrictlist,
-							  List *exprlist, List *oprlist,
-							  List **extra_clauses)
+							  List *restrictlist, List **extra_clauses)
 {
 	ListCell   *ic;
 
-	Assert(list_length(exprlist) == list_length(oprlist));
-
 	/* Short-circuit if no indexes... */
 	if (rel->indexlist == NIL)
 		return false;
@@ -4225,7 +4204,7 @@ relation_has_unique_index_ext(PlannerInfo *root, RelOptInfo *rel,
 	}
 
 	/* Short-circuit the easy case */
-	if (restrictlist == NIL && exprlist == NIL)
+	if (restrictlist == NIL)
 		return false;
 
 	/* Examine each index of the relation ... */
@@ -4247,14 +4226,12 @@ relation_has_unique_index_ext(PlannerInfo *root, RelOptInfo *rel,
 			continue;
 
 		/*
-		 * Try to find each index column in the lists of conditions.  This is
+		 * Try to find each index column in the list of conditions.  This is
 		 * O(N^2) or worse, but we expect all the lists to be short.
 		 */
 		for (c = 0; c < ind->nkeycolumns; c++)
 		{
-			bool		matched = false;
 			ListCell   *lc;
-			ListCell   *lc2;
 
 			foreach(lc, restrictlist)
 			{
@@ -4284,8 +4261,6 @@ relation_has_unique_index_ext(PlannerInfo *root, RelOptInfo *rel,
 
 				if (match_index_to_operand(rexpr, c, ind))
 				{
-					matched = true; /* column is unique */
-
 					if (bms_membership(rinfo->clause_relids) == BMS_SINGLETON)
 					{
 						MemoryContext oldMemCtx =
@@ -4303,43 +4278,11 @@ relation_has_unique_index_ext(PlannerInfo *root, RelOptInfo *rel,
 						MemoryContextSwitchTo(oldMemCtx);
 					}
 
-					break;
+					break;		/* found a match; column is unique */
 				}
 			}
 
-			if (matched)
-				continue;
-
-			forboth(lc, exprlist, lc2, oprlist)
-			{
-				Node	   *expr = (Node *) lfirst(lc);
-				Oid			opr = lfirst_oid(lc2);
-
-				/* See if the expression matches the index key */
-				if (!match_index_to_operand(expr, c, ind))
-					continue;
-
-				/*
-				 * The equality operator must be a member of the index
-				 * opfamily, else it is not asserting the right kind of
-				 * equality behavior for this index.  We assume the caller
-				 * determined it is an equality operator, so we don't need to
-				 * check any more tightly than this.
-				 */
-				if (!op_in_opfamily(opr, ind->opfamily[c]))
-					continue;
-
-				/*
-				 * XXX at some point we may need to check collations here too.
-				 * For the moment we assume all collations reduce to the same
-				 * notion of equality.
-				 */
-
-				matched = true; /* column is unique */
-				break;
-			}
-
-			if (!matched)
+			if (lc == NULL)
 				break;			/* no match; this index doesn't help us */
 		}
 
diff --git a/src/backend/optimizer/plan/analyzejoins.c b/src/backend/optimizer/plan/analyzejoins.c
index 4d55c2ea591..da92d8ee414 100644
--- a/src/backend/optimizer/plan/analyzejoins.c
+++ b/src/backend/optimizer/plan/analyzejoins.c
@@ -990,11 +990,10 @@ rel_is_distinct_for(PlannerInfo *root, RelOptInfo *rel, List *clause_list,
 	{
 		/*
 		 * Examine the indexes to see if we have a matching unique index.
-		 * relation_has_unique_index_ext automatically adds any usable
+		 * relation_has_unique_index_for automatically adds any usable
 		 * restriction clauses for the rel, so we needn't do that here.
 		 */
-		if (relation_has_unique_index_ext(root, rel, clause_list, NIL, NIL,
-										  extra_clauses))
+		if (relation_has_unique_index_for(root, rel, clause_list, extra_clauses))
 			return true;
 	}
 	else if (rel->rtekind == RTE_SUBQUERY)
diff --git a/src/include/optimizer/paths.h b/src/include/optimizer/paths.h
index 8410531f2d6..cbade77b717 100644
--- a/src/include/optimizer/paths.h
+++ b/src/include/optimizer/paths.h
@@ -71,10 +71,7 @@ extern void generate_partitionwise_join_paths(PlannerInfo *root,
 extern void create_index_paths(PlannerInfo *root, RelOptInfo *rel);
 extern bool relation_has_unique_index_for(PlannerInfo *root, RelOptInfo *rel,
 										  List *restrictlist,
-										  List *exprlist, List *oprlist);
-extern bool relation_has_unique_index_ext(PlannerInfo *root, RelOptInfo *rel,
-										  List *restrictlist, List *exprlist,
-										  List *oprlist, List **extra_clauses);
+										  List **extra_clauses);
 extern bool indexcol_is_bool_constant_for_query(PlannerInfo *root,
 												IndexOptInfo *index,
 												int indexcol);
-- 
2.43.0