PostgreSQL Source Code git master
Loading...
Searching...
No Matches
placeholder.h File Reference
#include "nodes/pathnodes.h"
Include dependency graph for placeholder.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Functions

PlaceHolderVarmake_placeholder_expr (PlannerInfo *root, Expr *expr, Relids phrels)
 
PlaceHolderInfofind_placeholder_info (PlannerInfo *root, PlaceHolderVar *phv)
 
void find_placeholders_in_jointree (PlannerInfo *root)
 
void fix_placeholder_input_needed_levels (PlannerInfo *root)
 
void rebuild_placeholder_attr_needed (PlannerInfo *root)
 
void add_placeholders_to_base_rels (PlannerInfo *root)
 
void add_placeholders_to_joinrel (PlannerInfo *root, RelOptInfo *joinrel, RelOptInfo *outer_rel, RelOptInfo *inner_rel, SpecialJoinInfo *sjinfo)
 
bool contain_placeholder_references_to (PlannerInfo *root, Node *clause, int relid)
 
Relids get_placeholder_nulling_relids (PlannerInfo *root, PlaceHolderInfo *phinfo)
 
Nodestrip_noop_phvs (Node *node)
 

Function Documentation

◆ add_placeholders_to_base_rels()

void add_placeholders_to_base_rels ( PlannerInfo root)
extern

Definition at line 358 of file placeholder.c.

359{
360 ListCell *lc;
361
362 foreach(lc, root->placeholder_list)
363 {
365 Relids eval_at = phinfo->ph_eval_at;
366 int varno;
367
368 if (bms_get_singleton_member(eval_at, &varno) &&
370 {
371 RelOptInfo *rel = find_base_rel(root, varno);
372
373 /*
374 * As in add_vars_to_targetlist(), a value computed at scan level
375 * has not yet been nulled by any outer join, so its phnullingrels
376 * should be empty.
377 */
378 Assert(phinfo->ph_var->phnullingrels == NULL);
379
380 /* Copying the PHV might be unnecessary here, but be safe */
381 rel->reltarget->exprs = lappend(rel->reltarget->exprs,
382 copyObject(phinfo->ph_var));
383 /* reltarget's cost and width fields will be updated later */
384 }
385 }
386}
bool bms_get_singleton_member(const Bitmapset *a, int *member)
Definition bitmapset.c:708
bool bms_nonempty_difference(const Bitmapset *a, const Bitmapset *b)
Definition bitmapset.c:634
#define Assert(condition)
Definition c.h:943
List * lappend(List *list, void *datum)
Definition list.c:339
#define copyObject(obj)
Definition nodes.h:232
#define lfirst(lc)
Definition pg_list.h:172
static int fb(int x)
tree ctl root
Definition radixtree.h:1857
RelOptInfo * find_base_rel(PlannerInfo *root, int relid)
Definition relnode.c:544
List * exprs
Definition pathnodes.h:1878
struct PathTarget * reltarget
Definition pathnodes.h:1045

References Assert, bms_get_singleton_member(), bms_nonempty_difference(), copyObject, PathTarget::exprs, fb(), find_base_rel(), lappend(), lfirst, RelOptInfo::reltarget, and root.

Referenced by query_planner().

◆ add_placeholders_to_joinrel()

void add_placeholders_to_joinrel ( PlannerInfo root,
RelOptInfo joinrel,
RelOptInfo outer_rel,
RelOptInfo inner_rel,
SpecialJoinInfo sjinfo 
)
extern

Definition at line 402 of file placeholder.c.

405{
406 Relids relids = joinrel->relids;
407 int64 tuple_width = joinrel->reltarget->width;
408 ListCell *lc;
409
410 foreach(lc, root->placeholder_list)
411 {
413
414 /* Is it computable here? */
415 if (bms_is_subset(phinfo->ph_eval_at, relids))
416 {
417 /* Is it still needed above this joinrel? */
418 if (bms_nonempty_difference(phinfo->ph_needed, relids))
419 {
420 /*
421 * Yes, but only add to tlist if it wasn't computed in either
422 * input; otherwise it should be there already. Also, we
423 * charge the cost of evaluating the contained expression if
424 * the PHV can be computed here but not in either input. This
425 * is a bit bogus because we make the decision based on the
426 * first pair of possible input relations considered for the
427 * joinrel. With other pairs, it might be possible to compute
428 * the PHV in one input or the other, and then we'd be double
429 * charging the PHV's cost for some join paths. For now, live
430 * with that; but we might want to improve it later by
431 * refiguring the reltarget costs for each pair of inputs.
432 */
433 if (!bms_is_subset(phinfo->ph_eval_at, outer_rel->relids) &&
434 !bms_is_subset(phinfo->ph_eval_at, inner_rel->relids))
435 {
436 /* Copying might be unnecessary here, but be safe */
438 QualCost cost;
439
440 /*
441 * It'll start out not nulled by anything. Joins above
442 * this one might add to its phnullingrels later, in much
443 * the same way as for Vars.
444 */
445 Assert(phv->phnullingrels == NULL);
446
447 joinrel->reltarget->exprs = lappend(joinrel->reltarget->exprs,
448 phv);
449 cost_qual_eval_node(&cost, (Node *) phv->phexpr, root);
450 joinrel->reltarget->cost.startup += cost.startup;
451 joinrel->reltarget->cost.per_tuple += cost.per_tuple;
452 tuple_width += phinfo->ph_width;
453 }
454 }
455
456 /*
457 * Also adjust joinrel's direct_lateral_relids to include the
458 * PHV's source rel(s). We must do this even if we're not
459 * actually going to emit the PHV, otherwise join_is_legal() will
460 * reject valid join orderings. (In principle maybe we could
461 * instead remove the joinrel's lateral_relids dependency; but
462 * that's complicated to get right, and cases where we're not
463 * going to emit the PHV are too rare to justify the work.)
464 *
465 * In principle we should only do this if the join doesn't yet
466 * include the PHV's source rel(s). But our caller
467 * build_join_rel() will clean things up by removing the join's
468 * own relids from its direct_lateral_relids, so we needn't
469 * account for that here.
470 */
471 joinrel->direct_lateral_relids =
473 phinfo->ph_lateral);
474 }
475 }
476
478}
bool bms_is_subset(const Bitmapset *a, const Bitmapset *b)
Definition bitmapset.c:412
Bitmapset * bms_add_members(Bitmapset *a, const Bitmapset *b)
Definition bitmapset.c:901
int64_t int64
Definition c.h:621
void cost_qual_eval_node(QualCost *cost, Node *qual, PlannerInfo *root)
Definition costsize.c:4926
int32 clamp_width_est(int64 tuple_width)
Definition costsize.c:243
Definition nodes.h:135
QualCost cost
Definition pathnodes.h:1884
Cost per_tuple
Definition pathnodes.h:121
Cost startup
Definition pathnodes.h:120
Relids relids
Definition pathnodes.h:1021
Relids direct_lateral_relids
Definition pathnodes.h:1062

References Assert, bms_add_members(), bms_is_subset(), bms_nonempty_difference(), clamp_width_est(), copyObject, PathTarget::cost, cost_qual_eval_node(), RelOptInfo::direct_lateral_relids, PathTarget::exprs, fb(), lappend(), lfirst, QualCost::per_tuple, RelOptInfo::relids, RelOptInfo::reltarget, root, QualCost::startup, and PathTarget::width.

Referenced by build_join_rel().

◆ contain_placeholder_references_to()

bool contain_placeholder_references_to ( PlannerInfo root,
Node clause,
int  relid 
)
extern

Definition at line 493 of file placeholder.c.

495{
497
498 /* We can answer quickly in the common case that there's no PHVs at all */
499 if (root->glob->lastPHId == 0)
500 return false;
501 /* Else run the recursive search */
502 context.relid = relid;
503 context.sublevels_up = 0;
504 return contain_placeholder_references_walker(clause, &context);
505}
static bool contain_placeholder_references_walker(Node *node, contain_placeholder_references_context *context)

References contain_placeholder_references_walker(), contain_placeholder_references_context::relid, root, and contain_placeholder_references_context::sublevels_up.

Referenced by make_outerjoininfo().

◆ find_placeholder_info()

PlaceHolderInfo * find_placeholder_info ( PlannerInfo root,
PlaceHolderVar phv 
)
extern

Definition at line 85 of file placeholder.c.

86{
89
90 /* if this ever isn't true, we'd need to be able to look in parent lists */
91 Assert(phv->phlevelsup == 0);
92
93 /* Use placeholder_array to look up existing PlaceHolderInfo quickly */
94 if (phv->phid < root->placeholder_array_size)
95 phinfo = root->placeholder_array[phv->phid];
96 else
97 phinfo = NULL;
98 if (phinfo != NULL)
99 {
100 Assert(phinfo->phid == phv->phid);
101 return phinfo;
102 }
103
104 /* Not found, so create it */
105 if (root->placeholdersFrozen)
106 elog(ERROR, "too late to create a new PlaceHolderInfo");
107
109
110 phinfo->phid = phv->phid;
111 phinfo->ph_var = copyObject(phv);
112
113 /*
114 * By convention, phinfo->ph_var->phnullingrels is always empty, since the
115 * PlaceHolderInfo represents the initially-calculated state of the
116 * PlaceHolderVar. PlaceHolderVars appearing in the query tree might have
117 * varying values of phnullingrels, reflecting outer joins applied above
118 * the calculation level.
119 */
120 phinfo->ph_var->phnullingrels = NULL;
121
122 /*
123 * Any referenced rels that are outside the PHV's syntactic scope are
124 * LATERAL references, which should be included in ph_lateral but not in
125 * ph_eval_at. If no referenced rels are within the syntactic scope,
126 * force evaluation at the syntactic location.
127 */
128 rels_used = pull_varnos(root, (Node *) phv->phexpr);
129 phinfo->ph_lateral = bms_difference(rels_used, phv->phrels);
130 phinfo->ph_eval_at = bms_int_members(rels_used, phv->phrels);
131 /* If no contained vars, force evaluation at syntactic location */
132 if (bms_is_empty(phinfo->ph_eval_at))
133 {
134 phinfo->ph_eval_at = bms_copy(phv->phrels);
135 Assert(!bms_is_empty(phinfo->ph_eval_at));
136 }
137 phinfo->ph_needed = NULL; /* initially it's unused */
138 /* for the moment, estimate width using just the datatype info */
139 phinfo->ph_width = get_typavgwidth(exprType((Node *) phv->phexpr),
140 exprTypmod((Node *) phv->phexpr));
141
142 /*
143 * Add to both placeholder_list and placeholder_array. Note: because we
144 * store pointers to the PlaceHolderInfos in two data structures, it'd be
145 * unsafe to pass the whole placeholder_list structure through
146 * expression_tree_mutator or the like --- or at least, you'd have to
147 * rebuild the placeholder_array afterwards.
148 */
149 root->placeholder_list = lappend(root->placeholder_list, phinfo);
150
151 if (phinfo->phid >= root->placeholder_array_size)
152 {
153 /* Must allocate or enlarge placeholder_array */
154 int new_size;
155
156 new_size = root->placeholder_array_size ? root->placeholder_array_size * 2 : 8;
157 while (phinfo->phid >= new_size)
158 new_size *= 2;
159 if (root->placeholder_array)
160 root->placeholder_array =
161 repalloc0_array(root->placeholder_array, PlaceHolderInfo *, root->placeholder_array_size, new_size);
162 else
163 root->placeholder_array =
165 root->placeholder_array_size = new_size;
166 }
167 root->placeholder_array[phinfo->phid] = phinfo;
168
169 /*
170 * The PHV's contained expression may contain other, lower-level PHVs. We
171 * now know we need to get those into the PlaceHolderInfo list, too, so we
172 * may as well do that immediately.
173 */
174 find_placeholders_in_expr(root, (Node *) phinfo->ph_var->phexpr);
175
176 return phinfo;
177}
Bitmapset * bms_difference(const Bitmapset *a, const Bitmapset *b)
Definition bitmapset.c:346
Bitmapset * bms_int_members(Bitmapset *a, const Bitmapset *b)
Definition bitmapset.c:1093
Bitmapset * bms_copy(const Bitmapset *a)
Definition bitmapset.c:122
#define bms_is_empty(a)
Definition bitmapset.h:118
#define ERROR
Definition elog.h:40
#define elog(elevel,...)
Definition elog.h:228
#define palloc0_array(type, count)
Definition fe_memutils.h:77
int32 get_typavgwidth(Oid typid, int32 typmod)
Definition lsyscache.c:2800
Oid exprType(const Node *expr)
Definition nodeFuncs.c:42
int32 exprTypmod(const Node *expr)
Definition nodeFuncs.c:304
#define makeNode(_type_)
Definition nodes.h:161
#define repalloc0_array(pointer, type, oldcount, count)
Definition palloc.h:109
static void find_placeholders_in_expr(PlannerInfo *root, Node *expr)
Relids pull_varnos(PlannerInfo *root, Node *node)
Definition var.c:114

References Assert, bms_copy(), bms_difference(), bms_int_members(), bms_is_empty, copyObject, elog, ERROR, exprType(), exprTypmod(), fb(), find_placeholders_in_expr(), get_typavgwidth(), lappend(), makeNode, palloc0_array, pull_varnos(), repalloc0_array, and root.

Referenced by add_vars_to_attr_needed(), add_vars_to_targetlist(), build_joinrel_tlist(), create_lateral_join_info(), extract_lateral_vars_from_PHVs(), find_placeholders_in_expr(), identify_current_nestloop_params(), process_subquery_nestloop_params(), replace_nestloop_params_mutator(), and set_rel_width().

◆ find_placeholders_in_jointree()

void find_placeholders_in_jointree ( PlannerInfo root)
extern

Definition at line 187 of file placeholder.c.

188{
189 /* This must be done before freezing the set of PHIs */
190 Assert(!root->placeholdersFrozen);
191
192 /* We need do nothing if the query contains no PlaceHolderVars */
193 if (root->glob->lastPHId != 0)
194 {
195 /* Start recursion at top of jointree */
196 Assert(root->parse->jointree != NULL &&
197 IsA(root->parse->jointree, FromExpr));
198 find_placeholders_recurse(root, (Node *) root->parse->jointree);
199 }
200}
#define IsA(nodeptr, _type_)
Definition nodes.h:164
static void find_placeholders_recurse(PlannerInfo *root, Node *jtnode)

References Assert, fb(), find_placeholders_recurse(), IsA, and root.

Referenced by query_planner().

◆ fix_placeholder_input_needed_levels()

void fix_placeholder_input_needed_levels ( PlannerInfo root)
extern

Definition at line 302 of file placeholder.c.

303{
304 ListCell *lc;
305
306 foreach(lc, root->placeholder_list)
307 {
309 List *vars = pull_var_clause((Node *) phinfo->ph_var->phexpr,
313
314 add_vars_to_targetlist(root, vars, phinfo->ph_eval_at);
316 }
317}
void add_vars_to_targetlist(PlannerInfo *root, List *vars, Relids where_needed)
Definition initsplan.c:290
void list_free(List *list)
Definition list.c:1546
#define PVC_RECURSE_AGGREGATES
Definition optimizer.h:198
#define PVC_RECURSE_WINDOWFUNCS
Definition optimizer.h:200
#define PVC_INCLUDE_PLACEHOLDERS
Definition optimizer.h:201
Definition pg_list.h:54
List * pull_var_clause(Node *node, int flags)
Definition var.c:653

References add_vars_to_targetlist(), fb(), lfirst, list_free(), pull_var_clause(), PVC_INCLUDE_PLACEHOLDERS, PVC_RECURSE_AGGREGATES, PVC_RECURSE_WINDOWFUNCS, and root.

Referenced by query_planner().

◆ get_placeholder_nulling_relids()

Relids get_placeholder_nulling_relids ( PlannerInfo root,
PlaceHolderInfo phinfo 
)
extern

Definition at line 561 of file placeholder.c.

562{
564 int relid = -1;
565
566 /*
567 * Form the union of all potential nulling OJs for each baserel included
568 * in ph_eval_at.
569 */
570 while ((relid = bms_next_member(phinfo->ph_eval_at, relid)) > 0)
571 {
572 RelOptInfo *rel = root->simple_rel_array[relid];
573
574 /* ignore the RTE_GROUP RTE */
575 if (relid == root->group_rtindex)
576 continue;
577
578 if (rel == NULL) /* must be an outer join */
579 {
580 Assert(bms_is_member(relid, root->outer_join_rels));
581 continue;
582 }
584 }
585
586 /* Now remove any OJs already included in ph_eval_at, and we're done. */
587 result = bms_del_members(result, phinfo->ph_eval_at);
588 return result;
589}
int bms_next_member(const Bitmapset *a, int prevbit)
Definition bitmapset.c:1290
Bitmapset * bms_del_members(Bitmapset *a, const Bitmapset *b)
Definition bitmapset.c:1145
bool bms_is_member(int x, const Bitmapset *a)
Definition bitmapset.c:510
uint32 result
Relids nulling_relids
Definition pathnodes.h:1085

References Assert, bms_add_members(), bms_del_members(), bms_is_member(), bms_next_member(), fb(), RelOptInfo::nulling_relids, result, and root.

Referenced by identify_current_nestloop_params().

◆ make_placeholder_expr()

PlaceHolderVar * make_placeholder_expr ( PlannerInfo root,
Expr expr,
Relids  phrels 
)
extern

Definition at line 56 of file placeholder.c.

57{
59
60 phv->phexpr = expr;
61 phv->phrels = phrels;
62 phv->phnullingrels = NULL; /* caller may change this later */
63 phv->phid = ++(root->glob->lastPHId);
64 phv->phlevelsup = 0; /* caller may change this later */
65
66 return phv;
67}

References fb(), makeNode, and root.

Referenced by add_nullingrels_if_needed(), mark_nullable_by_grouping(), and pullup_replace_vars_callback().

◆ rebuild_placeholder_attr_needed()

void rebuild_placeholder_attr_needed ( PlannerInfo root)
extern

Definition at line 329 of file placeholder.c.

330{
331 ListCell *lc;
332
333 foreach(lc, root->placeholder_list)
334 {
336 List *vars = pull_var_clause((Node *) phinfo->ph_var->phexpr,
340
343 }
344}
void add_vars_to_attr_needed(PlannerInfo *root, List *vars, Relids where_needed)
Definition initsplan.c:361

References add_vars_to_attr_needed(), fb(), lfirst, list_free(), pull_var_clause(), PVC_INCLUDE_PLACEHOLDERS, PVC_RECURSE_AGGREGATES, PVC_RECURSE_WINDOWFUNCS, and root.

Referenced by remove_leftjoinrel_from_query(), and remove_self_join_rel().

◆ strip_noop_phvs()

Node * strip_noop_phvs ( Node node)
extern

Definition at line 614 of file placeholder.c.

615{
616 /* Don't mutate/copy if no target PHVs exist */
617 if (!contain_noop_phv_walker(node, NULL))
618 return node;
619
620 return strip_noop_phvs_mutator(node, NULL);
621}
static Node * strip_noop_phvs_mutator(Node *node, void *context)
static bool contain_noop_phv_walker(Node *node, void *context)

References contain_noop_phv_walker(), fb(), and strip_noop_phvs_mutator().

Referenced by fix_indexqual_operand(), match_boolean_partition_clause(), match_clause_to_partition_key(), and match_index_to_operand().