1 /*-------------------------------------------------------------------------
5 * Copyright (c) 1994, Regents of the University of California
9 * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteManip.c,v 1.20 1998/10/08 18:29:52 momjian Exp $
11 *-------------------------------------------------------------------------
15 #include "nodes/pg_list.h"
16 #include "utils/elog.h"
17 #include "nodes/nodes.h"
18 #include "nodes/relation.h"
19 #include "nodes/primnodes.h"
20 #include "parser/parsetree.h" /* for getrelid() */
21 #include "utils/lsyscache.h"
22 #include "utils/builtins.h"
23 #include "rewrite/rewriteHandler.h"
24 #include "rewrite/rewriteManip.h"
25 #include "rewrite/rewriteSupport.h"
26 #include "rewrite/locks.h"
28 #include "nodes/plannodes.h"
29 #include "optimizer/clauses.h"
31 static void ResolveNew(RewriteInfo *info, List *targetlist,
32 Node **node, int sublevels_up);
37 OffsetVarNodes(Node *node, int offset)
41 switch (nodeTag(node))
45 TargetEntry *tle = (TargetEntry *) node;
47 OffsetVarNodes(tle->expr, offset);
52 Aggreg *agg = (Aggreg *) node;
54 OffsetVarNodes(agg->target, offset);
59 * This has to be done to make queries using groupclauses work
64 GroupClause *group = (GroupClause *) node;
66 OffsetVarNodes((Node *) (group->entry), offset);
71 Expr *expr = (Expr *) node;
73 OffsetVarNodes((Node *) expr->args, offset);
78 Iter *iter = (Iter *) node;
80 OffsetVarNodes((Node *) iter->iterexpr, offset);
85 ArrayRef *ref = (ArrayRef *) node;
87 OffsetVarNodes((Node *) ref->refupperindexpr, offset);
88 OffsetVarNodes((Node *) ref->reflowerindexpr, offset);
89 OffsetVarNodes((Node *) ref->refexpr, offset);
90 OffsetVarNodes((Node *) ref->refassgnexpr, offset);
95 Var *var = (Var *) node;
98 var->varnoold += offset;
105 foreach(l, (List *) node)
106 OffsetVarNodes(lfirst(l), offset);
111 SubLink *sublink = (SubLink *) node;
114 * We also have to adapt the variables used in
115 * sublink->lefthand and sublink->oper
117 OffsetVarNodes((Node *) (sublink->lefthand), offset);
120 * Make sure the first argument of sublink->oper points to
121 * the same var as sublink->lefthand does otherwise we
122 * will run into troubles using aggregates (aggno will not
125 lfirst(((Expr *) lfirst(sublink->oper))->args) =
126 lfirst(sublink->lefthand);
130 /* ignore the others */
136 ChangeVarNodes(Node *node, int old_varno, int new_varno, int sublevels_up)
140 switch (nodeTag(node))
144 TargetEntry *tle = (TargetEntry *) node;
146 ChangeVarNodes(tle->expr, old_varno, new_varno, sublevels_up);
151 Aggreg *agg = (Aggreg *) node;
153 ChangeVarNodes(agg->target, old_varno, new_varno, sublevels_up);
158 * This has to be done to make queries using groupclauses work
163 GroupClause *group = (GroupClause *) node;
165 ChangeVarNodes((Node *) (group->entry), old_varno, new_varno,
172 Expr *expr = (Expr *) node;
174 ChangeVarNodes((Node *) expr->args, old_varno, new_varno, sublevels_up);
179 Iter *iter = (Iter *) node;
181 ChangeVarNodes((Node *) iter->iterexpr, old_varno, new_varno, sublevels_up);
186 ArrayRef *ref = (ArrayRef *) node;
188 ChangeVarNodes((Node *) ref->refupperindexpr, old_varno, new_varno, sublevels_up);
189 ChangeVarNodes((Node *) ref->reflowerindexpr, old_varno, new_varno, sublevels_up);
190 ChangeVarNodes((Node *) ref->refexpr, old_varno, new_varno, sublevels_up);
191 ChangeVarNodes((Node *) ref->refassgnexpr, old_varno, new_varno, sublevels_up);
196 Var *var = (Var *) node;
198 if (var->varno == old_varno &&
199 var->varlevelsup == sublevels_up)
201 var->varno = new_varno;
202 var->varnoold = new_varno;
204 if (var->varlevelsup > 0)
205 OffsetVarNodes((Node *) var, 3);
213 foreach(l, (List *) node)
214 ChangeVarNodes(lfirst(l), old_varno, new_varno, sublevels_up);
219 SubLink *sublink = (SubLink *) node;
220 Query *query = (Query *) sublink->subselect;
222 ChangeVarNodes((Node *) query->qual, old_varno, new_varno,
226 * We also have to adapt the variables used in
227 * sublink->lefthand and sublink->oper
229 ChangeVarNodes((Node *) (sublink->lefthand), old_varno, new_varno,
233 * Make sure the first argument of sublink->oper points to
234 * the same var as sublink->lefthand does otherwise we
235 * will run into troubles using aggregates (aggno will not
240 * lfirst(((Expr *) lfirst(sublink->oper))->args) =
241 * lfirst(sublink->lefthand);
246 /* ignore the others */
252 AddQual(Query *parsetree, Node *qual)
260 copy = copyObject(qual);
261 old = parsetree->qual;
263 parsetree->qual = copy;
266 (Node *) make_andclause(makeList(parsetree->qual, copy, -1));
269 /* Adds the given havingQual to the one already contained in the parsetree just as
270 * AddQual does for the normal 'where' qual */
272 AddHavingQual(Query *parsetree, Node *havingQual)
277 if (havingQual == NULL)
280 copy = copyObject(havingQual);
281 old = parsetree->havingQual;
283 parsetree->havingQual = copy;
285 parsetree->havingQual =
286 (Node *) make_andclause(makeList(parsetree->havingQual, copy, -1));
291 AddNotQual(Query *parsetree, Node *qual)
298 copy = (Node *) make_notclause(copyObject(qual));
300 AddQual(parsetree, copy);
306 Const *c = makeNode(Const);
309 c->constlen = get_typlen(type);
310 c->constvalue = PointerGetDatum(NULL);
311 c->constisnull = true;
312 c->constbyval = get_typbyval(type);
318 FixResdomTypes(List *tlist)
324 TargetEntry *tle = lfirst(i);
326 if (nodeTag(tle->expr) == T_Var)
328 Var *var = (Var *) tle->expr;
330 tle->resdom->restype = var->vartype;
331 tle->resdom->restypmod = var->vartypmod;
338 FindMatchingNew(List *tlist, int attno)
344 TargetEntry *tle = lfirst(i);
346 if (tle->resdom->resno == attno)
353 FindMatchingTLEntry(List *tlist, char *e_attname)
359 TargetEntry *tle = lfirst(i);
362 resname = tle->resdom->resname;
363 if (!strcmp(e_attname, resname))
370 ResolveNew(RewriteInfo *info, List *targetlist, Node **nodePtr,
373 Node *node = *nodePtr;
378 switch (nodeTag(node))
381 ResolveNew(info, targetlist, &((TargetEntry *) node)->expr,
385 ResolveNew(info, targetlist, &((Aggreg *) node)->target,
389 ResolveNew(info, targetlist, (Node **) (&(((Expr *) node)->args)),
393 ResolveNew(info, targetlist, (Node **) (&(((Iter *) node)->iterexpr)),
397 ResolveNew(info, targetlist, (Node **) (&(((ArrayRef *) node)->refupperindexpr)),
399 ResolveNew(info, targetlist, (Node **) (&(((ArrayRef *) node)->reflowerindexpr)),
401 ResolveNew(info, targetlist, (Node **) (&(((ArrayRef *) node)->refexpr)),
403 ResolveNew(info, targetlist, (Node **) (&(((ArrayRef *) node)->refassgnexpr)),
408 int this_varno = (int) ((Var *) node)->varno;
409 int this_varlevelsup = (int) ((Var *) node)->varlevelsup;
412 if (this_varno == info->new_varno &&
413 this_varlevelsup == sublevels_up)
415 n = FindMatchingNew(targetlist,
416 ((Var *) node)->varattno);
419 if (info->event == CMD_UPDATE)
421 ((Var *) node)->varno = info->current_varno;
422 ((Var *) node)->varnoold = info->current_varno;
425 *nodePtr = make_null(((Var *) node)->vartype);
436 foreach(l, (List *) node)
437 ResolveNew(info, targetlist, (Node **) &(lfirst(l)),
443 SubLink *sublink = (SubLink *) node;
444 Query *query = (Query *) sublink->subselect;
446 ResolveNew(info, targetlist, (Node **) &(query->qual), sublevels_up + 1);
450 /* ignore the others */
456 FixNew(RewriteInfo *info, Query *parsetree)
458 ResolveNew(info, parsetree->targetList,
459 (Node **) &(info->rule_action->targetList), 0);
460 ResolveNew(info, parsetree->targetList, &info->rule_action->qual, 0);
464 nodeHandleRIRAttributeRule(Node **nodePtr,
473 Node *node = *nodePtr;
477 switch (nodeTag(node))
481 TargetEntry *tle = (TargetEntry *) node;
483 nodeHandleRIRAttributeRule(&tle->expr, rtable, targetlist,
484 rt_index, attr_num, modified, badsql,
490 Aggreg *agg = (Aggreg *) node;
492 nodeHandleRIRAttributeRule(&agg->target, rtable, targetlist,
493 rt_index, attr_num, modified, badsql,
499 Expr *expr = (Expr *) node;
501 nodeHandleRIRAttributeRule((Node **) (&(expr->args)), rtable,
502 targetlist, rt_index, attr_num,
509 Iter *iter = (Iter *) node;
511 nodeHandleRIRAttributeRule((Node **) (&(iter->iterexpr)), rtable,
512 targetlist, rt_index, attr_num,
519 ArrayRef *ref = (ArrayRef *) node;
521 nodeHandleRIRAttributeRule((Node **) (&(ref->refupperindexpr)), rtable,
522 targetlist, rt_index, attr_num,
525 nodeHandleRIRAttributeRule((Node **) (&(ref->reflowerindexpr)), rtable,
526 targetlist, rt_index, attr_num,
529 nodeHandleRIRAttributeRule((Node **) (&(ref->refexpr)), rtable,
530 targetlist, rt_index, attr_num,
533 nodeHandleRIRAttributeRule((Node **) (&(ref->refassgnexpr)), rtable,
534 targetlist, rt_index, attr_num,
541 int this_varno = ((Var *) node)->varno;
542 int this_varattno = ((Var *) node)->varattno;
543 int this_varlevelsup = ((Var *) node)->varlevelsup;
545 if (this_varno == rt_index &&
546 this_varattno == attr_num &&
547 this_varlevelsup == sublevels_up)
549 if (((Var *) node)->vartype == 32)
551 *nodePtr = make_null(((Var *) node)->vartype);
558 NameData name_to_look_for;
560 name_to_look_for.data[0] = '\0';
561 namestrcpy(&name_to_look_for,
562 (char *) get_attname(getrelid(this_varno,
565 if (name_to_look_for.data[0])
569 n = FindMatchingTLEntry(targetlist, (char *) &name_to_look_for);
571 *nodePtr = make_null(((Var *) node)->vartype);
584 foreach(i, (List *) node)
586 nodeHandleRIRAttributeRule((Node **) (&(lfirst(i))), rtable,
587 targetlist, rt_index, attr_num,
588 modified, badsql, sublevels_up);
594 SubLink *sublink = (SubLink *) node;
595 Query *query = (Query *) sublink->subselect;
597 nodeHandleRIRAttributeRule((Node **) &(query->qual), rtable, targetlist,
598 rt_index, attr_num, modified, badsql,
603 /* ignore the others */
609 * Handles 'on retrieve to relation.attribute
610 * do instead retrieve (attribute = expression) w/qual'
613 HandleRIRAttributeRule(Query *parsetree,
622 nodeHandleRIRAttributeRule((Node **) (&(parsetree->targetList)), rtable,
623 targetlist, rt_index, attr_num,
624 modified, badsql, 0);
625 nodeHandleRIRAttributeRule(&parsetree->qual, rtable, targetlist,
626 rt_index, attr_num, modified, badsql, 0);
631 nodeHandleViewRule(Node **nodePtr,
638 Node *node = *nodePtr;
643 switch (nodeTag(node))
647 TargetEntry *tle = (TargetEntry *) node;
649 nodeHandleViewRule(&(tle->expr), rtable, targetlist,
650 rt_index, modified, sublevels_up);
655 Aggreg *agg = (Aggreg *) node;
657 nodeHandleViewRule(&(agg->target), rtable, targetlist,
658 rt_index, modified, sublevels_up);
663 * This has to be done to make queries using groupclauses work
668 GroupClause *group = (GroupClause *) node;
670 nodeHandleViewRule((Node **) (&(group->entry)), rtable, targetlist,
671 rt_index, modified, sublevels_up);
676 Expr *expr = (Expr *) node;
678 nodeHandleViewRule((Node **) (&(expr->args)),
680 rt_index, modified, sublevels_up);
685 Iter *iter = (Iter *) node;
687 nodeHandleViewRule((Node **) (&(iter->iterexpr)),
689 rt_index, modified, sublevels_up);
694 ArrayRef *ref = (ArrayRef *) node;
696 nodeHandleViewRule((Node **) (&(ref->refupperindexpr)),
698 rt_index, modified, sublevels_up);
699 nodeHandleViewRule((Node **) (&(ref->reflowerindexpr)),
701 rt_index, modified, sublevels_up);
702 nodeHandleViewRule((Node **) (&(ref->refexpr)),
704 rt_index, modified, sublevels_up);
705 nodeHandleViewRule((Node **) (&(ref->refassgnexpr)),
707 rt_index, modified, sublevels_up);
712 Var *var = (Var *) node;
713 int this_varno = var->varno;
714 int this_varlevelsup = var->varlevelsup;
717 if (this_varno == rt_index &&
718 this_varlevelsup == sublevels_up)
720 n = FindMatchingTLEntry(targetlist,
721 get_attname(getrelid(this_varno,
725 *nodePtr = make_null(((Var *) node)->vartype);
729 * This is a hack: The varlevelsup of the orignal
730 * variable and the new one should be the same.
731 * Normally we adapt the node by changing a
732 * pointer to point to a var contained in
733 * 'targetlist'. In the targetlist all
734 * varlevelsups are 0 so if we want to change it
735 * to the original value we have to copy the node
736 * before! (Maybe this will cause troubles with
737 * some sophisticated queries on views?)
739 if (this_varlevelsup > 0)
740 *nodePtr = copyObject(n);
744 if (nodeTag(nodePtr) == T_Var)
745 ((Var *) *nodePtr)->varlevelsup = this_varlevelsup;
747 nodeHandleViewRule(&n, rtable, targetlist,
748 rt_index, modified, sublevels_up);
758 foreach(l, (List *) node)
760 nodeHandleViewRule((Node **) (&(lfirst(l))),
762 rt_index, modified, sublevels_up);
768 SubLink *sublink = (SubLink *) node;
769 Query *query = (Query *) sublink->subselect;
771 nodeHandleViewRule((Node **) &(query->qual), rtable, targetlist,
772 rt_index, modified, sublevels_up + 1);
775 * We also have to adapt the variables used in
776 * sublink->lefthand and sublink->oper
778 nodeHandleViewRule((Node **) &(sublink->lefthand), rtable,
779 targetlist, rt_index, modified, sublevels_up);
782 * Make sure the first argument of sublink->oper points to
783 * the same var as sublink->lefthand does otherwise we
784 * will run into troubles using aggregates (aggno will not
787 pfree(lfirst(((Expr *) lfirst(sublink->oper))->args));
788 lfirst(((Expr *) lfirst(sublink->oper))->args) =
789 lfirst(sublink->lefthand);
793 /* ignore the others */
800 HandleViewRule(Query *parsetree,
806 nodeHandleViewRule(&parsetree->qual, rtable, targetlist, rt_index,
808 nodeHandleViewRule((Node **) (&(parsetree->targetList)), rtable, targetlist,
809 rt_index, modified, 0);
812 * The variables in the havingQual and groupClause also have to be
815 nodeHandleViewRule(&parsetree->havingQual, rtable, targetlist, rt_index,
817 nodeHandleViewRule((Node **) (&(parsetree->groupClause)), rtable, targetlist, rt_index,