From c9fb279cd696a6460472fde7a037e667d958db78 Mon Sep 17 00:00:00 2001 From: "Zizhuan Liu(X-MAN)" <44973863@qq.com> Date: Mon, 17 Aug 2026 22:21:14 +0800 Subject: [PATCH v3] proper-handling-examine_variable-RelabelType --- src/backend/utils/adt/selfuncs.c | 88 +++++++++++++++++++++++++++----- 1 file changed, 75 insertions(+), 13 deletions(-) diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c index e27ec9e5..21ab207b 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 @@ -5656,6 +5657,7 @@ examine_variable(PlannerInfo *root, Node *node, int varRelid, Relids varnos; Relids basevarnos; RelOptInfo *onerel; + Node *save_node; /* Make sure we don't return dangling pointers in vardata */ MemSet(vardata, 0, sizeof(VariableStatData)); @@ -5673,12 +5675,24 @@ 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. + * eval_const_expressions() should already have stripped adjacent + * RelabelTypes. However, stripping PlaceHolderVars above may have + * brought previously separated RelabelTypes into adjacency, whether + * at the top level or within a deeper subtree. Therefore, run + * strip_all_adjacency_relabeltypes_walker() to normalize the expression. + * + * If the outermost RelabelType and its underlying argument have the same + * type, typmod, and collation, and the argument is a base Var, + * strip_all_adjacency_relabeltypes_walker() reduces the RelabelType chain + * to that Var, making the expression equivalent to a plain base Var. + * + * Keep the stripped result in save_node rather than modifying the + * original node. The result is used to compare against indexprs and + * extended-statistics expressions, which are also processed by + * eval_const_expressions() and compared using equal(). */ - while (IsA(basenode, RelabelType)) - basenode = (Node *) ((RelabelType *) basenode)->arg; + strip_all_adjacency_relabeltypes_walker(basenode, NULL); + save_node = basenode; /* Fast path for a simple Var */ if (IsA(basenode, Var) && @@ -5799,9 +5813,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(save_node, indexkey)) { /* * Found a match ... is it a unique index? Tests here @@ -5925,12 +5937,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(save_node, expr)) { /* * XXX Not sure if we should cache the tuple somewhere. @@ -9341,3 +9349,57 @@ brincostestimate(PlannerInfo *root, IndexPath *path, double loop_count, *indexPages = index->pages; } + +/* + * strip_all_adjacency_relabeltypes_walker + * Walker to deeply strip all adjacent RelabelTypes. + * + * If the outermost RelabelType and its underlying argument have the same + * type, typmod, and collation, and the argument is a base Var, + * strip_all_adjacency_relabeltypes_walker() reduces the RelabelType chain + * to that Var, making the expression equivalent to a plain base Var. + */ +static bool +strip_all_adjacency_relabeltypes_walker(Node *node, void *context) +{ + if (node == NULL) + return false; + + if (IsA(node, RelabelType)) + { + RelabelType *relabel = (RelabelType *) node; + + if (relabel->arg == NULL) + return false; + + if (IsA(relabel->arg, RelabelType)) + { + Expr *expr = relabel->arg; + + /* Strip adjacent RelabelTypes iteratively to avoid recursive calls. */ + while (expr && IsA(expr, RelabelType)) + expr = ((RelabelType *) expr)->arg; + + relabel->arg = expr; + + if (relabel->arg == NULL) + return false; + } + + if (IsA(relabel->arg, Var)) + { + Var *var = (Var *) relabel->arg; + + if (relabel->resulttype == var->vartype && + relabel->resulttypmod == var->vartypmod && + relabel->resultcollid == var->varcollid) + { + /* RelabelType equivalent to a plain base Var. */ + node = (Node *) var; + } + return false; + } + } + + return expression_tree_walker(node, strip_all_adjacency_relabeltypes_walker, context); +} -- 2.43.0