1 /*-------------------------------------------------------------------------
5 * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
6 * Portions Copyright (c) 1994, Regents of the University of California
10 * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteManip.c,v 1.70 2003/01/20 18:54:59 tgl Exp $
12 *-------------------------------------------------------------------------
16 #include "nodes/makefuncs.h"
17 #include "optimizer/clauses.h"
18 #include "optimizer/tlist.h"
19 #include "parser/parsetree.h"
20 #include "parser/parse_clause.h"
21 #include "rewrite/rewriteManip.h"
22 #include "utils/lsyscache.h"
25 static bool checkExprHasAggs_walker(Node *node, void *context);
26 static bool checkExprHasSubLink_walker(Node *node, void *context);
31 * Queries marked hasAggs might not have them any longer after
32 * rewriting. Check it.
35 checkExprHasAggs(Node *node)
38 * If a Query is passed, examine it --- but we will not recurse into
41 return query_or_expression_tree_walker(node,
42 checkExprHasAggs_walker,
44 QTW_IGNORE_RT_SUBQUERIES);
48 checkExprHasAggs_walker(Node *node, void *context)
52 if (IsA(node, Aggref))
53 return true; /* abort the tree traversal and return
55 return expression_tree_walker(node, checkExprHasAggs_walker, context);
59 * checkExprHasSubLink -
60 * Queries marked hasSubLinks might not have them any longer after
61 * rewriting. Check it.
64 checkExprHasSubLink(Node *node)
67 * If a Query is passed, examine it --- but we will not recurse into
70 return query_or_expression_tree_walker(node,
71 checkExprHasSubLink_walker,
73 QTW_IGNORE_RT_SUBQUERIES);
77 checkExprHasSubLink_walker(Node *node, void *context)
81 if (IsA(node, SubLink))
82 return true; /* abort the tree traversal and return
84 return expression_tree_walker(node, checkExprHasSubLink_walker, context);
89 * OffsetVarNodes - adjust Vars when appending one query's RT to another
91 * Find all Var nodes in the given tree with varlevelsup == sublevels_up,
92 * and increment their varno fields (rangetable indexes) by 'offset'.
93 * The varnoold fields are adjusted similarly. Also, adjust other nodes
94 * that contain rangetable indexes, such as RangeTblRef and JoinExpr.
96 * NOTE: although this has the form of a walker, we cheat and modify the
97 * nodes in-place. The given expression tree should have been copied
98 * earlier to ensure that no unwanted side-effects occur!
105 } OffsetVarNodes_context;
108 OffsetVarNodes_walker(Node *node, OffsetVarNodes_context *context)
114 Var *var = (Var *) node;
116 if (var->varlevelsup == context->sublevels_up)
118 var->varno += context->offset;
119 var->varnoold += context->offset;
123 if (IsA(node, RangeTblRef))
125 RangeTblRef *rtr = (RangeTblRef *) node;
127 if (context->sublevels_up == 0)
128 rtr->rtindex += context->offset;
129 /* the subquery itself is visited separately */
132 if (IsA(node, JoinExpr))
134 JoinExpr *j = (JoinExpr *) node;
136 if (context->sublevels_up == 0)
137 j->rtindex += context->offset;
138 /* fall through to examine children */
140 if (IsA(node, InClauseInfo))
142 InClauseInfo *ininfo = (InClauseInfo *) node;
144 if (context->sublevels_up == 0)
148 foreach(rt, ininfo->lefthand)
150 lfirsti(rt) += context->offset;
152 foreach(rt, ininfo->righthand)
154 lfirsti(rt) += context->offset;
157 /* fall through to examine children */
159 if (IsA(node, Query))
161 /* Recurse into subselects */
164 context->sublevels_up++;
165 result = query_tree_walker((Query *) node, OffsetVarNodes_walker,
166 (void *) context, 0);
167 context->sublevels_up--;
170 return expression_tree_walker(node, OffsetVarNodes_walker,
175 OffsetVarNodes(Node *node, int offset, int sublevels_up)
177 OffsetVarNodes_context context;
179 context.offset = offset;
180 context.sublevels_up = sublevels_up;
183 * Must be prepared to start with a Query or a bare expression tree;
184 * if it's a Query, go straight to query_tree_walker to make sure that
185 * sublevels_up doesn't get incremented prematurely.
187 if (node && IsA(node, Query))
189 Query *qry = (Query *) node;
193 * If we are starting at a Query, and sublevels_up is zero, then
194 * we must also fix rangetable indexes in the Query itself ---
195 * namely resultRelation and rowMarks entries. sublevels_up
196 * cannot be zero when recursing into a subquery, so there's no
197 * need to have the same logic inside OffsetVarNodes_walker.
199 if (sublevels_up == 0)
201 if (qry->resultRelation)
202 qry->resultRelation += offset;
203 foreach(l, qry->rowMarks)
204 lfirsti(l) += offset;
206 query_tree_walker(qry, OffsetVarNodes_walker,
207 (void *) &context, 0);
210 OffsetVarNodes_walker(node, &context);
214 * ChangeVarNodes - adjust Var nodes for a specific change of RT index
216 * Find all Var nodes in the given tree belonging to a specific relation
217 * (identified by sublevels_up and rt_index), and change their varno fields
218 * to 'new_index'. The varnoold fields are changed too. Also, adjust other
219 * nodes that contain rangetable indexes, such as RangeTblRef and JoinExpr.
221 * NOTE: although this has the form of a walker, we cheat and modify the
222 * nodes in-place. The given expression tree should have been copied
223 * earlier to ensure that no unwanted side-effects occur!
231 } ChangeVarNodes_context;
234 ChangeVarNodes_walker(Node *node, ChangeVarNodes_context *context)
240 Var *var = (Var *) node;
242 if (var->varlevelsup == context->sublevels_up &&
243 var->varno == context->rt_index)
245 var->varno = context->new_index;
246 var->varnoold = context->new_index;
250 if (IsA(node, RangeTblRef))
252 RangeTblRef *rtr = (RangeTblRef *) node;
254 if (context->sublevels_up == 0 &&
255 rtr->rtindex == context->rt_index)
256 rtr->rtindex = context->new_index;
257 /* the subquery itself is visited separately */
260 if (IsA(node, JoinExpr))
262 JoinExpr *j = (JoinExpr *) node;
264 if (context->sublevels_up == 0 &&
265 j->rtindex == context->rt_index)
266 j->rtindex = context->new_index;
267 /* fall through to examine children */
269 if (IsA(node, InClauseInfo))
271 InClauseInfo *ininfo = (InClauseInfo *) node;
273 if (context->sublevels_up == 0)
277 foreach(rt, ininfo->lefthand)
279 if (lfirsti(rt) == context->rt_index)
280 lfirsti(rt) = context->new_index;
282 foreach(rt, ininfo->righthand)
284 if (lfirsti(rt) == context->rt_index)
285 lfirsti(rt) = context->new_index;
288 /* fall through to examine children */
290 if (IsA(node, Query))
292 /* Recurse into subselects */
295 context->sublevels_up++;
296 result = query_tree_walker((Query *) node, ChangeVarNodes_walker,
297 (void *) context, 0);
298 context->sublevels_up--;
301 return expression_tree_walker(node, ChangeVarNodes_walker,
306 ChangeVarNodes(Node *node, int rt_index, int new_index, int sublevels_up)
308 ChangeVarNodes_context context;
310 context.rt_index = rt_index;
311 context.new_index = new_index;
312 context.sublevels_up = sublevels_up;
315 * Must be prepared to start with a Query or a bare expression tree;
316 * if it's a Query, go straight to query_tree_walker to make sure that
317 * sublevels_up doesn't get incremented prematurely.
319 if (node && IsA(node, Query))
321 Query *qry = (Query *) node;
325 * If we are starting at a Query, and sublevels_up is zero, then
326 * we must also fix rangetable indexes in the Query itself ---
327 * namely resultRelation and rowMarks entries. sublevels_up
328 * cannot be zero when recursing into a subquery, so there's no
329 * need to have the same logic inside ChangeVarNodes_walker.
331 if (sublevels_up == 0)
333 if (qry->resultRelation == rt_index)
334 qry->resultRelation = new_index;
335 foreach(l, qry->rowMarks)
337 if (lfirsti(l) == rt_index)
338 lfirsti(l) = new_index;
341 query_tree_walker(qry, ChangeVarNodes_walker,
342 (void *) &context, 0);
345 ChangeVarNodes_walker(node, &context);
349 * IncrementVarSublevelsUp - adjust Var nodes when pushing them down in tree
351 * Find all Var nodes in the given tree having varlevelsup >= min_sublevels_up,
352 * and add delta_sublevels_up to their varlevelsup value. This is needed when
353 * an expression that's correct for some nesting level is inserted into a
354 * subquery. Ordinarily the initial call has min_sublevels_up == 0 so that
355 * all Vars are affected. The point of min_sublevels_up is that we can
356 * increment it when we recurse into a sublink, so that local variables in
357 * that sublink are not affected, only outer references to vars that belong
358 * to the expression's original query level or parents thereof.
360 * NOTE: although this has the form of a walker, we cheat and modify the
361 * Var nodes in-place. The given expression tree should have been copied
362 * earlier to ensure that no unwanted side-effects occur!
367 int delta_sublevels_up;
368 int min_sublevels_up;
369 } IncrementVarSublevelsUp_context;
372 IncrementVarSublevelsUp_walker(Node *node,
373 IncrementVarSublevelsUp_context *context)
379 Var *var = (Var *) node;
381 if (var->varlevelsup >= context->min_sublevels_up)
382 var->varlevelsup += context->delta_sublevels_up;
385 if (IsA(node, Query))
387 /* Recurse into subselects */
390 context->min_sublevels_up++;
391 result = query_tree_walker((Query *) node,
392 IncrementVarSublevelsUp_walker,
393 (void *) context, 0);
394 context->min_sublevels_up--;
397 return expression_tree_walker(node, IncrementVarSublevelsUp_walker,
402 IncrementVarSublevelsUp(Node *node, int delta_sublevels_up,
403 int min_sublevels_up)
405 IncrementVarSublevelsUp_context context;
407 context.delta_sublevels_up = delta_sublevels_up;
408 context.min_sublevels_up = min_sublevels_up;
411 * Must be prepared to start with a Query or a bare expression tree;
412 * if it's a Query, we don't want to increment sublevels_up.
414 query_or_expression_tree_walker(node,
415 IncrementVarSublevelsUp_walker,
422 * rangeTableEntry_used - detect whether an RTE is referenced somewhere
423 * in var nodes or join or setOp trees of a query or expression.
430 } rangeTableEntry_used_context;
433 rangeTableEntry_used_walker(Node *node,
434 rangeTableEntry_used_context *context)
440 Var *var = (Var *) node;
442 if (var->varlevelsup == context->sublevels_up &&
443 var->varno == context->rt_index)
447 if (IsA(node, RangeTblRef))
449 RangeTblRef *rtr = (RangeTblRef *) node;
451 if (rtr->rtindex == context->rt_index &&
452 context->sublevels_up == 0)
454 /* the subquery itself is visited separately */
457 if (IsA(node, JoinExpr))
459 JoinExpr *j = (JoinExpr *) node;
461 if (j->rtindex == context->rt_index &&
462 context->sublevels_up == 0)
464 /* fall through to examine children */
466 if (IsA(node, InClauseInfo))
468 InClauseInfo *ininfo = (InClauseInfo *) node;
470 if (context->sublevels_up == 0 &&
471 (intMember(context->rt_index, ininfo->lefthand) ||
472 intMember(context->rt_index, ininfo->righthand)))
474 /* fall through to examine children */
476 if (IsA(node, Query))
478 /* Recurse into subselects */
481 context->sublevels_up++;
482 result = query_tree_walker((Query *) node, rangeTableEntry_used_walker,
483 (void *) context, 0);
484 context->sublevels_up--;
487 return expression_tree_walker(node, rangeTableEntry_used_walker,
492 rangeTableEntry_used(Node *node, int rt_index, int sublevels_up)
494 rangeTableEntry_used_context context;
496 context.rt_index = rt_index;
497 context.sublevels_up = sublevels_up;
500 * Must be prepared to start with a Query or a bare expression tree;
501 * if it's a Query, we don't want to increment sublevels_up.
503 return query_or_expression_tree_walker(node,
504 rangeTableEntry_used_walker,
512 * Check if a specific attribute number of a RTE is used
513 * somewhere in the query or expression.
521 } attribute_used_context;
524 attribute_used_walker(Node *node,
525 attribute_used_context *context)
531 Var *var = (Var *) node;
533 if (var->varlevelsup == context->sublevels_up &&
534 var->varno == context->rt_index &&
535 var->varattno == context->attno)
539 if (IsA(node, Query))
541 /* Recurse into subselects */
544 context->sublevels_up++;
545 result = query_tree_walker((Query *) node, attribute_used_walker,
546 (void *) context, 0);
547 context->sublevels_up--;
550 return expression_tree_walker(node, attribute_used_walker,
555 attribute_used(Node *node, int rt_index, int attno, int sublevels_up)
557 attribute_used_context context;
559 context.rt_index = rt_index;
560 context.attno = attno;
561 context.sublevels_up = sublevels_up;
564 * Must be prepared to start with a Query or a bare expression tree;
565 * if it's a Query, we don't want to increment sublevels_up.
567 return query_or_expression_tree_walker(node,
568 attribute_used_walker,
575 * If the given Query is an INSERT ... SELECT construct, extract and
576 * return the sub-Query node that represents the SELECT part. Otherwise
577 * return the given Query.
579 * If subquery_ptr is not NULL, then *subquery_ptr is set to the location
580 * of the link to the SELECT subquery inside parsetree, or NULL if not an
583 * This is a hack needed because transformations on INSERT ... SELECTs that
584 * appear in rule actions should be applied to the source SELECT, not to the
585 * INSERT part. Perhaps this can be cleaned up with redesigned querytrees.
588 getInsertSelectQuery(Query *parsetree, Query ***subquery_ptr)
591 RangeTblEntry *selectrte;
595 *subquery_ptr = NULL;
597 if (parsetree == NULL)
599 if (parsetree->commandType != CMD_INSERT)
603 * Currently, this is ONLY applied to rule-action queries, and so we
604 * expect to find the *OLD* and *NEW* placeholder entries in the given
605 * query. If they're not there, it must be an INSERT/SELECT in which
606 * they've been pushed down to the SELECT.
608 if (length(parsetree->rtable) >= 2 &&
609 strcmp(rt_fetch(PRS2_OLD_VARNO, parsetree->rtable)->eref->aliasname,
611 strcmp(rt_fetch(PRS2_NEW_VARNO, parsetree->rtable)->eref->aliasname,
614 Assert(parsetree->jointree && IsA(parsetree->jointree, FromExpr));
615 if (length(parsetree->jointree->fromlist) != 1)
616 elog(ERROR, "getInsertSelectQuery: expected to find SELECT subquery");
617 rtr = (RangeTblRef *) lfirst(parsetree->jointree->fromlist);
618 Assert(IsA(rtr, RangeTblRef));
619 selectrte = rt_fetch(rtr->rtindex, parsetree->rtable);
620 selectquery = selectrte->subquery;
621 if (!(selectquery && IsA(selectquery, Query) &&
622 selectquery->commandType == CMD_SELECT))
623 elog(ERROR, "getInsertSelectQuery: expected to find SELECT subquery");
624 if (length(selectquery->rtable) >= 2 &&
625 strcmp(rt_fetch(PRS2_OLD_VARNO, selectquery->rtable)->eref->aliasname,
627 strcmp(rt_fetch(PRS2_NEW_VARNO, selectquery->rtable)->eref->aliasname,
631 *subquery_ptr = &(selectrte->subquery);
634 elog(ERROR, "getInsertSelectQuery: can't find rule placeholders");
635 return NULL; /* not reached */
640 * Add the given qualifier condition to the query's WHERE clause
643 AddQual(Query *parsetree, Node *qual)
650 if (parsetree->commandType == CMD_UTILITY)
653 * There's noplace to put the qual on a utility statement.
655 * If it's a NOTIFY, silently ignore the qual; this means that the
656 * NOTIFY will execute, whether or not there are any qualifying
657 * rows. While clearly wrong, this is much more useful than
658 * refusing to execute the rule at all, and extra NOTIFY events
659 * are harmless for typical uses of NOTIFY.
661 * If it isn't a NOTIFY, error out, since unconditional execution of
662 * other utility stmts is unlikely to be wanted. (This case is
663 * not currently allowed anyway, but keep the test for safety.)
665 if (parsetree->utilityStmt && IsA(parsetree->utilityStmt, NotifyStmt))
668 elog(ERROR, "Conditional utility statements are not implemented");
671 /* INTERSECT want's the original, but we need to copy - Jan */
672 copy = copyObject(qual);
674 parsetree->jointree->quals = make_and_qual(parsetree->jointree->quals,
678 * Make sure query is marked correctly if added qual has sublinks or
679 * aggregates (not sure it can ever have aggs, but sublinks
682 parsetree->hasAggs |= checkExprHasAggs(copy);
683 parsetree->hasSubLinks |= checkExprHasSubLink(copy);
687 * Add the given havingQual to the one already contained in the parsetree
688 * just as AddQual does for the normal 'where' qual
691 AddHavingQual(Query *parsetree, Node *havingQual)
695 if (havingQual == NULL)
698 if (parsetree->commandType == CMD_UTILITY)
701 * There's noplace to put the qual on a utility statement.
703 * See comments in AddQual for motivation.
705 if (parsetree->utilityStmt && IsA(parsetree->utilityStmt, NotifyStmt))
708 elog(ERROR, "Conditional utility statements are not implemented");
711 /* INTERSECT want's the original, but we need to copy - Jan */
712 copy = copyObject(havingQual);
714 parsetree->havingQual = make_and_qual(parsetree->havingQual,
718 * Make sure query is marked correctly if added qual has sublinks or
719 * aggregates (not sure it can ever have aggs, but sublinks
722 parsetree->hasAggs |= checkExprHasAggs(copy);
723 parsetree->hasSubLinks |= checkExprHasSubLink(copy);
728 * Invert the given clause and add it to the WHERE qualifications of the
729 * given querytree. Inversion means "x IS NOT TRUE", not just "NOT x",
730 * else we will do the wrong thing when x evaluates to NULL.
733 AddInvertedQual(Query *parsetree, Node *qual)
735 BooleanTest *invqual;
740 /* Need not copy input qual, because AddQual will... */
741 invqual = makeNode(BooleanTest);
742 invqual->arg = (Expr *) qual;
743 invqual->booltesttype = IS_NOT_TRUE;
745 AddQual(parsetree, (Node *) invqual);
749 /* Find a targetlist entry by resno */
751 FindMatchingNew(List *tlist, int attno)
757 TargetEntry *tle = lfirst(i);
759 if (tle->resdom->resno == attno)
760 return (Node *) tle->expr;
767 /* Find a targetlist entry by resname */
769 FindMatchingTLEntry(List *tlist, char *e_attname)
775 TargetEntry *tle = lfirst(i);
778 resname = tle->resdom->resname;
779 if (strcmp(e_attname, resname) == 0)
788 * ResolveNew - replace Vars with corresponding items from a targetlist
790 * Vars matching target_varno and sublevels_up are replaced by the
791 * entry with matching resno from targetlist, if there is one.
792 * If not, we either change the unmatched Var's varno to update_varno
793 * (when event == CMD_UPDATE) or replace it with a constant NULL.
803 } ResolveNew_context;
806 ResolveNew_mutator(Node *node, ResolveNew_context *context)
812 Var *var = (Var *) node;
813 int this_varno = (int) var->varno;
814 int this_varlevelsup = (int) var->varlevelsup;
816 if (this_varno == context->target_varno &&
817 this_varlevelsup == context->sublevels_up)
821 /* band-aid: don't do the wrong thing with a whole-tuple Var */
822 if (var->varattno == InvalidAttrNumber)
823 elog(ERROR, "ResolveNew: can't handle whole-tuple reference");
825 n = FindMatchingNew(context->targetlist, var->varattno);
829 if (context->event == CMD_UPDATE)
831 /* For update, just change unmatched var's varno */
832 var = (Var *) copyObject(node);
833 var->varno = context->update_varno;
834 var->varnoold = context->update_varno;
839 /* Otherwise replace unmatched var with a null */
840 return (Node *) makeNullConst(var->vartype);
845 /* Make a copy of the tlist item to return */
847 /* Adjust varlevelsup if tlist item is from higher query */
848 if (this_varlevelsup > 0)
849 IncrementVarSublevelsUp(n, this_varlevelsup, 0);
853 /* otherwise fall through to copy the var normally */
856 if (IsA(node, Query))
858 /* Recurse into RTE subquery or not-yet-planned sublink subquery */
861 context->sublevels_up++;
862 newnode = query_tree_mutator((Query *) node,
866 context->sublevels_up--;
867 return (Node *) newnode;
869 return expression_tree_mutator(node, ResolveNew_mutator,
874 ResolveNew(Node *node, int target_varno, int sublevels_up,
875 List *targetlist, int event, int update_varno)
877 ResolveNew_context context;
879 context.target_varno = target_varno;
880 context.sublevels_up = sublevels_up;
881 context.targetlist = targetlist;
882 context.event = event;
883 context.update_varno = update_varno;
886 * Must be prepared to start with a Query or a bare expression tree;
887 * if it's a Query, we don't want to increment sublevels_up.
889 return query_or_expression_tree_mutator(node,
899 * HandleRIRAttributeRule
900 * Replace Vars matching a given RT index with copies of TL expressions.
902 * Handles 'on retrieve to relation.attribute
903 * do instead retrieve (attribute = expression) w/qual'
915 } HandleRIRAttributeRule_context;
918 HandleRIRAttributeRule_mutator(Node *node,
919 HandleRIRAttributeRule_context * context)
925 Var *var = (Var *) node;
926 int this_varno = var->varno;
927 int this_varattno = var->varattno;
928 int this_varlevelsup = var->varlevelsup;
930 if (this_varno == context->rt_index &&
931 this_varattno == context->attr_num &&
932 this_varlevelsup == context->sublevels_up)
934 if (var->vartype == 32)
935 { /* HACK: disallow SET variables */
936 *context->modified = TRUE;
937 *context->badsql = TRUE;
938 return (Node *) makeNullConst(var->vartype);
942 char *name_to_look_for;
944 name_to_look_for = get_attname(getrelid(this_varno,
947 if (name_to_look_for)
951 *context->modified = TRUE;
952 n = FindMatchingTLEntry(context->targetlist,
955 return (Node *) makeNullConst(var->vartype);
956 /* Make a copy of the tlist item to return */
960 * Adjust varlevelsup if tlist item is from higher
963 if (this_varlevelsup > 0)
964 IncrementVarSublevelsUp(n, this_varlevelsup, 0);
969 /* otherwise fall through to copy the var normally */
972 if (IsA(node, Query))
974 /* Recurse into RTE subquery or not-yet-planned sublink subquery */
977 context->sublevels_up++;
978 newnode = query_tree_mutator((Query *) node,
979 HandleRIRAttributeRule_mutator,
982 context->sublevels_up--;
983 return (Node *) newnode;
985 return expression_tree_mutator(node, HandleRIRAttributeRule_mutator,
990 HandleRIRAttributeRule(Query *parsetree,
998 HandleRIRAttributeRule_context context;
1000 context.rtable = rtable;
1001 context.targetlist = targetlist;
1002 context.rt_index = rt_index;
1003 context.attr_num = attr_num;
1004 context.modified = modified;
1005 context.badsql = badsql;
1006 context.sublevels_up = 0;
1008 query_tree_mutator(parsetree,
1009 HandleRIRAttributeRule_mutator,
1011 QTW_DONT_COPY_QUERY);
1014 #endif /* NOT_USED */