Fix oversight in previous error-reporting patch; mustn't pfree path string
[PostgreSQL.git] / src / backend / rewrite / rewriteManip.c
blob1f72330631b9300d075bbae10af265656a32078f
1 /*-------------------------------------------------------------------------
3 * rewriteManip.c
5 * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
6 * Portions Copyright (c) 1994, Regents of the University of California
9 * IDENTIFICATION
10 * $PostgreSQL$
12 *-------------------------------------------------------------------------
14 #include "postgres.h"
16 #include "catalog/pg_type.h"
17 #include "nodes/makefuncs.h"
18 #include "nodes/nodeFuncs.h"
19 #include "optimizer/clauses.h"
20 #include "parser/parse_coerce.h"
21 #include "parser/parse_relation.h"
22 #include "parser/parsetree.h"
23 #include "rewrite/rewriteManip.h"
26 typedef struct
28 int sublevels_up;
29 } contain_aggs_of_level_context;
31 typedef struct
33 int agg_location;
34 int sublevels_up;
35 } locate_agg_of_level_context;
37 static bool contain_aggs_of_level_walker(Node *node,
38 contain_aggs_of_level_context *context);
39 static bool locate_agg_of_level_walker(Node *node,
40 locate_agg_of_level_context *context);
41 static bool checkExprHasSubLink_walker(Node *node, void *context);
42 static Relids offset_relid_set(Relids relids, int offset);
43 static Relids adjust_relid_set(Relids relids, int oldrelid, int newrelid);
47 * checkExprHasAggs -
48 * Check if an expression contains an aggregate function call of the
49 * current query level.
51 bool
52 checkExprHasAggs(Node *node)
54 return contain_aggs_of_level(node, 0);
58 * contain_aggs_of_level -
59 * Check if an expression contains an aggregate function call of a
60 * specified query level.
62 * The objective of this routine is to detect whether there are aggregates
63 * belonging to the given query level. Aggregates belonging to subqueries
64 * or outer queries do NOT cause a true result. We must recurse into
65 * subqueries to detect outer-reference aggregates that logically belong to
66 * the specified query level.
68 bool
69 contain_aggs_of_level(Node *node, int levelsup)
71 contain_aggs_of_level_context context;
73 context.sublevels_up = levelsup;
76 * Must be prepared to start with a Query or a bare expression tree; if
77 * it's a Query, we don't want to increment sublevels_up.
79 return query_or_expression_tree_walker(node,
80 contain_aggs_of_level_walker,
81 (void *) &context,
82 0);
85 static bool
86 contain_aggs_of_level_walker(Node *node,
87 contain_aggs_of_level_context *context)
89 if (node == NULL)
90 return false;
91 if (IsA(node, Aggref))
93 if (((Aggref *) node)->agglevelsup == context->sublevels_up)
94 return true; /* abort the tree traversal and return true */
95 /* else fall through to examine argument */
97 if (IsA(node, Query))
99 /* Recurse into subselects */
100 bool result;
102 context->sublevels_up++;
103 result = query_tree_walker((Query *) node,
104 contain_aggs_of_level_walker,
105 (void *) context, 0);
106 context->sublevels_up--;
107 return result;
109 return expression_tree_walker(node, contain_aggs_of_level_walker,
110 (void *) context);
114 * locate_agg_of_level -
115 * Find the parse location of any aggregate of the specified query level.
117 * Returns -1 if no such agg is in the querytree, or if they all have
118 * unknown parse location. (The former case is probably caller error,
119 * but we don't bother to distinguish it from the latter case.)
121 * Note: it might seem appropriate to merge this functionality into
122 * contain_aggs_of_level, but that would complicate that function's API.
123 * Currently, the only uses of this function are for error reporting,
124 * and so shaving cycles probably isn't very important.
127 locate_agg_of_level(Node *node, int levelsup)
129 locate_agg_of_level_context context;
131 context.agg_location = -1; /* in case we find nothing */
132 context.sublevels_up = levelsup;
135 * Must be prepared to start with a Query or a bare expression tree; if
136 * it's a Query, we don't want to increment sublevels_up.
138 (void) query_or_expression_tree_walker(node,
139 locate_agg_of_level_walker,
140 (void *) &context,
143 return context.agg_location;
146 static bool
147 locate_agg_of_level_walker(Node *node,
148 locate_agg_of_level_context *context)
150 if (node == NULL)
151 return false;
152 if (IsA(node, Aggref))
154 if (((Aggref *) node)->agglevelsup == context->sublevels_up &&
155 ((Aggref *) node)->location >= 0)
157 context->agg_location = ((Aggref *) node)->location;
158 return true; /* abort the tree traversal and return true */
160 /* else fall through to examine argument */
162 if (IsA(node, Query))
164 /* Recurse into subselects */
165 bool result;
167 context->sublevels_up++;
168 result = query_tree_walker((Query *) node,
169 locate_agg_of_level_walker,
170 (void *) context, 0);
171 context->sublevels_up--;
172 return result;
174 return expression_tree_walker(node, locate_agg_of_level_walker,
175 (void *) context);
179 * checkExprHasSubLink -
180 * Check if an expression contains a SubLink.
182 bool
183 checkExprHasSubLink(Node *node)
186 * If a Query is passed, examine it --- but we should not recurse into
187 * sub-Queries that are in its rangetable or CTE list.
189 return query_or_expression_tree_walker(node,
190 checkExprHasSubLink_walker,
191 NULL,
192 QTW_IGNORE_RC_SUBQUERIES);
195 static bool
196 checkExprHasSubLink_walker(Node *node, void *context)
198 if (node == NULL)
199 return false;
200 if (IsA(node, SubLink))
201 return true; /* abort the tree traversal and return true */
202 return expression_tree_walker(node, checkExprHasSubLink_walker, context);
207 * OffsetVarNodes - adjust Vars when appending one query's RT to another
209 * Find all Var nodes in the given tree with varlevelsup == sublevels_up,
210 * and increment their varno fields (rangetable indexes) by 'offset'.
211 * The varnoold fields are adjusted similarly. Also, adjust other nodes
212 * that contain rangetable indexes, such as RangeTblRef and JoinExpr.
214 * NOTE: although this has the form of a walker, we cheat and modify the
215 * nodes in-place. The given expression tree should have been copied
216 * earlier to ensure that no unwanted side-effects occur!
219 typedef struct
221 int offset;
222 int sublevels_up;
223 } OffsetVarNodes_context;
225 static bool
226 OffsetVarNodes_walker(Node *node, OffsetVarNodes_context *context)
228 if (node == NULL)
229 return false;
230 if (IsA(node, Var))
232 Var *var = (Var *) node;
234 if (var->varlevelsup == context->sublevels_up)
236 var->varno += context->offset;
237 var->varnoold += context->offset;
239 return false;
241 if (IsA(node, CurrentOfExpr))
243 CurrentOfExpr *cexpr = (CurrentOfExpr *) node;
245 if (context->sublevels_up == 0)
246 cexpr->cvarno += context->offset;
247 return false;
249 if (IsA(node, RangeTblRef))
251 RangeTblRef *rtr = (RangeTblRef *) node;
253 if (context->sublevels_up == 0)
254 rtr->rtindex += context->offset;
255 /* the subquery itself is visited separately */
256 return false;
258 if (IsA(node, JoinExpr))
260 JoinExpr *j = (JoinExpr *) node;
262 if (context->sublevels_up == 0)
263 j->rtindex += context->offset;
264 /* fall through to examine children */
266 if (IsA(node, FlattenedSubLink))
268 FlattenedSubLink *fslink = (FlattenedSubLink *) node;
270 if (context->sublevels_up == 0)
272 fslink->lefthand = offset_relid_set(fslink->lefthand,
273 context->offset);
274 fslink->righthand = offset_relid_set(fslink->righthand,
275 context->offset);
277 /* fall through to examine children */
279 if (IsA(node, PlaceHolderVar))
281 PlaceHolderVar *phv = (PlaceHolderVar *) node;
283 if (phv->phlevelsup == context->sublevels_up)
285 phv->phrels = offset_relid_set(phv->phrels,
286 context->offset);
288 /* fall through to examine children */
290 if (IsA(node, AppendRelInfo))
292 AppendRelInfo *appinfo = (AppendRelInfo *) node;
294 if (context->sublevels_up == 0)
296 appinfo->parent_relid += context->offset;
297 appinfo->child_relid += context->offset;
299 /* fall through to examine children */
301 /* Shouldn't need to handle other planner auxiliary nodes here */
302 Assert(!IsA(node, SpecialJoinInfo));
303 Assert(!IsA(node, PlaceHolderInfo));
305 if (IsA(node, Query))
307 /* Recurse into subselects */
308 bool result;
310 context->sublevels_up++;
311 result = query_tree_walker((Query *) node, OffsetVarNodes_walker,
312 (void *) context, 0);
313 context->sublevels_up--;
314 return result;
316 return expression_tree_walker(node, OffsetVarNodes_walker,
317 (void *) context);
320 void
321 OffsetVarNodes(Node *node, int offset, int sublevels_up)
323 OffsetVarNodes_context context;
325 context.offset = offset;
326 context.sublevels_up = sublevels_up;
329 * Must be prepared to start with a Query or a bare expression tree; if
330 * it's a Query, go straight to query_tree_walker to make sure that
331 * sublevels_up doesn't get incremented prematurely.
333 if (node && IsA(node, Query))
335 Query *qry = (Query *) node;
338 * If we are starting at a Query, and sublevels_up is zero, then we
339 * must also fix rangetable indexes in the Query itself --- namely
340 * resultRelation and rowMarks entries. sublevels_up cannot be zero
341 * when recursing into a subquery, so there's no need to have the same
342 * logic inside OffsetVarNodes_walker.
344 if (sublevels_up == 0)
346 ListCell *l;
348 if (qry->resultRelation)
349 qry->resultRelation += offset;
350 foreach(l, qry->rowMarks)
352 RowMarkClause *rc = (RowMarkClause *) lfirst(l);
354 rc->rti += offset;
357 query_tree_walker(qry, OffsetVarNodes_walker,
358 (void *) &context, 0);
360 else
361 OffsetVarNodes_walker(node, &context);
364 static Relids
365 offset_relid_set(Relids relids, int offset)
367 Relids result = NULL;
368 Relids tmprelids;
369 int rtindex;
371 tmprelids = bms_copy(relids);
372 while ((rtindex = bms_first_member(tmprelids)) >= 0)
373 result = bms_add_member(result, rtindex + offset);
374 bms_free(tmprelids);
375 return result;
379 * ChangeVarNodes - adjust Var nodes for a specific change of RT index
381 * Find all Var nodes in the given tree belonging to a specific relation
382 * (identified by sublevels_up and rt_index), and change their varno fields
383 * to 'new_index'. The varnoold fields are changed too. Also, adjust other
384 * nodes that contain rangetable indexes, such as RangeTblRef and JoinExpr.
386 * NOTE: although this has the form of a walker, we cheat and modify the
387 * nodes in-place. The given expression tree should have been copied
388 * earlier to ensure that no unwanted side-effects occur!
391 typedef struct
393 int rt_index;
394 int new_index;
395 int sublevels_up;
396 } ChangeVarNodes_context;
398 static bool
399 ChangeVarNodes_walker(Node *node, ChangeVarNodes_context *context)
401 if (node == NULL)
402 return false;
403 if (IsA(node, Var))
405 Var *var = (Var *) node;
407 if (var->varlevelsup == context->sublevels_up &&
408 var->varno == context->rt_index)
410 var->varno = context->new_index;
411 var->varnoold = context->new_index;
413 return false;
415 if (IsA(node, CurrentOfExpr))
417 CurrentOfExpr *cexpr = (CurrentOfExpr *) node;
419 if (context->sublevels_up == 0 &&
420 cexpr->cvarno == context->rt_index)
421 cexpr->cvarno = context->new_index;
422 return false;
424 if (IsA(node, RangeTblRef))
426 RangeTblRef *rtr = (RangeTblRef *) node;
428 if (context->sublevels_up == 0 &&
429 rtr->rtindex == context->rt_index)
430 rtr->rtindex = context->new_index;
431 /* the subquery itself is visited separately */
432 return false;
434 if (IsA(node, JoinExpr))
436 JoinExpr *j = (JoinExpr *) node;
438 if (context->sublevels_up == 0 &&
439 j->rtindex == context->rt_index)
440 j->rtindex = context->new_index;
441 /* fall through to examine children */
443 if (IsA(node, FlattenedSubLink))
445 FlattenedSubLink *fslink = (FlattenedSubLink *) node;
447 if (context->sublevels_up == 0)
449 fslink->lefthand = adjust_relid_set(fslink->lefthand,
450 context->rt_index,
451 context->new_index);
452 fslink->righthand = adjust_relid_set(fslink->righthand,
453 context->rt_index,
454 context->new_index);
456 /* fall through to examine children */
458 if (IsA(node, PlaceHolderVar))
460 PlaceHolderVar *phv = (PlaceHolderVar *) node;
462 if (phv->phlevelsup == context->sublevels_up)
464 phv->phrels = adjust_relid_set(phv->phrels,
465 context->rt_index,
466 context->new_index);
468 /* fall through to examine children */
470 if (IsA(node, AppendRelInfo))
472 AppendRelInfo *appinfo = (AppendRelInfo *) node;
474 if (context->sublevels_up == 0)
476 if (appinfo->parent_relid == context->rt_index)
477 appinfo->parent_relid = context->new_index;
478 if (appinfo->child_relid == context->rt_index)
479 appinfo->child_relid = context->new_index;
481 /* fall through to examine children */
483 /* Shouldn't need to handle other planner auxiliary nodes here */
484 Assert(!IsA(node, SpecialJoinInfo));
485 Assert(!IsA(node, PlaceHolderInfo));
487 if (IsA(node, Query))
489 /* Recurse into subselects */
490 bool result;
492 context->sublevels_up++;
493 result = query_tree_walker((Query *) node, ChangeVarNodes_walker,
494 (void *) context, 0);
495 context->sublevels_up--;
496 return result;
498 return expression_tree_walker(node, ChangeVarNodes_walker,
499 (void *) context);
502 void
503 ChangeVarNodes(Node *node, int rt_index, int new_index, int sublevels_up)
505 ChangeVarNodes_context context;
507 context.rt_index = rt_index;
508 context.new_index = new_index;
509 context.sublevels_up = sublevels_up;
512 * Must be prepared to start with a Query or a bare expression tree; if
513 * it's a Query, go straight to query_tree_walker to make sure that
514 * sublevels_up doesn't get incremented prematurely.
516 if (node && IsA(node, Query))
518 Query *qry = (Query *) node;
521 * If we are starting at a Query, and sublevels_up is zero, then we
522 * must also fix rangetable indexes in the Query itself --- namely
523 * resultRelation and rowMarks entries. sublevels_up cannot be zero
524 * when recursing into a subquery, so there's no need to have the same
525 * logic inside ChangeVarNodes_walker.
527 if (sublevels_up == 0)
529 ListCell *l;
531 if (qry->resultRelation == rt_index)
532 qry->resultRelation = new_index;
533 foreach(l, qry->rowMarks)
535 RowMarkClause *rc = (RowMarkClause *) lfirst(l);
537 if (rc->rti == rt_index)
538 rc->rti = new_index;
541 query_tree_walker(qry, ChangeVarNodes_walker,
542 (void *) &context, 0);
544 else
545 ChangeVarNodes_walker(node, &context);
549 * Substitute newrelid for oldrelid in a Relid set
551 static Relids
552 adjust_relid_set(Relids relids, int oldrelid, int newrelid)
554 if (bms_is_member(oldrelid, relids))
556 /* Ensure we have a modifiable copy */
557 relids = bms_copy(relids);
558 /* Remove old, add new */
559 relids = bms_del_member(relids, oldrelid);
560 relids = bms_add_member(relids, newrelid);
562 return relids;
566 * IncrementVarSublevelsUp - adjust Var nodes when pushing them down in tree
568 * Find all Var nodes in the given tree having varlevelsup >= min_sublevels_up,
569 * and add delta_sublevels_up to their varlevelsup value. This is needed when
570 * an expression that's correct for some nesting level is inserted into a
571 * subquery. Ordinarily the initial call has min_sublevels_up == 0 so that
572 * all Vars are affected. The point of min_sublevels_up is that we can
573 * increment it when we recurse into a sublink, so that local variables in
574 * that sublink are not affected, only outer references to vars that belong
575 * to the expression's original query level or parents thereof.
577 * Likewise for other nodes containing levelsup fields, such as Aggref.
579 * NOTE: although this has the form of a walker, we cheat and modify the
580 * Var nodes in-place. The given expression tree should have been copied
581 * earlier to ensure that no unwanted side-effects occur!
584 typedef struct
586 int delta_sublevels_up;
587 int min_sublevels_up;
588 } IncrementVarSublevelsUp_context;
590 static bool
591 IncrementVarSublevelsUp_walker(Node *node,
592 IncrementVarSublevelsUp_context *context)
594 if (node == NULL)
595 return false;
596 if (IsA(node, Var))
598 Var *var = (Var *) node;
600 if (var->varlevelsup >= context->min_sublevels_up)
601 var->varlevelsup += context->delta_sublevels_up;
602 return false; /* done here */
604 if (IsA(node, CurrentOfExpr))
606 /* this should not happen */
607 if (context->min_sublevels_up == 0)
608 elog(ERROR, "cannot push down CurrentOfExpr");
609 return false;
611 if (IsA(node, Aggref))
613 Aggref *agg = (Aggref *) node;
615 if (agg->agglevelsup >= context->min_sublevels_up)
616 agg->agglevelsup += context->delta_sublevels_up;
617 /* fall through to recurse into argument */
619 if (IsA(node, PlaceHolderVar))
621 PlaceHolderVar *phv = (PlaceHolderVar *) node;
623 if (phv->phlevelsup >= context->min_sublevels_up)
624 phv->phlevelsup += context->delta_sublevels_up;
625 /* fall through to recurse into argument */
627 if (IsA(node, RangeTblEntry))
629 RangeTblEntry *rte = (RangeTblEntry *) node;
631 if (rte->rtekind == RTE_CTE)
633 if (rte->ctelevelsup >= context->min_sublevels_up)
634 rte->ctelevelsup += context->delta_sublevels_up;
636 return false; /* allow range_table_walker to continue */
638 if (IsA(node, Query))
640 /* Recurse into subselects */
641 bool result;
643 context->min_sublevels_up++;
644 result = query_tree_walker((Query *) node,
645 IncrementVarSublevelsUp_walker,
646 (void *) context,
647 QTW_EXAMINE_RTES);
648 context->min_sublevels_up--;
649 return result;
651 return expression_tree_walker(node, IncrementVarSublevelsUp_walker,
652 (void *) context);
655 void
656 IncrementVarSublevelsUp(Node *node, int delta_sublevels_up,
657 int min_sublevels_up)
659 IncrementVarSublevelsUp_context context;
661 context.delta_sublevels_up = delta_sublevels_up;
662 context.min_sublevels_up = min_sublevels_up;
665 * Must be prepared to start with a Query or a bare expression tree; if
666 * it's a Query, we don't want to increment sublevels_up.
668 query_or_expression_tree_walker(node,
669 IncrementVarSublevelsUp_walker,
670 (void *) &context,
671 QTW_EXAMINE_RTES);
675 * IncrementVarSublevelsUp_rtable -
676 * Same as IncrementVarSublevelsUp, but to be invoked on a range table.
678 void
679 IncrementVarSublevelsUp_rtable(List *rtable, int delta_sublevels_up,
680 int min_sublevels_up)
682 IncrementVarSublevelsUp_context context;
684 context.delta_sublevels_up = delta_sublevels_up;
685 context.min_sublevels_up = min_sublevels_up;
687 range_table_walker(rtable,
688 IncrementVarSublevelsUp_walker,
689 (void *) &context,
690 QTW_EXAMINE_RTES);
695 * rangeTableEntry_used - detect whether an RTE is referenced somewhere
696 * in var nodes or join or setOp trees of a query or expression.
699 typedef struct
701 int rt_index;
702 int sublevels_up;
703 } rangeTableEntry_used_context;
705 static bool
706 rangeTableEntry_used_walker(Node *node,
707 rangeTableEntry_used_context *context)
709 if (node == NULL)
710 return false;
711 if (IsA(node, Var))
713 Var *var = (Var *) node;
715 if (var->varlevelsup == context->sublevels_up &&
716 var->varno == context->rt_index)
717 return true;
718 return false;
720 if (IsA(node, CurrentOfExpr))
722 CurrentOfExpr *cexpr = (CurrentOfExpr *) node;
724 if (context->sublevels_up == 0 &&
725 cexpr->cvarno == context->rt_index)
726 return true;
727 return false;
729 if (IsA(node, RangeTblRef))
731 RangeTblRef *rtr = (RangeTblRef *) node;
733 if (rtr->rtindex == context->rt_index &&
734 context->sublevels_up == 0)
735 return true;
736 /* the subquery itself is visited separately */
737 return false;
739 if (IsA(node, JoinExpr))
741 JoinExpr *j = (JoinExpr *) node;
743 if (j->rtindex == context->rt_index &&
744 context->sublevels_up == 0)
745 return true;
746 /* fall through to examine children */
748 /* Shouldn't need to handle planner auxiliary nodes here */
749 Assert(!IsA(node, FlattenedSubLink));
750 Assert(!IsA(node, PlaceHolderVar));
751 Assert(!IsA(node, SpecialJoinInfo));
752 Assert(!IsA(node, AppendRelInfo));
753 Assert(!IsA(node, PlaceHolderInfo));
755 if (IsA(node, Query))
757 /* Recurse into subselects */
758 bool result;
760 context->sublevels_up++;
761 result = query_tree_walker((Query *) node, rangeTableEntry_used_walker,
762 (void *) context, 0);
763 context->sublevels_up--;
764 return result;
766 return expression_tree_walker(node, rangeTableEntry_used_walker,
767 (void *) context);
770 bool
771 rangeTableEntry_used(Node *node, int rt_index, int sublevels_up)
773 rangeTableEntry_used_context context;
775 context.rt_index = rt_index;
776 context.sublevels_up = sublevels_up;
779 * Must be prepared to start with a Query or a bare expression tree; if
780 * it's a Query, we don't want to increment sublevels_up.
782 return query_or_expression_tree_walker(node,
783 rangeTableEntry_used_walker,
784 (void *) &context,
790 * attribute_used -
791 * Check if a specific attribute number of a RTE is used
792 * somewhere in the query or expression.
795 typedef struct
797 int rt_index;
798 int attno;
799 int sublevels_up;
800 } attribute_used_context;
802 static bool
803 attribute_used_walker(Node *node,
804 attribute_used_context *context)
806 if (node == NULL)
807 return false;
808 if (IsA(node, Var))
810 Var *var = (Var *) node;
812 if (var->varlevelsup == context->sublevels_up &&
813 var->varno == context->rt_index &&
814 var->varattno == context->attno)
815 return true;
816 return false;
818 if (IsA(node, Query))
820 /* Recurse into subselects */
821 bool result;
823 context->sublevels_up++;
824 result = query_tree_walker((Query *) node, attribute_used_walker,
825 (void *) context, 0);
826 context->sublevels_up--;
827 return result;
829 return expression_tree_walker(node, attribute_used_walker,
830 (void *) context);
833 bool
834 attribute_used(Node *node, int rt_index, int attno, int sublevels_up)
836 attribute_used_context context;
838 context.rt_index = rt_index;
839 context.attno = attno;
840 context.sublevels_up = sublevels_up;
843 * Must be prepared to start with a Query or a bare expression tree; if
844 * it's a Query, we don't want to increment sublevels_up.
846 return query_or_expression_tree_walker(node,
847 attribute_used_walker,
848 (void *) &context,
854 * If the given Query is an INSERT ... SELECT construct, extract and
855 * return the sub-Query node that represents the SELECT part. Otherwise
856 * return the given Query.
858 * If subquery_ptr is not NULL, then *subquery_ptr is set to the location
859 * of the link to the SELECT subquery inside parsetree, or NULL if not an
860 * INSERT ... SELECT.
862 * This is a hack needed because transformations on INSERT ... SELECTs that
863 * appear in rule actions should be applied to the source SELECT, not to the
864 * INSERT part. Perhaps this can be cleaned up with redesigned querytrees.
866 Query *
867 getInsertSelectQuery(Query *parsetree, Query ***subquery_ptr)
869 Query *selectquery;
870 RangeTblEntry *selectrte;
871 RangeTblRef *rtr;
873 if (subquery_ptr)
874 *subquery_ptr = NULL;
876 if (parsetree == NULL)
877 return parsetree;
878 if (parsetree->commandType != CMD_INSERT)
879 return parsetree;
882 * Currently, this is ONLY applied to rule-action queries, and so we
883 * expect to find the *OLD* and *NEW* placeholder entries in the given
884 * query. If they're not there, it must be an INSERT/SELECT in which
885 * they've been pushed down to the SELECT.
887 if (list_length(parsetree->rtable) >= 2 &&
888 strcmp(rt_fetch(PRS2_OLD_VARNO, parsetree->rtable)->eref->aliasname,
889 "*OLD*") == 0 &&
890 strcmp(rt_fetch(PRS2_NEW_VARNO, parsetree->rtable)->eref->aliasname,
891 "*NEW*") == 0)
892 return parsetree;
893 Assert(parsetree->jointree && IsA(parsetree->jointree, FromExpr));
894 if (list_length(parsetree->jointree->fromlist) != 1)
895 elog(ERROR, "expected to find SELECT subquery");
896 rtr = (RangeTblRef *) linitial(parsetree->jointree->fromlist);
897 Assert(IsA(rtr, RangeTblRef));
898 selectrte = rt_fetch(rtr->rtindex, parsetree->rtable);
899 selectquery = selectrte->subquery;
900 if (!(selectquery && IsA(selectquery, Query) &&
901 selectquery->commandType == CMD_SELECT))
902 elog(ERROR, "expected to find SELECT subquery");
903 if (list_length(selectquery->rtable) >= 2 &&
904 strcmp(rt_fetch(PRS2_OLD_VARNO, selectquery->rtable)->eref->aliasname,
905 "*OLD*") == 0 &&
906 strcmp(rt_fetch(PRS2_NEW_VARNO, selectquery->rtable)->eref->aliasname,
907 "*NEW*") == 0)
909 if (subquery_ptr)
910 *subquery_ptr = &(selectrte->subquery);
911 return selectquery;
913 elog(ERROR, "could not find rule placeholders");
914 return NULL; /* not reached */
919 * Add the given qualifier condition to the query's WHERE clause
921 void
922 AddQual(Query *parsetree, Node *qual)
924 Node *copy;
926 if (qual == NULL)
927 return;
929 if (parsetree->commandType == CMD_UTILITY)
932 * There's noplace to put the qual on a utility statement.
934 * If it's a NOTIFY, silently ignore the qual; this means that the
935 * NOTIFY will execute, whether or not there are any qualifying rows.
936 * While clearly wrong, this is much more useful than refusing to
937 * execute the rule at all, and extra NOTIFY events are harmless for
938 * typical uses of NOTIFY.
940 * If it isn't a NOTIFY, error out, since unconditional execution of
941 * other utility stmts is unlikely to be wanted. (This case is not
942 * currently allowed anyway, but keep the test for safety.)
944 if (parsetree->utilityStmt && IsA(parsetree->utilityStmt, NotifyStmt))
945 return;
946 else
947 ereport(ERROR,
948 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
949 errmsg("conditional utility statements are not implemented")));
952 if (parsetree->setOperations != NULL)
955 * There's noplace to put the qual on a setop statement, either. (This
956 * could be fixed, but right now the planner simply ignores any qual
957 * condition on a setop query.)
959 ereport(ERROR,
960 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
961 errmsg("conditional UNION/INTERSECT/EXCEPT statements are not implemented")));
964 /* INTERSECT want's the original, but we need to copy - Jan */
965 copy = copyObject(qual);
967 parsetree->jointree->quals = make_and_qual(parsetree->jointree->quals,
968 copy);
971 * We had better not have stuck an aggregate into the WHERE clause.
973 Assert(!checkExprHasAggs(copy));
976 * Make sure query is marked correctly if added qual has sublinks. Need
977 * not search qual when query is already marked.
979 if (!parsetree->hasSubLinks)
980 parsetree->hasSubLinks = checkExprHasSubLink(copy);
985 * Invert the given clause and add it to the WHERE qualifications of the
986 * given querytree. Inversion means "x IS NOT TRUE", not just "NOT x",
987 * else we will do the wrong thing when x evaluates to NULL.
989 void
990 AddInvertedQual(Query *parsetree, Node *qual)
992 BooleanTest *invqual;
994 if (qual == NULL)
995 return;
997 /* Need not copy input qual, because AddQual will... */
998 invqual = makeNode(BooleanTest);
999 invqual->arg = (Expr *) qual;
1000 invqual->booltesttype = IS_NOT_TRUE;
1002 AddQual(parsetree, (Node *) invqual);
1007 * ResolveNew - replace Vars with corresponding items from a targetlist
1009 * Vars matching target_varno and sublevels_up are replaced by the
1010 * entry with matching resno from targetlist, if there is one.
1011 * If not, we either change the unmatched Var's varno to update_varno
1012 * (when event == CMD_UPDATE) or replace it with a constant NULL.
1014 * The caller must also provide target_rte, the RTE describing the target
1015 * relation. This is needed to handle whole-row Vars referencing the target.
1016 * We expand such Vars into RowExpr constructs.
1018 * Note: the business with inserted_sublink is needed to update hasSubLinks
1019 * in subqueries when the replacement adds a subquery inside a subquery.
1020 * Messy, isn't it? We do not need to do similar pushups for hasAggs,
1021 * because it isn't possible for this transformation to insert a level-zero
1022 * aggregate reference into a subquery --- it could only insert outer aggs.
1025 typedef struct
1027 int target_varno;
1028 int sublevels_up;
1029 RangeTblEntry *target_rte;
1030 List *targetlist;
1031 int event;
1032 int update_varno;
1033 bool inserted_sublink;
1034 } ResolveNew_context;
1036 static Node *
1037 resolve_one_var(Var *var, ResolveNew_context *context)
1039 TargetEntry *tle;
1041 tle = get_tle_by_resno(context->targetlist, var->varattno);
1043 if (tle == NULL)
1045 /* Failed to find column in insert/update tlist */
1046 if (context->event == CMD_UPDATE)
1048 /* For update, just change unmatched var's varno */
1049 var = (Var *) copyObject(var);
1050 var->varno = context->update_varno;
1051 var->varnoold = context->update_varno;
1052 return (Node *) var;
1054 else
1056 /* Otherwise replace unmatched var with a null */
1057 /* need coerce_to_domain in case of NOT NULL domain constraint */
1058 return coerce_to_domain((Node *) makeNullConst(var->vartype,
1059 var->vartypmod),
1060 InvalidOid, -1,
1061 var->vartype,
1062 COERCE_IMPLICIT_CAST,
1064 false,
1065 false);
1068 else
1070 /* Make a copy of the tlist item to return */
1071 Node *n = copyObject(tle->expr);
1073 /* Adjust varlevelsup if tlist item is from higher query */
1074 if (var->varlevelsup > 0)
1075 IncrementVarSublevelsUp(n, var->varlevelsup, 0);
1076 /* Report it if we are adding a sublink to query */
1077 if (!context->inserted_sublink)
1078 context->inserted_sublink = checkExprHasSubLink(n);
1079 return n;
1083 static Node *
1084 ResolveNew_mutator(Node *node, ResolveNew_context *context)
1086 if (node == NULL)
1087 return NULL;
1088 if (IsA(node, Var))
1090 Var *var = (Var *) node;
1091 int this_varno = (int) var->varno;
1092 int this_varlevelsup = (int) var->varlevelsup;
1094 if (this_varno == context->target_varno &&
1095 this_varlevelsup == context->sublevels_up)
1097 if (var->varattno == InvalidAttrNumber)
1099 /* Must expand whole-tuple reference into RowExpr */
1100 RowExpr *rowexpr;
1101 List *colnames;
1102 List *fields;
1105 * If generating an expansion for a var of a named rowtype
1106 * (ie, this is a plain relation RTE), then we must include
1107 * dummy items for dropped columns. If the var is RECORD (ie,
1108 * this is a JOIN), then omit dropped columns. Either way,
1109 * attach column names to the RowExpr for use of ruleutils.c.
1111 expandRTE(context->target_rte,
1112 this_varno, this_varlevelsup, var->location,
1113 (var->vartype != RECORDOID),
1114 &colnames, &fields);
1115 /* Adjust the generated per-field Vars... */
1116 fields = (List *) ResolveNew_mutator((Node *) fields,
1117 context);
1118 rowexpr = makeNode(RowExpr);
1119 rowexpr->args = fields;
1120 rowexpr->row_typeid = var->vartype;
1121 rowexpr->row_format = COERCE_IMPLICIT_CAST;
1122 rowexpr->colnames = colnames;
1123 rowexpr->location = -1;
1125 return (Node *) rowexpr;
1128 /* Normal case for scalar variable */
1129 return resolve_one_var(var, context);
1131 /* otherwise fall through to copy the var normally */
1133 else if (IsA(node, CurrentOfExpr))
1135 CurrentOfExpr *cexpr = (CurrentOfExpr *) node;
1136 int this_varno = (int) cexpr->cvarno;
1138 if (this_varno == context->target_varno &&
1139 context->sublevels_up == 0)
1142 * We get here if a WHERE CURRENT OF expression turns out to apply
1143 * to a view. Someday we might be able to translate the
1144 * expression to apply to an underlying table of the view, but
1145 * right now it's not implemented.
1147 ereport(ERROR,
1148 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1149 errmsg("WHERE CURRENT OF on a view is not implemented")));
1151 /* otherwise fall through to copy the expr normally */
1153 else if (IsA(node, Query))
1155 /* Recurse into RTE subquery or not-yet-planned sublink subquery */
1156 Query *newnode;
1157 bool save_inserted_sublink;
1159 context->sublevels_up++;
1160 save_inserted_sublink = context->inserted_sublink;
1161 context->inserted_sublink = false;
1162 newnode = query_tree_mutator((Query *) node,
1163 ResolveNew_mutator,
1164 (void *) context,
1166 newnode->hasSubLinks |= context->inserted_sublink;
1167 context->inserted_sublink = save_inserted_sublink;
1168 context->sublevels_up--;
1169 return (Node *) newnode;
1171 return expression_tree_mutator(node, ResolveNew_mutator,
1172 (void *) context);
1175 Node *
1176 ResolveNew(Node *node, int target_varno, int sublevels_up,
1177 RangeTblEntry *target_rte,
1178 List *targetlist, int event, int update_varno)
1180 Node *result;
1181 ResolveNew_context context;
1183 context.target_varno = target_varno;
1184 context.sublevels_up = sublevels_up;
1185 context.target_rte = target_rte;
1186 context.targetlist = targetlist;
1187 context.event = event;
1188 context.update_varno = update_varno;
1189 context.inserted_sublink = false;
1192 * Must be prepared to start with a Query or a bare expression tree; if
1193 * it's a Query, we don't want to increment sublevels_up.
1195 result = query_or_expression_tree_mutator(node,
1196 ResolveNew_mutator,
1197 (void *) &context,
1200 if (context.inserted_sublink)
1202 if (IsA(result, Query))
1203 ((Query *) result)->hasSubLinks = true;
1206 * Note: if we're called on a non-Query node then it's the caller's
1207 * responsibility to update hasSubLinks in the ancestor Query. This is
1208 * pretty fragile and perhaps should be rethought ...
1212 return result;