1/*-------------------------------------------------------------------------
4 * Functions for assigning PARAM_EXEC slots during planning.
6 * This module is responsible for managing three planner data structures:
8 * root->glob->paramExecTypes: records actual assignments of PARAM_EXEC slots.
9 * The i'th list element holds the data type OID of the i'th parameter slot.
10 * (Elements can be InvalidOid if they represent slots that are needed for
11 * chgParam signaling, but will never hold a value at runtime.) This list is
12 * global to the whole plan since the executor has only one PARAM_EXEC array.
13 * Assignments are permanent for the plan: we never remove entries once added.
15 * root->plan_params: a list of PlannerParamItem nodes, recording Vars and
16 * PlaceHolderVars that the root's query level needs to supply to lower-level
17 * subqueries, along with the PARAM_EXEC number to use for each such value.
18 * Elements are added to this list while planning a subquery, and the list
19 * is reset to empty after completion of each subquery.
21 * root->curOuterParams: a list of NestLoopParam nodes, recording Vars and
22 * PlaceHolderVars that some outer level of nestloop needs to pass down to
23 * a lower-level plan node in its righthand side. Elements are added to this
24 * list as createplan.c creates lower Plan nodes that need such Params, and
25 * are removed when it creates a NestLoop Plan node that will supply those
28 * The latter two data structures are used to prevent creating multiple
29 * PARAM_EXEC slots (each requiring work to fill) when the same upper
30 * SubPlan or NestLoop supplies a value that is referenced in more than
31 * one place in its child plan nodes. However, when the same Var has to
32 * be supplied to different subplan trees by different SubPlan or NestLoop
33 * parent nodes, we don't recognize any commonality; a fresh plan_params or
34 * curOuterParams entry will be made (since the old one has been removed
35 * when we finished processing the earlier SubPlan or NestLoop) and a fresh
36 * PARAM_EXEC number will be assigned. At one time we tried to avoid
37 * allocating duplicate PARAM_EXEC numbers in such cases, but it's harder
38 * than it seems to avoid bugs due to overlapping Param lifetimes, so we
39 * don't risk that anymore. Minimizing the number of PARAM_EXEC slots
40 * doesn't really save much executor work anyway.
43 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
44 * Portions Copyright (c) 1994, Regents of the University of California
47 * src/backend/optimizer/util/paramassign.c
49 *-------------------------------------------------------------------------
61 * Select a PARAM_EXEC number to identify the given Var as a parameter for
62 * the current subquery. (It might already have one.)
63 * Record the need for the Var in the proper upper-level root->plan_params.
72 /* Find the query level the Var belongs to */
73 for (levelsup = var->
varlevelsup; levelsup > 0; levelsup--)
76 /* If there's already a matching PlannerParamItem there, just use it */
77 foreach(ppl,
root->plan_params)
85 * This comparison must match _equalVar(), except for ignoring
86 * varlevelsup. Note that _equalVar() ignores varnosyn,
87 * varattnosyn, and location, so this does too.
91 pvar->vartype == var->vartype &&
92 pvar->vartypmod == var->vartypmod &&
93 pvar->varcollid == var->varcollid &&
95 bms_equal(pvar->varnullingrels, var->varnullingrels))
100 /* Nope, so make a new one */
116 * Generate a Param node to replace the given Var,
117 * which is expected to have varlevelsup > 0 (ie, it is not local).
118 * Record the need for the Var in the proper upper-level root->plan_params.
128 /* Find the Var in the appropriate plan_params, or add it if not present */
143 * Select a PARAM_EXEC number to identify the given PlaceHolderVar as a
144 * parameter for the current subquery. (It might already have one.)
145 * Record the need for the PHV in the proper upper-level root->plan_params.
147 * This is just like assign_param_for_var, except for PlaceHolderVars.
156 /* Find the query level the PHV belongs to */
157 for (levelsup = phv->
phlevelsup; levelsup > 0; levelsup--)
160 /* If there's already a matching PlannerParamItem there, just use it */
161 foreach(ppl,
root->plan_params)
168 /* We assume comparing the PHIDs is sufficient */
174 /* Nope, so make a new one */
191 * Generate a Param node to replace the given PlaceHolderVar,
192 * which is expected to have phlevelsup > 0 (ie, it is not local).
193 * Record the need for the PHV in the proper upper-level root->plan_params.
195 * This is just like replace_outer_var, except for PlaceHolderVars.
205 /* Find the PHV in the appropriate plan_params, or add it if not present */
220 * Generate a Param node to replace the given Aggref
221 * which is expected to have agglevelsup > 0 (ie, it is not local).
222 * Record the need for the Aggref in the proper upper-level root->plan_params.
231 Assert(agg->agglevelsup > 0 && agg->agglevelsup <
root->query_level);
233 /* Find the query level the Aggref belongs to */
234 for (levelsup = agg->agglevelsup; levelsup > 0; levelsup--)
238 * It does not seem worthwhile to try to de-duplicate references to outer
239 * aggs. Just make a new slot every time.
243 Assert(agg->agglevelsup == 0);
265 * Generate a Param node to replace the given GroupingFunc expression which is
266 * expected to have agglevelsup > 0 (ie, it is not local).
267 * Record the need for the GroupingFunc in the proper upper-level
280 /* Find the query level the GroupingFunc belongs to */
281 for (levelsup = grp->
agglevelsup; levelsup > 0; levelsup--)
285 * It does not seem worthwhile to try to de-duplicate references to outer
286 * aggs. Just make a new slot every time.
312 * Generate a Param node to replace the given MergeSupportFunc expression
313 * which is expected to be in the RETURNING list of an upper-level MERGE
314 * query. Record the need for the MergeSupportFunc in the proper upper-level
327 * The parser should have ensured that the MergeSupportFunc is in the
328 * RETURNING list of an upper-level MERGE query, so find that query.
334 elog(
ERROR,
"MergeSupportFunc found outside MERGE");
338 * It does not seem worthwhile to try to de-duplicate references to outer
339 * MergeSupportFunc expressions. Just make a new slot every time.
363 * Generate a Param node to replace the given ReturningExpr expression which
364 * is expected to have retlevelsup > 0 (ie, it is not local). Record the need
365 * for the ReturningExpr in the proper upper-level root->plan_params.
377 /* Find the query level the ReturningExpr belongs to */
378 for (levelsup = rexpr->
retlevelsup; levelsup > 0; levelsup--)
382 * It does not seem worthwhile to try to de-duplicate references to outer
383 * ReturningExprs. Just make a new slot every time.
409 * Generate a Param node to replace the given Var,
410 * which is expected to come from some upper NestLoop plan node.
411 * Record the need for the Var in root->curOuterParams.
420 /* Is this Var already listed in root->curOuterParams? */
421 foreach(lc,
root->curOuterParams)
426 /* Yes, so just make a Param referencing this NLP's slot */
438 /* No, so assign a PARAM_EXEC slot for a new NLP */
445 /* Add it to the list of required NLPs */
451 /* And return the replacement Param */
456 * Generate a Param node to replace the given PlaceHolderVar,
457 * which is expected to come from some upper NestLoop plan node.
458 * Record the need for the PHV in root->curOuterParams.
460 * This is just like replace_nestloop_param_var, except for PlaceHolderVars.
469 /* Is this PHV already listed in root->curOuterParams? */
470 foreach(lc,
root->curOuterParams)
475 /* Yes, so just make a Param referencing this NLP's slot */
487 /* No, so assign a PARAM_EXEC slot for a new NLP */
493 /* Add it to the list of required NLPs */
499 /* And return the replacement Param */
504 * process_subquery_nestloop_params
505 * Handle params of a parameterized subquery that need to be fed
506 * from an outer nestloop.
508 * Currently, that would be *all* params that a subquery in FROM has demanded
509 * from the current query level, since they must be LATERAL references.
511 * subplan_params is a list of PlannerParamItems that we intend to pass to
512 * a subquery-in-FROM. (This was constructed in root->plan_params while
513 * planning the subquery, but isn't there anymore when this is called.)
515 * The subplan's references to the outer variables are already represented
516 * as PARAM_EXEC Params, since that conversion was done by the routines above
517 * while planning the subquery. So we need not modify the subplan or the
518 * PlannerParamItems here. What we do need to do is add entries to
519 * root->curOuterParams to signal the parent nestloop plan node that it must
520 * provide these values. This differs from replace_nestloop_param_var in
521 * that the PARAM_EXEC slots to use have already been determined.
523 * Note that we also use root->curOuterRels as an implicit parameter for
531 foreach(lc, subplan_params)
541 /* If not from a nestloop outer rel, complain */
543 elog(
ERROR,
"non-LATERAL parameter required by subquery");
545 /* Is this param already listed in root->curOuterParams? */
546 foreach(lc2,
root->curOuterParams)
549 if (nlp->paramno == pitem->
paramId)
552 /* Present, so nothing to do */
571 /* If not from a nestloop outer rel, complain */
574 elog(
ERROR,
"non-LATERAL parameter required by subquery");
576 /* Is this param already listed in root->curOuterParams? */
577 foreach(lc2,
root->curOuterParams)
580 if (nlp->paramno == pitem->
paramId)
583 /* Present, so nothing to do */
597 elog(
ERROR,
"unexpected type of subquery parameter");
602 * Identify any NestLoopParams that should be supplied by a NestLoop
603 * plan node with the specified lefthand rels and required-outer rels.
604 * Remove them from the active root->curOuterParams list and return
605 * them as the result list.
607 * Vars and PHVs appearing in the result list must have nullingrel sets
608 * that could validly appear in the lefthand rel's output. Ordinarily that
609 * would be true already, but if we have applied outer join identity 3,
610 * there could be more or fewer nullingrel bits in the nodes appearing in
611 * curOuterParams than are in the nominal leftrelids. We deal with that by
612 * forcing their nullingrel sets to include exactly the outer-join relids
613 * that appear in leftrelids and can null the respective Var or PHV.
614 * This fix is a bit ad-hoc and intellectually unsatisfactory, because it's
615 * essentially jumping to the conclusion that we've placed evaluation of
616 * the nestloop parameters correctly, and thus it defeats the intent of the
617 * subsequent nullingrel cross-checks in setrefs.c. But the alternative
618 * seems to be to generate multiple versions of each laterally-parameterized
619 * subquery, which'd be unduly expensive.
631 * We'll be able to evaluate a PHV in the lefthand path if it uses the
632 * lefthand rels plus any available required-outer rels. But don't do so
633 * if it uses *only* required-outer rels; in that case it should be
634 * evaluated higher in the tree. For Vars, no such hair-splitting is
635 * necessary since they depend on only one relid.
638 allleftrelids =
bms_union(leftrelids, outerrelids);
640 allleftrelids = leftrelids;
643 foreach(cell,
root->curOuterParams)
648 * We are looking for Vars and PHVs that can be supplied by the
649 * lefthand rels. When we find one, it's okay to modify it in-place
650 * because all the routines above make a fresh copy to put into
669 Relids eval_at = phinfo->ph_eval_at;
678 * Deal with an edge case: if the PHV was pulled up out of a
679 * subquery and it contains a subquery that was originally
680 * pushed down from this query level, then that will still be
681 * represented as a SubLink, because SS_process_sublinks won't
682 * recurse into outer PHVs, so it didn't get transformed
683 * during expression preprocessing in the subquery. We need a
684 * version of the PHV that has a SubPlan, which we can get
685 * from the current query level's placeholder_list. This is
686 * quite grotty of course, but dealing with it earlier in the
687 * handling of subplan params would be just as grotty, and it
688 * might end up being a waste of cycles if we don't decide to
689 * treat the PHV as a NestLoopParam. (Perhaps that whole
690 * mechanism should be redesigned someday, but today is not
693 if (
root->parse->hasSubLinks)
698 * The ph_var will have empty nullingrels, but that
699 * doesn't matter since we're about to overwrite
700 * phv->phnullingrels. Other fields should be OK already.
717 * Generate a new Param node that will not conflict with any other.
719 * This is used to create Params representing subplan outputs or
720 * NestLoop parameters.
722 * We don't need to build a PlannerParamItem for such a Param, but we do
723 * need to make sure we record the type in paramExecTypes (otherwise,
724 * there won't be a slot allocated for it).
746 * Assign a (nonnegative) PARAM_EXEC ID for a special parameter (one that
747 * is not actually used to carry a value at runtime). Such parameters are
748 * used for special runtime signaling purposes, such as connecting a
749 * recursive union node to its worktable scan node or forcing plan
750 * re-evaluation within the EvalPlanQual mechanism. No actual Param node
751 * exists with this ID, however.
Bitmapset * bms_intersect(const Bitmapset *a, const Bitmapset *b)
bool bms_equal(const Bitmapset *a, const Bitmapset *b)
bool bms_is_subset(const Bitmapset *a, const Bitmapset *b)
bool bms_is_member(int x, const Bitmapset *a)
Bitmapset * bms_union(const Bitmapset *a, const Bitmapset *b)
bool bms_overlap(const Bitmapset *a, const Bitmapset *b)
bool equal(const void *a, const void *b)
Assert(PointerIsAligned(start, uint64))
if(TABLE==NULL||TABLE_index==NULL)
List * lappend(List *list, void *datum)
List * lappend_oid(List *list, Oid datum)
Oid exprType(const Node *expr)
int32 exprTypmod(const Node *expr)
Oid exprCollation(const Node *expr)
int exprLocation(const Node *expr)
#define IsA(nodeptr, _type_)
Param * replace_outer_merge_support(PlannerInfo *root, MergeSupportFunc *msf)
static int assign_param_for_var(PlannerInfo *root, Var *var)
static int assign_param_for_placeholdervar(PlannerInfo *root, PlaceHolderVar *phv)
Param * generate_new_exec_param(PlannerInfo *root, Oid paramtype, int32 paramtypmod, Oid paramcollation)
Param * replace_outer_agg(PlannerInfo *root, Aggref *agg)
Param * replace_outer_returning(PlannerInfo *root, ReturningExpr *rexpr)
Param * replace_outer_grouping(PlannerInfo *root, GroupingFunc *grp)
Param * replace_outer_var(PlannerInfo *root, Var *var)
void process_subquery_nestloop_params(PlannerInfo *root, List *subplan_params)
List * identify_current_nestloop_params(PlannerInfo *root, Relids leftrelids, Relids outerrelids)
Param * replace_outer_placeholdervar(PlannerInfo *root, PlaceHolderVar *phv)
Param * replace_nestloop_param_placeholdervar(PlannerInfo *root, PlaceHolderVar *phv)
int assign_special_exec_param(PlannerInfo *root)
Param * replace_nestloop_param_var(PlannerInfo *root, Var *var)
#define lfirst_node(type, lc)
static int list_length(const List *l)
#define foreach_delete_current(lst, var_or_cell)
Relids get_placeholder_nulling_relids(PlannerInfo *root, PlaceHolderInfo *phinfo)
PlaceHolderInfo * find_placeholder_info(PlannerInfo *root, PlaceHolderVar *phv)
void IncrementVarSublevelsUp(Node *node, int delta_sublevels_up, int min_sublevels_up)
VarReturningType varreturningtype