1 /*-------------------------------------------------------------------------
5 * Copyright (c) 1994, Regents of the University of California
9 * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteManip.c,v 1.22 1998/10/21 16:21:26 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);
39 OffsetVarNodes(Node *node, int offset, int sublevels_up)
44 switch(nodeTag(node)) {
47 TargetEntry *tle = (TargetEntry *)node;
58 Aggreg *agg = (Aggreg *)node;
61 (Node *)(agg->target),
69 GroupClause *grp = (GroupClause *)node;
80 Expr *exp = (Expr *)node;
91 Iter *iter = (Iter *)node;
94 (Node *)(iter->iterexpr),
102 ArrayRef *ref = (ArrayRef *)node;
105 (Node *)(ref->refupperindexpr),
109 (Node *)(ref->reflowerindexpr),
113 (Node *)(ref->refexpr),
117 (Node *)(ref->refassgnexpr),
125 Var *var = (Var *)node;
127 if (var->varlevelsup == sublevels_up) {
128 var->varno += offset;
129 var->varnoold += offset;
144 foreach (l, (List *)node)
154 SubLink *sub = (SubLink *)node;
157 (Node *)(sub->lefthand),
162 (Node *)(sub->subselect),
170 Query *qry = (Query *)node;
173 (Node *)(qry->targetList),
183 (Node *)(qry->havingQual),
188 (Node *)(qry->groupClause),
195 elog(NOTICE, "unknown node tag %d in OffsetVarNodes()", nodeTag(node));
196 elog(NOTICE, "Node is: %s", nodeToString(node));
208 ChangeVarNodes(Node *node, int rt_index, int new_index, int sublevels_up)
213 switch(nodeTag(node)) {
216 TargetEntry *tle = (TargetEntry *)node;
228 Aggreg *agg = (Aggreg *)node;
231 (Node *)(agg->target),
240 GroupClause *grp = (GroupClause *)node;
243 (Node *)(grp->entry),
252 Expr *exp = (Expr *)node;
264 Iter *iter = (Iter *)node;
267 (Node *)(iter->iterexpr),
276 ArrayRef *ref = (ArrayRef *)node;
279 (Node *)(ref->refupperindexpr),
284 (Node *)(ref->reflowerindexpr),
289 (Node *)(ref->refexpr),
294 (Node *)(ref->refassgnexpr),
303 Var *var = (Var *)node;
305 if (var->varlevelsup == sublevels_up &&
306 var->varno == rt_index) {
307 var->varno = new_index;
308 var->varnoold = new_index;
323 foreach (l, (List *)node)
334 SubLink *sub = (SubLink *)node;
337 (Node *)(sub->lefthand),
343 (Node *)(sub->subselect),
352 Query *qry = (Query *)node;
355 (Node *)(qry->targetList),
367 (Node *)(qry->havingQual),
373 (Node *)(qry->groupClause),
381 elog(NOTICE, "unknown node tag %d in ChangeVarNodes()", nodeTag(node));
382 elog(NOTICE, "Node is: %s", nodeToString(node));
392 AddQual(Query *parsetree, Node *qual)
400 copy = copyObject(qual);
401 old = parsetree->qual;
403 parsetree->qual = copy;
406 (Node *) make_andclause(makeList(parsetree->qual, copy, -1));
409 /* Adds the given havingQual to the one already contained in the parsetree just as
410 * AddQual does for the normal 'where' qual */
412 AddHavingQual(Query *parsetree, Node *havingQual)
417 if (havingQual == NULL)
420 copy = copyObject(havingQual);
421 old = parsetree->havingQual;
423 parsetree->havingQual = copy;
425 parsetree->havingQual =
426 (Node *) make_andclause(makeList(parsetree->havingQual, copy, -1));
431 AddNotQual(Query *parsetree, Node *qual)
438 copy = (Node *) make_notclause(copyObject(qual));
440 AddQual(parsetree, copy);
446 Const *c = makeNode(Const);
449 c->constlen = get_typlen(type);
450 c->constvalue = PointerGetDatum(NULL);
451 c->constisnull = true;
452 c->constbyval = get_typbyval(type);
458 FixResdomTypes(List *tlist)
464 TargetEntry *tle = lfirst(i);
466 if (nodeTag(tle->expr) == T_Var)
468 Var *var = (Var *) tle->expr;
470 tle->resdom->restype = var->vartype;
471 tle->resdom->restypmod = var->vartypmod;
478 FindMatchingNew(List *tlist, int attno)
484 TargetEntry *tle = lfirst(i);
486 if (tle->resdom->resno == attno)
493 FindMatchingTLEntry(List *tlist, char *e_attname)
499 TargetEntry *tle = lfirst(i);
502 resname = tle->resdom->resname;
503 if (!strcmp(e_attname, resname))
510 ResolveNew(RewriteInfo *info, List *targetlist, Node **nodePtr,
513 Node *node = *nodePtr;
518 switch (nodeTag(node))
521 ResolveNew(info, targetlist, &((TargetEntry *) node)->expr,
525 ResolveNew(info, targetlist, &((Aggreg *) node)->target,
529 ResolveNew(info, targetlist, (Node **) (&(((Expr *) node)->args)),
533 ResolveNew(info, targetlist, (Node **) (&(((Iter *) node)->iterexpr)),
537 ResolveNew(info, targetlist, (Node **) (&(((ArrayRef *) node)->refupperindexpr)),
539 ResolveNew(info, targetlist, (Node **) (&(((ArrayRef *) node)->reflowerindexpr)),
541 ResolveNew(info, targetlist, (Node **) (&(((ArrayRef *) node)->refexpr)),
543 ResolveNew(info, targetlist, (Node **) (&(((ArrayRef *) node)->refassgnexpr)),
548 int this_varno = (int) ((Var *) node)->varno;
549 int this_varlevelsup = (int) ((Var *) node)->varlevelsup;
552 if (this_varno == info->new_varno &&
553 this_varlevelsup == sublevels_up)
555 n = FindMatchingNew(targetlist,
556 ((Var *) node)->varattno);
559 if (info->event == CMD_UPDATE)
561 *nodePtr = n = copyObject(node);
562 ((Var *) n)->varno = info->current_varno;
563 ((Var *) n)->varnoold = info->current_varno;
566 *nodePtr = make_null(((Var *) node)->vartype);
569 *nodePtr = copyObject(n);
577 foreach(l, (List *) node)
578 ResolveNew(info, targetlist, (Node **) &(lfirst(l)),
584 SubLink *sublink = (SubLink *) node;
585 Query *query = (Query *) sublink->subselect;
587 ResolveNew(info, targetlist, (Node **) &(query->qual), sublevels_up + 1);
591 /* ignore the others */
597 FixNew(RewriteInfo *info, Query *parsetree)
599 ResolveNew(info, parsetree->targetList,
600 (Node **) &(info->rule_action->targetList), 0);
601 ResolveNew(info, parsetree->targetList, &info->rule_action->qual, 0);
605 nodeHandleRIRAttributeRule(Node **nodePtr,
614 Node *node = *nodePtr;
618 switch (nodeTag(node))
622 TargetEntry *tle = (TargetEntry *) node;
624 nodeHandleRIRAttributeRule(&tle->expr, rtable, targetlist,
625 rt_index, attr_num, modified, badsql,
631 Aggreg *agg = (Aggreg *) node;
633 nodeHandleRIRAttributeRule(&agg->target, rtable, targetlist,
634 rt_index, attr_num, modified, badsql,
640 Expr *expr = (Expr *) node;
642 nodeHandleRIRAttributeRule((Node **) (&(expr->args)), rtable,
643 targetlist, rt_index, attr_num,
650 Iter *iter = (Iter *) node;
652 nodeHandleRIRAttributeRule((Node **) (&(iter->iterexpr)), rtable,
653 targetlist, rt_index, attr_num,
660 ArrayRef *ref = (ArrayRef *) node;
662 nodeHandleRIRAttributeRule((Node **) (&(ref->refupperindexpr)), rtable,
663 targetlist, rt_index, attr_num,
666 nodeHandleRIRAttributeRule((Node **) (&(ref->reflowerindexpr)), rtable,
667 targetlist, rt_index, attr_num,
670 nodeHandleRIRAttributeRule((Node **) (&(ref->refexpr)), rtable,
671 targetlist, rt_index, attr_num,
674 nodeHandleRIRAttributeRule((Node **) (&(ref->refassgnexpr)), rtable,
675 targetlist, rt_index, attr_num,
682 int this_varno = ((Var *) node)->varno;
683 int this_varattno = ((Var *) node)->varattno;
684 int this_varlevelsup = ((Var *) node)->varlevelsup;
686 if (this_varno == rt_index &&
687 this_varattno == attr_num &&
688 this_varlevelsup == sublevels_up)
690 if (((Var *) node)->vartype == 32)
692 *nodePtr = make_null(((Var *) node)->vartype);
699 NameData name_to_look_for;
701 name_to_look_for.data[0] = '\0';
702 namestrcpy(&name_to_look_for,
703 (char *) get_attname(getrelid(this_varno,
706 if (name_to_look_for.data[0])
710 n = FindMatchingTLEntry(targetlist, (char *) &name_to_look_for);
712 *nodePtr = make_null(((Var *) node)->vartype);
725 foreach(i, (List *) node)
727 nodeHandleRIRAttributeRule((Node **) (&(lfirst(i))), rtable,
728 targetlist, rt_index, attr_num,
729 modified, badsql, sublevels_up);
735 SubLink *sublink = (SubLink *) node;
736 Query *query = (Query *) sublink->subselect;
738 nodeHandleRIRAttributeRule((Node **) &(query->qual), rtable, targetlist,
739 rt_index, attr_num, modified, badsql,
744 /* ignore the others */
750 * Handles 'on retrieve to relation.attribute
751 * do instead retrieve (attribute = expression) w/qual'
754 HandleRIRAttributeRule(Query *parsetree,
763 nodeHandleRIRAttributeRule((Node **) (&(parsetree->targetList)), rtable,
764 targetlist, rt_index, attr_num,
765 modified, badsql, 0);
766 nodeHandleRIRAttributeRule(&parsetree->qual, rtable, targetlist,
767 rt_index, attr_num, modified, badsql, 0);
772 nodeHandleViewRule(Node **nodePtr,
779 Node *node = *nodePtr;
784 switch (nodeTag(node))
788 TargetEntry *tle = (TargetEntry *) node;
790 nodeHandleViewRule(&(tle->expr), rtable, targetlist,
791 rt_index, modified, sublevels_up);
796 Aggreg *agg = (Aggreg *) node;
798 nodeHandleViewRule(&(agg->target), rtable, targetlist,
799 rt_index, modified, sublevels_up);
804 * This has to be done to make queries using groupclauses work
809 GroupClause *group = (GroupClause *) node;
811 nodeHandleViewRule((Node **) (&(group->entry)), rtable, targetlist,
812 rt_index, modified, sublevels_up);
817 Expr *expr = (Expr *) node;
819 nodeHandleViewRule((Node **) (&(expr->args)),
821 rt_index, modified, sublevels_up);
826 Iter *iter = (Iter *) node;
828 nodeHandleViewRule((Node **) (&(iter->iterexpr)),
830 rt_index, modified, sublevels_up);
835 ArrayRef *ref = (ArrayRef *) node;
837 nodeHandleViewRule((Node **) (&(ref->refupperindexpr)),
839 rt_index, modified, sublevels_up);
840 nodeHandleViewRule((Node **) (&(ref->reflowerindexpr)),
842 rt_index, modified, sublevels_up);
843 nodeHandleViewRule((Node **) (&(ref->refexpr)),
845 rt_index, modified, sublevels_up);
846 nodeHandleViewRule((Node **) (&(ref->refassgnexpr)),
848 rt_index, modified, sublevels_up);
853 Var *var = (Var *) node;
854 int this_varno = var->varno;
855 int this_varlevelsup = var->varlevelsup;
858 if (this_varno == rt_index &&
859 this_varlevelsup == sublevels_up)
861 n = FindMatchingTLEntry(targetlist,
862 get_attname(getrelid(this_varno,
866 *nodePtr = make_null(((Var *) node)->vartype);
870 * This is a hack: The varlevelsup of the orignal
871 * variable and the new one should be the same.
872 * Normally we adapt the node by changing a
873 * pointer to point to a var contained in
874 * 'targetlist'. In the targetlist all
875 * varlevelsups are 0 so if we want to change it
876 * to the original value we have to copy the node
877 * before! (Maybe this will cause troubles with
878 * some sophisticated queries on views?)
880 if (this_varlevelsup > 0)
881 *nodePtr = copyObject(n);
885 if (nodeTag(nodePtr) == T_Var)
886 ((Var *) *nodePtr)->varlevelsup = this_varlevelsup;
888 nodeHandleViewRule(&n, rtable, targetlist,
889 rt_index, modified, sublevels_up);
899 foreach(l, (List *) node)
901 nodeHandleViewRule((Node **) (&(lfirst(l))),
903 rt_index, modified, sublevels_up);
909 SubLink *sublink = (SubLink *) node;
910 Query *query = (Query *) sublink->subselect;
912 nodeHandleViewRule((Node **) &(query->qual), rtable, targetlist,
913 rt_index, modified, sublevels_up + 1);
916 * We also have to adapt the variables used in
917 * sublink->lefthand and sublink->oper
919 nodeHandleViewRule((Node **) &(sublink->lefthand), rtable,
920 targetlist, rt_index, modified, sublevels_up);
923 * Make sure the first argument of sublink->oper points to
924 * the same var as sublink->lefthand does otherwise we
925 * will run into troubles using aggregates (aggno will not
928 pfree(lfirst(((Expr *) lfirst(sublink->oper))->args));
929 lfirst(((Expr *) lfirst(sublink->oper))->args) =
930 lfirst(sublink->lefthand);
934 /* ignore the others */
941 HandleViewRule(Query *parsetree,
947 nodeHandleViewRule(&parsetree->qual, rtable, targetlist, rt_index,
949 nodeHandleViewRule((Node **) (&(parsetree->targetList)), rtable, targetlist,
950 rt_index, modified, 0);
953 * The variables in the havingQual and groupClause also have to be
956 nodeHandleViewRule(&parsetree->havingQual, rtable, targetlist, rt_index,
958 nodeHandleViewRule((Node **) (&(parsetree->groupClause)), rtable, targetlist, rt_index,