PostgreSQL Source Code git master
Loading...
Searching...
No Matches
placeholder.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * placeholder.c
4 * PlaceHolderVar and PlaceHolderInfo manipulation routines
5 *
6 *
7 * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
8 * Portions Copyright (c) 1994, Regents of the University of California
9 *
10 *
11 * IDENTIFICATION
12 * src/backend/optimizer/util/placeholder.c
13 *
14 *-------------------------------------------------------------------------
15 */
16#include "postgres.h"
17
18#include "nodes/nodeFuncs.h"
19#include "optimizer/cost.h"
20#include "optimizer/optimizer.h"
21#include "optimizer/pathnode.h"
23#include "optimizer/planmain.h"
24#include "utils/lsyscache.h"
25
26
32
33/* Local functions */
34static void find_placeholders_recurse(PlannerInfo *root, Node *jtnode);
38static bool contain_noop_phv_walker(Node *node, void *context);
39static Node *strip_noop_phvs_mutator(Node *node, void *context);
40
41
42/*
43 * make_placeholder_expr
44 * Make a PlaceHolderVar for the given expression.
45 *
46 * phrels is the syntactic location (as a set of relids) to attribute
47 * to the expression.
48 *
49 * The caller is responsible for adjusting phlevelsup and phnullingrels
50 * as needed. Because we do not know here which query level the PHV
51 * will be associated with, it's important that this function touches
52 * only root->glob; messing with other parts of PlannerInfo would be
53 * likely to do the wrong thing.
54 */
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}
68
69/*
70 * find_placeholder_info
71 * Fetch the PlaceHolderInfo for the given PHV
72 *
73 * If the PlaceHolderInfo doesn't exist yet, create it if we haven't yet
74 * frozen the set of PlaceHolderInfos for the query; else throw an error.
75 *
76 * This is separate from make_placeholder_expr because subquery pullup has
77 * to make PlaceHolderVars for expressions that might not be used at all in
78 * the upper query, or might not remain after const-expression simplification.
79 * We build PlaceHolderInfos only for PHVs that are still present in the
80 * simplified query passed to query_planner().
81 *
82 * Note: this should only be called after query_planner() has started.
83 */
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}
178
179/*
180 * find_placeholders_in_jointree
181 * Search the jointree for PlaceHolderVars, and build PlaceHolderInfos
182 *
183 * We don't need to look at the targetlist because build_base_rel_tlists()
184 * will already have made entries for any PHVs in the tlist.
185 */
186void
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}
201
202/*
203 * find_placeholders_recurse
204 * One recursion level of find_placeholders_in_jointree.
205 *
206 * jtnode is the current jointree node to examine.
207 */
208static void
210{
211 if (jtnode == NULL)
212 return;
213 if (IsA(jtnode, RangeTblRef))
214 {
215 /* No quals to deal with here */
216 }
217 else if (IsA(jtnode, FromExpr))
218 {
219 FromExpr *f = (FromExpr *) jtnode;
220 ListCell *l;
221
222 /*
223 * First, recurse to handle child joins.
224 */
225 foreach(l, f->fromlist)
226 {
228 }
229
230 /*
231 * Now process the top-level quals.
232 */
234 }
235 else if (IsA(jtnode, JoinExpr))
236 {
237 JoinExpr *j = (JoinExpr *) jtnode;
238
239 /*
240 * First, recurse to handle child joins.
241 */
244
245 /* Process the qual clauses */
247 }
248 else
249 elog(ERROR, "unrecognized node type: %d",
250 (int) nodeTag(jtnode));
251}
252
253/*
254 * find_placeholders_in_expr
255 * Find all PlaceHolderVars in the given expression, and create
256 * PlaceHolderInfo entries for them.
257 */
258static void
260{
261 List *vars;
262 ListCell *vl;
263
264 /*
265 * pull_var_clause does more than we need here, but it'll do and it's
266 * convenient to use.
267 */
268 vars = pull_var_clause(expr,
272 foreach(vl, vars)
273 {
275
276 /* Ignore any plain Vars */
277 if (!IsA(phv, PlaceHolderVar))
278 continue;
279
280 /* Create a PlaceHolderInfo entry if there's not one already */
282 }
284}
285
286/*
287 * fix_placeholder_input_needed_levels
288 * Adjust the "needed at" levels for placeholder inputs
289 *
290 * This is called after we've finished determining the eval_at levels for
291 * all placeholders. We need to make sure that all vars and placeholders
292 * needed to evaluate each placeholder will be available at the scan or join
293 * level where the evaluation will be done. (It might seem that scan-level
294 * evaluations aren't interesting, but that's not so: a LATERAL reference
295 * within a placeholder's expression needs to cause the referenced var or
296 * placeholder to be marked as needed in the scan where it's evaluated.)
297 * Note that this loop can have side-effects on the ph_needed sets of other
298 * PlaceHolderInfos; that's okay because we don't examine ph_needed here, so
299 * there are no ordering issues to worry about.
300 */
301void
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}
318
319/*
320 * rebuild_placeholder_attr_needed
321 * Put back attr_needed bits for Vars/PHVs needed in PlaceHolderVars.
322 *
323 * This is used to rebuild attr_needed/ph_needed sets after removal of a
324 * useless outer join. It should match what
325 * fix_placeholder_input_needed_levels did, except that we call
326 * add_vars_to_attr_needed not add_vars_to_targetlist.
327 */
328void
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}
345
346/*
347 * add_placeholders_to_base_rels
348 * Add any required PlaceHolderVars to base rels' targetlists.
349 *
350 * If any placeholder can be computed at a base rel and is needed above it,
351 * add it to that rel's targetlist. This might look like it could be merged
352 * with fix_placeholder_input_needed_levels, but it must be separate because
353 * join removal happens in between, and can change the ph_eval_at sets. There
354 * is essentially the same logic in add_placeholders_to_joinrel, but we can't
355 * do that part until joinrels are formed.
356 */
357void
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}
387
388/*
389 * add_placeholders_to_joinrel
390 * Add any newly-computable PlaceHolderVars to a join rel's targetlist;
391 * and if computable PHVs contain lateral references, add those
392 * references to the joinrel's direct_lateral_relids.
393 *
394 * A join rel should emit a PlaceHolderVar if (a) the PHV can be computed
395 * at or below this join level and (b) the PHV is needed above this level.
396 * Our caller build_join_rel() has already added any PHVs that were computed
397 * in either join input rel, so we need add only newly-computable ones to
398 * the targetlist. However, direct_lateral_relids must be updated for every
399 * PHV computable at or below this join, as explained below.
400 */
401void
404 SpecialJoinInfo *sjinfo)
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}
479
480/*
481 * contain_placeholder_references_to
482 * Detect whether any PlaceHolderVars in the given clause contain
483 * references to the given relid (typically an OJ relid).
484 *
485 * "Contain" means that there's a use of the relid inside the PHV's
486 * contained expression, so that changing the nullability status of
487 * the rel might change what the PHV computes.
488 *
489 * The code here to cope with upper-level PHVs is likely dead, but keep it
490 * anyway just in case.
491 */
492bool
494 int relid)
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}
506
507static bool
510{
511 if (node == NULL)
512 return false;
513 if (IsA(node, PlaceHolderVar))
514 {
516
517 /* We should just look through PHVs of other query levels */
518 if (phv->phlevelsup == context->sublevels_up)
519 {
520 /* If phrels matches, we found what we came for */
521 if (bms_is_member(context->relid, phv->phrels))
522 return true;
523
524 /*
525 * We should not examine phnullingrels: what we are looking for is
526 * references in the contained expression, not OJs that might null
527 * the result afterwards. Also, we don't need to recurse into the
528 * contained expression, because phrels should adequately
529 * summarize what's in there. So we're done here.
530 */
531 return false;
532 }
533 }
534 else if (IsA(node, Query))
535 {
536 /* Recurse into RTE subquery or not-yet-planned sublink subquery */
537 bool result;
538
539 context->sublevels_up++;
540 result = query_tree_walker((Query *) node,
542 context,
543 0);
544 context->sublevels_up--;
545 return result;
546 }
548 context);
549}
550
551/*
552 * Compute the set of outer-join relids that can null a placeholder.
553 *
554 * This is analogous to RelOptInfo.nulling_relids for Vars, but we compute it
555 * on-the-fly rather than saving it somewhere. Currently the value is needed
556 * at most once per query, so there's little value in doing otherwise. If it
557 * ever gains more widespread use, perhaps we should cache the result in
558 * PlaceHolderInfo.
559 */
560Relids
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}
590
591/*
592 * strip_noop_phvs
593 * Strip no-op PlaceHolderVar nodes from the given expression tree.
594 *
595 * A PlaceHolderVar that is not marked as nullable (i.e., its phnullingrels
596 * is empty) is effectively a no-op when it appears in a relation-scan-level
597 * expression. This function strips such PlaceHolderVars, which is useful
598 * for matching expressions to index keys or partition keys in cases where
599 * the expression has been wrapped in PlaceHolderVars during subquery pullup.
600 *
601 * IMPORTANT: the caller must ensure that the expression is a scan-level
602 * expression, so that non-nullable PlaceHolderVars in it are indeed no-ops.
603 *
604 * The removal is performed recursively because PlaceHolderVars can be nested
605 * or interleaved with other node types. We must peel back all layers to
606 * expose the base expression.
607 *
608 * As a performance optimization, we first use a lightweight walker to check
609 * for the presence of strippable PlaceHolderVars. The expensive mutator is
610 * invoked only if a candidate is found, avoiding unnecessary memory allocation
611 * and tree copying in the common case where no PlaceHolderVars are present.
612 */
613Node *
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}
622
623/*
624 * contain_noop_phv_walker
625 * Detect if there are any PlaceHolderVars in the tree that are candidates
626 * for stripping.
627 *
628 * We identify a PlaceHolderVar as strippable only if its phnullingrels is
629 * empty.
630 */
631static bool
632contain_noop_phv_walker(Node *node, void *context)
633{
634 if (node == NULL)
635 return false;
636
637 if (IsA(node, PlaceHolderVar))
638 {
640
641 if (bms_is_empty(phv->phnullingrels))
642 return true;
643 }
644
646 context);
647}
648
649/*
650 * strip_noop_phvs_mutator
651 * Recursively remove PlaceHolderVars that are not marked nullable.
652 *
653 * We strip a PlaceHolderVar only if its phnullingrels is empty, replacing it
654 * with its contained expression.
655 */
656static Node *
657strip_noop_phvs_mutator(Node *node, void *context)
658{
659 if (node == NULL)
660 return NULL;
661
662 if (IsA(node, PlaceHolderVar))
663 {
665
666 if (bms_is_empty(phv->phnullingrels))
667 {
668 /* Recurse on its contained expression */
669 return strip_noop_phvs_mutator((Node *) phv->phexpr,
670 context);
671 }
672
673 /* Otherwise, keep this PHV but check its contained expression */
674 }
675
677 context);
678}
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
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_subset(const Bitmapset *a, const Bitmapset *b)
Definition bitmapset.c:412
bool bms_is_member(int x, const Bitmapset *a)
Definition bitmapset.c:510
Bitmapset * bms_add_members(Bitmapset *a, const Bitmapset *b)
Definition bitmapset.c:901
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
Bitmapset * bms_copy(const Bitmapset *a)
Definition bitmapset.c:122
#define bms_is_empty(a)
Definition bitmapset.h:118
#define Assert(condition)
Definition c.h:943
int64_t int64
Definition c.h:621
uint32 result
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
#define ERROR
Definition elog.h:40
#define elog(elevel,...)
Definition elog.h:228
#define palloc0_array(type, count)
Definition fe_memutils.h:77
void add_vars_to_targetlist(PlannerInfo *root, List *vars, Relids where_needed)
Definition initsplan.c:290
void add_vars_to_attr_needed(PlannerInfo *root, List *vars, Relids where_needed)
Definition initsplan.c:361
int j
Definition isn.c:78
List * lappend(List *list, void *datum)
Definition list.c:339
void list_free(List *list)
Definition list.c:1546
int32 get_typavgwidth(Oid typid, int32 typmod)
Definition lsyscache.c:2773
Oid exprType(const Node *expr)
Definition nodeFuncs.c:42
int32 exprTypmod(const Node *expr)
Definition nodeFuncs.c:304
#define expression_tree_mutator(n, m, c)
Definition nodeFuncs.h:155
#define query_tree_walker(q, w, c, f)
Definition nodeFuncs.h:158
#define expression_tree_walker(n, w, c)
Definition nodeFuncs.h:153
#define IsA(nodeptr, _type_)
Definition nodes.h:164
#define copyObject(obj)
Definition nodes.h:232
#define nodeTag(nodeptr)
Definition nodes.h:139
#define makeNode(_type_)
Definition nodes.h:161
#define PVC_RECURSE_AGGREGATES
Definition optimizer.h:198
#define PVC_RECURSE_WINDOWFUNCS
Definition optimizer.h:200
#define PVC_INCLUDE_PLACEHOLDERS
Definition optimizer.h:201
#define repalloc0_array(pointer, type, oldcount, count)
Definition palloc.h:109
#define lfirst(lc)
Definition pg_list.h:172
Relids get_placeholder_nulling_relids(PlannerInfo *root, PlaceHolderInfo *phinfo)
bool contain_placeholder_references_to(PlannerInfo *root, Node *clause, int relid)
PlaceHolderInfo * find_placeholder_info(PlannerInfo *root, PlaceHolderVar *phv)
Definition placeholder.c:85
void add_placeholders_to_joinrel(PlannerInfo *root, RelOptInfo *joinrel, RelOptInfo *outer_rel, RelOptInfo *inner_rel, SpecialJoinInfo *sjinfo)
void add_placeholders_to_base_rels(PlannerInfo *root)
PlaceHolderVar * make_placeholder_expr(PlannerInfo *root, Expr *expr, Relids phrels)
Definition placeholder.c:56
static Node * strip_noop_phvs_mutator(Node *node, void *context)
static bool contain_placeholder_references_walker(Node *node, contain_placeholder_references_context *context)
void fix_placeholder_input_needed_levels(PlannerInfo *root)
static void find_placeholders_in_expr(PlannerInfo *root, Node *expr)
void rebuild_placeholder_attr_needed(PlannerInfo *root)
static void find_placeholders_recurse(PlannerInfo *root, Node *jtnode)
static bool contain_noop_phv_walker(Node *node, void *context)
void find_placeholders_in_jointree(PlannerInfo *root)
Node * strip_noop_phvs(Node *node)
static int fb(int x)
tree ctl root
Definition radixtree.h:1857
RelOptInfo * find_base_rel(PlannerInfo *root, int relid)
Definition relnode.c:544
Node * quals
Definition primnodes.h:2385
List * fromlist
Definition primnodes.h:2384
Definition pg_list.h:54
Definition nodes.h:135
List * exprs
Definition pathnodes.h:1878
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
struct PathTarget * reltarget
Definition pathnodes.h:1045
Relids direct_lateral_relids
Definition pathnodes.h:1062
Relids nulling_relids
Definition pathnodes.h:1085
Relids pull_varnos(PlannerInfo *root, Node *node)
Definition var.c:114
List * pull_var_clause(Node *node, int flags)
Definition var.c:653