1 /*-------------------------------------------------------------------------
5 * Copyright (c) 1994, Regents of the University of California
9 * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteManip.c,v 1.23 1998/12/14 00:02:17 thomas 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),
196 CaseExpr *exp = (CaseExpr *)node;
204 (Node *)(exp->defresult),
212 CaseWhen *exp = (CaseWhen *)node;
220 (Node *)(exp->result),
227 elog(NOTICE, "unknown node tag %d in OffsetVarNodes()", nodeTag(node));
228 elog(NOTICE, "Node is: %s", nodeToString(node));
240 ChangeVarNodes(Node *node, int rt_index, int new_index, int sublevels_up)
245 switch(nodeTag(node)) {
248 TargetEntry *tle = (TargetEntry *)node;
260 Aggreg *agg = (Aggreg *)node;
263 (Node *)(agg->target),
272 GroupClause *grp = (GroupClause *)node;
275 (Node *)(grp->entry),
284 Expr *exp = (Expr *)node;
296 Iter *iter = (Iter *)node;
299 (Node *)(iter->iterexpr),
308 ArrayRef *ref = (ArrayRef *)node;
311 (Node *)(ref->refupperindexpr),
316 (Node *)(ref->reflowerindexpr),
321 (Node *)(ref->refexpr),
326 (Node *)(ref->refassgnexpr),
335 Var *var = (Var *)node;
337 if (var->varlevelsup == sublevels_up &&
338 var->varno == rt_index) {
339 var->varno = new_index;
340 var->varnoold = new_index;
355 foreach (l, (List *)node)
366 SubLink *sub = (SubLink *)node;
369 (Node *)(sub->lefthand),
375 (Node *)(sub->subselect),
384 Query *qry = (Query *)node;
387 (Node *)(qry->targetList),
399 (Node *)(qry->havingQual),
405 (Node *)(qry->groupClause),
414 CaseExpr *exp = (CaseExpr *)node;
423 (Node *)(exp->defresult),
432 CaseWhen *exp = (CaseWhen *)node;
441 (Node *)(exp->result),
449 elog(NOTICE, "unknown node tag %d in ChangeVarNodes()", nodeTag(node));
450 elog(NOTICE, "Node is: %s", nodeToString(node));
460 AddQual(Query *parsetree, Node *qual)
468 copy = copyObject(qual);
469 old = parsetree->qual;
471 parsetree->qual = copy;
474 (Node *) make_andclause(makeList(parsetree->qual, copy, -1));
477 /* Adds the given havingQual to the one already contained in the parsetree just as
478 * AddQual does for the normal 'where' qual */
480 AddHavingQual(Query *parsetree, Node *havingQual)
485 if (havingQual == NULL)
488 copy = copyObject(havingQual);
489 old = parsetree->havingQual;
491 parsetree->havingQual = copy;
493 parsetree->havingQual =
494 (Node *) make_andclause(makeList(parsetree->havingQual, copy, -1));
499 AddNotQual(Query *parsetree, Node *qual)
506 copy = (Node *) make_notclause(copyObject(qual));
508 AddQual(parsetree, copy);
514 Const *c = makeNode(Const);
517 c->constlen = get_typlen(type);
518 c->constvalue = PointerGetDatum(NULL);
519 c->constisnull = true;
520 c->constbyval = get_typbyval(type);
526 FixResdomTypes(List *tlist)
532 TargetEntry *tle = lfirst(i);
534 if (nodeTag(tle->expr) == T_Var)
536 Var *var = (Var *) tle->expr;
538 tle->resdom->restype = var->vartype;
539 tle->resdom->restypmod = var->vartypmod;
546 FindMatchingNew(List *tlist, int attno)
552 TargetEntry *tle = lfirst(i);
554 if (tle->resdom->resno == attno)
561 FindMatchingTLEntry(List *tlist, char *e_attname)
567 TargetEntry *tle = lfirst(i);
570 resname = tle->resdom->resname;
571 if (!strcmp(e_attname, resname))
578 ResolveNew(RewriteInfo *info, List *targetlist, Node **nodePtr,
581 Node *node = *nodePtr;
586 switch (nodeTag(node))
589 ResolveNew(info, targetlist, &((TargetEntry *) node)->expr,
593 ResolveNew(info, targetlist, &((Aggreg *) node)->target,
597 ResolveNew(info, targetlist, (Node **) (&(((Expr *) node)->args)),
601 ResolveNew(info, targetlist, (Node **) (&(((Iter *) node)->iterexpr)),
605 ResolveNew(info, targetlist, (Node **) (&(((ArrayRef *) node)->refupperindexpr)),
607 ResolveNew(info, targetlist, (Node **) (&(((ArrayRef *) node)->reflowerindexpr)),
609 ResolveNew(info, targetlist, (Node **) (&(((ArrayRef *) node)->refexpr)),
611 ResolveNew(info, targetlist, (Node **) (&(((ArrayRef *) node)->refassgnexpr)),
616 int this_varno = (int) ((Var *) node)->varno;
617 int this_varlevelsup = (int) ((Var *) node)->varlevelsup;
620 if (this_varno == info->new_varno &&
621 this_varlevelsup == sublevels_up)
623 n = FindMatchingNew(targetlist,
624 ((Var *) node)->varattno);
627 if (info->event == CMD_UPDATE)
629 *nodePtr = n = copyObject(node);
630 ((Var *) n)->varno = info->current_varno;
631 ((Var *) n)->varnoold = info->current_varno;
634 *nodePtr = make_null(((Var *) node)->vartype);
637 *nodePtr = copyObject(n);
645 foreach(l, (List *) node)
646 ResolveNew(info, targetlist, (Node **) &(lfirst(l)),
652 SubLink *sublink = (SubLink *) node;
653 Query *query = (Query *) sublink->subselect;
655 ResolveNew(info, targetlist, (Node **) &(query->qual), sublevels_up + 1);
659 /* ignore the others */
665 FixNew(RewriteInfo *info, Query *parsetree)
667 ResolveNew(info, parsetree->targetList,
668 (Node **) &(info->rule_action->targetList), 0);
669 ResolveNew(info, parsetree->targetList, &info->rule_action->qual, 0);
673 nodeHandleRIRAttributeRule(Node **nodePtr,
682 Node *node = *nodePtr;
686 switch (nodeTag(node))
690 TargetEntry *tle = (TargetEntry *) node;
692 nodeHandleRIRAttributeRule(&tle->expr, rtable, targetlist,
693 rt_index, attr_num, modified, badsql,
699 Aggreg *agg = (Aggreg *) node;
701 nodeHandleRIRAttributeRule(&agg->target, rtable, targetlist,
702 rt_index, attr_num, modified, badsql,
708 Expr *expr = (Expr *) node;
710 nodeHandleRIRAttributeRule((Node **) (&(expr->args)), rtable,
711 targetlist, rt_index, attr_num,
718 Iter *iter = (Iter *) node;
720 nodeHandleRIRAttributeRule((Node **) (&(iter->iterexpr)), rtable,
721 targetlist, rt_index, attr_num,
728 ArrayRef *ref = (ArrayRef *) node;
730 nodeHandleRIRAttributeRule((Node **) (&(ref->refupperindexpr)), rtable,
731 targetlist, rt_index, attr_num,
734 nodeHandleRIRAttributeRule((Node **) (&(ref->reflowerindexpr)), rtable,
735 targetlist, rt_index, attr_num,
738 nodeHandleRIRAttributeRule((Node **) (&(ref->refexpr)), rtable,
739 targetlist, rt_index, attr_num,
742 nodeHandleRIRAttributeRule((Node **) (&(ref->refassgnexpr)), rtable,
743 targetlist, rt_index, attr_num,
750 int this_varno = ((Var *) node)->varno;
751 int this_varattno = ((Var *) node)->varattno;
752 int this_varlevelsup = ((Var *) node)->varlevelsup;
754 if (this_varno == rt_index &&
755 this_varattno == attr_num &&
756 this_varlevelsup == sublevels_up)
758 if (((Var *) node)->vartype == 32)
760 *nodePtr = make_null(((Var *) node)->vartype);
767 NameData name_to_look_for;
769 name_to_look_for.data[0] = '\0';
770 namestrcpy(&name_to_look_for,
771 (char *) get_attname(getrelid(this_varno,
774 if (name_to_look_for.data[0])
778 n = FindMatchingTLEntry(targetlist, (char *) &name_to_look_for);
780 *nodePtr = make_null(((Var *) node)->vartype);
793 foreach(i, (List *) node)
795 nodeHandleRIRAttributeRule((Node **) (&(lfirst(i))), rtable,
796 targetlist, rt_index, attr_num,
797 modified, badsql, sublevels_up);
803 SubLink *sublink = (SubLink *) node;
804 Query *query = (Query *) sublink->subselect;
806 nodeHandleRIRAttributeRule((Node **) &(query->qual), rtable, targetlist,
807 rt_index, attr_num, modified, badsql,
812 /* ignore the others */
818 * Handles 'on retrieve to relation.attribute
819 * do instead retrieve (attribute = expression) w/qual'
822 HandleRIRAttributeRule(Query *parsetree,
831 nodeHandleRIRAttributeRule((Node **) (&(parsetree->targetList)), rtable,
832 targetlist, rt_index, attr_num,
833 modified, badsql, 0);
834 nodeHandleRIRAttributeRule(&parsetree->qual, rtable, targetlist,
835 rt_index, attr_num, modified, badsql, 0);
840 nodeHandleViewRule(Node **nodePtr,
847 Node *node = *nodePtr;
852 switch (nodeTag(node))
856 TargetEntry *tle = (TargetEntry *) node;
858 nodeHandleViewRule(&(tle->expr), rtable, targetlist,
859 rt_index, modified, sublevels_up);
864 Aggreg *agg = (Aggreg *) node;
866 nodeHandleViewRule(&(agg->target), rtable, targetlist,
867 rt_index, modified, sublevels_up);
872 * This has to be done to make queries using groupclauses work
877 GroupClause *group = (GroupClause *) node;
879 nodeHandleViewRule((Node **) (&(group->entry)), rtable, targetlist,
880 rt_index, modified, sublevels_up);
885 Expr *expr = (Expr *) node;
887 nodeHandleViewRule((Node **) (&(expr->args)),
889 rt_index, modified, sublevels_up);
894 Iter *iter = (Iter *) node;
896 nodeHandleViewRule((Node **) (&(iter->iterexpr)),
898 rt_index, modified, sublevels_up);
903 ArrayRef *ref = (ArrayRef *) node;
905 nodeHandleViewRule((Node **) (&(ref->refupperindexpr)),
907 rt_index, modified, sublevels_up);
908 nodeHandleViewRule((Node **) (&(ref->reflowerindexpr)),
910 rt_index, modified, sublevels_up);
911 nodeHandleViewRule((Node **) (&(ref->refexpr)),
913 rt_index, modified, sublevels_up);
914 nodeHandleViewRule((Node **) (&(ref->refassgnexpr)),
916 rt_index, modified, sublevels_up);
921 Var *var = (Var *) node;
922 int this_varno = var->varno;
923 int this_varlevelsup = var->varlevelsup;
926 if (this_varno == rt_index &&
927 this_varlevelsup == sublevels_up)
929 n = FindMatchingTLEntry(targetlist,
930 get_attname(getrelid(this_varno,
934 *nodePtr = make_null(((Var *) node)->vartype);
938 * This is a hack: The varlevelsup of the orignal
939 * variable and the new one should be the same.
940 * Normally we adapt the node by changing a
941 * pointer to point to a var contained in
942 * 'targetlist'. In the targetlist all
943 * varlevelsups are 0 so if we want to change it
944 * to the original value we have to copy the node
945 * before! (Maybe this will cause troubles with
946 * some sophisticated queries on views?)
948 if (this_varlevelsup > 0)
949 *nodePtr = copyObject(n);
953 if (nodeTag(nodePtr) == T_Var)
954 ((Var *) *nodePtr)->varlevelsup = this_varlevelsup;
956 nodeHandleViewRule(&n, rtable, targetlist,
957 rt_index, modified, sublevels_up);
967 foreach(l, (List *) node)
969 nodeHandleViewRule((Node **) (&(lfirst(l))),
971 rt_index, modified, sublevels_up);
977 SubLink *sublink = (SubLink *) node;
978 Query *query = (Query *) sublink->subselect;
980 nodeHandleViewRule((Node **) &(query->qual), rtable, targetlist,
981 rt_index, modified, sublevels_up + 1);
984 * We also have to adapt the variables used in
985 * sublink->lefthand and sublink->oper
987 nodeHandleViewRule((Node **) &(sublink->lefthand), rtable,
988 targetlist, rt_index, modified, sublevels_up);
991 * Make sure the first argument of sublink->oper points to
992 * the same var as sublink->lefthand does otherwise we
993 * will run into troubles using aggregates (aggno will not
996 pfree(lfirst(((Expr *) lfirst(sublink->oper))->args));
997 lfirst(((Expr *) lfirst(sublink->oper))->args) =
998 lfirst(sublink->lefthand);
1002 /* ignore the others */
1009 HandleViewRule(Query *parsetree,
1015 nodeHandleViewRule(&parsetree->qual, rtable, targetlist, rt_index,
1017 nodeHandleViewRule((Node **) (&(parsetree->targetList)), rtable, targetlist,
1018 rt_index, modified, 0);
1021 * The variables in the havingQual and groupClause also have to be
1024 nodeHandleViewRule(&parsetree->havingQual, rtable, targetlist, rt_index,
1026 nodeHandleViewRule((Node **) (&(parsetree->groupClause)), rtable, targetlist, rt_index,