#include "postgres.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/pathnode.h"
#include "optimizer/placeholder.h"
#include "optimizer/planmain.h"
#include "optimizer/var.h"
#include "utils/lsyscache.h"
Go to the source code of this file.
Functions | |
static Relids | find_placeholders_recurse (PlannerInfo *root, Node *jtnode) |
static void | mark_placeholders_in_expr (PlannerInfo *root, Node *expr, Relids relids) |
PlaceHolderVar * | make_placeholder_expr (PlannerInfo *root, Expr *expr, Relids phrels) |
PlaceHolderInfo * | find_placeholder_info (PlannerInfo *root, PlaceHolderVar *phv, bool create_new_ph) |
void | find_placeholders_in_jointree (PlannerInfo *root) |
void | mark_placeholder_maybe_needed (PlannerInfo *root, PlaceHolderInfo *phinfo, Relids relids) |
void | update_placeholder_eval_levels (PlannerInfo *root, SpecialJoinInfo *new_sjinfo) |
void | fix_placeholder_input_needed_levels (PlannerInfo *root) |
void | add_placeholders_to_base_rels (PlannerInfo *root) |
void | add_placeholders_to_joinrel (PlannerInfo *root, RelOptInfo *joinrel) |
void add_placeholders_to_base_rels | ( | PlannerInfo * | root | ) |
Definition at line 415 of file placeholder.c.
References bms_membership(), bms_nonempty_difference(), BMS_SINGLETON, bms_singleton_member(), copyObject(), find_base_rel(), lappend(), lfirst, PlaceHolderInfo::ph_eval_at, PlaceHolderInfo::ph_needed, PlaceHolderInfo::ph_var, PlannerInfo::placeholder_list, and RelOptInfo::reltargetlist.
Referenced by query_planner().
{ ListCell *lc; foreach(lc, root->placeholder_list) { PlaceHolderInfo *phinfo = (PlaceHolderInfo *) lfirst(lc); Relids eval_at = phinfo->ph_eval_at; if (bms_membership(eval_at) == BMS_SINGLETON && bms_nonempty_difference(phinfo->ph_needed, eval_at)) { int varno = bms_singleton_member(eval_at); RelOptInfo *rel = find_base_rel(root, varno); rel->reltargetlist = lappend(rel->reltargetlist, copyObject(phinfo->ph_var)); } } }
void add_placeholders_to_joinrel | ( | PlannerInfo * | root, | |
RelOptInfo * | joinrel | |||
) |
Definition at line 446 of file placeholder.c.
References bms_is_subset(), bms_nonempty_difference(), lappend(), lfirst, PlaceHolderInfo::ph_eval_at, PlaceHolderInfo::ph_needed, PlaceHolderInfo::ph_var, PlaceHolderInfo::ph_width, PlannerInfo::placeholder_list, RelOptInfo::relids, RelOptInfo::reltargetlist, and RelOptInfo::width.
Referenced by build_join_rel().
{ Relids relids = joinrel->relids; ListCell *lc; foreach(lc, root->placeholder_list) { PlaceHolderInfo *phinfo = (PlaceHolderInfo *) lfirst(lc); /* Is it still needed above this joinrel? */ if (bms_nonempty_difference(phinfo->ph_needed, relids)) { /* Is it computable here? */ if (bms_is_subset(phinfo->ph_eval_at, relids)) { /* Yup, add it to the output */ joinrel->reltargetlist = lappend(joinrel->reltargetlist, phinfo->ph_var); joinrel->width += phinfo->ph_width; } } } }
PlaceHolderInfo* find_placeholder_info | ( | PlannerInfo * | root, | |
PlaceHolderVar * | phv, | |||
bool | create_new_ph | |||
) |
Definition at line 69 of file placeholder.c.
References Assert, copyObject(), elog, ERROR, exprType(), exprTypmod(), get_typavgwidth(), lappend(), lfirst, makeNode, PlaceHolderInfo::ph_eval_at, PlaceHolderInfo::ph_may_need, PlaceHolderInfo::ph_needed, PlaceHolderInfo::ph_var, PlaceHolderInfo::ph_width, PlaceHolderVar::phid, PlaceHolderInfo::phid, PlaceHolderVar::phlevelsup, PlannerInfo::placeholder_list, and pull_varnos().
Referenced by add_vars_to_targetlist(), create_lateral_join_info(), create_nestloop_plan(), mark_placeholders_in_expr(), process_subquery_nestloop_params(), replace_nestloop_params_mutator(), and set_rel_width().
{ PlaceHolderInfo *phinfo; ListCell *lc; /* if this ever isn't true, we'd need to be able to look in parent lists */ Assert(phv->phlevelsup == 0); foreach(lc, root->placeholder_list) { phinfo = (PlaceHolderInfo *) lfirst(lc); if (phinfo->phid == phv->phid) return phinfo; } /* Not found, so create it */ if (!create_new_ph) elog(ERROR, "too late to create a new PlaceHolderInfo"); phinfo = makeNode(PlaceHolderInfo); phinfo->phid = phv->phid; phinfo->ph_var = copyObject(phv); phinfo->ph_eval_at = pull_varnos((Node *) phv); /* ph_eval_at may change later, see update_placeholder_eval_levels */ phinfo->ph_needed = NULL; /* initially it's unused */ phinfo->ph_may_need = NULL; /* for the moment, estimate width using just the datatype info */ phinfo->ph_width = get_typavgwidth(exprType((Node *) phv->phexpr), exprTypmod((Node *) phv->phexpr)); root->placeholder_list = lappend(root->placeholder_list, phinfo); return phinfo; }
void find_placeholders_in_jointree | ( | PlannerInfo * | root | ) |
Definition at line 114 of file placeholder.c.
References Assert, find_placeholders_recurse(), PlannerInfo::glob, IsA, Query::jointree, PlannerGlobal::lastPHId, NULL, and PlannerInfo::parse.
Referenced by query_planner().
static Relids find_placeholders_recurse | ( | PlannerInfo * | root, | |
Node * | jtnode | |||
) | [static] |
Definition at line 136 of file placeholder.c.
References bms_join(), bms_make_singleton(), elog, ERROR, FromExpr::fromlist, IsA, JoinExpr::larg, lfirst, mark_placeholders_in_expr(), nodeTag, NULL, JoinExpr::quals, FromExpr::quals, and JoinExpr::rarg.
Referenced by find_placeholders_in_jointree().
{ Relids jtrelids; if (jtnode == NULL) return NULL; if (IsA(jtnode, RangeTblRef)) { int varno = ((RangeTblRef *) jtnode)->rtindex; /* No quals to deal with, just return correct result */ jtrelids = bms_make_singleton(varno); } else if (IsA(jtnode, FromExpr)) { FromExpr *f = (FromExpr *) jtnode; ListCell *l; /* * First, recurse to handle child joins, and form their relid set. */ jtrelids = NULL; foreach(l, f->fromlist) { Relids sub_relids; sub_relids = find_placeholders_recurse(root, lfirst(l)); jtrelids = bms_join(jtrelids, sub_relids); } /* * Now process the top-level quals. */ mark_placeholders_in_expr(root, f->quals, jtrelids); } else if (IsA(jtnode, JoinExpr)) { JoinExpr *j = (JoinExpr *) jtnode; Relids leftids, rightids; /* * First, recurse to handle child joins, and form their relid set. */ leftids = find_placeholders_recurse(root, j->larg); rightids = find_placeholders_recurse(root, j->rarg); jtrelids = bms_join(leftids, rightids); /* Process the qual clauses */ mark_placeholders_in_expr(root, j->quals, jtrelids); } else { elog(ERROR, "unrecognized node type: %d", (int) nodeTag(jtnode)); jtrelids = NULL; /* keep compiler quiet */ } return jtrelids; }
void fix_placeholder_input_needed_levels | ( | PlannerInfo * | root | ) |
Definition at line 381 of file placeholder.c.
References add_vars_to_targetlist(), bms_membership(), lfirst, list_free(), PlaceHolderInfo::ph_eval_at, PlaceHolderInfo::ph_var, PlaceHolderVar::phexpr, PlannerInfo::placeholder_list, pull_var_clause(), PVC_INCLUDE_PLACEHOLDERS, and PVC_RECURSE_AGGREGATES.
Referenced by query_planner().
{ ListCell *lc; foreach(lc, root->placeholder_list) { PlaceHolderInfo *phinfo = (PlaceHolderInfo *) lfirst(lc); Relids eval_at = phinfo->ph_eval_at; /* No work unless it'll be evaluated above baserel level */ if (bms_membership(eval_at) == BMS_MULTIPLE) { List *vars = pull_var_clause((Node *) phinfo->ph_var->phexpr, PVC_RECURSE_AGGREGATES, PVC_INCLUDE_PLACEHOLDERS); add_vars_to_targetlist(root, vars, eval_at, false); list_free(vars); } } }
PlaceHolderVar* make_placeholder_expr | ( | PlannerInfo * | root, | |
Expr * | expr, | |||
Relids | phrels | |||
) |
Definition at line 39 of file placeholder.c.
References PlannerInfo::glob, PlannerGlobal::lastPHId, makeNode, PlaceHolderVar::phexpr, PlaceHolderVar::phid, PlaceHolderVar::phlevelsup, and PlaceHolderVar::phrels.
Referenced by pullup_replace_vars_callback().
{ PlaceHolderVar *phv = makeNode(PlaceHolderVar); phv->phexpr = expr; phv->phrels = phrels; phv->phid = ++(root->glob->lastPHId); phv->phlevelsup = 0; return phv; }
void mark_placeholder_maybe_needed | ( | PlannerInfo * | root, | |
PlaceHolderInfo * | phinfo, | |||
Relids | relids | |||
) |
Definition at line 250 of file placeholder.c.
References bms_add_members(), bms_free(), bms_union(), mark_placeholders_in_expr(), PlaceHolderInfo::ph_eval_at, PlaceHolderInfo::ph_may_need, PlaceHolderInfo::ph_var, PlaceHolderVar::phexpr, and PlaceHolderVar::phrels.
Referenced by add_vars_to_targetlist(), and mark_placeholders_in_expr().
{ Relids est_eval_level; /* Mark the PHV as possibly needed at the given syntactic level */ phinfo->ph_may_need = bms_add_members(phinfo->ph_may_need, relids); /* * This is a bit tricky: the PHV's contained expression may contain other, * lower-level PHVs. We need to get those into the PlaceHolderInfo list, * but they aren't going to be needed where the outer PHV is referenced. * Rather, they'll be needed where the outer PHV is evaluated. We can * estimate that conservatively as the syntactic location of the PHV's * expression, but not less than the level of any Vars it contains. * (Normally the Vars would come from below the syntactic location anyway, * but this might not be true if the PHV contains any LATERAL references.) */ est_eval_level = bms_union(phinfo->ph_var->phrels, phinfo->ph_eval_at); /* Now recurse to take care of any such PHVs */ mark_placeholders_in_expr(root, (Node *) phinfo->ph_var->phexpr, est_eval_level); bms_free(est_eval_level); }
static void mark_placeholders_in_expr | ( | PlannerInfo * | root, | |
Node * | expr, | |||
Relids | relids | |||
) | [static] |
Definition at line 205 of file placeholder.c.
References find_placeholder_info(), IsA, lfirst, list_free(), mark_placeholder_maybe_needed(), pull_var_clause(), PVC_INCLUDE_PLACEHOLDERS, and PVC_RECURSE_AGGREGATES.
Referenced by find_placeholders_recurse(), and mark_placeholder_maybe_needed().
{ List *vars; ListCell *vl; /* * pull_var_clause does more than we need here, but it'll do and it's * convenient to use. */ vars = pull_var_clause(expr, PVC_RECURSE_AGGREGATES, PVC_INCLUDE_PLACEHOLDERS); foreach(vl, vars) { PlaceHolderVar *phv = (PlaceHolderVar *) lfirst(vl); PlaceHolderInfo *phinfo; /* Ignore any plain Vars */ if (!IsA(phv, PlaceHolderVar)) continue; /* Create a PlaceHolderInfo entry if there's not one already */ phinfo = find_placeholder_info(root, phv, true); /* Mark it, and recursively process any contained placeholders */ mark_placeholder_maybe_needed(root, phinfo, relids); } list_free(vars); }
void update_placeholder_eval_levels | ( | PlannerInfo * | root, | |
SpecialJoinInfo * | new_sjinfo | |||
) |
Definition at line 302 of file placeholder.c.
References bms_add_members(), bms_is_subset(), bms_overlap(), JOIN_FULL, PlannerInfo::join_info_list, SpecialJoinInfo::jointype, lfirst, SpecialJoinInfo::min_lefthand, SpecialJoinInfo::min_righthand, PlaceHolderInfo::ph_eval_at, PlaceHolderInfo::ph_var, PlaceHolderVar::phrels, PlannerInfo::placeholder_list, SpecialJoinInfo::syn_lefthand, and SpecialJoinInfo::syn_righthand.
Referenced by deconstruct_recurse().
{ 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); phinfo->ph_eval_at = eval_at; } }