#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;
}
}
1.7.1