1 /*-------------------------------------------------------------------------
5 * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
6 * Portions Copyright (c) 1994, Regents of the University of California
10 * $PostgreSQL: pgsql/src/backend/rewrite/rewriteManip.c,v 1.110 2008/08/22 00:16:04 tgl Exp $
12 *-------------------------------------------------------------------------
16 #include "catalog/pg_type.h"
17 #include "nodes/makefuncs.h"
18 #include "optimizer/clauses.h"
19 #include "parser/parse_coerce.h"
20 #include "parser/parse_relation.h"
21 #include "parser/parsetree.h"
22 #include "rewrite/rewriteManip.h"
28 } contain_aggs_of_level_context;
30 static bool contain_aggs_of_level_walker(Node *node,
31 contain_aggs_of_level_context *context);
32 static bool checkExprHasSubLink_walker(Node *node, void *context);
33 static Relids offset_relid_set(Relids relids, int offset);
34 static Relids adjust_relid_set(Relids relids, int oldrelid, int newrelid);
39 * Check if an expression contains an aggregate function call.
42 checkExprHasAggs(Node *node)
44 return contain_aggs_of_level(node, 0);
48 * contain_aggs_of_level -
49 * Check if an expression contains an aggregate function call of a
50 * specified query level.
52 * The objective of this routine is to detect whether there are aggregates
53 * belonging to the given query level. Aggregates belonging to subqueries
54 * or outer queries do NOT cause a true result. We must recurse into
55 * subqueries to detect outer-reference aggregates that logically belong to
56 * the specified query level.
59 contain_aggs_of_level(Node *node, int levelsup)
61 contain_aggs_of_level_context context;
63 context.sublevels_up = levelsup;
66 * Must be prepared to start with a Query or a bare expression tree; if
67 * it's a Query, we don't want to increment sublevels_up.
69 return query_or_expression_tree_walker(node,
70 contain_aggs_of_level_walker,
76 contain_aggs_of_level_walker(Node *node,
77 contain_aggs_of_level_context *context)
81 if (IsA(node, Aggref))
83 if (((Aggref *) node)->agglevelsup == context->sublevels_up)
84 return true; /* abort the tree traversal and return true */
85 /* else fall through to examine argument */
89 /* Recurse into subselects */
92 context->sublevels_up++;
93 result = query_tree_walker((Query *) node,
94 contain_aggs_of_level_walker,
96 context->sublevels_up--;
99 return expression_tree_walker(node, contain_aggs_of_level_walker,
104 * checkExprHasSubLink -
105 * Check if an expression contains a SubLink.
108 checkExprHasSubLink(Node *node)
111 * If a Query is passed, examine it --- but we need not recurse into
114 return query_or_expression_tree_walker(node,
115 checkExprHasSubLink_walker,
117 QTW_IGNORE_RT_SUBQUERIES);
121 checkExprHasSubLink_walker(Node *node, void *context)
125 if (IsA(node, SubLink))
126 return true; /* abort the tree traversal and return true */
127 return expression_tree_walker(node, checkExprHasSubLink_walker, context);
132 * OffsetVarNodes - adjust Vars when appending one query's RT to another
134 * Find all Var nodes in the given tree with varlevelsup == sublevels_up,
135 * and increment their varno fields (rangetable indexes) by 'offset'.
136 * The varnoold fields are adjusted similarly. Also, adjust other nodes
137 * that contain rangetable indexes, such as RangeTblRef and JoinExpr.
139 * NOTE: although this has the form of a walker, we cheat and modify the
140 * nodes in-place. The given expression tree should have been copied
141 * earlier to ensure that no unwanted side-effects occur!
148 } OffsetVarNodes_context;
151 OffsetVarNodes_walker(Node *node, OffsetVarNodes_context *context)
157 Var *var = (Var *) node;
159 if (var->varlevelsup == context->sublevels_up)
161 var->varno += context->offset;
162 var->varnoold += context->offset;
166 if (IsA(node, CurrentOfExpr))
168 CurrentOfExpr *cexpr = (CurrentOfExpr *) node;
170 if (context->sublevels_up == 0)
171 cexpr->cvarno += context->offset;
174 if (IsA(node, RangeTblRef))
176 RangeTblRef *rtr = (RangeTblRef *) node;
178 if (context->sublevels_up == 0)
179 rtr->rtindex += context->offset;
180 /* the subquery itself is visited separately */
183 if (IsA(node, JoinExpr))
185 JoinExpr *j = (JoinExpr *) node;
187 if (context->sublevels_up == 0)
188 j->rtindex += context->offset;
189 /* fall through to examine children */
191 if (IsA(node, FlattenedSubLink))
193 FlattenedSubLink *fslink = (FlattenedSubLink *) node;
195 if (context->sublevels_up == 0)
197 fslink->lefthand = offset_relid_set(fslink->lefthand,
199 fslink->righthand = offset_relid_set(fslink->righthand,
202 /* fall through to examine children */
204 if (IsA(node, AppendRelInfo))
206 AppendRelInfo *appinfo = (AppendRelInfo *) node;
208 if (context->sublevels_up == 0)
210 appinfo->parent_relid += context->offset;
211 appinfo->child_relid += context->offset;
213 /* fall through to examine children */
215 if (IsA(node, Query))
217 /* Recurse into subselects */
220 context->sublevels_up++;
221 result = query_tree_walker((Query *) node, OffsetVarNodes_walker,
222 (void *) context, 0);
223 context->sublevels_up--;
226 return expression_tree_walker(node, OffsetVarNodes_walker,
231 OffsetVarNodes(Node *node, int offset, int sublevels_up)
233 OffsetVarNodes_context context;
235 context.offset = offset;
236 context.sublevels_up = sublevels_up;
239 * Must be prepared to start with a Query or a bare expression tree; if
240 * it's a Query, go straight to query_tree_walker to make sure that
241 * sublevels_up doesn't get incremented prematurely.
243 if (node && IsA(node, Query))
245 Query *qry = (Query *) node;
248 * If we are starting at a Query, and sublevels_up is zero, then we
249 * must also fix rangetable indexes in the Query itself --- namely
250 * resultRelation and rowMarks entries. sublevels_up cannot be zero
251 * when recursing into a subquery, so there's no need to have the same
252 * logic inside OffsetVarNodes_walker.
254 if (sublevels_up == 0)
258 if (qry->resultRelation)
259 qry->resultRelation += offset;
260 foreach(l, qry->rowMarks)
262 RowMarkClause *rc = (RowMarkClause *) lfirst(l);
267 query_tree_walker(qry, OffsetVarNodes_walker,
268 (void *) &context, 0);
271 OffsetVarNodes_walker(node, &context);
275 offset_relid_set(Relids relids, int offset)
277 Relids result = NULL;
281 tmprelids = bms_copy(relids);
282 while ((rtindex = bms_first_member(tmprelids)) >= 0)
283 result = bms_add_member(result, rtindex + offset);
289 * ChangeVarNodes - adjust Var nodes for a specific change of RT index
291 * Find all Var nodes in the given tree belonging to a specific relation
292 * (identified by sublevels_up and rt_index), and change their varno fields
293 * to 'new_index'. The varnoold fields are changed too. Also, adjust other
294 * nodes that contain rangetable indexes, such as RangeTblRef and JoinExpr.
296 * NOTE: although this has the form of a walker, we cheat and modify the
297 * nodes in-place. The given expression tree should have been copied
298 * earlier to ensure that no unwanted side-effects occur!
306 } ChangeVarNodes_context;
309 ChangeVarNodes_walker(Node *node, ChangeVarNodes_context *context)
315 Var *var = (Var *) node;
317 if (var->varlevelsup == context->sublevels_up &&
318 var->varno == context->rt_index)
320 var->varno = context->new_index;
321 var->varnoold = context->new_index;
325 if (IsA(node, CurrentOfExpr))
327 CurrentOfExpr *cexpr = (CurrentOfExpr *) node;
329 if (context->sublevels_up == 0 &&
330 cexpr->cvarno == context->rt_index)
331 cexpr->cvarno = context->new_index;
334 if (IsA(node, RangeTblRef))
336 RangeTblRef *rtr = (RangeTblRef *) node;
338 if (context->sublevels_up == 0 &&
339 rtr->rtindex == context->rt_index)
340 rtr->rtindex = context->new_index;
341 /* the subquery itself is visited separately */
344 if (IsA(node, JoinExpr))
346 JoinExpr *j = (JoinExpr *) node;
348 if (context->sublevels_up == 0 &&
349 j->rtindex == context->rt_index)
350 j->rtindex = context->new_index;
351 /* fall through to examine children */
353 if (IsA(node, FlattenedSubLink))
355 FlattenedSubLink *fslink = (FlattenedSubLink *) node;
357 if (context->sublevels_up == 0)
359 fslink->lefthand = adjust_relid_set(fslink->lefthand,
362 fslink->righthand = adjust_relid_set(fslink->righthand,
366 /* fall through to examine children */
368 if (IsA(node, AppendRelInfo))
370 AppendRelInfo *appinfo = (AppendRelInfo *) node;
372 if (context->sublevels_up == 0)
374 if (appinfo->parent_relid == context->rt_index)
375 appinfo->parent_relid = context->new_index;
376 if (appinfo->child_relid == context->rt_index)
377 appinfo->child_relid = context->new_index;
379 /* fall through to examine children */
381 if (IsA(node, Query))
383 /* Recurse into subselects */
386 context->sublevels_up++;
387 result = query_tree_walker((Query *) node, ChangeVarNodes_walker,
388 (void *) context, 0);
389 context->sublevels_up--;
392 return expression_tree_walker(node, ChangeVarNodes_walker,
397 ChangeVarNodes(Node *node, int rt_index, int new_index, int sublevels_up)
399 ChangeVarNodes_context context;
401 context.rt_index = rt_index;
402 context.new_index = new_index;
403 context.sublevels_up = sublevels_up;
406 * Must be prepared to start with a Query or a bare expression tree; if
407 * it's a Query, go straight to query_tree_walker to make sure that
408 * sublevels_up doesn't get incremented prematurely.
410 if (node && IsA(node, Query))
412 Query *qry = (Query *) node;
415 * If we are starting at a Query, and sublevels_up is zero, then we
416 * must also fix rangetable indexes in the Query itself --- namely
417 * resultRelation and rowMarks entries. sublevels_up cannot be zero
418 * when recursing into a subquery, so there's no need to have the same
419 * logic inside ChangeVarNodes_walker.
421 if (sublevels_up == 0)
425 if (qry->resultRelation == rt_index)
426 qry->resultRelation = new_index;
427 foreach(l, qry->rowMarks)
429 RowMarkClause *rc = (RowMarkClause *) lfirst(l);
431 if (rc->rti == rt_index)
435 query_tree_walker(qry, ChangeVarNodes_walker,
436 (void *) &context, 0);
439 ChangeVarNodes_walker(node, &context);
443 * Substitute newrelid for oldrelid in a Relid set
446 adjust_relid_set(Relids relids, int oldrelid, int newrelid)
448 if (bms_is_member(oldrelid, relids))
450 /* Ensure we have a modifiable copy */
451 relids = bms_copy(relids);
452 /* Remove old, add new */
453 relids = bms_del_member(relids, oldrelid);
454 relids = bms_add_member(relids, newrelid);
460 * IncrementVarSublevelsUp - adjust Var nodes when pushing them down in tree
462 * Find all Var nodes in the given tree having varlevelsup >= min_sublevels_up,
463 * and add delta_sublevels_up to their varlevelsup value. This is needed when
464 * an expression that's correct for some nesting level is inserted into a
465 * subquery. Ordinarily the initial call has min_sublevels_up == 0 so that
466 * all Vars are affected. The point of min_sublevels_up is that we can
467 * increment it when we recurse into a sublink, so that local variables in
468 * that sublink are not affected, only outer references to vars that belong
469 * to the expression's original query level or parents thereof.
471 * Aggref nodes are adjusted similarly.
473 * NOTE: although this has the form of a walker, we cheat and modify the
474 * Var nodes in-place. The given expression tree should have been copied
475 * earlier to ensure that no unwanted side-effects occur!
480 int delta_sublevels_up;
481 int min_sublevels_up;
482 } IncrementVarSublevelsUp_context;
485 IncrementVarSublevelsUp_walker(Node *node,
486 IncrementVarSublevelsUp_context *context)
492 Var *var = (Var *) node;
494 if (var->varlevelsup >= context->min_sublevels_up)
495 var->varlevelsup += context->delta_sublevels_up;
496 return false; /* done here */
498 if (IsA(node, CurrentOfExpr))
500 /* this should not happen */
501 if (context->min_sublevels_up == 0)
502 elog(ERROR, "cannot push down CurrentOfExpr");
505 if (IsA(node, Aggref))
507 Aggref *agg = (Aggref *) node;
509 if (agg->agglevelsup >= context->min_sublevels_up)
510 agg->agglevelsup += context->delta_sublevels_up;
511 /* fall through to recurse into argument */
513 if (IsA(node, Query))
515 /* Recurse into subselects */
518 context->min_sublevels_up++;
519 result = query_tree_walker((Query *) node,
520 IncrementVarSublevelsUp_walker,
521 (void *) context, 0);
522 context->min_sublevels_up--;
525 return expression_tree_walker(node, IncrementVarSublevelsUp_walker,
530 IncrementVarSublevelsUp(Node *node, int delta_sublevels_up,
531 int min_sublevels_up)
533 IncrementVarSublevelsUp_context context;
535 context.delta_sublevels_up = delta_sublevels_up;
536 context.min_sublevels_up = min_sublevels_up;
539 * Must be prepared to start with a Query or a bare expression tree; if
540 * it's a Query, we don't want to increment sublevels_up.
542 query_or_expression_tree_walker(node,
543 IncrementVarSublevelsUp_walker,
549 * IncrementVarSublevelsUp_rtable -
550 * Same as IncrementVarSublevelsUp, but to be invoked on a range table.
553 IncrementVarSublevelsUp_rtable(List *rtable, int delta_sublevels_up,
554 int min_sublevels_up)
556 IncrementVarSublevelsUp_context context;
558 context.delta_sublevels_up = delta_sublevels_up;
559 context.min_sublevels_up = min_sublevels_up;
561 range_table_walker(rtable,
562 IncrementVarSublevelsUp_walker,
569 * rangeTableEntry_used - detect whether an RTE is referenced somewhere
570 * in var nodes or join or setOp trees of a query or expression.
577 } rangeTableEntry_used_context;
580 rangeTableEntry_used_walker(Node *node,
581 rangeTableEntry_used_context *context)
587 Var *var = (Var *) node;
589 if (var->varlevelsup == context->sublevels_up &&
590 var->varno == context->rt_index)
594 if (IsA(node, CurrentOfExpr))
596 CurrentOfExpr *cexpr = (CurrentOfExpr *) node;
598 if (context->sublevels_up == 0 &&
599 cexpr->cvarno == context->rt_index)
603 if (IsA(node, RangeTblRef))
605 RangeTblRef *rtr = (RangeTblRef *) node;
607 if (rtr->rtindex == context->rt_index &&
608 context->sublevels_up == 0)
610 /* the subquery itself is visited separately */
613 if (IsA(node, JoinExpr))
615 JoinExpr *j = (JoinExpr *) node;
617 if (j->rtindex == context->rt_index &&
618 context->sublevels_up == 0)
620 /* fall through to examine children */
622 /* Shouldn't need to handle planner auxiliary nodes here */
623 Assert(!IsA(node, FlattenedSubLink));
624 Assert(!IsA(node, SpecialJoinInfo));
625 Assert(!IsA(node, AppendRelInfo));
627 if (IsA(node, Query))
629 /* Recurse into subselects */
632 context->sublevels_up++;
633 result = query_tree_walker((Query *) node, rangeTableEntry_used_walker,
634 (void *) context, 0);
635 context->sublevels_up--;
638 return expression_tree_walker(node, rangeTableEntry_used_walker,
643 rangeTableEntry_used(Node *node, int rt_index, int sublevels_up)
645 rangeTableEntry_used_context context;
647 context.rt_index = rt_index;
648 context.sublevels_up = sublevels_up;
651 * Must be prepared to start with a Query or a bare expression tree; if
652 * it's a Query, we don't want to increment sublevels_up.
654 return query_or_expression_tree_walker(node,
655 rangeTableEntry_used_walker,
663 * Check if a specific attribute number of a RTE is used
664 * somewhere in the query or expression.
672 } attribute_used_context;
675 attribute_used_walker(Node *node,
676 attribute_used_context *context)
682 Var *var = (Var *) node;
684 if (var->varlevelsup == context->sublevels_up &&
685 var->varno == context->rt_index &&
686 var->varattno == context->attno)
690 if (IsA(node, Query))
692 /* Recurse into subselects */
695 context->sublevels_up++;
696 result = query_tree_walker((Query *) node, attribute_used_walker,
697 (void *) context, 0);
698 context->sublevels_up--;
701 return expression_tree_walker(node, attribute_used_walker,
706 attribute_used(Node *node, int rt_index, int attno, int sublevels_up)
708 attribute_used_context context;
710 context.rt_index = rt_index;
711 context.attno = attno;
712 context.sublevels_up = sublevels_up;
715 * Must be prepared to start with a Query or a bare expression tree; if
716 * it's a Query, we don't want to increment sublevels_up.
718 return query_or_expression_tree_walker(node,
719 attribute_used_walker,
726 * If the given Query is an INSERT ... SELECT construct, extract and
727 * return the sub-Query node that represents the SELECT part. Otherwise
728 * return the given Query.
730 * If subquery_ptr is not NULL, then *subquery_ptr is set to the location
731 * of the link to the SELECT subquery inside parsetree, or NULL if not an
734 * This is a hack needed because transformations on INSERT ... SELECTs that
735 * appear in rule actions should be applied to the source SELECT, not to the
736 * INSERT part. Perhaps this can be cleaned up with redesigned querytrees.
739 getInsertSelectQuery(Query *parsetree, Query ***subquery_ptr)
742 RangeTblEntry *selectrte;
746 *subquery_ptr = NULL;
748 if (parsetree == NULL)
750 if (parsetree->commandType != CMD_INSERT)
754 * Currently, this is ONLY applied to rule-action queries, and so we
755 * expect to find the *OLD* and *NEW* placeholder entries in the given
756 * query. If they're not there, it must be an INSERT/SELECT in which
757 * they've been pushed down to the SELECT.
759 if (list_length(parsetree->rtable) >= 2 &&
760 strcmp(rt_fetch(PRS2_OLD_VARNO, parsetree->rtable)->eref->aliasname,
762 strcmp(rt_fetch(PRS2_NEW_VARNO, parsetree->rtable)->eref->aliasname,
765 Assert(parsetree->jointree && IsA(parsetree->jointree, FromExpr));
766 if (list_length(parsetree->jointree->fromlist) != 1)
767 elog(ERROR, "expected to find SELECT subquery");
768 rtr = (RangeTblRef *) linitial(parsetree->jointree->fromlist);
769 Assert(IsA(rtr, RangeTblRef));
770 selectrte = rt_fetch(rtr->rtindex, parsetree->rtable);
771 selectquery = selectrte->subquery;
772 if (!(selectquery && IsA(selectquery, Query) &&
773 selectquery->commandType == CMD_SELECT))
774 elog(ERROR, "expected to find SELECT subquery");
775 if (list_length(selectquery->rtable) >= 2 &&
776 strcmp(rt_fetch(PRS2_OLD_VARNO, selectquery->rtable)->eref->aliasname,
778 strcmp(rt_fetch(PRS2_NEW_VARNO, selectquery->rtable)->eref->aliasname,
782 *subquery_ptr = &(selectrte->subquery);
785 elog(ERROR, "could not find rule placeholders");
786 return NULL; /* not reached */
791 * Add the given qualifier condition to the query's WHERE clause
794 AddQual(Query *parsetree, Node *qual)
801 if (parsetree->commandType == CMD_UTILITY)
804 * There's noplace to put the qual on a utility statement.
806 * If it's a NOTIFY, silently ignore the qual; this means that the
807 * NOTIFY will execute, whether or not there are any qualifying rows.
808 * While clearly wrong, this is much more useful than refusing to
809 * execute the rule at all, and extra NOTIFY events are harmless for
810 * typical uses of NOTIFY.
812 * If it isn't a NOTIFY, error out, since unconditional execution of
813 * other utility stmts is unlikely to be wanted. (This case is not
814 * currently allowed anyway, but keep the test for safety.)
816 if (parsetree->utilityStmt && IsA(parsetree->utilityStmt, NotifyStmt))
820 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
821 errmsg("conditional utility statements are not implemented")));
824 if (parsetree->setOperations != NULL)
827 * There's noplace to put the qual on a setop statement, either. (This
828 * could be fixed, but right now the planner simply ignores any qual
829 * condition on a setop query.)
832 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
833 errmsg("conditional UNION/INTERSECT/EXCEPT statements are not implemented")));
836 /* INTERSECT want's the original, but we need to copy - Jan */
837 copy = copyObject(qual);
839 parsetree->jointree->quals = make_and_qual(parsetree->jointree->quals,
843 * We had better not have stuck an aggregate into the WHERE clause.
845 Assert(!checkExprHasAggs(copy));
848 * Make sure query is marked correctly if added qual has sublinks. Need
849 * not search qual when query is already marked.
851 if (!parsetree->hasSubLinks)
852 parsetree->hasSubLinks = checkExprHasSubLink(copy);
857 * Invert the given clause and add it to the WHERE qualifications of the
858 * given querytree. Inversion means "x IS NOT TRUE", not just "NOT x",
859 * else we will do the wrong thing when x evaluates to NULL.
862 AddInvertedQual(Query *parsetree, Node *qual)
864 BooleanTest *invqual;
869 /* Need not copy input qual, because AddQual will... */
870 invqual = makeNode(BooleanTest);
871 invqual->arg = (Expr *) qual;
872 invqual->booltesttype = IS_NOT_TRUE;
874 AddQual(parsetree, (Node *) invqual);
879 * ResolveNew - replace Vars with corresponding items from a targetlist
881 * Vars matching target_varno and sublevels_up are replaced by the
882 * entry with matching resno from targetlist, if there is one.
883 * If not, we either change the unmatched Var's varno to update_varno
884 * (when event == CMD_UPDATE) or replace it with a constant NULL.
886 * The caller must also provide target_rte, the RTE describing the target
887 * relation. This is needed to handle whole-row Vars referencing the target.
888 * We expand such Vars into RowExpr constructs.
890 * Note: the business with inserted_sublink is needed to update hasSubLinks
891 * in subqueries when the replacement adds a subquery inside a subquery.
892 * Messy, isn't it? We do not need to do similar pushups for hasAggs,
893 * because it isn't possible for this transformation to insert a level-zero
894 * aggregate reference into a subquery --- it could only insert outer aggs.
901 RangeTblEntry *target_rte;
905 bool inserted_sublink;
906 } ResolveNew_context;
909 resolve_one_var(Var *var, ResolveNew_context *context)
913 tle = get_tle_by_resno(context->targetlist, var->varattno);
917 /* Failed to find column in insert/update tlist */
918 if (context->event == CMD_UPDATE)
920 /* For update, just change unmatched var's varno */
921 var = (Var *) copyObject(var);
922 var->varno = context->update_varno;
923 var->varnoold = context->update_varno;
928 /* Otherwise replace unmatched var with a null */
929 /* need coerce_to_domain in case of NOT NULL domain constraint */
930 return coerce_to_domain((Node *) makeNullConst(var->vartype,
934 COERCE_IMPLICIT_CAST,
941 /* Make a copy of the tlist item to return */
942 Node *n = copyObject(tle->expr);
944 /* Adjust varlevelsup if tlist item is from higher query */
945 if (var->varlevelsup > 0)
946 IncrementVarSublevelsUp(n, var->varlevelsup, 0);
947 /* Report it if we are adding a sublink to query */
948 if (!context->inserted_sublink)
949 context->inserted_sublink = checkExprHasSubLink(n);
955 ResolveNew_mutator(Node *node, ResolveNew_context *context)
961 Var *var = (Var *) node;
962 int this_varno = (int) var->varno;
963 int this_varlevelsup = (int) var->varlevelsup;
965 if (this_varno == context->target_varno &&
966 this_varlevelsup == context->sublevels_up)
968 if (var->varattno == InvalidAttrNumber)
970 /* Must expand whole-tuple reference into RowExpr */
975 * If generating an expansion for a var of a named rowtype
976 * (ie, this is a plain relation RTE), then we must include
977 * dummy items for dropped columns. If the var is RECORD (ie,
978 * this is a JOIN), then omit dropped columns.
980 expandRTE(context->target_rte,
981 this_varno, this_varlevelsup,
982 (var->vartype != RECORDOID),
984 /* Adjust the generated per-field Vars... */
985 fields = (List *) ResolveNew_mutator((Node *) fields,
987 rowexpr = makeNode(RowExpr);
988 rowexpr->args = fields;
989 rowexpr->row_typeid = var->vartype;
990 rowexpr->row_format = COERCE_IMPLICIT_CAST;
992 return (Node *) rowexpr;
995 /* Normal case for scalar variable */
996 return resolve_one_var(var, context);
998 /* otherwise fall through to copy the var normally */
1000 else if (IsA(node, CurrentOfExpr))
1002 CurrentOfExpr *cexpr = (CurrentOfExpr *) node;
1003 int this_varno = (int) cexpr->cvarno;
1005 if (this_varno == context->target_varno &&
1006 context->sublevels_up == 0)
1009 * We get here if a WHERE CURRENT OF expression turns out to apply
1010 * to a view. Someday we might be able to translate the
1011 * expression to apply to an underlying table of the view, but
1012 * right now it's not implemented.
1015 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1016 errmsg("WHERE CURRENT OF on a view is not implemented")));
1018 /* otherwise fall through to copy the expr normally */
1020 else if (IsA(node, Query))
1022 /* Recurse into RTE subquery or not-yet-planned sublink subquery */
1024 bool save_inserted_sublink;
1026 context->sublevels_up++;
1027 save_inserted_sublink = context->inserted_sublink;
1028 context->inserted_sublink = false;
1029 newnode = query_tree_mutator((Query *) node,
1033 newnode->hasSubLinks |= context->inserted_sublink;
1034 context->inserted_sublink = save_inserted_sublink;
1035 context->sublevels_up--;
1036 return (Node *) newnode;
1038 return expression_tree_mutator(node, ResolveNew_mutator,
1043 ResolveNew(Node *node, int target_varno, int sublevels_up,
1044 RangeTblEntry *target_rte,
1045 List *targetlist, int event, int update_varno)
1048 ResolveNew_context context;
1050 context.target_varno = target_varno;
1051 context.sublevels_up = sublevels_up;
1052 context.target_rte = target_rte;
1053 context.targetlist = targetlist;
1054 context.event = event;
1055 context.update_varno = update_varno;
1056 context.inserted_sublink = false;
1059 * Must be prepared to start with a Query or a bare expression tree; if
1060 * it's a Query, we don't want to increment sublevels_up.
1062 result = query_or_expression_tree_mutator(node,
1067 if (context.inserted_sublink)
1069 if (IsA(result, Query))
1070 ((Query *) result)->hasSubLinks = true;
1073 * Note: if we're called on a non-Query node then it's the caller's
1074 * responsibility to update hasSubLinks in the ancestor Query. This is
1075 * pretty fragile and perhaps should be rethought ...