This is an automated email from the ASF dual-hosted git repository.
chenjinbao1989 pushed a commit to branch cbdb-postgres-merge
in repository https://gitbox.apache.org/repos/asf/cloudberry.git
The following commit(s) were added to refs/heads/cbdb-postgres-merge by this
push:
new 2d4feaf4a2b Bring update_placeholder_eval_levels back
2d4feaf4a2b is described below
commit 2d4feaf4a2ba764ad43d3679b3902dc590012d89
Author: Jinbao Chen <[email protected]>
AuthorDate: Sat Nov 22 22:09:33 2025 +0800
Bring update_placeholder_eval_levels back
---
src/backend/optimizer/plan/initsplan.c | 5 +-
src/backend/optimizer/util/placeholder.c | 94 ++++++++++++++++++++++++++++++++
src/include/optimizer/placeholder.h | 1 +
3 files changed, 99 insertions(+), 1 deletion(-)
diff --git a/src/backend/optimizer/plan/initsplan.c
b/src/backend/optimizer/plan/initsplan.c
index 8b29d23a032..b65897043ca 100644
--- a/src/backend/optimizer/plan/initsplan.c
+++ b/src/backend/optimizer/plan/initsplan.c
@@ -1216,7 +1216,7 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode,
/* Compute qualscope etc */
jtitem->qualscope =
bms_union(left_item->qualscope,
right_item->qualscope);
- jtitem->inner_join_rels = jtitem->qualscope;
+ jtitem->inner_join_rels =
bms_copy(jtitem->qualscope);
jtitem->left_rels = left_item->qualscope;
jtitem->right_rels = right_item->qualscope;
/* Inner join adds no restrictions for quals */
@@ -1531,7 +1531,10 @@ deconstruct_distribute(PlannerInfo *root, JoinTreeItem
*jtitem)
/* And add the SpecialJoinInfo to join_info_list */
if (sjinfo)
+ {
root->join_info_list = lappend(root->join_info_list,
sjinfo);
+ update_placeholder_eval_levels(root, sjinfo);
+ }
}
else
{
diff --git a/src/backend/optimizer/util/placeholder.c
b/src/backend/optimizer/util/placeholder.c
index 200ae30edb8..2282632d1cc 100644
--- a/src/backend/optimizer/util/placeholder.c
+++ b/src/backend/optimizer/util/placeholder.c
@@ -281,6 +281,100 @@ find_placeholders_in_expr(PlannerInfo *root, Node *expr)
list_free(vars);
}
+/*
+ * update_placeholder_eval_levels
+ * Adjust the target evaluation levels for placeholders
+ *
+ * The initial eval_at level set by find_placeholder_info was the set of
+ * rels used in the placeholder's expression (or the whole subselect below
+ * the placeholder's syntactic location, if the expr is variable-free).
+ * If the query contains any outer joins that can null any of those rels,
+ * we must delay evaluation to above those joins.
+ *
+ * We repeat this operation each time we add another outer join to
+ * root->join_info_list. It's somewhat annoying to have to do that, but
+ * since we don't have very much information on the placeholders' locations,
+ * it's hard to avoid. Each placeholder's eval_at level must be correct
+ * by the time it starts to figure in outer-join delay decisions for higher
+ * outer joins.
+ *
+ * In future we might want to put additional policy/heuristics here to
+ * try to determine an optimal evaluation level. The current rules will
+ * result in evaluation at the lowest possible level. However, pushing a
+ * placeholder eval up the tree is likely to further constrain evaluation
+ * order for outer joins, so it could easily be counterproductive; and we
+ * don't have enough information at this point to make an intelligent choice.
+ */
+void
+update_placeholder_eval_levels(PlannerInfo *root, SpecialJoinInfo *new_sjinfo)
+{
+ ListCell *lc1;
+
+ foreach(lc1, root->placeholder_list)
+ {
+ PlaceHolderInfo *phinfo = (PlaceHolderInfo *) lfirst(lc1);
+ Relids syn_level = phinfo->ph_var->phrels;
+ Relids eval_at;
+ bool found_some;
+ ListCell *lc2;
+
+ /*
+ * We don't need to do any work on this placeholder unless the
+ * newly-added outer join is syntactically beneath its location.
+ */
+ if (!bms_is_subset(new_sjinfo->syn_lefthand, syn_level) ||
+ !bms_is_subset(new_sjinfo->syn_righthand, syn_level))
+ continue;
+
+ /*
+ * Check for delays due to lower outer joins. This is the same
logic
+ * as in check_outerjoin_delay in initsplan.c, except that we
don't
+ * have anything to do with the delay_upper_joins flags; delay
of
+ * upper outer joins will be handled later, based on the eval_at
+ * values we compute now.
+ */
+ eval_at = phinfo->ph_eval_at;
+
+ do
+ {
+ found_some = false;
+ foreach(lc2, root->join_info_list)
+ {
+ SpecialJoinInfo *sjinfo = (SpecialJoinInfo *)
lfirst(lc2);
+
+ /* disregard joins not within the PHV's
sub-select */
+ if (!bms_is_subset(sjinfo->syn_lefthand,
syn_level) ||
+ !bms_is_subset(sjinfo->syn_righthand,
syn_level))
+ continue;
+
+ /* do we reference any nullable rels of this
OJ? */
+ if (bms_overlap(eval_at, sjinfo->min_righthand)
||
+ (sjinfo->jointype == JOIN_FULL &&
+ bms_overlap(eval_at,
sjinfo->min_lefthand)))
+ {
+ /* yes; have we included all its rels
in eval_at? */
+ if
(!bms_is_subset(sjinfo->min_lefthand, eval_at) ||
+
!bms_is_subset(sjinfo->min_righthand, eval_at))
+ {
+ /* no, so add them in */
+ eval_at =
bms_add_members(eval_at,
+
sjinfo->min_lefthand);
+ eval_at =
bms_add_members(eval_at,
+
sjinfo->min_righthand);
+ /* we'll need another iteration
*/
+ found_some = true;
+ }
+ }
+ }
+ } while (found_some);
+
+ /* Can't move the PHV's eval_at level to above its syntactic
level */
+ Assert(bms_is_subset(eval_at, syn_level));
+
+ phinfo->ph_eval_at = eval_at;
+ }
+}
+
/*
* fix_placeholder_input_needed_levels
* Adjust the "needed at" levels for placeholder inputs
diff --git a/src/include/optimizer/placeholder.h
b/src/include/optimizer/placeholder.h
index 6653ac3fdc9..86c2b9151e6 100644
--- a/src/include/optimizer/placeholder.h
+++ b/src/include/optimizer/placeholder.h
@@ -32,5 +32,6 @@ extern bool contain_placeholder_references_to(PlannerInfo
*root, Node *clause,
int relid);
extern void make_placeholders_for_subplans(PlannerInfo *root);
+extern void update_placeholder_eval_levels(PlannerInfo *root, SpecialJoinInfo
*new_sjinfo);
#endif /* PLACEHOLDER_H */
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]