PostgreSQL Source Code  git master
var.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * var.c
4  * Var node manipulation routines
5  *
6  * Note: for most purposes, PlaceHolderVar is considered a Var too,
7  * even if its contained expression is variable-free. Also, CurrentOfExpr
8  * is treated as a Var for purposes of determining whether an expression
9  * contains variables.
10  *
11  *
12  * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
13  * Portions Copyright (c) 1994, Regents of the University of California
14  *
15  *
16  * IDENTIFICATION
17  * src/backend/optimizer/util/var.c
18  *
19  *-------------------------------------------------------------------------
20  */
21 #include "postgres.h"
22 
23 #include "access/sysattr.h"
24 #include "nodes/nodeFuncs.h"
25 #include "optimizer/clauses.h"
26 #include "optimizer/optimizer.h"
27 #include "optimizer/placeholder.h"
28 #include "optimizer/prep.h"
29 #include "parser/parsetree.h"
30 #include "rewrite/rewriteManip.h"
31 
32 
33 typedef struct
34 {
39 
40 typedef struct
41 {
45 
46 typedef struct
47 {
51 
52 typedef struct
53 {
57 
58 typedef struct
59 {
61  int flags;
63 
64 typedef struct
65 {
66  PlannerInfo *root; /* could be NULL! */
67  Query *query; /* outer Query */
69  bool possible_sublink; /* could aliases include a SubLink? */
70  bool inserted_sublink; /* have we inserted a SubLink? */
72 
73 static bool pull_varnos_walker(Node *node,
76 static bool pull_vars_walker(Node *node, pull_vars_context *context);
77 static bool contain_var_clause_walker(Node *node, void *context);
78 static bool contain_vars_of_level_walker(Node *node, int *sublevels_up);
79 static bool locate_var_of_level_walker(Node *node,
81 static bool pull_var_clause_walker(Node *node,
88  Var *oldvar);
90  Var *oldvar);
91 static bool is_standard_join_alias_expression(Node *newnode, Var *oldvar);
92 static void adjust_standard_join_alias_expression(Node *newnode, Var *oldvar);
93 static Relids alias_relid_set(Query *query, Relids relids);
94 
95 
96 /*
97  * pull_varnos
98  * Create a set of all the distinct varnos present in a parsetree.
99  * Only varnos that reference level-zero rtable entries are considered.
100  *
101  * The result includes outer-join relids mentioned in Var.varnullingrels and
102  * PlaceHolderVar.phnullingrels fields in the parsetree.
103  *
104  * "root" can be passed as NULL if it is not necessary to process
105  * PlaceHolderVars.
106  *
107  * NOTE: this is used on not-yet-planned expressions. It may therefore find
108  * bare SubLinks, and if so it needs to recurse into them to look for uplevel
109  * references to the desired rtable level! But when we find a completed
110  * SubPlan, we only need to look at the parameters passed to the subplan.
111  */
112 Relids
114 {
116 
117  context.varnos = NULL;
118  context.root = root;
119  context.sublevels_up = 0;
120 
121  /*
122  * Must be prepared to start with a Query or a bare expression tree; if
123  * it's a Query, we don't want to increment sublevels_up.
124  */
127  (void *) &context,
128  0);
129 
130  return context.varnos;
131 }
132 
133 /*
134  * pull_varnos_of_level
135  * Create a set of all the distinct varnos present in a parsetree.
136  * Only Vars of the specified level are considered.
137  */
138 Relids
140 {
142 
143  context.varnos = NULL;
144  context.root = root;
145  context.sublevels_up = levelsup;
146 
147  /*
148  * Must be prepared to start with a Query or a bare expression tree; if
149  * it's a Query, we don't want to increment sublevels_up.
150  */
153  (void *) &context,
154  0);
155 
156  return context.varnos;
157 }
158 
159 static bool
161 {
162  if (node == NULL)
163  return false;
164  if (IsA(node, Var))
165  {
166  Var *var = (Var *) node;
167 
168  if (var->varlevelsup == context->sublevels_up)
169  {
170  context->varnos = bms_add_member(context->varnos, var->varno);
171  context->varnos = bms_add_members(context->varnos,
172  var->varnullingrels);
173  }
174  return false;
175  }
176  if (IsA(node, CurrentOfExpr))
177  {
178  CurrentOfExpr *cexpr = (CurrentOfExpr *) node;
179 
180  if (context->sublevels_up == 0)
181  context->varnos = bms_add_member(context->varnos, cexpr->cvarno);
182  return false;
183  }
184  if (IsA(node, PlaceHolderVar))
185  {
186  PlaceHolderVar *phv = (PlaceHolderVar *) node;
187 
188  /*
189  * If a PlaceHolderVar is not of the target query level, ignore it,
190  * instead recursing into its expression to see if it contains any
191  * vars that are of the target level. We'll also do that when the
192  * caller doesn't pass a "root" pointer. (We probably shouldn't see
193  * PlaceHolderVars at all in such cases, but if we do, this is a
194  * reasonable behavior.)
195  */
196  if (phv->phlevelsup == context->sublevels_up &&
197  context->root != NULL)
198  {
199  /*
200  * Ideally, the PHV's contribution to context->varnos is its
201  * ph_eval_at set. However, this code can be invoked before
202  * that's been computed. If we cannot find a PlaceHolderInfo,
203  * fall back to the conservative assumption that the PHV will be
204  * evaluated at its syntactic level (phv->phrels).
205  *
206  * Another problem is that a PlaceHolderVar can appear in quals or
207  * tlists that have been translated for use in a child appendrel.
208  * Typically such a PHV is a parameter expression sourced by some
209  * other relation, so that the translation from parent appendrel
210  * to child doesn't change its phrels, and we should still take
211  * ph_eval_at at face value. But in corner cases, the PHV's
212  * original phrels can include the parent appendrel itself, in
213  * which case the translated PHV will have the child appendrel in
214  * phrels, and we must translate ph_eval_at to match.
215  */
216  PlaceHolderInfo *phinfo = NULL;
217 
218  if (phv->phlevelsup == 0)
219  {
220  if (phv->phid < context->root->placeholder_array_size)
221  phinfo = context->root->placeholder_array[phv->phid];
222  }
223  if (phinfo == NULL)
224  {
225  /* No PlaceHolderInfo yet, use phrels */
226  context->varnos = bms_add_members(context->varnos,
227  phv->phrels);
228  }
229  else if (bms_equal(phv->phrels, phinfo->ph_var->phrels))
230  {
231  /* Normal case: use ph_eval_at */
232  context->varnos = bms_add_members(context->varnos,
233  phinfo->ph_eval_at);
234  }
235  else
236  {
237  /* Translated PlaceHolderVar: translate ph_eval_at to match */
238  Relids newevalat,
239  delta;
240 
241  /* remove what was removed from phv->phrels ... */
242  delta = bms_difference(phinfo->ph_var->phrels, phv->phrels);
243  newevalat = bms_difference(phinfo->ph_eval_at, delta);
244  /* ... then if that was in fact part of ph_eval_at ... */
245  if (!bms_equal(newevalat, phinfo->ph_eval_at))
246  {
247  /* ... add what was added */
248  delta = bms_difference(phv->phrels, phinfo->ph_var->phrels);
249  newevalat = bms_join(newevalat, delta);
250  }
251  context->varnos = bms_join(context->varnos,
252  newevalat);
253  }
254 
255  /*
256  * In all three cases, include phnullingrels in the result. We
257  * don't worry about possibly needing to translate it, because
258  * appendrels only translate varnos of baserels, not outer joins.
259  */
260  context->varnos = bms_add_members(context->varnos,
261  phv->phnullingrels);
262  return false; /* don't recurse into expression */
263  }
264  }
265  else if (IsA(node, Query))
266  {
267  /* Recurse into RTE subquery or not-yet-planned sublink subquery */
268  bool result;
269 
270  context->sublevels_up++;
271  result = query_tree_walker((Query *) node, pull_varnos_walker,
272  (void *) context, 0);
273  context->sublevels_up--;
274  return result;
275  }
277  (void *) context);
278 }
279 
280 
281 /*
282  * pull_varattnos
283  * Find all the distinct attribute numbers present in an expression tree,
284  * and add them to the initial contents of *varattnos.
285  * Only Vars of the given varno and rtable level zero are considered.
286  *
287  * Attribute numbers are offset by FirstLowInvalidHeapAttributeNumber so that
288  * we can include system attributes (e.g., OID) in the bitmap representation.
289  *
290  * Currently, this does not support unplanned subqueries; that is not needed
291  * for current uses. It will handle already-planned SubPlan nodes, though,
292  * looking into only the "testexpr" and the "args" list. (The subplan cannot
293  * contain any other references to Vars of the current level.)
294  */
295 void
296 pull_varattnos(Node *node, Index varno, Bitmapset **varattnos)
297 {
299 
300  context.varattnos = *varattnos;
301  context.varno = varno;
302 
303  (void) pull_varattnos_walker(node, &context);
304 
305  *varattnos = context.varattnos;
306 }
307 
308 static bool
310 {
311  if (node == NULL)
312  return false;
313  if (IsA(node, Var))
314  {
315  Var *var = (Var *) node;
316 
317  if (var->varno == context->varno && var->varlevelsup == 0)
318  context->varattnos =
319  bms_add_member(context->varattnos,
321  return false;
322  }
323 
324  /* Should not find an unplanned subquery */
325  Assert(!IsA(node, Query));
326 
328  (void *) context);
329 }
330 
331 
332 /*
333  * pull_vars_of_level
334  * Create a list of all Vars (and PlaceHolderVars) referencing the
335  * specified query level in the given parsetree.
336  *
337  * Caution: the Vars are not copied, only linked into the list.
338  */
339 List *
340 pull_vars_of_level(Node *node, int levelsup)
341 {
343 
344  context.vars = NIL;
345  context.sublevels_up = levelsup;
346 
347  /*
348  * Must be prepared to start with a Query or a bare expression tree; if
349  * it's a Query, we don't want to increment sublevels_up.
350  */
353  (void *) &context,
354  0);
355 
356  return context.vars;
357 }
358 
359 static bool
361 {
362  if (node == NULL)
363  return false;
364  if (IsA(node, Var))
365  {
366  Var *var = (Var *) node;
367 
368  if (var->varlevelsup == context->sublevels_up)
369  context->vars = lappend(context->vars, var);
370  return false;
371  }
372  if (IsA(node, PlaceHolderVar))
373  {
374  PlaceHolderVar *phv = (PlaceHolderVar *) node;
375 
376  if (phv->phlevelsup == context->sublevels_up)
377  context->vars = lappend(context->vars, phv);
378  /* we don't want to look into the contained expression */
379  return false;
380  }
381  if (IsA(node, Query))
382  {
383  /* Recurse into RTE subquery or not-yet-planned sublink subquery */
384  bool result;
385 
386  context->sublevels_up++;
387  result = query_tree_walker((Query *) node, pull_vars_walker,
388  (void *) context, 0);
389  context->sublevels_up--;
390  return result;
391  }
393  (void *) context);
394 }
395 
396 
397 /*
398  * contain_var_clause
399  * Recursively scan a clause to discover whether it contains any Var nodes
400  * (of the current query level).
401  *
402  * Returns true if any varnode found.
403  *
404  * Does not examine subqueries, therefore must only be used after reduction
405  * of sublinks to subplans!
406  */
407 bool
409 {
410  return contain_var_clause_walker(node, NULL);
411 }
412 
413 static bool
415 {
416  if (node == NULL)
417  return false;
418  if (IsA(node, Var))
419  {
420  if (((Var *) node)->varlevelsup == 0)
421  return true; /* abort the tree traversal and return true */
422  return false;
423  }
424  if (IsA(node, CurrentOfExpr))
425  return true;
426  if (IsA(node, PlaceHolderVar))
427  {
428  if (((PlaceHolderVar *) node)->phlevelsup == 0)
429  return true; /* abort the tree traversal and return true */
430  /* else fall through to check the contained expr */
431  }
433 }
434 
435 
436 /*
437  * contain_vars_of_level
438  * Recursively scan a clause to discover whether it contains any Var nodes
439  * of the specified query level.
440  *
441  * Returns true if any such Var found.
442  *
443  * Will recurse into sublinks. Also, may be invoked directly on a Query.
444  */
445 bool
446 contain_vars_of_level(Node *node, int levelsup)
447 {
448  int sublevels_up = levelsup;
449 
452  (void *) &sublevels_up,
453  0);
454 }
455 
456 static bool
457 contain_vars_of_level_walker(Node *node, int *sublevels_up)
458 {
459  if (node == NULL)
460  return false;
461  if (IsA(node, Var))
462  {
463  if (((Var *) node)->varlevelsup == *sublevels_up)
464  return true; /* abort tree traversal and return true */
465  return false;
466  }
467  if (IsA(node, CurrentOfExpr))
468  {
469  if (*sublevels_up == 0)
470  return true;
471  return false;
472  }
473  if (IsA(node, PlaceHolderVar))
474  {
475  if (((PlaceHolderVar *) node)->phlevelsup == *sublevels_up)
476  return true; /* abort the tree traversal and return true */
477  /* else fall through to check the contained expr */
478  }
479  if (IsA(node, Query))
480  {
481  /* Recurse into subselects */
482  bool result;
483 
484  (*sublevels_up)++;
485  result = query_tree_walker((Query *) node,
487  (void *) sublevels_up,
488  0);
489  (*sublevels_up)--;
490  return result;
491  }
492  return expression_tree_walker(node,
494  (void *) sublevels_up);
495 }
496 
497 
498 /*
499  * locate_var_of_level
500  * Find the parse location of any Var of the specified query level.
501  *
502  * Returns -1 if no such Var is in the querytree, or if they all have
503  * unknown parse location. (The former case is probably caller error,
504  * but we don't bother to distinguish it from the latter case.)
505  *
506  * Will recurse into sublinks. Also, may be invoked directly on a Query.
507  *
508  * Note: it might seem appropriate to merge this functionality into
509  * contain_vars_of_level, but that would complicate that function's API.
510  * Currently, the only uses of this function are for error reporting,
511  * and so shaving cycles probably isn't very important.
512  */
513 int
514 locate_var_of_level(Node *node, int levelsup)
515 {
517 
518  context.var_location = -1; /* in case we find nothing */
519  context.sublevels_up = levelsup;
520 
523  (void *) &context,
524  0);
525 
526  return context.var_location;
527 }
528 
529 static bool
532 {
533  if (node == NULL)
534  return false;
535  if (IsA(node, Var))
536  {
537  Var *var = (Var *) node;
538 
539  if (var->varlevelsup == context->sublevels_up &&
540  var->location >= 0)
541  {
542  context->var_location = var->location;
543  return true; /* abort tree traversal and return true */
544  }
545  return false;
546  }
547  if (IsA(node, CurrentOfExpr))
548  {
549  /* since CurrentOfExpr doesn't carry location, nothing we can do */
550  return false;
551  }
552  /* No extra code needed for PlaceHolderVar; just look in contained expr */
553  if (IsA(node, Query))
554  {
555  /* Recurse into subselects */
556  bool result;
557 
558  context->sublevels_up++;
559  result = query_tree_walker((Query *) node,
561  (void *) context,
562  0);
563  context->sublevels_up--;
564  return result;
565  }
566  return expression_tree_walker(node,
568  (void *) context);
569 }
570 
571 
572 /*
573  * pull_var_clause
574  * Recursively pulls all Var nodes from an expression clause.
575  *
576  * Aggrefs are handled according to these bits in 'flags':
577  * PVC_INCLUDE_AGGREGATES include Aggrefs in output list
578  * PVC_RECURSE_AGGREGATES recurse into Aggref arguments
579  * neither flag throw error if Aggref found
580  * Vars within an Aggref's expression are included in the result only
581  * when PVC_RECURSE_AGGREGATES is specified.
582  *
583  * WindowFuncs are handled according to these bits in 'flags':
584  * PVC_INCLUDE_WINDOWFUNCS include WindowFuncs in output list
585  * PVC_RECURSE_WINDOWFUNCS recurse into WindowFunc arguments
586  * neither flag throw error if WindowFunc found
587  * Vars within a WindowFunc's expression are included in the result only
588  * when PVC_RECURSE_WINDOWFUNCS is specified.
589  *
590  * PlaceHolderVars are handled according to these bits in 'flags':
591  * PVC_INCLUDE_PLACEHOLDERS include PlaceHolderVars in output list
592  * PVC_RECURSE_PLACEHOLDERS recurse into PlaceHolderVar arguments
593  * neither flag throw error if PlaceHolderVar found
594  * Vars within a PHV's expression are included in the result only
595  * when PVC_RECURSE_PLACEHOLDERS is specified.
596  *
597  * GroupingFuncs are treated exactly like Aggrefs, and so do not need
598  * their own flag bits.
599  *
600  * CurrentOfExpr nodes are ignored in all cases.
601  *
602  * Upper-level vars (with varlevelsup > 0) should not be seen here,
603  * likewise for upper-level Aggrefs and PlaceHolderVars.
604  *
605  * Returns list of nodes found. Note the nodes themselves are not
606  * copied, only referenced.
607  *
608  * Does not examine subqueries, therefore must only be used after reduction
609  * of sublinks to subplans!
610  */
611 List *
612 pull_var_clause(Node *node, int flags)
613 {
615 
616  /* Assert that caller has not specified inconsistent flags */
623 
624  context.varlist = NIL;
625  context.flags = flags;
626 
628  return context.varlist;
629 }
630 
631 static bool
633 {
634  if (node == NULL)
635  return false;
636  if (IsA(node, Var))
637  {
638  if (((Var *) node)->varlevelsup != 0)
639  elog(ERROR, "Upper-level Var found where not expected");
640  context->varlist = lappend(context->varlist, node);
641  return false;
642  }
643  else if (IsA(node, Aggref))
644  {
645  if (((Aggref *) node)->agglevelsup != 0)
646  elog(ERROR, "Upper-level Aggref found where not expected");
647  if (context->flags & PVC_INCLUDE_AGGREGATES)
648  {
649  context->varlist = lappend(context->varlist, node);
650  /* we do NOT descend into the contained expression */
651  return false;
652  }
653  else if (context->flags & PVC_RECURSE_AGGREGATES)
654  {
655  /* fall through to recurse into the aggregate's arguments */
656  }
657  else
658  elog(ERROR, "Aggref found where not expected");
659  }
660  else if (IsA(node, GroupingFunc))
661  {
662  if (((GroupingFunc *) node)->agglevelsup != 0)
663  elog(ERROR, "Upper-level GROUPING found where not expected");
664  if (context->flags & PVC_INCLUDE_AGGREGATES)
665  {
666  context->varlist = lappend(context->varlist, node);
667  /* we do NOT descend into the contained expression */
668  return false;
669  }
670  else if (context->flags & PVC_RECURSE_AGGREGATES)
671  {
672  /* fall through to recurse into the GroupingFunc's arguments */
673  }
674  else
675  elog(ERROR, "GROUPING found where not expected");
676  }
677  else if (IsA(node, WindowFunc))
678  {
679  /* WindowFuncs have no levelsup field to check ... */
680  if (context->flags & PVC_INCLUDE_WINDOWFUNCS)
681  {
682  context->varlist = lappend(context->varlist, node);
683  /* we do NOT descend into the contained expressions */
684  return false;
685  }
686  else if (context->flags & PVC_RECURSE_WINDOWFUNCS)
687  {
688  /* fall through to recurse into the windowfunc's arguments */
689  }
690  else
691  elog(ERROR, "WindowFunc found where not expected");
692  }
693  else if (IsA(node, PlaceHolderVar))
694  {
695  if (((PlaceHolderVar *) node)->phlevelsup != 0)
696  elog(ERROR, "Upper-level PlaceHolderVar found where not expected");
697  if (context->flags & PVC_INCLUDE_PLACEHOLDERS)
698  {
699  context->varlist = lappend(context->varlist, node);
700  /* we do NOT descend into the contained expression */
701  return false;
702  }
703  else if (context->flags & PVC_RECURSE_PLACEHOLDERS)
704  {
705  /* fall through to recurse into the placeholder's expression */
706  }
707  else
708  elog(ERROR, "PlaceHolderVar found where not expected");
709  }
711  (void *) context);
712 }
713 
714 
715 /*
716  * flatten_join_alias_vars
717  * Replace Vars that reference JOIN outputs with references to the original
718  * relation variables instead. This allows quals involving such vars to be
719  * pushed down. Whole-row Vars that reference JOIN relations are expanded
720  * into RowExpr constructs that name the individual output Vars. This
721  * is necessary since we will not scan the JOIN as a base relation, which
722  * is the only way that the executor can directly handle whole-row Vars.
723  *
724  * This also adjusts relid sets found in some expression node types to
725  * substitute the contained base+OJ rels for any join relid.
726  *
727  * If a JOIN contains sub-selects that have been flattened, its join alias
728  * entries might now be arbitrary expressions, not just Vars. This affects
729  * this function in two important ways. First, we might find ourselves
730  * inserting SubLink expressions into subqueries, and we must make sure that
731  * their Query.hasSubLinks fields get set to true if so. If there are any
732  * SubLinks in the join alias lists, the outer Query should already have
733  * hasSubLinks = true, so this is only relevant to un-flattened subqueries.
734  * Second, we have to preserve any varnullingrels info attached to the
735  * alias Vars we're replacing. If the replacement expression is a Var or
736  * PlaceHolderVar or constructed from those, we can just add the
737  * varnullingrels bits to the existing nullingrels field(s); otherwise
738  * we have to add a PlaceHolderVar wrapper.
739  *
740  * NOTE: this is also used by the parser, to expand join alias Vars before
741  * checking GROUP BY validity. For that use-case, root will be NULL, which
742  * is why we have to pass the Query separately. We need the root itself only
743  * for making PlaceHolderVars. We can avoid making PlaceHolderVars in the
744  * parser's usage because it won't be dealing with arbitrary expressions:
745  * so long as adjust_standard_join_alias_expression can handle everything
746  * the parser would make as a join alias expression, we're OK.
747  */
748 Node *
750 {
752 
753  /*
754  * We do not expect this to be applied to the whole Query, only to
755  * expressions or LATERAL subqueries. Hence, if the top node is a Query,
756  * it's okay to immediately increment sublevels_up.
757  */
758  Assert(node != (Node *) query);
759 
760  context.root = root;
761  context.query = query;
762  context.sublevels_up = 0;
763  /* flag whether join aliases could possibly contain SubLinks */
764  context.possible_sublink = query->hasSubLinks;
765  /* if hasSubLinks is already true, no need to work hard */
766  context.inserted_sublink = query->hasSubLinks;
767 
769 }
770 
771 static Node *
774 {
775  if (node == NULL)
776  return NULL;
777  if (IsA(node, Var))
778  {
779  Var *var = (Var *) node;
780  RangeTblEntry *rte;
781  Node *newvar;
782 
783  /* No change unless Var belongs to a JOIN of the target level */
784  if (var->varlevelsup != context->sublevels_up)
785  return node; /* no need to copy, really */
786  rte = rt_fetch(var->varno, context->query->rtable);
787  if (rte->rtekind != RTE_JOIN)
788  return node;
789  if (var->varattno == InvalidAttrNumber)
790  {
791  /* Must expand whole-row reference */
792  RowExpr *rowexpr;
793  List *fields = NIL;
794  List *colnames = NIL;
795  ListCell *lv;
796  ListCell *ln;
797 
798  Assert(list_length(rte->joinaliasvars) == list_length(rte->eref->colnames));
799  forboth(lv, rte->joinaliasvars, ln, rte->eref->colnames)
800  {
801  newvar = (Node *) lfirst(lv);
802  /* Ignore dropped columns */
803  if (newvar == NULL)
804  continue;
805  newvar = copyObject(newvar);
806 
807  /*
808  * If we are expanding an alias carried down from an upper
809  * query, must adjust its varlevelsup fields.
810  */
811  if (context->sublevels_up != 0)
812  IncrementVarSublevelsUp(newvar, context->sublevels_up, 0);
813  /* Preserve original Var's location, if possible */
814  if (IsA(newvar, Var))
815  ((Var *) newvar)->location = var->location;
816  /* Recurse in case join input is itself a join */
817  /* (also takes care of setting inserted_sublink if needed) */
818  newvar = flatten_join_alias_vars_mutator(newvar, context);
819  fields = lappend(fields, newvar);
820  /* We need the names of non-dropped columns, too */
821  colnames = lappend(colnames, copyObject((Node *) lfirst(ln)));
822  }
823  rowexpr = makeNode(RowExpr);
824  rowexpr->args = fields;
825  rowexpr->row_typeid = var->vartype;
826  rowexpr->row_format = COERCE_IMPLICIT_CAST;
827  /* vartype will always be RECORDOID, so we always need colnames */
828  rowexpr->colnames = colnames;
829  rowexpr->location = var->location;
830 
831  /* Lastly, add any varnullingrels to the replacement expression */
832  return add_nullingrels_if_needed(context->root, (Node *) rowexpr,
833  var);
834  }
835 
836  /* Expand join alias reference */
837  Assert(var->varattno > 0);
838  newvar = (Node *) list_nth(rte->joinaliasvars, var->varattno - 1);
839  Assert(newvar != NULL);
840  newvar = copyObject(newvar);
841 
842  /*
843  * If we are expanding an alias carried down from an upper query, must
844  * adjust its varlevelsup fields.
845  */
846  if (context->sublevels_up != 0)
847  IncrementVarSublevelsUp(newvar, context->sublevels_up, 0);
848 
849  /* Preserve original Var's location, if possible */
850  if (IsA(newvar, Var))
851  ((Var *) newvar)->location = var->location;
852 
853  /* Recurse in case join input is itself a join */
854  newvar = flatten_join_alias_vars_mutator(newvar, context);
855 
856  /* Detect if we are adding a sublink to query */
857  if (context->possible_sublink && !context->inserted_sublink)
858  context->inserted_sublink = checkExprHasSubLink(newvar);
859 
860  /* Lastly, add any varnullingrels to the replacement expression */
861  return add_nullingrels_if_needed(context->root, newvar, var);
862  }
863  if (IsA(node, PlaceHolderVar))
864  {
865  /* Copy the PlaceHolderVar node with correct mutation of subnodes */
866  PlaceHolderVar *phv;
867 
870  (void *) context);
871  /* now fix PlaceHolderVar's relid sets */
872  if (phv->phlevelsup == context->sublevels_up)
873  {
874  phv->phrels = alias_relid_set(context->query,
875  phv->phrels);
876  /* we *don't* change phnullingrels */
877  }
878  return (Node *) phv;
879  }
880 
881  if (IsA(node, Query))
882  {
883  /* Recurse into RTE subquery or not-yet-planned sublink subquery */
884  Query *newnode;
885  bool save_inserted_sublink;
886 
887  context->sublevels_up++;
888  save_inserted_sublink = context->inserted_sublink;
889  context->inserted_sublink = ((Query *) node)->hasSubLinks;
890  newnode = query_tree_mutator((Query *) node,
892  (void *) context,
894  newnode->hasSubLinks |= context->inserted_sublink;
895  context->inserted_sublink = save_inserted_sublink;
896  context->sublevels_up--;
897  return (Node *) newnode;
898  }
899  /* Already-planned tree not supported */
900  Assert(!IsA(node, SubPlan));
901  Assert(!IsA(node, AlternativeSubPlan));
902  /* Shouldn't need to handle these planner auxiliary nodes here */
903  Assert(!IsA(node, SpecialJoinInfo));
904  Assert(!IsA(node, PlaceHolderInfo));
905  Assert(!IsA(node, MinMaxAggInfo));
906 
908  (void *) context);
909 }
910 
911 /*
912  * flatten_group_exprs
913  * Replace Vars that reference GROUP outputs with the underlying grouping
914  * expressions.
915  *
916  * We have to preserve any varnullingrels info attached to the group Vars we're
917  * replacing. If the replacement expression is a Var or PlaceHolderVar or
918  * constructed from those, we can just add the varnullingrels bits to the
919  * existing nullingrels field(s); otherwise we have to add a PlaceHolderVar
920  * wrapper.
921  *
922  * NOTE: this is also used by ruleutils.c, to deparse one query parsetree back
923  * to source text. For that use-case, root will be NULL, which is why we have
924  * to pass the Query separately. We need the root itself only for preserving
925  * varnullingrels. We can avoid preserving varnullingrels in the ruleutils.c's
926  * usage because it does not make any difference to the deparsed source text.
927  */
928 Node *
930 {
932 
933  /*
934  * We do not expect this to be applied to the whole Query, only to
935  * expressions or LATERAL subqueries. Hence, if the top node is a Query,
936  * it's okay to immediately increment sublevels_up.
937  */
938  Assert(node != (Node *) query);
939 
940  context.root = root;
941  context.query = query;
942  context.sublevels_up = 0;
943  /* flag whether grouping expressions could possibly contain SubLinks */
944  context.possible_sublink = query->hasSubLinks;
945  /* if hasSubLinks is already true, no need to work hard */
946  context.inserted_sublink = query->hasSubLinks;
947 
948  return flatten_group_exprs_mutator(node, &context);
949 }
950 
951 static Node *
954 {
955  if (node == NULL)
956  return NULL;
957  if (IsA(node, Var))
958  {
959  Var *var = (Var *) node;
960  RangeTblEntry *rte;
961  Node *newvar;
962 
963  /* No change unless Var belongs to the GROUP of the target level */
964  if (var->varlevelsup != context->sublevels_up)
965  return node; /* no need to copy, really */
966  rte = rt_fetch(var->varno, context->query->rtable);
967  if (rte->rtekind != RTE_GROUP)
968  return node;
969 
970  /* Expand group exprs reference */
971  Assert(var->varattno > 0);
972  newvar = (Node *) list_nth(rte->groupexprs, var->varattno - 1);
973  Assert(newvar != NULL);
974  newvar = copyObject(newvar);
975 
976  /*
977  * If we are expanding an expr carried down from an upper query, must
978  * adjust its varlevelsup fields.
979  */
980  if (context->sublevels_up != 0)
981  IncrementVarSublevelsUp(newvar, context->sublevels_up, 0);
982 
983  /* Preserve original Var's location, if possible */
984  if (IsA(newvar, Var))
985  ((Var *) newvar)->location = var->location;
986 
987  /* Detect if we are adding a sublink to query */
988  if (context->possible_sublink && !context->inserted_sublink)
989  context->inserted_sublink = checkExprHasSubLink(newvar);
990 
991  /* Lastly, add any varnullingrels to the replacement expression */
992  return mark_nullable_by_grouping(context->root, newvar, var);
993  }
994 
995  if (IsA(node, Aggref))
996  {
997  Aggref *agg = (Aggref *) node;
998 
999  if ((int) agg->agglevelsup == context->sublevels_up)
1000  {
1001  /*
1002  * If we find an aggregate call of the original level, do not
1003  * recurse into its normal arguments, ORDER BY arguments, or
1004  * filter; there are no grouped vars there. But we should check
1005  * direct arguments as though they weren't in an aggregate.
1006  */
1007  agg = copyObject(agg);
1008  agg->aggdirectargs = (List *)
1010 
1011  return (Node *) agg;
1012  }
1013 
1014  /*
1015  * We can skip recursing into aggregates of higher levels altogether,
1016  * since they could not possibly contain Vars of concern to us (see
1017  * transformAggregateCall). We do need to look at aggregates of lower
1018  * levels, however.
1019  */
1020  if ((int) agg->agglevelsup > context->sublevels_up)
1021  return node;
1022  }
1023 
1024  if (IsA(node, GroupingFunc))
1025  {
1026  GroupingFunc *grp = (GroupingFunc *) node;
1027 
1028  /*
1029  * If we find a GroupingFunc node of the original or higher level, do
1030  * not recurse into its arguments; there are no grouped vars there.
1031  */
1032  if ((int) grp->agglevelsup >= context->sublevels_up)
1033  return node;
1034  }
1035 
1036  if (IsA(node, Query))
1037  {
1038  /* Recurse into RTE subquery or not-yet-planned sublink subquery */
1039  Query *newnode;
1040  bool save_inserted_sublink;
1041 
1042  context->sublevels_up++;
1043  save_inserted_sublink = context->inserted_sublink;
1044  context->inserted_sublink = ((Query *) node)->hasSubLinks;
1045  newnode = query_tree_mutator((Query *) node,
1047  (void *) context,
1049  newnode->hasSubLinks |= context->inserted_sublink;
1050  context->inserted_sublink = save_inserted_sublink;
1051  context->sublevels_up--;
1052  return (Node *) newnode;
1053  }
1054 
1056  (void *) context);
1057 }
1058 
1059 /*
1060  * Add oldvar's varnullingrels, if any, to a flattened grouping expression.
1061  * The newnode has been copied, so we can modify it freely.
1062  */
1063 static Node *
1065 {
1066  Relids relids;
1067 
1068  if (root == NULL)
1069  return newnode;
1070  if (oldvar->varnullingrels == NULL)
1071  return newnode; /* nothing to do */
1072 
1073  Assert(bms_equal(oldvar->varnullingrels,
1074  bms_make_singleton(root->group_rtindex)));
1075 
1076  relids = pull_varnos_of_level(root, newnode, oldvar->varlevelsup);
1077 
1078  if (!bms_is_empty(relids))
1079  {
1080  /*
1081  * If the newnode is not variable-free, we set the nullingrels of Vars
1082  * or PHVs that are contained in the expression. This is not really
1083  * 'correct' in theory, because it is the whole expression that can be
1084  * nullable by grouping sets, not its individual vars. But it works
1085  * in practice, because what we need is that the expression can be
1086  * somehow distinguished from the same expression in ECs, and marking
1087  * its vars is sufficient for this purpose.
1088  */
1089  newnode = add_nulling_relids(newnode,
1090  relids,
1091  oldvar->varnullingrels);
1092  }
1093  else /* variable-free? */
1094  {
1095  /*
1096  * If the newnode is variable-free and does not contain volatile
1097  * functions or set-returning functions, it can be treated as a member
1098  * of EC that is redundant. So wrap it in a new PlaceHolderVar to
1099  * carry the nullingrels. Otherwise we do not bother to make any
1100  * changes.
1101  *
1102  * Aggregate functions and window functions are not allowed in
1103  * grouping expressions.
1104  */
1105  Assert(!contain_agg_clause(newnode));
1106  Assert(!contain_window_function(newnode));
1107 
1108  if (!contain_volatile_functions(newnode) &&
1109  !expression_returns_set(newnode))
1110  {
1111  PlaceHolderVar *newphv;
1112  Relids phrels;
1113 
1114  phrels = get_relids_in_jointree((Node *) root->parse->jointree,
1115  true, false);
1116  Assert(!bms_is_empty(phrels));
1117 
1118  newphv = make_placeholder_expr(root, (Expr *) newnode, phrels);
1119  /* newphv has zero phlevelsup and NULL phnullingrels; fix it */
1120  newphv->phlevelsup = oldvar->varlevelsup;
1121  newphv->phnullingrels = bms_copy(oldvar->varnullingrels);
1122  newnode = (Node *) newphv;
1123  }
1124  }
1125 
1126  return newnode;
1127 }
1128 
1129 /*
1130  * Add oldvar's varnullingrels, if any, to a flattened join alias expression.
1131  * The newnode has been copied, so we can modify it freely.
1132  */
1133 static Node *
1135 {
1136  if (oldvar->varnullingrels == NULL)
1137  return newnode; /* nothing to do */
1138  /* If possible, do it by adding to existing nullingrel fields */
1139  if (is_standard_join_alias_expression(newnode, oldvar))
1140  adjust_standard_join_alias_expression(newnode, oldvar);
1141  else if (root)
1142  {
1143  /*
1144  * We can insert a PlaceHolderVar to carry the nullingrels. However,
1145  * deciding where to evaluate the PHV is slightly tricky. We first
1146  * try to evaluate it at the natural semantic level of the new
1147  * expression; but if that expression is variable-free, fall back to
1148  * evaluating it at the join that the oldvar is an alias Var for.
1149  */
1150  PlaceHolderVar *newphv;
1151  Index levelsup = oldvar->varlevelsup;
1152  Relids phrels = pull_varnos_of_level(root, newnode, levelsup);
1153 
1154  if (bms_is_empty(phrels)) /* variable-free? */
1155  {
1156  if (levelsup != 0) /* this won't work otherwise */
1157  elog(ERROR, "unsupported join alias expression");
1158  phrels = get_relids_for_join(root->parse, oldvar->varno);
1159  /* If it's an outer join, eval below not above the join */
1160  phrels = bms_del_member(phrels, oldvar->varno);
1161  Assert(!bms_is_empty(phrels));
1162  }
1163  newphv = make_placeholder_expr(root, (Expr *) newnode, phrels);
1164  /* newphv has zero phlevelsup and NULL phnullingrels; fix it */
1165  newphv->phlevelsup = levelsup;
1166  newphv->phnullingrels = bms_copy(oldvar->varnullingrels);
1167  newnode = (Node *) newphv;
1168  }
1169  else
1170  {
1171  /* ooops, we're missing support for something the parser can make */
1172  elog(ERROR, "unsupported join alias expression");
1173  }
1174  return newnode;
1175 }
1176 
1177 /*
1178  * Check to see if we can insert nullingrels into this join alias expression
1179  * without use of a separate PlaceHolderVar.
1180  *
1181  * This will handle Vars, PlaceHolderVars, and implicit-coercion and COALESCE
1182  * expressions built from those. This coverage needs to handle anything
1183  * that the parser would put into joinaliasvars.
1184  */
1185 static bool
1187 {
1188  if (newnode == NULL)
1189  return false;
1190  if (IsA(newnode, Var) &&
1191  ((Var *) newnode)->varlevelsup == oldvar->varlevelsup)
1192  return true;
1193  else if (IsA(newnode, PlaceHolderVar) &&
1194  ((PlaceHolderVar *) newnode)->phlevelsup == oldvar->varlevelsup)
1195  return true;
1196  else if (IsA(newnode, FuncExpr))
1197  {
1198  FuncExpr *fexpr = (FuncExpr *) newnode;
1199 
1200  /*
1201  * We need to assume that the function wouldn't produce non-NULL from
1202  * NULL, which is reasonable for implicit coercions but otherwise not
1203  * so much. (Looking at its strictness is likely overkill, and anyway
1204  * it would cause us to fail if someone forgot to mark an implicit
1205  * coercion as strict.)
1206  */
1207  if (fexpr->funcformat != COERCE_IMPLICIT_CAST ||
1208  fexpr->args == NIL)
1209  return false;
1210 
1211  /*
1212  * Examine only the first argument --- coercions might have additional
1213  * arguments that are constants.
1214  */
1215  return is_standard_join_alias_expression(linitial(fexpr->args), oldvar);
1216  }
1217  else if (IsA(newnode, RelabelType))
1218  {
1219  RelabelType *relabel = (RelabelType *) newnode;
1220 
1221  /* This definitely won't produce non-NULL from NULL */
1222  return is_standard_join_alias_expression((Node *) relabel->arg, oldvar);
1223  }
1224  else if (IsA(newnode, CoerceViaIO))
1225  {
1226  CoerceViaIO *iocoerce = (CoerceViaIO *) newnode;
1227 
1228  /* This definitely won't produce non-NULL from NULL */
1229  return is_standard_join_alias_expression((Node *) iocoerce->arg, oldvar);
1230  }
1231  else if (IsA(newnode, ArrayCoerceExpr))
1232  {
1233  ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) newnode;
1234 
1235  /* This definitely won't produce non-NULL from NULL (at array level) */
1236  return is_standard_join_alias_expression((Node *) acoerce->arg, oldvar);
1237  }
1238  else if (IsA(newnode, CoalesceExpr))
1239  {
1240  CoalesceExpr *cexpr = (CoalesceExpr *) newnode;
1241  ListCell *lc;
1242 
1243  Assert(cexpr->args != NIL);
1244  foreach(lc, cexpr->args)
1245  {
1246  if (!is_standard_join_alias_expression(lfirst(lc), oldvar))
1247  return false;
1248  }
1249  return true;
1250  }
1251  else
1252  return false;
1253 }
1254 
1255 /*
1256  * Insert nullingrels into an expression accepted by
1257  * is_standard_join_alias_expression.
1258  */
1259 static void
1261 {
1262  if (IsA(newnode, Var) &&
1263  ((Var *) newnode)->varlevelsup == oldvar->varlevelsup)
1264  {
1265  Var *newvar = (Var *) newnode;
1266 
1267  newvar->varnullingrels = bms_add_members(newvar->varnullingrels,
1268  oldvar->varnullingrels);
1269  }
1270  else if (IsA(newnode, PlaceHolderVar) &&
1271  ((PlaceHolderVar *) newnode)->phlevelsup == oldvar->varlevelsup)
1272  {
1273  PlaceHolderVar *newphv = (PlaceHolderVar *) newnode;
1274 
1275  newphv->phnullingrels = bms_add_members(newphv->phnullingrels,
1276  oldvar->varnullingrels);
1277  }
1278  else if (IsA(newnode, FuncExpr))
1279  {
1280  FuncExpr *fexpr = (FuncExpr *) newnode;
1281 
1283  }
1284  else if (IsA(newnode, RelabelType))
1285  {
1286  RelabelType *relabel = (RelabelType *) newnode;
1287 
1288  adjust_standard_join_alias_expression((Node *) relabel->arg, oldvar);
1289  }
1290  else if (IsA(newnode, CoerceViaIO))
1291  {
1292  CoerceViaIO *iocoerce = (CoerceViaIO *) newnode;
1293 
1294  adjust_standard_join_alias_expression((Node *) iocoerce->arg, oldvar);
1295  }
1296  else if (IsA(newnode, ArrayCoerceExpr))
1297  {
1298  ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) newnode;
1299 
1300  adjust_standard_join_alias_expression((Node *) acoerce->arg, oldvar);
1301  }
1302  else if (IsA(newnode, CoalesceExpr))
1303  {
1304  CoalesceExpr *cexpr = (CoalesceExpr *) newnode;
1305  ListCell *lc;
1306 
1307  Assert(cexpr->args != NIL);
1308  foreach(lc, cexpr->args)
1309  {
1311  }
1312  }
1313  else
1314  Assert(false);
1315 }
1316 
1317 /*
1318  * alias_relid_set: in a set of RT indexes, replace joins by their
1319  * underlying base+OJ relids
1320  */
1321 static Relids
1323 {
1324  Relids result = NULL;
1325  int rtindex;
1326 
1327  rtindex = -1;
1328  while ((rtindex = bms_next_member(relids, rtindex)) >= 0)
1329  {
1330  RangeTblEntry *rte = rt_fetch(rtindex, query->rtable);
1331 
1332  if (rte->rtekind == RTE_JOIN)
1333  result = bms_join(result, get_relids_for_join(query, rtindex));
1334  else
1335  result = bms_add_member(result, rtindex);
1336  }
1337  return result;
1338 }
#define InvalidAttrNumber
Definition: attnum.h:23
Bitmapset * bms_join(Bitmapset *a, Bitmapset *b)
Definition: bitmapset.c:1230
bool bms_equal(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:142
int bms_next_member(const Bitmapset *a, int prevbit)
Definition: bitmapset.c:1306
Bitmapset * bms_make_singleton(int x)
Definition: bitmapset.c:216
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:815
Bitmapset * bms_difference(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:346
Bitmapset * bms_add_members(Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:917
Bitmapset * bms_del_member(Bitmapset *a, int x)
Definition: bitmapset.c:868
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:861
unsigned int Index
Definition: c.h:617
bool contain_agg_clause(Node *clause)
Definition: clauses.c:177
bool contain_window_function(Node *clause)
Definition: clauses.c:214
bool contain_volatile_functions(Node *clause)
Definition: clauses.c:538
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
List * lappend(List *list, void *datum)
Definition: list.c:339
bool expression_returns_set(Node *clause)
Definition: nodeFuncs.c:758
#define expression_tree_mutator(n, m, c)
Definition: nodeFuncs.h:155
#define query_tree_walker(q, w, c, f)
Definition: nodeFuncs.h:158
#define query_or_expression_tree_walker(n, w, c, f)
Definition: nodeFuncs.h:171
#define QTW_IGNORE_GROUPEXPRS
Definition: nodeFuncs.h:32
#define expression_tree_walker(n, w, c)
Definition: nodeFuncs.h:153
#define query_tree_mutator(q, m, c, f)
Definition: nodeFuncs.h:160
#define QTW_IGNORE_JOINALIASES
Definition: nodeFuncs.h:25
#define IsA(nodeptr, _type_)
Definition: nodes.h:158
#define copyObject(obj)
Definition: nodes.h:224
#define makeNode(_type_)
Definition: nodes.h:155
#define PVC_RECURSE_AGGREGATES
Definition: optimizer.h:187
#define PVC_RECURSE_PLACEHOLDERS
Definition: optimizer.h:191
#define PVC_RECURSE_WINDOWFUNCS
Definition: optimizer.h:189
#define PVC_INCLUDE_WINDOWFUNCS
Definition: optimizer.h:188
#define PVC_INCLUDE_PLACEHOLDERS
Definition: optimizer.h:190
#define PVC_INCLUDE_AGGREGATES
Definition: optimizer.h:186
@ RTE_JOIN
Definition: parsenodes.h:1019
@ RTE_GROUP
Definition: parsenodes.h:1028
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
#define lfirst(lc)
Definition: pg_list.h:172
static int list_length(const List *l)
Definition: pg_list.h:152
#define NIL
Definition: pg_list.h:68
#define forboth(cell1, list1, cell2, list2)
Definition: pg_list.h:518
#define linitial(l)
Definition: pg_list.h:178
static void * list_nth(const List *list, int n)
Definition: pg_list.h:299
PlaceHolderVar * make_placeholder_expr(PlannerInfo *root, Expr *expr, Relids phrels)
Definition: placeholder.c:54
Relids get_relids_for_join(Query *query, int joinrelid)
Relids get_relids_in_jointree(Node *jtnode, bool include_outer_joins, bool include_inner_joins)
@ COERCE_IMPLICIT_CAST
Definition: primnodes.h:736
tree context
Definition: radixtree.h:1835
tree ctl root
Definition: radixtree.h:1886
bool checkExprHasSubLink(Node *node)
Definition: rewriteManip.c:295
Node * add_nulling_relids(Node *node, const Bitmapset *target_relids, const Bitmapset *added_relids)
void IncrementVarSublevelsUp(Node *node, int delta_sublevels_up, int min_sublevels_up)
Definition: rewriteManip.c:849
List * aggdirectargs
Definition: primnodes.h:465
List * args
Definition: primnodes.h:1492
Expr * arg
Definition: primnodes.h:1207
List * args
Definition: primnodes.h:768
Index agglevelsup
Definition: primnodes.h:551
Definition: pg_list.h:54
Definition: nodes.h:129
Relids ph_eval_at
Definition: pathnodes.h:3095
PlaceHolderVar * ph_var
Definition: pathnodes.h:3092
Relids phnullingrels
Definition: pathnodes.h:2798
Index phlevelsup
Definition: pathnodes.h:2804
List * rtable
Definition: parsenodes.h:170
RTEKind rtekind
Definition: parsenodes.h:1047
Expr * arg
Definition: primnodes.h:1184
List * args
Definition: primnodes.h:1411
ParseLoc location
Definition: primnodes.h:1435
Definition: primnodes.h:248
ParseLoc location
Definition: primnodes.h:293
AttrNumber varattno
Definition: primnodes.h:260
int varno
Definition: primnodes.h:255
Index varlevelsup
Definition: primnodes.h:280
PlannerInfo * root
Definition: var.c:66
Bitmapset * varattnos
Definition: var.c:42
PlannerInfo * root
Definition: var.c:36
int sublevels_up
Definition: var.c:37
Relids varnos
Definition: var.c:35
int sublevels_up
Definition: var.c:49
List * vars
Definition: var.c:48
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:27
static bool pull_varattnos_walker(Node *node, pull_varattnos_context *context)
Definition: var.c:309
List * pull_vars_of_level(Node *node, int levelsup)
Definition: var.c:340
static Node * add_nullingrels_if_needed(PlannerInfo *root, Node *newnode, Var *oldvar)
Definition: var.c:1134
bool contain_vars_of_level(Node *node, int levelsup)
Definition: var.c:446
List * pull_var_clause(Node *node, int flags)
Definition: var.c:612
static Node * flatten_join_alias_vars_mutator(Node *node, flatten_join_alias_vars_context *context)
Definition: var.c:772
bool contain_var_clause(Node *node)
Definition: var.c:408
Relids pull_varnos_of_level(PlannerInfo *root, Node *node, int levelsup)
Definition: var.c:139
Relids pull_varnos(PlannerInfo *root, Node *node)
Definition: var.c:113
static bool pull_varnos_walker(Node *node, pull_varnos_context *context)
Definition: var.c:160
static bool pull_var_clause_walker(Node *node, pull_var_clause_context *context)
Definition: var.c:632
static Node * flatten_group_exprs_mutator(Node *node, flatten_join_alias_vars_context *context)
Definition: var.c:952
static Relids alias_relid_set(Query *query, Relids relids)
Definition: var.c:1322
static bool contain_vars_of_level_walker(Node *node, int *sublevels_up)
Definition: var.c:457
static bool is_standard_join_alias_expression(Node *newnode, Var *oldvar)
Definition: var.c:1186
static Node * mark_nullable_by_grouping(PlannerInfo *root, Node *newnode, Var *oldvar)
Definition: var.c:1064
Node * flatten_join_alias_vars(PlannerInfo *root, Query *query, Node *node)
Definition: var.c:749
void pull_varattnos(Node *node, Index varno, Bitmapset **varattnos)
Definition: var.c:296
static void adjust_standard_join_alias_expression(Node *newnode, Var *oldvar)
Definition: var.c:1260
static bool locate_var_of_level_walker(Node *node, locate_var_of_level_context *context)
Definition: var.c:530
int locate_var_of_level(Node *node, int levelsup)
Definition: var.c:514
static bool contain_var_clause_walker(Node *node, void *context)
Definition: var.c:414
Node * flatten_group_exprs(PlannerInfo *root, Query *query, Node *node)
Definition: var.c:929
static bool pull_vars_walker(Node *node, pull_vars_context *context)
Definition: var.c:360