1 /*-------------------------------------------------------------------------
5 * Portions Copyright (c) 1996-2001, 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.60 2001/10/28 06:25:49 momjian 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 /* macros borrowed from expression_tree_mutator */
27 #define FLATCOPY(newnode, node, nodetype) \
28 ( (newnode) = makeNode(nodetype), \
29 memcpy((newnode), (node), sizeof(nodetype)) )
31 #define MUTATE(newfield, oldfield, fieldtype, mutator, context) \
32 ( (newfield) = (fieldtype) mutator((Node *) (oldfield), (context)) )
34 static bool checkExprHasAggs_walker(Node *node, void *context);
35 static bool checkExprHasSubLink_walker(Node *node, void *context);
40 * Queries marked hasAggs might not have them any longer after
41 * rewriting. Check it.
44 checkExprHasAggs(Node *node)
47 * If a Query is passed, examine it --- but we will not recurse into
50 if (node && IsA(node, Query))
51 return query_tree_walker((Query *) node, checkExprHasAggs_walker,
54 return checkExprHasAggs_walker(node, NULL);
58 checkExprHasAggs_walker(Node *node, void *context)
62 if (IsA(node, Aggref))
63 return true; /* abort the tree traversal and return
65 return expression_tree_walker(node, checkExprHasAggs_walker, context);
69 * checkExprHasSubLink -
70 * Queries marked hasSubLinks might not have them any longer after
71 * rewriting. Check it.
74 checkExprHasSubLink(Node *node)
77 * If a Query is passed, examine it --- but we will not recurse into
80 if (node && IsA(node, Query))
81 return query_tree_walker((Query *) node, checkExprHasSubLink_walker,
84 return checkExprHasSubLink_walker(node, NULL);
88 checkExprHasSubLink_walker(Node *node, void *context)
92 if (IsA(node, SubLink))
93 return true; /* abort the tree traversal and return
95 return expression_tree_walker(node, checkExprHasSubLink_walker, context);
100 * OffsetVarNodes - adjust Vars when appending one query's RT to another
102 * Find all Var nodes in the given tree with varlevelsup == sublevels_up,
103 * and increment their varno fields (rangetable indexes) by 'offset'.
104 * The varnoold fields are adjusted similarly. Also, RangeTblRef nodes
105 * in join trees and setOp trees are adjusted.
107 * NOTE: although this has the form of a walker, we cheat and modify the
108 * nodes in-place. The given expression tree should have been copied
109 * earlier to ensure that no unwanted side-effects occur!
116 } OffsetVarNodes_context;
119 OffsetVarNodes_walker(Node *node, OffsetVarNodes_context *context)
125 Var *var = (Var *) node;
127 if (var->varlevelsup == context->sublevels_up)
129 var->varno += context->offset;
130 var->varnoold += context->offset;
134 if (IsA(node, RangeTblRef))
136 RangeTblRef *rtr = (RangeTblRef *) node;
138 if (context->sublevels_up == 0)
139 rtr->rtindex += context->offset;
140 /* the subquery itself is visited separately */
143 if (IsA(node, Query))
145 /* Recurse into subselects */
148 context->sublevels_up++;
149 result = query_tree_walker((Query *) node, OffsetVarNodes_walker,
150 (void *) context, true);
151 context->sublevels_up--;
154 return expression_tree_walker(node, OffsetVarNodes_walker,
159 OffsetVarNodes(Node *node, int offset, int sublevels_up)
161 OffsetVarNodes_context context;
163 context.offset = offset;
164 context.sublevels_up = sublevels_up;
167 * Must be prepared to start with a Query or a bare expression tree;
168 * if it's a Query, go straight to query_tree_walker to make sure that
169 * sublevels_up doesn't get incremented prematurely.
171 if (node && IsA(node, Query))
173 Query *qry = (Query *) node;
177 * If we are starting at a Query, and sublevels_up is zero, then
178 * we must also fix rangetable indexes in the Query itself ---
179 * namely resultRelation and rowMarks entries. sublevels_up
180 * cannot be zero when recursing into a subquery, so there's no
181 * need to have the same logic inside OffsetVarNodes_walker.
183 if (sublevels_up == 0)
185 if (qry->resultRelation)
186 qry->resultRelation += offset;
187 foreach(l, qry->rowMarks)
188 lfirsti(l) += offset;
190 query_tree_walker(qry, OffsetVarNodes_walker,
191 (void *) &context, true);
194 OffsetVarNodes_walker(node, &context);
198 * ChangeVarNodes - adjust Var nodes for a specific change of RT index
200 * Find all Var nodes in the given tree belonging to a specific relation
201 * (identified by sublevels_up and rt_index), and change their varno fields
202 * to 'new_index'. The varnoold fields are changed too. Also, RangeTblRef
203 * nodes in join trees and setOp trees are adjusted.
205 * NOTE: although this has the form of a walker, we cheat and modify the
206 * nodes in-place. The given expression tree should have been copied
207 * earlier to ensure that no unwanted side-effects occur!
215 } ChangeVarNodes_context;
218 ChangeVarNodes_walker(Node *node, ChangeVarNodes_context *context)
224 Var *var = (Var *) node;
226 if (var->varlevelsup == context->sublevels_up &&
227 var->varno == context->rt_index)
229 var->varno = context->new_index;
230 var->varnoold = context->new_index;
234 if (IsA(node, RangeTblRef))
236 RangeTblRef *rtr = (RangeTblRef *) node;
238 if (context->sublevels_up == 0 &&
239 rtr->rtindex == context->rt_index)
240 rtr->rtindex = context->new_index;
241 /* the subquery itself is visited separately */
244 if (IsA(node, Query))
246 /* Recurse into subselects */
249 context->sublevels_up++;
250 result = query_tree_walker((Query *) node, ChangeVarNodes_walker,
251 (void *) context, true);
252 context->sublevels_up--;
255 return expression_tree_walker(node, ChangeVarNodes_walker,
260 ChangeVarNodes(Node *node, int rt_index, int new_index, int sublevels_up)
262 ChangeVarNodes_context context;
264 context.rt_index = rt_index;
265 context.new_index = new_index;
266 context.sublevels_up = sublevels_up;
269 * Must be prepared to start with a Query or a bare expression tree;
270 * if it's a Query, go straight to query_tree_walker to make sure that
271 * sublevels_up doesn't get incremented prematurely.
273 if (node && IsA(node, Query))
275 Query *qry = (Query *) node;
279 * If we are starting at a Query, and sublevels_up is zero, then
280 * we must also fix rangetable indexes in the Query itself ---
281 * namely resultRelation and rowMarks entries. sublevels_up
282 * cannot be zero when recursing into a subquery, so there's no
283 * need to have the same logic inside ChangeVarNodes_walker.
285 if (sublevels_up == 0)
287 if (qry->resultRelation == rt_index)
288 qry->resultRelation = new_index;
289 foreach(l, qry->rowMarks)
291 if (lfirsti(l) == rt_index)
292 lfirsti(l) = new_index;
295 query_tree_walker(qry, ChangeVarNodes_walker,
296 (void *) &context, true);
299 ChangeVarNodes_walker(node, &context);
303 * IncrementVarSublevelsUp - adjust Var nodes when pushing them down in tree
305 * Find all Var nodes in the given tree having varlevelsup >= min_sublevels_up,
306 * and add delta_sublevels_up to their varlevelsup value. This is needed when
307 * an expression that's correct for some nesting level is inserted into a
308 * subquery. Ordinarily the initial call has min_sublevels_up == 0 so that
309 * all Vars are affected. The point of min_sublevels_up is that we can
310 * increment it when we recurse into a sublink, so that local variables in
311 * that sublink are not affected, only outer references to vars that belong
312 * to the expression's original query level or parents thereof.
314 * NOTE: although this has the form of a walker, we cheat and modify the
315 * Var nodes in-place. The given expression tree should have been copied
316 * earlier to ensure that no unwanted side-effects occur!
321 int delta_sublevels_up;
322 int min_sublevels_up;
323 } IncrementVarSublevelsUp_context;
326 IncrementVarSublevelsUp_walker(Node *node,
327 IncrementVarSublevelsUp_context *context)
333 Var *var = (Var *) node;
335 if (var->varlevelsup >= context->min_sublevels_up)
336 var->varlevelsup += context->delta_sublevels_up;
339 if (IsA(node, Query))
341 /* Recurse into subselects */
344 context->min_sublevels_up++;
345 result = query_tree_walker((Query *) node,
346 IncrementVarSublevelsUp_walker,
347 (void *) context, true);
348 context->min_sublevels_up--;
351 return expression_tree_walker(node, IncrementVarSublevelsUp_walker,
356 IncrementVarSublevelsUp(Node *node, int delta_sublevels_up,
357 int min_sublevels_up)
359 IncrementVarSublevelsUp_context context;
361 context.delta_sublevels_up = delta_sublevels_up;
362 context.min_sublevels_up = min_sublevels_up;
365 * Must be prepared to start with a Query or a bare expression tree;
366 * if it's a Query, go straight to query_tree_walker to make sure that
367 * sublevels_up doesn't get incremented prematurely.
369 if (node && IsA(node, Query))
370 query_tree_walker((Query *) node, IncrementVarSublevelsUp_walker,
371 (void *) &context, true);
373 IncrementVarSublevelsUp_walker(node, &context);
378 * rangeTableEntry_used - detect whether an RTE is referenced somewhere
379 * in var nodes or join or setOp trees of a query or expression.
386 } rangeTableEntry_used_context;
389 rangeTableEntry_used_walker(Node *node,
390 rangeTableEntry_used_context *context)
396 Var *var = (Var *) node;
398 if (var->varlevelsup == context->sublevels_up &&
399 var->varno == context->rt_index)
403 if (IsA(node, RangeTblRef))
405 RangeTblRef *rtr = (RangeTblRef *) node;
407 if (rtr->rtindex == context->rt_index &&
408 context->sublevels_up == 0)
410 /* the subquery itself is visited separately */
413 if (IsA(node, Query))
415 /* Recurse into subselects */
418 context->sublevels_up++;
419 result = query_tree_walker((Query *) node, rangeTableEntry_used_walker,
420 (void *) context, true);
421 context->sublevels_up--;
424 return expression_tree_walker(node, rangeTableEntry_used_walker,
429 rangeTableEntry_used(Node *node, int rt_index, int sublevels_up)
431 rangeTableEntry_used_context context;
433 context.rt_index = rt_index;
434 context.sublevels_up = sublevels_up;
437 * Must be prepared to start with a Query or a bare expression tree;
438 * if it's a Query, go straight to query_tree_walker to make sure that
439 * sublevels_up doesn't get incremented prematurely.
441 if (node && IsA(node, Query))
442 return query_tree_walker((Query *) node, rangeTableEntry_used_walker,
443 (void *) &context, true);
445 return rangeTableEntry_used_walker(node, &context);
451 * Check if a specific attribute number of a RTE is used
452 * somewhere in the query or expression.
460 } attribute_used_context;
463 attribute_used_walker(Node *node,
464 attribute_used_context *context)
470 Var *var = (Var *) node;
472 if (var->varlevelsup == context->sublevels_up &&
473 var->varno == context->rt_index &&
474 var->varattno == context->attno)
478 if (IsA(node, Query))
480 /* Recurse into subselects */
483 context->sublevels_up++;
484 result = query_tree_walker((Query *) node, attribute_used_walker,
485 (void *) context, true);
486 context->sublevels_up--;
489 return expression_tree_walker(node, attribute_used_walker,
494 attribute_used(Node *node, int rt_index, int attno, int sublevels_up)
496 attribute_used_context context;
498 context.rt_index = rt_index;
499 context.attno = attno;
500 context.sublevels_up = sublevels_up;
503 * Must be prepared to start with a Query or a bare expression tree;
504 * if it's a Query, go straight to query_tree_walker to make sure that
505 * sublevels_up doesn't get incremented prematurely.
507 if (node && IsA(node, Query))
508 return query_tree_walker((Query *) node, attribute_used_walker,
509 (void *) &context, true);
511 return attribute_used_walker(node, &context);
516 * If the given Query is an INSERT ... SELECT construct, extract and
517 * return the sub-Query node that represents the SELECT part. Otherwise
518 * return the given Query.
520 * If subquery_ptr is not NULL, then *subquery_ptr is set to the location
521 * of the link to the SELECT subquery inside parsetree, or NULL if not an
524 * This is a hack needed because transformations on INSERT ... SELECTs that
525 * appear in rule actions should be applied to the source SELECT, not to the
526 * INSERT part. Perhaps this can be cleaned up with redesigned querytrees.
529 getInsertSelectQuery(Query *parsetree, Query ***subquery_ptr)
532 RangeTblEntry *selectrte;
536 *subquery_ptr = NULL;
538 if (parsetree == NULL)
540 if (parsetree->commandType != CMD_INSERT)
544 * Currently, this is ONLY applied to rule-action queries, and so we
545 * expect to find the *OLD* and *NEW* placeholder entries in the given
546 * query. If they're not there, it must be an INSERT/SELECT in which
547 * they've been pushed down to the SELECT.
549 if (length(parsetree->rtable) >= 2 &&
550 strcmp(rt_fetch(PRS2_OLD_VARNO, parsetree->rtable)->eref->relname,
552 strcmp(rt_fetch(PRS2_NEW_VARNO, parsetree->rtable)->eref->relname,
555 Assert(parsetree->jointree && IsA(parsetree->jointree, FromExpr));
556 if (length(parsetree->jointree->fromlist) != 1)
557 elog(ERROR, "getInsertSelectQuery: expected to find SELECT subquery");
558 rtr = (RangeTblRef *) lfirst(parsetree->jointree->fromlist);
559 Assert(IsA(rtr, RangeTblRef));
560 selectrte = rt_fetch(rtr->rtindex, parsetree->rtable);
561 selectquery = selectrte->subquery;
562 if (!(selectquery && IsA(selectquery, Query) &&
563 selectquery->commandType == CMD_SELECT))
564 elog(ERROR, "getInsertSelectQuery: expected to find SELECT subquery");
565 if (length(selectquery->rtable) >= 2 &&
566 strcmp(rt_fetch(PRS2_OLD_VARNO, selectquery->rtable)->eref->relname,
568 strcmp(rt_fetch(PRS2_NEW_VARNO, selectquery->rtable)->eref->relname,
572 *subquery_ptr = &(selectrte->subquery);
575 elog(ERROR, "getInsertSelectQuery: can't find rule placeholders");
576 return NULL; /* not reached */
581 * Add the given qualifier condition to the query's WHERE clause
584 AddQual(Query *parsetree, Node *qual)
591 if (parsetree->commandType == CMD_UTILITY)
594 * There's noplace to put the qual on a utility statement.
596 * If it's a NOTIFY, silently ignore the qual; this means that the
597 * NOTIFY will execute, whether or not there are any qualifying
598 * rows. While clearly wrong, this is much more useful than
599 * refusing to execute the rule at all, and extra NOTIFY events
600 * are harmless for typical uses of NOTIFY.
602 * If it isn't a NOTIFY, error out, since unconditional execution of
603 * other utility stmts is unlikely to be wanted. (This case is
604 * not currently allowed anyway, but keep the test for safety.)
606 if (parsetree->utilityStmt && IsA(parsetree->utilityStmt, NotifyStmt))
609 elog(ERROR, "Conditional utility statements are not implemented");
612 /* INTERSECT want's the original, but we need to copy - Jan */
613 copy = copyObject(qual);
615 parsetree->jointree->quals = make_and_qual(parsetree->jointree->quals,
619 * Make sure query is marked correctly if added qual has sublinks or
620 * aggregates (not sure it can ever have aggs, but sublinks
623 parsetree->hasAggs |= checkExprHasAggs(copy);
624 parsetree->hasSubLinks |= checkExprHasSubLink(copy);
628 * Add the given havingQual to the one already contained in the parsetree
629 * just as AddQual does for the normal 'where' qual
632 AddHavingQual(Query *parsetree, Node *havingQual)
636 if (havingQual == NULL)
639 if (parsetree->commandType == CMD_UTILITY)
642 * There's noplace to put the qual on a utility statement.
644 * See comments in AddQual for motivation.
646 if (parsetree->utilityStmt && IsA(parsetree->utilityStmt, NotifyStmt))
649 elog(ERROR, "Conditional utility statements are not implemented");
652 /* INTERSECT want's the original, but we need to copy - Jan */
653 copy = copyObject(havingQual);
655 parsetree->havingQual = make_and_qual(parsetree->havingQual,
659 * Make sure query is marked correctly if added qual has sublinks or
660 * aggregates (not sure it can ever have aggs, but sublinks
663 parsetree->hasAggs |= checkExprHasAggs(copy);
664 parsetree->hasSubLinks |= checkExprHasSubLink(copy);
669 AddNotHavingQual(Query *parsetree, Node *havingQual)
673 if (havingQual == NULL)
676 /* Need not copy input qual, because AddHavingQual will... */
677 notqual = (Node *) make_notclause((Expr *) havingQual);
679 AddHavingQual(parsetree, notqual);
684 AddNotQual(Query *parsetree, Node *qual)
691 /* Need not copy input qual, because AddQual will... */
692 notqual = (Node *) make_notclause((Expr *) qual);
694 AddQual(parsetree, notqual);
698 /* Find a targetlist entry by resno */
700 FindMatchingNew(List *tlist, int attno)
706 TargetEntry *tle = lfirst(i);
708 if (tle->resdom->resno == attno)
716 /* Find a targetlist entry by resname */
718 FindMatchingTLEntry(List *tlist, char *e_attname)
724 TargetEntry *tle = lfirst(i);
727 resname = tle->resdom->resname;
728 if (strcmp(e_attname, resname) == 0)
737 * ResolveNew - replace Vars with corresponding items from a targetlist
739 * Vars matching target_varno and sublevels_up are replaced by the
740 * entry with matching resno from targetlist, if there is one.
741 * If not, we either change the unmatched Var's varno to update_varno
742 * (when event == CMD_UPDATE) or replace it with a constant NULL.
752 } ResolveNew_context;
755 ResolveNew_mutator(Node *node, ResolveNew_context *context)
761 Var *var = (Var *) node;
762 int this_varno = (int) var->varno;
763 int this_varlevelsup = (int) var->varlevelsup;
765 if (this_varno == context->target_varno &&
766 this_varlevelsup == context->sublevels_up)
770 /* band-aid: don't do the wrong thing with a whole-tuple Var */
771 if (var->varattno == InvalidAttrNumber)
772 elog(ERROR, "ResolveNew: can't handle whole-tuple reference");
774 n = FindMatchingNew(context->targetlist, var->varattno);
778 if (context->event == CMD_UPDATE)
780 /* For update, just change unmatched var's varno */
781 var = (Var *) copyObject(node);
782 var->varno = context->update_varno;
783 var->varnoold = context->update_varno;
788 /* Otherwise replace unmatched var with a null */
789 return (Node *) makeNullConst(var->vartype);
794 /* Make a copy of the tlist item to return */
796 /* Adjust varlevelsup if tlist item is from higher query */
797 if (this_varlevelsup > 0)
798 IncrementVarSublevelsUp(n, this_varlevelsup, 0);
802 /* otherwise fall through to copy the var normally */
806 * Since expression_tree_mutator won't touch subselects, we have to
807 * handle them specially.
809 if (IsA(node, SubLink))
811 SubLink *sublink = (SubLink *) node;
814 FLATCOPY(newnode, sublink, SubLink);
815 MUTATE(newnode->lefthand, sublink->lefthand, List *,
816 ResolveNew_mutator, context);
817 MUTATE(newnode->subselect, sublink->subselect, Node *,
818 ResolveNew_mutator, context);
819 return (Node *) newnode;
821 if (IsA(node, Query))
823 Query *query = (Query *) node;
826 FLATCOPY(newnode, query, Query);
827 context->sublevels_up++;
828 query_tree_mutator(newnode, ResolveNew_mutator, context, true);
829 context->sublevels_up--;
830 return (Node *) newnode;
832 return expression_tree_mutator(node, ResolveNew_mutator,
837 ResolveNew(Node *node, int target_varno, int sublevels_up,
838 List *targetlist, int event, int update_varno)
840 ResolveNew_context context;
842 context.target_varno = target_varno;
843 context.sublevels_up = sublevels_up;
844 context.targetlist = targetlist;
845 context.event = event;
846 context.update_varno = update_varno;
849 * Must be prepared to start with a Query or a bare expression tree;
850 * if it's a Query, go straight to query_tree_mutator to make sure
851 * that sublevels_up doesn't get incremented prematurely.
853 if (node && IsA(node, Query))
855 Query *query = (Query *) node;
858 FLATCOPY(newnode, query, Query);
859 query_tree_mutator(newnode, ResolveNew_mutator,
860 (void *) &context, true);
861 return (Node *) newnode;
864 return ResolveNew_mutator(node, &context);
871 * HandleRIRAttributeRule
872 * Replace Vars matching a given RT index with copies of TL expressions.
874 * Handles 'on retrieve to relation.attribute
875 * do instead retrieve (attribute = expression) w/qual'
887 } HandleRIRAttributeRule_context;
890 HandleRIRAttributeRule_mutator(Node *node,
891 HandleRIRAttributeRule_context * context)
897 Var *var = (Var *) node;
898 int this_varno = var->varno;
899 int this_varattno = var->varattno;
900 int this_varlevelsup = var->varlevelsup;
902 if (this_varno == context->rt_index &&
903 this_varattno == context->attr_num &&
904 this_varlevelsup == context->sublevels_up)
906 if (var->vartype == 32)
907 { /* HACK: disallow SET variables */
908 *context->modified = TRUE;
909 *context->badsql = TRUE;
910 return (Node *) makeNullConst(var->vartype);
914 char *name_to_look_for;
916 name_to_look_for = get_attname(getrelid(this_varno,
919 if (name_to_look_for)
923 *context->modified = TRUE;
924 n = FindMatchingTLEntry(context->targetlist,
927 return (Node *) makeNullConst(var->vartype);
928 /* Make a copy of the tlist item to return */
932 * Adjust varlevelsup if tlist item is from higher
935 if (this_varlevelsup > 0)
936 IncrementVarSublevelsUp(n, this_varlevelsup, 0);
941 /* otherwise fall through to copy the var normally */
945 * Since expression_tree_mutator won't touch subselects, we have to
946 * handle them specially.
948 if (IsA(node, SubLink))
950 SubLink *sublink = (SubLink *) node;
953 FLATCOPY(newnode, sublink, SubLink);
954 MUTATE(newnode->lefthand, sublink->lefthand, List *,
955 HandleRIRAttributeRule_mutator, context);
956 MUTATE(newnode->subselect, sublink->subselect, Node *,
957 HandleRIRAttributeRule_mutator, context);
958 return (Node *) newnode;
960 if (IsA(node, Query))
962 Query *query = (Query *) node;
965 FLATCOPY(newnode, query, Query);
966 context->sublevels_up++;
967 query_tree_mutator(newnode, HandleRIRAttributeRule_mutator,
969 context->sublevels_up--;
970 return (Node *) newnode;
972 return expression_tree_mutator(node, HandleRIRAttributeRule_mutator,
977 HandleRIRAttributeRule(Query *parsetree,
985 HandleRIRAttributeRule_context context;
987 context.rtable = rtable;
988 context.targetlist = targetlist;
989 context.rt_index = rt_index;
990 context.attr_num = attr_num;
991 context.modified = modified;
992 context.badsql = badsql;
993 context.sublevels_up = 0;
995 query_tree_mutator(parsetree, HandleRIRAttributeRule_mutator,
996 (void *) &context, true);
999 #endif /* NOT_USED */