PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
rewriteManip.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * rewriteManip.c
4  *
5  * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
6  * Portions Copyright (c) 1994, Regents of the University of California
7  *
8  *
9  * IDENTIFICATION
10  * src/backend/rewrite/rewriteManip.c
11  *
12  *-------------------------------------------------------------------------
13  */
14 #include "postgres.h"
15 
16 #include "catalog/pg_type.h"
17 #include "nodes/makefuncs.h"
18 #include "nodes/nodeFuncs.h"
19 #include "nodes/plannodes.h"
20 #include "optimizer/clauses.h"
21 #include "parser/parse_coerce.h"
22 #include "parser/parse_relation.h"
23 #include "parser/parsetree.h"
24 #include "rewrite/rewriteManip.h"
25 
26 
27 typedef struct
28 {
31 
32 typedef struct
33 {
37 
38 typedef struct
39 {
42 
43 static bool contain_aggs_of_level_walker(Node *node,
45 static bool locate_agg_of_level_walker(Node *node,
47 static bool contain_windowfuncs_walker(Node *node, void *context);
48 static bool locate_windowfunc_walker(Node *node,
49  locate_windowfunc_context *context);
50 static bool checkExprHasSubLink_walker(Node *node, void *context);
51 static Relids offset_relid_set(Relids relids, int offset);
52 static Relids adjust_relid_set(Relids relids, int oldrelid, int newrelid);
53 
54 
55 /*
56  * contain_aggs_of_level -
57  * Check if an expression contains an aggregate function call of a
58  * specified query level.
59  *
60  * The objective of this routine is to detect whether there are aggregates
61  * belonging to the given query level. Aggregates belonging to subqueries
62  * or outer queries do NOT cause a true result. We must recurse into
63  * subqueries to detect outer-reference aggregates that logically belong to
64  * the specified query level.
65  */
66 bool
67 contain_aggs_of_level(Node *node, int levelsup)
68 {
70 
71  context.sublevels_up = levelsup;
72 
73  /*
74  * Must be prepared to start with a Query or a bare expression tree; if
75  * it's a Query, we don't want to increment sublevels_up.
76  */
79  (void *) &context,
80  0);
81 }
82 
83 static bool
86 {
87  if (node == NULL)
88  return false;
89  if (IsA(node, Aggref))
90  {
91  if (((Aggref *) node)->agglevelsup == context->sublevels_up)
92  return true; /* abort the tree traversal and return true */
93  /* else fall through to examine argument */
94  }
95  if (IsA(node, GroupingFunc))
96  {
97  if (((GroupingFunc *) node)->agglevelsup == context->sublevels_up)
98  return true;
99  /* else fall through to examine argument */
100  }
101  if (IsA(node, Query))
102  {
103  /* Recurse into subselects */
104  bool result;
105 
106  context->sublevels_up++;
107  result = query_tree_walker((Query *) node,
109  (void *) context, 0);
110  context->sublevels_up--;
111  return result;
112  }
114  (void *) context);
115 }
116 
117 /*
118  * locate_agg_of_level -
119  * Find the parse location of any aggregate of the specified query level.
120  *
121  * Returns -1 if no such agg is in the querytree, or if they all have
122  * unknown parse location. (The former case is probably caller error,
123  * but we don't bother to distinguish it from the latter case.)
124  *
125  * Note: it might seem appropriate to merge this functionality into
126  * contain_aggs_of_level, but that would complicate that function's API.
127  * Currently, the only uses of this function are for error reporting,
128  * and so shaving cycles probably isn't very important.
129  */
130 int
131 locate_agg_of_level(Node *node, int levelsup)
132 {
134 
135  context.agg_location = -1; /* in case we find nothing */
136  context.sublevels_up = levelsup;
137 
138  /*
139  * Must be prepared to start with a Query or a bare expression tree; if
140  * it's a Query, we don't want to increment sublevels_up.
141  */
144  (void *) &context,
145  0);
146 
147  return context.agg_location;
148 }
149 
150 static bool
153 {
154  if (node == NULL)
155  return false;
156  if (IsA(node, Aggref))
157  {
158  if (((Aggref *) node)->agglevelsup == context->sublevels_up &&
159  ((Aggref *) node)->location >= 0)
160  {
161  context->agg_location = ((Aggref *) node)->location;
162  return true; /* abort the tree traversal and return true */
163  }
164  /* else fall through to examine argument */
165  }
166  if (IsA(node, GroupingFunc))
167  {
168  if (((GroupingFunc *) node)->agglevelsup == context->sublevels_up &&
169  ((GroupingFunc *) node)->location >= 0)
170  {
171  context->agg_location = ((GroupingFunc *) node)->location;
172  return true; /* abort the tree traversal and return true */
173  }
174  }
175  if (IsA(node, Query))
176  {
177  /* Recurse into subselects */
178  bool result;
179 
180  context->sublevels_up++;
181  result = query_tree_walker((Query *) node,
183  (void *) context, 0);
184  context->sublevels_up--;
185  return result;
186  }
188  (void *) context);
189 }
190 
191 /*
192  * contain_windowfuncs -
193  * Check if an expression contains a window function call of the
194  * current query level.
195  */
196 bool
198 {
199  /*
200  * Must be prepared to start with a Query or a bare expression tree; if
201  * it's a Query, we don't want to increment sublevels_up.
202  */
205  NULL,
206  0);
207 }
208 
209 static bool
210 contain_windowfuncs_walker(Node *node, void *context)
211 {
212  if (node == NULL)
213  return false;
214  if (IsA(node, WindowFunc))
215  return true; /* abort the tree traversal and return true */
216  /* Mustn't recurse into subselects */
218  (void *) context);
219 }
220 
221 /*
222  * locate_windowfunc -
223  * Find the parse location of any windowfunc of the current query level.
224  *
225  * Returns -1 if no such windowfunc is in the querytree, or if they all have
226  * unknown parse location. (The former case is probably caller error,
227  * but we don't bother to distinguish it from the latter case.)
228  *
229  * Note: it might seem appropriate to merge this functionality into
230  * contain_windowfuncs, but that would complicate that function's API.
231  * Currently, the only uses of this function are for error reporting,
232  * and so shaving cycles probably isn't very important.
233  */
234 int
236 {
238 
239  context.win_location = -1; /* in case we find nothing */
240 
241  /*
242  * Must be prepared to start with a Query or a bare expression tree; if
243  * it's a Query, we don't want to increment sublevels_up.
244  */
247  (void *) &context,
248  0);
249 
250  return context.win_location;
251 }
252 
253 static bool
255 {
256  if (node == NULL)
257  return false;
258  if (IsA(node, WindowFunc))
259  {
260  if (((WindowFunc *) node)->location >= 0)
261  {
262  context->win_location = ((WindowFunc *) node)->location;
263  return true; /* abort the tree traversal and return true */
264  }
265  /* else fall through to examine argument */
266  }
267  /* Mustn't recurse into subselects */
269  (void *) context);
270 }
271 
272 /*
273  * checkExprHasSubLink -
274  * Check if an expression contains a SubLink.
275  */
276 bool
278 {
279  /*
280  * If a Query is passed, examine it --- but we should not recurse into
281  * sub-Queries that are in its rangetable or CTE list.
282  */
285  NULL,
287 }
288 
289 static bool
290 checkExprHasSubLink_walker(Node *node, void *context)
291 {
292  if (node == NULL)
293  return false;
294  if (IsA(node, SubLink))
295  return true; /* abort the tree traversal and return true */
296  return expression_tree_walker(node, checkExprHasSubLink_walker, context);
297 }
298 
299 /*
300  * Check for MULTIEXPR Param within expression tree
301  *
302  * We intentionally don't descend into SubLinks: only Params at the current
303  * query level are of interest.
304  */
305 static bool
306 contains_multiexpr_param(Node *node, void *context)
307 {
308  if (node == NULL)
309  return false;
310  if (IsA(node, Param))
311  {
312  if (((Param *) node)->paramkind == PARAM_MULTIEXPR)
313  return true; /* abort the tree traversal and return true */
314  return false;
315  }
316  return expression_tree_walker(node, contains_multiexpr_param, context);
317 }
318 
319 
320 /*
321  * OffsetVarNodes - adjust Vars when appending one query's RT to another
322  *
323  * Find all Var nodes in the given tree with varlevelsup == sublevels_up,
324  * and increment their varno fields (rangetable indexes) by 'offset'.
325  * The varnoold fields are adjusted similarly. Also, adjust other nodes
326  * that contain rangetable indexes, such as RangeTblRef and JoinExpr.
327  *
328  * NOTE: although this has the form of a walker, we cheat and modify the
329  * nodes in-place. The given expression tree should have been copied
330  * earlier to ensure that no unwanted side-effects occur!
331  */
332 
333 typedef struct
334 {
335  int offset;
338 
339 static bool
341 {
342  if (node == NULL)
343  return false;
344  if (IsA(node, Var))
345  {
346  Var *var = (Var *) node;
347 
348  if (var->varlevelsup == context->sublevels_up)
349  {
350  var->varno += context->offset;
351  var->varnoold += context->offset;
352  }
353  return false;
354  }
355  if (IsA(node, CurrentOfExpr))
356  {
357  CurrentOfExpr *cexpr = (CurrentOfExpr *) node;
358 
359  if (context->sublevels_up == 0)
360  cexpr->cvarno += context->offset;
361  return false;
362  }
363  if (IsA(node, RangeTblRef))
364  {
365  RangeTblRef *rtr = (RangeTblRef *) node;
366 
367  if (context->sublevels_up == 0)
368  rtr->rtindex += context->offset;
369  /* the subquery itself is visited separately */
370  return false;
371  }
372  if (IsA(node, JoinExpr))
373  {
374  JoinExpr *j = (JoinExpr *) node;
375 
376  if (j->rtindex && context->sublevels_up == 0)
377  j->rtindex += context->offset;
378  /* fall through to examine children */
379  }
380  if (IsA(node, PlaceHolderVar))
381  {
382  PlaceHolderVar *phv = (PlaceHolderVar *) node;
383 
384  if (phv->phlevelsup == context->sublevels_up)
385  {
386  phv->phrels = offset_relid_set(phv->phrels,
387  context->offset);
388  }
389  /* fall through to examine children */
390  }
391  if (IsA(node, AppendRelInfo))
392  {
393  AppendRelInfo *appinfo = (AppendRelInfo *) node;
394 
395  if (context->sublevels_up == 0)
396  {
397  appinfo->parent_relid += context->offset;
398  appinfo->child_relid += context->offset;
399  }
400  /* fall through to examine children */
401  }
402  /* Shouldn't need to handle other planner auxiliary nodes here */
403  Assert(!IsA(node, PlanRowMark));
404  Assert(!IsA(node, SpecialJoinInfo));
405  Assert(!IsA(node, PlaceHolderInfo));
406  Assert(!IsA(node, MinMaxAggInfo));
407 
408  if (IsA(node, Query))
409  {
410  /* Recurse into subselects */
411  bool result;
412 
413  context->sublevels_up++;
414  result = query_tree_walker((Query *) node, OffsetVarNodes_walker,
415  (void *) context, 0);
416  context->sublevels_up--;
417  return result;
418  }
420  (void *) context);
421 }
422 
423 void
424 OffsetVarNodes(Node *node, int offset, int sublevels_up)
425 {
426  OffsetVarNodes_context context;
427 
428  context.offset = offset;
429  context.sublevels_up = sublevels_up;
430 
431  /*
432  * Must be prepared to start with a Query or a bare expression tree; if
433  * it's a Query, go straight to query_tree_walker to make sure that
434  * sublevels_up doesn't get incremented prematurely.
435  */
436  if (node && IsA(node, Query))
437  {
438  Query *qry = (Query *) node;
439 
440  /*
441  * If we are starting at a Query, and sublevels_up is zero, then we
442  * must also fix rangetable indexes in the Query itself --- namely
443  * resultRelation, exclRelIndex and rowMarks entries. sublevels_up
444  * cannot be zero when recursing into a subquery, so there's no need
445  * to have the same logic inside OffsetVarNodes_walker.
446  */
447  if (sublevels_up == 0)
448  {
449  ListCell *l;
450 
451  if (qry->resultRelation)
452  qry->resultRelation += offset;
453 
454  if (qry->onConflict && qry->onConflict->exclRelIndex)
455  qry->onConflict->exclRelIndex += offset;
456 
457  foreach(l, qry->rowMarks)
458  {
459  RowMarkClause *rc = (RowMarkClause *) lfirst(l);
460 
461  rc->rti += offset;
462  }
463  }
465  (void *) &context, 0);
466  }
467  else
468  OffsetVarNodes_walker(node, &context);
469 }
470 
471 static Relids
472 offset_relid_set(Relids relids, int offset)
473 {
474  Relids result = NULL;
475  int rtindex;
476 
477  rtindex = -1;
478  while ((rtindex = bms_next_member(relids, rtindex)) >= 0)
479  result = bms_add_member(result, rtindex + offset);
480  return result;
481 }
482 
483 /*
484  * ChangeVarNodes - adjust Var nodes for a specific change of RT index
485  *
486  * Find all Var nodes in the given tree belonging to a specific relation
487  * (identified by sublevels_up and rt_index), and change their varno fields
488  * to 'new_index'. The varnoold fields are changed too. Also, adjust other
489  * nodes that contain rangetable indexes, such as RangeTblRef and JoinExpr.
490  *
491  * NOTE: although this has the form of a walker, we cheat and modify the
492  * nodes in-place. The given expression tree should have been copied
493  * earlier to ensure that no unwanted side-effects occur!
494  */
495 
496 typedef struct
497 {
498  int rt_index;
502 
503 static bool
505 {
506  if (node == NULL)
507  return false;
508  if (IsA(node, Var))
509  {
510  Var *var = (Var *) node;
511 
512  if (var->varlevelsup == context->sublevels_up &&
513  var->varno == context->rt_index)
514  {
515  var->varno = context->new_index;
516  var->varnoold = context->new_index;
517  }
518  return false;
519  }
520  if (IsA(node, CurrentOfExpr))
521  {
522  CurrentOfExpr *cexpr = (CurrentOfExpr *) node;
523 
524  if (context->sublevels_up == 0 &&
525  cexpr->cvarno == context->rt_index)
526  cexpr->cvarno = context->new_index;
527  return false;
528  }
529  if (IsA(node, RangeTblRef))
530  {
531  RangeTblRef *rtr = (RangeTblRef *) node;
532 
533  if (context->sublevels_up == 0 &&
534  rtr->rtindex == context->rt_index)
535  rtr->rtindex = context->new_index;
536  /* the subquery itself is visited separately */
537  return false;
538  }
539  if (IsA(node, JoinExpr))
540  {
541  JoinExpr *j = (JoinExpr *) node;
542 
543  if (context->sublevels_up == 0 &&
544  j->rtindex == context->rt_index)
545  j->rtindex = context->new_index;
546  /* fall through to examine children */
547  }
548  if (IsA(node, PlaceHolderVar))
549  {
550  PlaceHolderVar *phv = (PlaceHolderVar *) node;
551 
552  if (phv->phlevelsup == context->sublevels_up)
553  {
554  phv->phrels = adjust_relid_set(phv->phrels,
555  context->rt_index,
556  context->new_index);
557  }
558  /* fall through to examine children */
559  }
560  if (IsA(node, PlanRowMark))
561  {
562  PlanRowMark *rowmark = (PlanRowMark *) node;
563 
564  if (context->sublevels_up == 0)
565  {
566  if (rowmark->rti == context->rt_index)
567  rowmark->rti = context->new_index;
568  if (rowmark->prti == context->rt_index)
569  rowmark->prti = context->new_index;
570  }
571  return false;
572  }
573  if (IsA(node, AppendRelInfo))
574  {
575  AppendRelInfo *appinfo = (AppendRelInfo *) node;
576 
577  if (context->sublevels_up == 0)
578  {
579  if (appinfo->parent_relid == context->rt_index)
580  appinfo->parent_relid = context->new_index;
581  if (appinfo->child_relid == context->rt_index)
582  appinfo->child_relid = context->new_index;
583  }
584  /* fall through to examine children */
585  }
586  /* Shouldn't need to handle other planner auxiliary nodes here */
587  Assert(!IsA(node, SpecialJoinInfo));
588  Assert(!IsA(node, PlaceHolderInfo));
589  Assert(!IsA(node, MinMaxAggInfo));
590 
591  if (IsA(node, Query))
592  {
593  /* Recurse into subselects */
594  bool result;
595 
596  context->sublevels_up++;
597  result = query_tree_walker((Query *) node, ChangeVarNodes_walker,
598  (void *) context, 0);
599  context->sublevels_up--;
600  return result;
601  }
603  (void *) context);
604 }
605 
606 void
607 ChangeVarNodes(Node *node, int rt_index, int new_index, int sublevels_up)
608 {
609  ChangeVarNodes_context context;
610 
611  context.rt_index = rt_index;
612  context.new_index = new_index;
613  context.sublevels_up = sublevels_up;
614 
615  /*
616  * Must be prepared to start with a Query or a bare expression tree; if
617  * it's a Query, go straight to query_tree_walker to make sure that
618  * sublevels_up doesn't get incremented prematurely.
619  */
620  if (node && IsA(node, Query))
621  {
622  Query *qry = (Query *) node;
623 
624  /*
625  * If we are starting at a Query, and sublevels_up is zero, then we
626  * must also fix rangetable indexes in the Query itself --- namely
627  * resultRelation and rowMarks entries. sublevels_up cannot be zero
628  * when recursing into a subquery, so there's no need to have the same
629  * logic inside ChangeVarNodes_walker.
630  */
631  if (sublevels_up == 0)
632  {
633  ListCell *l;
634 
635  if (qry->resultRelation == rt_index)
636  qry->resultRelation = new_index;
637 
638  /* this is unlikely to ever be used, but ... */
639  if (qry->onConflict && qry->onConflict->exclRelIndex == rt_index)
640  qry->onConflict->exclRelIndex = new_index;
641 
642  foreach(l, qry->rowMarks)
643  {
644  RowMarkClause *rc = (RowMarkClause *) lfirst(l);
645 
646  if (rc->rti == rt_index)
647  rc->rti = new_index;
648  }
649  }
651  (void *) &context, 0);
652  }
653  else
654  ChangeVarNodes_walker(node, &context);
655 }
656 
657 /*
658  * Substitute newrelid for oldrelid in a Relid set
659  */
660 static Relids
661 adjust_relid_set(Relids relids, int oldrelid, int newrelid)
662 {
663  if (bms_is_member(oldrelid, relids))
664  {
665  /* Ensure we have a modifiable copy */
666  relids = bms_copy(relids);
667  /* Remove old, add new */
668  relids = bms_del_member(relids, oldrelid);
669  relids = bms_add_member(relids, newrelid);
670  }
671  return relids;
672 }
673 
674 /*
675  * IncrementVarSublevelsUp - adjust Var nodes when pushing them down in tree
676  *
677  * Find all Var nodes in the given tree having varlevelsup >= min_sublevels_up,
678  * and add delta_sublevels_up to their varlevelsup value. This is needed when
679  * an expression that's correct for some nesting level is inserted into a
680  * subquery. Ordinarily the initial call has min_sublevels_up == 0 so that
681  * all Vars are affected. The point of min_sublevels_up is that we can
682  * increment it when we recurse into a sublink, so that local variables in
683  * that sublink are not affected, only outer references to vars that belong
684  * to the expression's original query level or parents thereof.
685  *
686  * Likewise for other nodes containing levelsup fields, such as Aggref.
687  *
688  * NOTE: although this has the form of a walker, we cheat and modify the
689  * Var nodes in-place. The given expression tree should have been copied
690  * earlier to ensure that no unwanted side-effects occur!
691  */
692 
693 typedef struct
694 {
698 
699 static bool
702 {
703  if (node == NULL)
704  return false;
705  if (IsA(node, Var))
706  {
707  Var *var = (Var *) node;
708 
709  if (var->varlevelsup >= context->min_sublevels_up)
710  var->varlevelsup += context->delta_sublevels_up;
711  return false; /* done here */
712  }
713  if (IsA(node, CurrentOfExpr))
714  {
715  /* this should not happen */
716  if (context->min_sublevels_up == 0)
717  elog(ERROR, "cannot push down CurrentOfExpr");
718  return false;
719  }
720  if (IsA(node, Aggref))
721  {
722  Aggref *agg = (Aggref *) node;
723 
724  if (agg->agglevelsup >= context->min_sublevels_up)
725  agg->agglevelsup += context->delta_sublevels_up;
726  /* fall through to recurse into argument */
727  }
728  if (IsA(node, GroupingFunc))
729  {
730  GroupingFunc *grp = (GroupingFunc *) node;
731 
732  if (grp->agglevelsup >= context->min_sublevels_up)
733  grp->agglevelsup += context->delta_sublevels_up;
734  /* fall through to recurse into argument */
735  }
736  if (IsA(node, PlaceHolderVar))
737  {
738  PlaceHolderVar *phv = (PlaceHolderVar *) node;
739 
740  if (phv->phlevelsup >= context->min_sublevels_up)
741  phv->phlevelsup += context->delta_sublevels_up;
742  /* fall through to recurse into argument */
743  }
744  if (IsA(node, RangeTblEntry))
745  {
746  RangeTblEntry *rte = (RangeTblEntry *) node;
747 
748  if (rte->rtekind == RTE_CTE)
749  {
750  if (rte->ctelevelsup >= context->min_sublevels_up)
751  rte->ctelevelsup += context->delta_sublevels_up;
752  }
753  return false; /* allow range_table_walker to continue */
754  }
755  if (IsA(node, Query))
756  {
757  /* Recurse into subselects */
758  bool result;
759 
760  context->min_sublevels_up++;
761  result = query_tree_walker((Query *) node,
763  (void *) context,
765  context->min_sublevels_up--;
766  return result;
767  }
769  (void *) context);
770 }
771 
772 void
773 IncrementVarSublevelsUp(Node *node, int delta_sublevels_up,
774  int min_sublevels_up)
775 {
777 
778  context.delta_sublevels_up = delta_sublevels_up;
779  context.min_sublevels_up = min_sublevels_up;
780 
781  /*
782  * Must be prepared to start with a Query or a bare expression tree; if
783  * it's a Query, we don't want to increment sublevels_up.
784  */
787  (void *) &context,
789 }
790 
791 /*
792  * IncrementVarSublevelsUp_rtable -
793  * Same as IncrementVarSublevelsUp, but to be invoked on a range table.
794  */
795 void
796 IncrementVarSublevelsUp_rtable(List *rtable, int delta_sublevels_up,
797  int min_sublevels_up)
798 {
800 
801  context.delta_sublevels_up = delta_sublevels_up;
802  context.min_sublevels_up = min_sublevels_up;
803 
804  range_table_walker(rtable,
806  (void *) &context,
808 }
809 
810 
811 /*
812  * rangeTableEntry_used - detect whether an RTE is referenced somewhere
813  * in var nodes or join or setOp trees of a query or expression.
814  */
815 
816 typedef struct
817 {
818  int rt_index;
821 
822 static bool
825 {
826  if (node == NULL)
827  return false;
828  if (IsA(node, Var))
829  {
830  Var *var = (Var *) node;
831 
832  if (var->varlevelsup == context->sublevels_up &&
833  var->varno == context->rt_index)
834  return true;
835  return false;
836  }
837  if (IsA(node, CurrentOfExpr))
838  {
839  CurrentOfExpr *cexpr = (CurrentOfExpr *) node;
840 
841  if (context->sublevels_up == 0 &&
842  cexpr->cvarno == context->rt_index)
843  return true;
844  return false;
845  }
846  if (IsA(node, RangeTblRef))
847  {
848  RangeTblRef *rtr = (RangeTblRef *) node;
849 
850  if (rtr->rtindex == context->rt_index &&
851  context->sublevels_up == 0)
852  return true;
853  /* the subquery itself is visited separately */
854  return false;
855  }
856  if (IsA(node, JoinExpr))
857  {
858  JoinExpr *j = (JoinExpr *) node;
859 
860  if (j->rtindex == context->rt_index &&
861  context->sublevels_up == 0)
862  return true;
863  /* fall through to examine children */
864  }
865  /* Shouldn't need to handle planner auxiliary nodes here */
866  Assert(!IsA(node, PlaceHolderVar));
867  Assert(!IsA(node, PlanRowMark));
868  Assert(!IsA(node, SpecialJoinInfo));
869  Assert(!IsA(node, AppendRelInfo));
870  Assert(!IsA(node, PlaceHolderInfo));
871  Assert(!IsA(node, MinMaxAggInfo));
872 
873  if (IsA(node, Query))
874  {
875  /* Recurse into subselects */
876  bool result;
877 
878  context->sublevels_up++;
880  (void *) context, 0);
881  context->sublevels_up--;
882  return result;
883  }
885  (void *) context);
886 }
887 
888 bool
889 rangeTableEntry_used(Node *node, int rt_index, int sublevels_up)
890 {
892 
893  context.rt_index = rt_index;
894  context.sublevels_up = sublevels_up;
895 
896  /*
897  * Must be prepared to start with a Query or a bare expression tree; if
898  * it's a Query, we don't want to increment sublevels_up.
899  */
902  (void *) &context,
903  0);
904 }
905 
906 
907 /*
908  * If the given Query is an INSERT ... SELECT construct, extract and
909  * return the sub-Query node that represents the SELECT part. Otherwise
910  * return the given Query.
911  *
912  * If subquery_ptr is not NULL, then *subquery_ptr is set to the location
913  * of the link to the SELECT subquery inside parsetree, or NULL if not an
914  * INSERT ... SELECT.
915  *
916  * This is a hack needed because transformations on INSERT ... SELECTs that
917  * appear in rule actions should be applied to the source SELECT, not to the
918  * INSERT part. Perhaps this can be cleaned up with redesigned querytrees.
919  */
920 Query *
921 getInsertSelectQuery(Query *parsetree, Query ***subquery_ptr)
922 {
923  Query *selectquery;
924  RangeTblEntry *selectrte;
925  RangeTblRef *rtr;
926 
927  if (subquery_ptr)
928  *subquery_ptr = NULL;
929 
930  if (parsetree == NULL)
931  return parsetree;
932  if (parsetree->commandType != CMD_INSERT)
933  return parsetree;
934 
935  /*
936  * Currently, this is ONLY applied to rule-action queries, and so we
937  * expect to find the OLD and NEW placeholder entries in the given query.
938  * If they're not there, it must be an INSERT/SELECT in which they've been
939  * pushed down to the SELECT.
940  */
941  if (list_length(parsetree->rtable) >= 2 &&
942  strcmp(rt_fetch(PRS2_OLD_VARNO, parsetree->rtable)->eref->aliasname,
943  "old") == 0 &&
944  strcmp(rt_fetch(PRS2_NEW_VARNO, parsetree->rtable)->eref->aliasname,
945  "new") == 0)
946  return parsetree;
947  Assert(parsetree->jointree && IsA(parsetree->jointree, FromExpr));
948  if (list_length(parsetree->jointree->fromlist) != 1)
949  elog(ERROR, "expected to find SELECT subquery");
950  rtr = (RangeTblRef *) linitial(parsetree->jointree->fromlist);
951  Assert(IsA(rtr, RangeTblRef));
952  selectrte = rt_fetch(rtr->rtindex, parsetree->rtable);
953  selectquery = selectrte->subquery;
954  if (!(selectquery && IsA(selectquery, Query) &&
955  selectquery->commandType == CMD_SELECT))
956  elog(ERROR, "expected to find SELECT subquery");
957  if (list_length(selectquery->rtable) >= 2 &&
958  strcmp(rt_fetch(PRS2_OLD_VARNO, selectquery->rtable)->eref->aliasname,
959  "old") == 0 &&
960  strcmp(rt_fetch(PRS2_NEW_VARNO, selectquery->rtable)->eref->aliasname,
961  "new") == 0)
962  {
963  if (subquery_ptr)
964  *subquery_ptr = &(selectrte->subquery);
965  return selectquery;
966  }
967  elog(ERROR, "could not find rule placeholders");
968  return NULL; /* not reached */
969 }
970 
971 
972 /*
973  * Add the given qualifier condition to the query's WHERE clause
974  */
975 void
976 AddQual(Query *parsetree, Node *qual)
977 {
978  Node *copy;
979 
980  if (qual == NULL)
981  return;
982 
983  if (parsetree->commandType == CMD_UTILITY)
984  {
985  /*
986  * There's noplace to put the qual on a utility statement.
987  *
988  * If it's a NOTIFY, silently ignore the qual; this means that the
989  * NOTIFY will execute, whether or not there are any qualifying rows.
990  * While clearly wrong, this is much more useful than refusing to
991  * execute the rule at all, and extra NOTIFY events are harmless for
992  * typical uses of NOTIFY.
993  *
994  * If it isn't a NOTIFY, error out, since unconditional execution of
995  * other utility stmts is unlikely to be wanted. (This case is not
996  * currently allowed anyway, but keep the test for safety.)
997  */
998  if (parsetree->utilityStmt && IsA(parsetree->utilityStmt, NotifyStmt))
999  return;
1000  else
1001  ereport(ERROR,
1002  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1003  errmsg("conditional utility statements are not implemented")));
1004  }
1005 
1006  if (parsetree->setOperations != NULL)
1007  {
1008  /*
1009  * There's noplace to put the qual on a setop statement, either. (This
1010  * could be fixed, but right now the planner simply ignores any qual
1011  * condition on a setop query.)
1012  */
1013  ereport(ERROR,
1014  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1015  errmsg("conditional UNION/INTERSECT/EXCEPT statements are not implemented")));
1016  }
1017 
1018  /* INTERSECT want's the original, but we need to copy - Jan */
1019  copy = copyObject(qual);
1020 
1021  parsetree->jointree->quals = make_and_qual(parsetree->jointree->quals,
1022  copy);
1023 
1024  /*
1025  * We had better not have stuck an aggregate into the WHERE clause.
1026  */
1027  Assert(!contain_aggs_of_level(copy, 0));
1028 
1029  /*
1030  * Make sure query is marked correctly if added qual has sublinks. Need
1031  * not search qual when query is already marked.
1032  */
1033  if (!parsetree->hasSubLinks)
1034  parsetree->hasSubLinks = checkExprHasSubLink(copy);
1035 }
1036 
1037 
1038 /*
1039  * Invert the given clause and add it to the WHERE qualifications of the
1040  * given querytree. Inversion means "x IS NOT TRUE", not just "NOT x",
1041  * else we will do the wrong thing when x evaluates to NULL.
1042  */
1043 void
1044 AddInvertedQual(Query *parsetree, Node *qual)
1045 {
1046  BooleanTest *invqual;
1047 
1048  if (qual == NULL)
1049  return;
1050 
1051  /* Need not copy input qual, because AddQual will... */
1052  invqual = makeNode(BooleanTest);
1053  invqual->arg = (Expr *) qual;
1054  invqual->booltesttype = IS_NOT_TRUE;
1055  invqual->location = -1;
1056 
1057  AddQual(parsetree, (Node *) invqual);
1058 }
1059 
1060 
1061 /*
1062  * replace_rte_variables() finds all Vars in an expression tree
1063  * that reference a particular RTE, and replaces them with substitute
1064  * expressions obtained from a caller-supplied callback function.
1065  *
1066  * When invoking replace_rte_variables on a portion of a Query, pass the
1067  * address of the containing Query's hasSubLinks field as outer_hasSubLinks.
1068  * Otherwise, pass NULL, but inserting a SubLink into a non-Query expression
1069  * will then cause an error.
1070  *
1071  * Note: the business with inserted_sublink is needed to update hasSubLinks
1072  * in subqueries when the replacement adds a subquery inside a subquery.
1073  * Messy, isn't it? We do not need to do similar pushups for hasAggs,
1074  * because it isn't possible for this transformation to insert a level-zero
1075  * aggregate reference into a subquery --- it could only insert outer aggs.
1076  * Likewise for hasWindowFuncs.
1077  *
1078  * Note: usually, we'd not expose the mutator function or context struct
1079  * for a function like this. We do so because callbacks often find it
1080  * convenient to recurse directly to the mutator on sub-expressions of
1081  * what they will return.
1082  */
1083 Node *
1084 replace_rte_variables(Node *node, int target_varno, int sublevels_up,
1086  void *callback_arg,
1087  bool *outer_hasSubLinks)
1088 {
1089  Node *result;
1091 
1092  context.callback = callback;
1093  context.callback_arg = callback_arg;
1094  context.target_varno = target_varno;
1095  context.sublevels_up = sublevels_up;
1096 
1097  /*
1098  * We try to initialize inserted_sublink to true if there is no need to
1099  * detect new sublinks because the query already has some.
1100  */
1101  if (node && IsA(node, Query))
1102  context.inserted_sublink = ((Query *) node)->hasSubLinks;
1103  else if (outer_hasSubLinks)
1104  context.inserted_sublink = *outer_hasSubLinks;
1105  else
1106  context.inserted_sublink = false;
1107 
1108  /*
1109  * Must be prepared to start with a Query or a bare expression tree; if
1110  * it's a Query, we don't want to increment sublevels_up.
1111  */
1112  result = query_or_expression_tree_mutator(node,
1114  (void *) &context,
1115  0);
1116 
1117  if (context.inserted_sublink)
1118  {
1119  if (result && IsA(result, Query))
1120  ((Query *) result)->hasSubLinks = true;
1121  else if (outer_hasSubLinks)
1122  *outer_hasSubLinks = true;
1123  else
1124  elog(ERROR, "replace_rte_variables inserted a SubLink, but has noplace to record it");
1125  }
1126 
1127  return result;
1128 }
1129 
1130 Node *
1133 {
1134  if (node == NULL)
1135  return NULL;
1136  if (IsA(node, Var))
1137  {
1138  Var *var = (Var *) node;
1139 
1140  if (var->varno == context->target_varno &&
1141  var->varlevelsup == context->sublevels_up)
1142  {
1143  /* Found a matching variable, make the substitution */
1144  Node *newnode;
1145 
1146  newnode = (*context->callback) (var, context);
1147  /* Detect if we are adding a sublink to query */
1148  if (!context->inserted_sublink)
1149  context->inserted_sublink = checkExprHasSubLink(newnode);
1150  return newnode;
1151  }
1152  /* otherwise fall through to copy the var normally */
1153  }
1154  else if (IsA(node, CurrentOfExpr))
1155  {
1156  CurrentOfExpr *cexpr = (CurrentOfExpr *) node;
1157 
1158  if (cexpr->cvarno == context->target_varno &&
1159  context->sublevels_up == 0)
1160  {
1161  /*
1162  * We get here if a WHERE CURRENT OF expression turns out to apply
1163  * to a view. Someday we might be able to translate the
1164  * expression to apply to an underlying table of the view, but
1165  * right now it's not implemented.
1166  */
1167  ereport(ERROR,
1168  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1169  errmsg("WHERE CURRENT OF on a view is not implemented")));
1170  }
1171  /* otherwise fall through to copy the expr normally */
1172  }
1173  else if (IsA(node, Query))
1174  {
1175  /* Recurse into RTE subquery or not-yet-planned sublink subquery */
1176  Query *newnode;
1177  bool save_inserted_sublink;
1178 
1179  context->sublevels_up++;
1180  save_inserted_sublink = context->inserted_sublink;
1181  context->inserted_sublink = ((Query *) node)->hasSubLinks;
1182  newnode = query_tree_mutator((Query *) node,
1184  (void *) context,
1185  0);
1186  newnode->hasSubLinks |= context->inserted_sublink;
1187  context->inserted_sublink = save_inserted_sublink;
1188  context->sublevels_up--;
1189  return (Node *) newnode;
1190  }
1192  (void *) context);
1193 }
1194 
1195 
1196 /*
1197  * map_variable_attnos() finds all user-column Vars in an expression tree
1198  * that reference a particular RTE, and adjusts their varattnos according
1199  * to the given mapping array (varattno n is replaced by attno_map[n-1]).
1200  * Vars for system columns are not modified.
1201  *
1202  * A zero in the mapping array represents a dropped column, which should not
1203  * appear in the expression.
1204  *
1205  * If the expression tree contains a whole-row Var for the target RTE,
1206  * *found_whole_row is returned as TRUE. In addition, if to_rowtype is
1207  * not InvalidOid, we modify the Var's vartype and insert a ConvertRowTypeExpr
1208  * to map back to the orignal rowtype. Callers that don't provide to_rowtype
1209  * should report an error if *found_row_type is true; we don't do that here
1210  * because we don't know exactly what wording for the error message would
1211  * be most appropriate. The caller will be aware of the context.
1212  *
1213  * This could be built using replace_rte_variables and a callback function,
1214  * but since we don't ever need to insert sublinks, replace_rte_variables is
1215  * overly complicated.
1216  */
1217 
1218 typedef struct
1219 {
1220  int target_varno; /* RTE index to search for */
1221  int sublevels_up; /* (current) nesting depth */
1222  const AttrNumber *attno_map; /* map array for user attnos */
1223  int map_length; /* number of entries in attno_map[] */
1224  /* Target type when converting whole-row vars */
1226  bool *found_whole_row; /* output flag */
1228 
1229 static Node *
1231  map_variable_attnos_context *context)
1232 {
1233  if (node == NULL)
1234  return NULL;
1235  if (IsA(node, Var))
1236  {
1237  Var *var = (Var *) node;
1238 
1239  if (var->varno == context->target_varno &&
1240  var->varlevelsup == context->sublevels_up)
1241  {
1242  /* Found a matching variable, make the substitution */
1243  Var *newvar = (Var *) palloc(sizeof(Var));
1244  int attno = var->varattno;
1245 
1246  *newvar = *var;
1247  if (attno > 0)
1248  {
1249  /* user-defined column, replace attno */
1250  if (attno > context->map_length ||
1251  context->attno_map[attno - 1] == 0)
1252  elog(ERROR, "unexpected varattno %d in expression to be mapped",
1253  attno);
1254  newvar->varattno = newvar->varoattno = context->attno_map[attno - 1];
1255  }
1256  else if (attno == 0)
1257  {
1258  /* whole-row variable, warn caller */
1259  *(context->found_whole_row) = true;
1260 
1261  /* If the callers expects us to convert the same, do so. */
1262  if (OidIsValid(context->to_rowtype))
1263  {
1264  /* No support for RECORDOID. */
1265  Assert(var->vartype != RECORDOID);
1266 
1267  /* Don't convert unless necessary. */
1268  if (context->to_rowtype != var->vartype)
1269  {
1270  ConvertRowtypeExpr *r;
1271 
1272  /* Var itself is converted to the requested type. */
1273  newvar->vartype = context->to_rowtype;
1274 
1275  /*
1276  * And a conversion node on top to convert back to the
1277  * original type.
1278  */
1280  r->arg = (Expr *) newvar;
1281  r->resulttype = var->vartype;
1283  r->location = -1;
1284 
1285  return (Node *) r;
1286  }
1287  }
1288  }
1289  return (Node *) newvar;
1290  }
1291  /* otherwise fall through to copy the var normally */
1292  }
1293  else if (IsA(node, Query))
1294  {
1295  /* Recurse into RTE subquery or not-yet-planned sublink subquery */
1296  Query *newnode;
1297 
1298  context->sublevels_up++;
1299  newnode = query_tree_mutator((Query *) node,
1301  (void *) context,
1302  0);
1303  context->sublevels_up--;
1304  return (Node *) newnode;
1305  }
1307  (void *) context);
1308 }
1309 
1310 Node *
1312  int target_varno, int sublevels_up,
1313  const AttrNumber *attno_map, int map_length,
1314  Oid to_rowtype, bool *found_whole_row)
1315 {
1317 
1318  context.target_varno = target_varno;
1319  context.sublevels_up = sublevels_up;
1320  context.attno_map = attno_map;
1321  context.map_length = map_length;
1322  context.to_rowtype = to_rowtype;
1323  context.found_whole_row = found_whole_row;
1324 
1325  *found_whole_row = false;
1326 
1327  /*
1328  * Must be prepared to start with a Query or a bare expression tree; if
1329  * it's a Query, we don't want to increment sublevels_up.
1330  */
1333  (void *) &context,
1334  0);
1335 }
1336 
1337 
1338 /*
1339  * ReplaceVarsFromTargetList - replace Vars with items from a targetlist
1340  *
1341  * Vars matching target_varno and sublevels_up are replaced by the
1342  * entry with matching resno from targetlist, if there is one.
1343  *
1344  * If there is no matching resno for such a Var, the action depends on the
1345  * nomatch_option:
1346  * REPLACEVARS_REPORT_ERROR: throw an error
1347  * REPLACEVARS_CHANGE_VARNO: change Var's varno to nomatch_varno
1348  * REPLACEVARS_SUBSTITUTE_NULL: replace Var with a NULL Const of same type
1349  *
1350  * The caller must also provide target_rte, the RTE describing the target
1351  * relation. This is needed to handle whole-row Vars referencing the target.
1352  * We expand such Vars into RowExpr constructs.
1353  *
1354  * outer_hasSubLinks works the same as for replace_rte_variables().
1355  */
1356 
1357 typedef struct
1358 {
1364 
1365 static Node *
1368 {
1370  TargetEntry *tle;
1371 
1372  if (var->varattno == InvalidAttrNumber)
1373  {
1374  /* Must expand whole-tuple reference into RowExpr */
1375  RowExpr *rowexpr;
1376  List *colnames;
1377  List *fields;
1378 
1379  /*
1380  * If generating an expansion for a var of a named rowtype (ie, this
1381  * is a plain relation RTE), then we must include dummy items for
1382  * dropped columns. If the var is RECORD (ie, this is a JOIN), then
1383  * omit dropped columns. Either way, attach column names to the
1384  * RowExpr for use of ruleutils.c.
1385  */
1386  expandRTE(rcon->target_rte,
1387  var->varno, var->varlevelsup, var->location,
1388  (var->vartype != RECORDOID),
1389  &colnames, &fields);
1390  /* Adjust the generated per-field Vars... */
1391  fields = (List *) replace_rte_variables_mutator((Node *) fields,
1392  context);
1393  rowexpr = makeNode(RowExpr);
1394  rowexpr->args = fields;
1395  rowexpr->row_typeid = var->vartype;
1396  rowexpr->row_format = COERCE_IMPLICIT_CAST;
1397  rowexpr->colnames = colnames;
1398  rowexpr->location = var->location;
1399 
1400  return (Node *) rowexpr;
1401  }
1402 
1403  /* Normal case referencing one targetlist element */
1404  tle = get_tle_by_resno(rcon->targetlist, var->varattno);
1405 
1406  if (tle == NULL || tle->resjunk)
1407  {
1408  /* Failed to find column in targetlist */
1409  switch (rcon->nomatch_option)
1410  {
1412  /* fall through, throw error below */
1413  break;
1414 
1416  var = (Var *) copyObject(var);
1417  var->varno = rcon->nomatch_varno;
1418  var->varnoold = rcon->nomatch_varno;
1419  return (Node *) var;
1420 
1422 
1423  /*
1424  * If Var is of domain type, we should add a CoerceToDomain
1425  * node, in case there is a NOT NULL domain constraint.
1426  */
1427  return coerce_to_domain((Node *) makeNullConst(var->vartype,
1428  var->vartypmod,
1429  var->varcollid),
1430  InvalidOid, -1,
1431  var->vartype,
1433  -1,
1434  false,
1435  false);
1436  }
1437  elog(ERROR, "could not find replacement targetlist entry for attno %d",
1438  var->varattno);
1439  return NULL; /* keep compiler quiet */
1440  }
1441  else
1442  {
1443  /* Make a copy of the tlist item to return */
1444  Expr *newnode = copyObject(tle->expr);
1445 
1446  /* Must adjust varlevelsup if tlist item is from higher query */
1447  if (var->varlevelsup > 0)
1448  IncrementVarSublevelsUp((Node *) newnode, var->varlevelsup, 0);
1449 
1450  /*
1451  * Check to see if the tlist item contains a PARAM_MULTIEXPR Param,
1452  * and throw error if so. This case could only happen when expanding
1453  * an ON UPDATE rule's NEW variable and the referenced tlist item in
1454  * the original UPDATE command is part of a multiple assignment. There
1455  * seems no practical way to handle such cases without multiple
1456  * evaluation of the multiple assignment's sub-select, which would
1457  * create semantic oddities that users of rules would probably prefer
1458  * not to cope with. So treat it as an unimplemented feature.
1459  */
1460  if (contains_multiexpr_param((Node *) newnode, NULL))
1461  ereport(ERROR,
1462  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1463  errmsg("NEW variables in ON UPDATE rules cannot reference columns that are part of a multiple assignment in the subject UPDATE command")));
1464 
1465  return (Node *) newnode;
1466  }
1467 }
1468 
1469 Node *
1471  int target_varno, int sublevels_up,
1472  RangeTblEntry *target_rte,
1473  List *targetlist,
1474  ReplaceVarsNoMatchOption nomatch_option,
1475  int nomatch_varno,
1476  bool *outer_hasSubLinks)
1477 {
1479 
1480  context.target_rte = target_rte;
1481  context.targetlist = targetlist;
1482  context.nomatch_option = nomatch_option;
1483  context.nomatch_varno = nomatch_varno;
1484 
1485  return replace_rte_variables(node, target_varno, sublevels_up,
1487  (void *) &context,
1488  outer_hasSubLinks);
1489 }
Node * make_and_qual(Node *qual1, Node *qual2)
Definition: clauses.c:348
bool query_tree_walker(Query *query, bool(*walker)(), void *context, int flags)
Definition: nodeFuncs.c:2246
Query * getInsertSelectQuery(Query *parsetree, Query ***subquery_ptr)
Definition: rewriteManip.c:921
List * args
Definition: primnodes.h:986
#define IsA(nodeptr, _type_)
Definition: nodes.h:560
void OffsetVarNodes(Node *node, int offset, int sublevels_up)
Definition: rewriteManip.c:424
Index varlevelsup
Definition: primnodes.h:173
Node * expression_tree_mutator(Node *node, Node *(*mutator)(), void *context)
Definition: nodeFuncs.c:2410
Bitmapset * bms_copy(const Bitmapset *a)
Definition: bitmapset.c:111
void IncrementVarSublevelsUp(Node *node, int delta_sublevels_up, int min_sublevels_up)
Definition: rewriteManip.c:773
static bool checkExprHasSubLink_walker(Node *node, void *context)
Definition: rewriteManip.c:290
FromExpr * jointree
Definition: parsenodes.h:136
bool checkExprHasSubLink(Node *node)
Definition: rewriteManip.c:277
OnConflictExpr * onConflict
Definition: parsenodes.h:142
void AddInvertedQual(Query *parsetree, Node *qual)
Node *(* replace_rte_variables_callback)(Var *var, replace_rte_variables_context *context)
Definition: rewriteManip.h:22
int bms_next_member(const Bitmapset *a, int prevbit)
Definition: bitmapset.c:937
int resultRelation
Definition: parsenodes.h:120
static bool OffsetVarNodes_walker(Node *node, OffsetVarNodes_context *context)
Definition: rewriteManip.c:340
Definition: nodes.h:509
ReplaceVarsNoMatchOption
Definition: rewriteManip.h:34
int errcode(int sqlerrcode)
Definition: elog.c:575
Index prti
Definition: plannodes.h:1005
AttrNumber varattno
Definition: primnodes.h:168
return result
Definition: formatting.c:1633
int locate_windowfunc(Node *node)
Definition: rewriteManip.c:235
replace_rte_variables_callback callback
Definition: rewriteManip.h:27
List * fromlist
Definition: primnodes.h:1471
static bool IncrementVarSublevelsUp_walker(Node *node, IncrementVarSublevelsUp_context *context)
Definition: rewriteManip.c:700
unsigned int Oid
Definition: postgres_ext.h:31
List * rowMarks
Definition: parsenodes.h:161
Node * utilityStmt
Definition: parsenodes.h:118
Definition: primnodes.h:163
#define OidIsValid(objectId)
Definition: c.h:538
static Relids offset_relid_set(Relids relids, int offset)
Definition: rewriteManip.c:472
Node * quals
Definition: primnodes.h:1472
void IncrementVarSublevelsUp_rtable(List *rtable, int delta_sublevels_up, int min_sublevels_up)
Definition: rewriteManip.c:796
Const * makeNullConst(Oid consttype, int32 consttypmod, Oid constcollid)
Definition: makefuncs.c:334
#define QTW_IGNORE_RC_SUBQUERIES
Definition: nodeFuncs.h:22
static bool contain_windowfuncs_walker(Node *node, void *context)
Definition: rewriteManip.c:210
Index varnoold
Definition: primnodes.h:176
static bool contains_multiexpr_param(Node *node, void *context)
Definition: rewriteManip.c:306
#define QTW_EXAMINE_RTES
Definition: nodeFuncs.h:25
#define linitial(l)
Definition: pg_list.h:111
List * rtable
Definition: parsenodes.h:135
Relids phrels
Definition: relation.h:1853
#define ERROR
Definition: elog.h:43
List * colnames
Definition: primnodes.h:999
static Node * ReplaceVarsFromTargetList_callback(Var *var, replace_rte_variables_context *context)
Node * replace_rte_variables_mutator(Node *node, replace_rte_variables_context *context)
Oid vartype
Definition: primnodes.h:170
Node * coerce_to_domain(Node *arg, Oid baseTypeId, int32 baseTypeMod, Oid typeId, CoercionForm cformat, int location, bool hideInputCoercion, bool lengthCoercionDone)
Definition: parse_coerce.c:648
static void callback(struct sockaddr *addr, struct sockaddr *mask, void *unused)
Definition: test_ifaddrs.c:48
int location
Definition: primnodes.h:178
int location
Definition: primnodes.h:1000
static Relids adjust_relid_set(Relids relids, int oldrelid, int newrelid)
Definition: rewriteManip.c:661
Expr * arg
Definition: primnodes.h:1203
Index agglevelsup
Definition: primnodes.h:309
#define RECORDOID
Definition: pg_type.h:680
#define ereport(elevel, rest)
Definition: elog.h:122
Node * map_variable_attnos(Node *node, int target_varno, int sublevels_up, const AttrNumber *attno_map, int map_length, Oid to_rowtype, bool *found_whole_row)
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
#define PRS2_OLD_VARNO
Definition: primnodes.h:160
bool query_or_expression_tree_walker(Node *node, bool(*walker)(), void *context, int flags)
Definition: nodeFuncs.c:3178
int locate_agg_of_level(Node *node, int levelsup)
Definition: rewriteManip.c:131
Index varno
Definition: primnodes.h:166
Node * ReplaceVarsFromTargetList(Node *node, int target_varno, int sublevels_up, RangeTblEntry *target_rte, List *targetlist, ReplaceVarsNoMatchOption nomatch_option, int nomatch_varno, bool *outer_hasSubLinks)
void expandRTE(RangeTblEntry *rte, int rtindex, int sublevels_up, int location, bool include_dropped, List **colnames, List **colvars)
BoolTestType booltesttype
Definition: primnodes.h:1204
Index agglevelsup
Definition: primnodes.h:345
CoercionForm convertformat
Definition: primnodes.h:862
#define InvalidOid
Definition: postgres_ext.h:36
CmdType commandType
Definition: parsenodes.h:110
static Node * map_variable_attnos_mutator(Node *node, map_variable_attnos_context *context)
#define makeNode(_type_)
Definition: nodes.h:557
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:676
#define lfirst(lc)
Definition: pg_list.h:106
Node * query_or_expression_tree_mutator(Node *node, Node *(*mutator)(), void *context, int flags)
Definition: nodeFuncs.c:3201
void AddQual(Query *parsetree, Node *qual)
Definition: rewriteManip.c:976
bool range_table_walker(List *rtable, bool(*walker)(), void *context, int flags)
Definition: nodeFuncs.c:2290
bool expression_tree_walker(Node *node, bool(*walker)(), void *context)
Definition: nodeFuncs.c:1843
Oid row_typeid
Definition: primnodes.h:987
static int list_length(const List *l)
Definition: pg_list.h:89
Index ctelevelsup
Definition: parsenodes.h:1015
const AttrNumber * attno_map
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:698
#define InvalidAttrNumber
Definition: attnum.h:23
bool contain_aggs_of_level(Node *node, int levelsup)
Definition: rewriteManip.c:67
static bool locate_windowfunc_walker(Node *node, locate_windowfunc_context *context)
Definition: rewriteManip.c:254
AttrNumber varoattno
Definition: primnodes.h:177
RTEKind rtekind
Definition: parsenodes.h:944
static bool ChangeVarNodes_walker(Node *node, ChangeVarNodes_context *context)
Definition: rewriteManip.c:504
Node * setOperations
Definition: parsenodes.h:163
Query * subquery
Definition: parsenodes.h:967
Index phlevelsup
Definition: relation.h:1855
void * palloc(Size size)
Definition: mcxt.c:849
int errmsg(const char *fmt,...)
Definition: elog.c:797
bool hasSubLinks
Definition: parsenodes.h:126
static bool rangeTableEntry_used_walker(Node *node, rangeTableEntry_used_context *context)
Definition: rewriteManip.c:823
Node * replace_rte_variables(Node *node, int target_varno, int sublevels_up, replace_rte_variables_callback callback, void *callback_arg, bool *outer_hasSubLinks)
TargetEntry * get_tle_by_resno(List *tlist, AttrNumber resno)
Oid varcollid
Definition: primnodes.h:172
void ChangeVarNodes(Node *node, int rt_index, int new_index, int sublevels_up)
Definition: rewriteManip.c:607
bool rangeTableEntry_used(Node *node, int rt_index, int sublevels_up)
Definition: rewriteManip.c:889
#define elog
Definition: elog.h:219
Index child_relid
Definition: relation.h:1978
#define copyObject(obj)
Definition: nodes.h:622
ReplaceVarsNoMatchOption nomatch_option
Index parent_relid
Definition: relation.h:1977
static bool contain_aggs_of_level_walker(Node *node, contain_aggs_of_level_context *context)
Definition: rewriteManip.c:84
CoercionForm row_format
Definition: primnodes.h:998
Bitmapset * bms_del_member(Bitmapset *a, int x)
Definition: bitmapset.c:735
static bool locate_agg_of_level_walker(Node *node, locate_agg_of_level_context *context)
Definition: rewriteManip.c:151
int rtindex
Definition: primnodes.h:1456
Definition: pg_list.h:45
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:420
int16 AttrNumber
Definition: attnum.h:21
bool contain_windowfuncs(Node *node)
Definition: rewriteManip.c:197
#define PRS2_NEW_VARNO
Definition: primnodes.h:161
Query * query_tree_mutator(Query *query, Node *(*mutator)(), void *context, int flags)
Definition: nodeFuncs.c:3068
int32 vartypmod
Definition: primnodes.h:171