From e7772b9f52f43f91b95b8206c20d4bce4b254889 Mon Sep 17 00:00:00 2001
From: "Zizhuan Liu(X-MAN)" <44973863@qq.com>
Date: Tue, 18 Aug 2026 20:32:07 +0800
Subject: [PATCH v4] proper-handling-examine_variable-RelabelType. discussion:
 https://www.postgresql.org/message-id/flat/CACJufxGLCiyhM+P0gxesg2x--PTrMY3PszqSqOq_H4QS_oq3Jg@mail.gmail.com
 commitfest: https://commitfest.postgresql.org/patch/6397/ discussion:
 https://www.postgresql.org/message-id/flat/E1va3GH-003FBe-35%40gemulon.postgresql.org

---
 src/backend/utils/adt/selfuncs.c | 78 ++++++++++++++++++++++++++------
 1 file changed, 64 insertions(+), 14 deletions(-)

diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c
index e27ec9e5..bff72c4c 100644
--- a/src/backend/utils/adt/selfuncs.c
+++ b/src/backend/utils/adt/selfuncs.c
@@ -274,6 +274,7 @@ static bool get_actual_variable_endpoint(Relation heapRel,
 static RelOptInfo *find_join_input_rel(PlannerInfo *root, Relids relids);
 static double btcost_correlation(IndexOptInfo *index,
 								 VariableStatData *vardata);
+static bool strip_all_adjacency_relabeltypes_walker(Node *node, void *context);
 
 /* Define support routines for MCV hash tables */
 #define SH_PREFIX				MCVHashTable
@@ -5673,12 +5674,14 @@ examine_variable(PlannerInfo *root, Node *node, int varRelid,
 	basenode = strip_all_phvs_deep(root, node);
 
 	/*
-	 * Look inside any binary-compatible relabeling.  We need to handle nested
-	 * RelabelType nodes here, because the prior stripping of PlaceHolderVars
-	 * may have brought separate RelabelTypes into adjacency.
-	 */
-	while (IsA(basenode, RelabelType))
-		basenode = (Node *) ((RelabelType *) basenode)->arg;
+	* eval_const_expressions() should already have stripped adjacent
+	* RelabelTypes. However, stripping PlaceHolderVars above may have
+	* brought previously separated RelabelTypes into adjacency, either
+	* at the top level or within a deeper subtree. Normalize the expression
+	* before calling equal() so that structurally equivalent expressions
+	* can be matched, as in eval_const_expressions().
+	*/
+	strip_all_adjacency_relabeltypes_walker(basenode, NULL);
 
 	/* Fast path for a simple Var */
 	if (IsA(basenode, Var) &&
@@ -5799,9 +5802,7 @@ examine_variable(PlannerInfo *root, Node *node, int varRelid,
 					if (indexpr_item == NULL)
 						elog(ERROR, "too few entries in indexprs list");
 					indexkey = (Node *) lfirst(indexpr_item);
-					if (indexkey && IsA(indexkey, RelabelType))
-						indexkey = (Node *) ((RelabelType *) indexkey)->arg;
-					if (equal(node, indexkey))
+					if (equal(basenode, indexkey))
 					{
 						/*
 						 * Found a match ... is it a unique index? Tests here
@@ -5925,12 +5926,8 @@ examine_variable(PlannerInfo *root, Node *node, int varRelid,
 
 				Assert(expr);
 
-				/* strip RelabelType before comparing it */
-				if (expr && IsA(expr, RelabelType))
-					expr = (Node *) ((RelabelType *) expr)->arg;
-
 				/* found a match, see if we can extract pg_statistic row */
-				if (equal(node, expr))
+				if (equal(basenode, expr))
 				{
 					/*
 					 * XXX Not sure if we should cache the tuple somewhere.
@@ -9341,3 +9338,56 @@ brincostestimate(PlannerInfo *root, IndexPath *path, double loop_count,
 
 	*indexPages = index->pages;
 }
+
+/*
+ * strip_all_adjacency_relabeltypes_walker
+ *		Walker to deeply strip all adjacent RelabelTypes.
+ *
+ * If node is RelabelType, the behavior is almost like applyRelabelType().
+ */
+static bool
+strip_all_adjacency_relabeltypes_walker(Node *node, void *context)
+{
+	if (node == NULL)
+		return false;
+
+	if (IsA(node, RelabelType))
+	{
+		RelabelType 	*relabel = (RelabelType *) node;
+		Node			*arg = (Node *) relabel->arg;
+
+		/* If we find stacked RelabelTypes (eg, from foo::int::oid) we can discard
+		 * all but the top one, and must do so to ensure that semantically
+		 * equivalent expressions are equal().
+		 */
+		while (arg && IsA(arg, RelabelType))
+			arg = (Node *) ((RelabelType *) arg)->arg;
+
+		relabel->arg = (Expr *) arg;
+
+		if (arg == NULL)
+			return false;
+
+		if (IsA(arg, Const))
+		{
+			/* Modify the Const directly to preserve const-flatness. */
+			Const	   *con = (Const *) arg;
+
+			con->consttype = relabel->resulttype;
+			con->consttypmod = relabel->resulttypmod;
+			con->constcollid = relabel->resultcollid;
+			/* We keep the Const's original location. */
+			node = arg;
+
+			return false;
+		}
+		else if (exprType(arg) == relabel->resulttype &&
+			exprTypmod(arg) == relabel->resulttypmod &&
+			exprCollation(arg) == relabel->resultcollid)
+		{
+			node = arg;
+		}
+	}
+
+	return expression_tree_walker(node, strip_all_adjacency_relabeltypes_walker, context);
+}
-- 
2.43.0

