1 /*-------------------------------------------------------------------------
5 * Copyright (c) 1994, Regents of the University of California
9 * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteManip.c,v 1.37 1999/07/16 04:59:40 momjian Exp $
11 *-------------------------------------------------------------------------
16 #include "optimizer/clauses.h"
17 #include "parser/parsetree.h"
18 #include "rewrite/rewriteManip.h"
19 #include "utils/builtins.h"
20 #include "utils/lsyscache.h"
22 static void ResolveNew(RewriteInfo *info, List *targetlist,
23 Node **node, int sublevels_up);
30 OffsetVarNodes(Node *node, int offset, int sublevels_up)
35 switch (nodeTag(node))
39 TargetEntry *tle = (TargetEntry *) node;
50 Aggref *aggref = (Aggref *) node;
53 (Node *) (aggref->target),
64 Expr *exp = (Expr *) node;
75 Iter *iter = (Iter *) node;
78 (Node *) (iter->iterexpr),
86 ArrayRef *ref = (ArrayRef *) node;
89 (Node *) (ref->refupperindexpr),
93 (Node *) (ref->reflowerindexpr),
97 (Node *) (ref->refexpr),
101 (Node *) (ref->refassgnexpr),
109 Var *var = (Var *) node;
111 if (var->varlevelsup == sublevels_up)
113 var->varno += offset;
114 var->varnoold += offset;
129 foreach(l, (List *) node)
139 SubLink *sub = (SubLink *) node;
144 * We also have to adapt the variables used in
145 * sub->lefthand and sub->oper
148 (Node *) (sub->lefthand),
153 (Node *) (sub->subselect),
158 * Make sure the first argument of sub->oper points to the
159 * same var as sub->lefthand does otherwise we will run
160 * into troubles using aggregates (aggno will not be set
163 tmp_lefthand = sub->lefthand;
164 foreach(tmp_oper, sub->oper)
166 lfirst(((Expr *) lfirst(tmp_oper))->args) =
167 lfirst(tmp_lefthand);
168 tmp_lefthand = lnext(tmp_lefthand);
175 Query *qry = (Query *) node;
178 (Node *) (qry->targetList),
183 (Node *) (qry->qual),
188 (Node *) (qry->havingQual),
196 CaseExpr *exp = (CaseExpr *) node;
199 (Node *) (exp->args),
204 (Node *) (exp->defresult),
212 CaseWhen *exp = (CaseWhen *) node;
215 (Node *) (exp->expr),
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))
249 TargetEntry *tle = (TargetEntry *) node;
252 (Node *) (tle->expr),
261 Aggref *aggref = (Aggref *) node;
264 (Node *) (aggref->target),
276 Expr *exp = (Expr *) node;
279 (Node *) (exp->args),
288 Iter *iter = (Iter *) node;
291 (Node *) (iter->iterexpr),
300 ArrayRef *ref = (ArrayRef *) node;
303 (Node *) (ref->refupperindexpr),
308 (Node *) (ref->reflowerindexpr),
313 (Node *) (ref->refexpr),
318 (Node *) (ref->refassgnexpr),
327 Var *var = (Var *) node;
329 if (var->varlevelsup == sublevels_up &&
330 var->varno == rt_index)
332 var->varno = new_index;
333 var->varnoold = new_index;
348 foreach(l, (List *) node)
359 SubLink *sub = (SubLink *) node;
364 (Node *) (sub->lefthand),
370 (Node *) (sub->subselect),
376 * Make sure the first argument of sub->oper points to the
377 * same var as sub->lefthand does otherwise we will run
378 * into troubles using aggregates (aggno will not be set
381 tmp_lefthand = sub->lefthand;
382 foreach(tmp_oper, sub->oper)
384 lfirst(((Expr *) lfirst(tmp_oper))->args) =
385 lfirst(tmp_lefthand);
386 tmp_lefthand = lnext(tmp_lefthand);
393 Query *qry = (Query *) node;
396 (Node *) (qry->targetList),
402 (Node *) (qry->qual),
408 (Node *) (qry->havingQual),
417 CaseExpr *exp = (CaseExpr *) node;
420 (Node *) (exp->args),
426 (Node *) (exp->defresult),
435 CaseWhen *exp = (CaseWhen *) node;
438 (Node *) (exp->expr),
444 (Node *) (exp->result),
452 elog(NOTICE, "unknown node tag %d in ChangeVarNodes()", nodeTag(node));
453 elog(NOTICE, "Node is: %s", nodeToString(node));
463 AddQual(Query *parsetree, Node *qual)
471 /* INTERSECT want's the original, but we need to copy - Jan */
473 copy = copyObject(qual);
475 old = parsetree->qual;
477 parsetree->qual = copy;
479 parsetree->qual = (Node *) make_andclause(makeList(parsetree->qual, copy, -1));
482 /* Adds the given havingQual to the one already contained in the parsetree just as
483 * AddQual does for the normal 'where' qual */
485 AddHavingQual(Query *parsetree, Node *havingQual)
490 if (havingQual == NULL)
493 /* INTERSECT want's the original, but we need to copy - Jan */
494 /* copy = havingQual; */
495 copy = copyObject(havingQual);
497 old = parsetree->havingQual;
499 parsetree->havingQual = copy;
501 parsetree->havingQual = (Node *) make_andclause(makeList(parsetree->havingQual, copy, -1));
506 AddNotHavingQual(Query *parsetree, Node *havingQual)
510 if (havingQual == NULL)
513 /* INTERSECT want's the original, but we need to copy - Jan */
514 /* copy = (Node *) make_notclause((Expr *)havingQual); */
515 copy = (Node *) make_notclause((Expr *) copyObject(havingQual));
517 AddHavingQual(parsetree, copy);
522 AddNotQual(Query *parsetree, Node *qual)
529 /* INTERSECT want's the original, but we need to copy - Jan */
530 /* copy = (Node *) make_notclause((Expr *)qual); */
531 copy = (Node *) make_notclause((Expr *) copyObject(qual));
533 AddQual(parsetree, copy);
538 AddGroupClause(Query *parsetree, List *group_by, List *tlist)
542 GroupClause *groupclause;
546 new_resno = length(parsetree->targetList);
550 groupclause = (GroupClause *) copyObject(lfirst(l));
554 if (((TargetEntry *) lfirst(tl))->resdom->resgroupref ==
555 groupclause->tleGroupref)
557 tle = (TargetEntry *) copyObject(lfirst(tl));
562 elog(ERROR, "AddGroupClause(): GROUP BY entry not found in rules targetlist");
564 tle->resdom->resno = ++new_resno;
565 tle->resdom->resjunk = true;
566 tle->resdom->resgroupref = length(parsetree->groupClause) + 1;
567 groupclause->tleGroupref = tle->resdom->resgroupref;
569 parsetree->targetList = lappend(parsetree->targetList, tle);
570 parsetree->groupClause = lappend(parsetree->groupClause, groupclause);
577 Const *c = makeNode(Const);
580 c->constlen = get_typlen(type);
581 c->constvalue = PointerGetDatum(NULL);
582 c->constisnull = true;
583 c->constbyval = get_typbyval(type);
589 FixResdomTypes(List *tlist)
595 TargetEntry *tle = lfirst(i);
597 if (nodeTag(tle->expr) == T_Var)
599 Var *var = (Var *) tle->expr;
601 tle->resdom->restype = var->vartype;
602 tle->resdom->restypmod = var->vartypmod;
610 FindMatchingNew(List *tlist, int attno)
616 TargetEntry *tle = lfirst(i);
618 if (tle->resdom->resno == attno)
625 FindMatchingTLEntry(List *tlist, char *e_attname)
631 TargetEntry *tle = lfirst(i);
634 resname = tle->resdom->resname;
635 if (!strcmp(e_attname, resname))
642 ResolveNew(RewriteInfo *info, List *targetlist, Node **nodePtr,
645 Node *node = *nodePtr;
650 switch (nodeTag(node))
653 ResolveNew(info, targetlist, &((TargetEntry *) node)->expr,
657 ResolveNew(info, targetlist, &((Aggref *) node)->target,
661 ResolveNew(info, targetlist, (Node **) (&(((Expr *) node)->args)),
665 ResolveNew(info, targetlist, (Node **) (&(((Iter *) node)->iterexpr)),
669 ResolveNew(info, targetlist, (Node **) (&(((ArrayRef *) node)->refupperindexpr)),
671 ResolveNew(info, targetlist, (Node **) (&(((ArrayRef *) node)->reflowerindexpr)),
673 ResolveNew(info, targetlist, (Node **) (&(((ArrayRef *) node)->refexpr)),
675 ResolveNew(info, targetlist, (Node **) (&(((ArrayRef *) node)->refassgnexpr)),
680 int this_varno = (int) ((Var *) node)->varno;
681 int this_varlevelsup = (int) ((Var *) node)->varlevelsup;
684 if (this_varno == info->new_varno &&
685 this_varlevelsup == sublevels_up)
687 n = FindMatchingNew(targetlist,
688 ((Var *) node)->varattno);
691 if (info->event == CMD_UPDATE)
693 *nodePtr = n = copyObject(node);
694 ((Var *) n)->varno = info->current_varno;
695 ((Var *) n)->varnoold = info->current_varno;
698 *nodePtr = make_null(((Var *) node)->vartype);
702 *nodePtr = copyObject(n);
703 ((Var *) *nodePtr)->varlevelsup = this_varlevelsup;
712 foreach(l, (List *) node)
713 ResolveNew(info, targetlist, (Node **) &(lfirst(l)),
719 SubLink *sublink = (SubLink *) node;
720 Query *query = (Query *) sublink->subselect;
722 ResolveNew(info, targetlist, (Node **) &(query->qual), sublevels_up + 1);
728 /* ignore the others */
734 FixNew(RewriteInfo *info, Query *parsetree)
736 ResolveNew(info, parsetree->targetList,
737 (Node **) &(info->rule_action->targetList), 0);
738 ResolveNew(info, parsetree->targetList,
739 (Node **) &info->rule_action->qual, 0);
740 ResolveNew(info, parsetree->targetList,
741 (Node **) &(info->rule_action->groupClause), 0);
745 nodeHandleRIRAttributeRule(Node **nodePtr,
754 Node *node = *nodePtr;
758 switch (nodeTag(node))
762 TargetEntry *tle = (TargetEntry *) node;
764 nodeHandleRIRAttributeRule(&tle->expr, rtable, targetlist,
765 rt_index, attr_num, modified, badsql,
771 Aggref *aggref = (Aggref *) node;
773 nodeHandleRIRAttributeRule(&aggref->target, rtable, targetlist,
774 rt_index, attr_num, modified, badsql,
780 Expr *expr = (Expr *) node;
782 nodeHandleRIRAttributeRule((Node **) (&(expr->args)), rtable,
783 targetlist, rt_index, attr_num,
790 Iter *iter = (Iter *) node;
792 nodeHandleRIRAttributeRule((Node **) (&(iter->iterexpr)), rtable,
793 targetlist, rt_index, attr_num,
800 ArrayRef *ref = (ArrayRef *) node;
802 nodeHandleRIRAttributeRule((Node **) (&(ref->refupperindexpr)), rtable,
803 targetlist, rt_index, attr_num,
806 nodeHandleRIRAttributeRule((Node **) (&(ref->reflowerindexpr)), rtable,
807 targetlist, rt_index, attr_num,
810 nodeHandleRIRAttributeRule((Node **) (&(ref->refexpr)), rtable,
811 targetlist, rt_index, attr_num,
814 nodeHandleRIRAttributeRule((Node **) (&(ref->refassgnexpr)), rtable,
815 targetlist, rt_index, attr_num,
822 int this_varno = ((Var *) node)->varno;
823 int this_varattno = ((Var *) node)->varattno;
824 int this_varlevelsup = ((Var *) node)->varlevelsup;
826 if (this_varno == rt_index &&
827 this_varattno == attr_num &&
828 this_varlevelsup == sublevels_up)
830 if (((Var *) node)->vartype == 32)
832 *nodePtr = make_null(((Var *) node)->vartype);
839 NameData name_to_look_for;
841 name_to_look_for.data[0] = '\0';
842 namestrcpy(&name_to_look_for,
843 (char *) get_attname(getrelid(this_varno,
846 if (name_to_look_for.data[0])
850 n = FindMatchingTLEntry(targetlist, (char *) &name_to_look_for);
852 *nodePtr = make_null(((Var *) node)->vartype);
865 foreach(i, (List *) node)
867 nodeHandleRIRAttributeRule((Node **) (&(lfirst(i))), rtable,
868 targetlist, rt_index, attr_num,
869 modified, badsql, sublevels_up);
875 SubLink *sublink = (SubLink *) node;
876 Query *query = (Query *) sublink->subselect;
878 nodeHandleRIRAttributeRule((Node **) &(query->qual), rtable, targetlist,
879 rt_index, attr_num, modified, badsql,
884 /* ignore the others */
890 * Handles 'on retrieve to relation.attribute
891 * do instead retrieve (attribute = expression) w/qual'
894 HandleRIRAttributeRule(Query *parsetree,
903 nodeHandleRIRAttributeRule((Node **) (&(parsetree->targetList)), rtable,
904 targetlist, rt_index, attr_num,
905 modified, badsql, 0);
906 nodeHandleRIRAttributeRule(&parsetree->qual, rtable, targetlist,
907 rt_index, attr_num, modified, badsql, 0);
912 nodeHandleViewRule(Node **nodePtr,
919 Node *node = *nodePtr;
924 switch (nodeTag(node))
928 TargetEntry *tle = (TargetEntry *) node;
930 nodeHandleViewRule(&(tle->expr), rtable, targetlist,
931 rt_index, modified, sublevels_up);
936 Aggref *aggref = (Aggref *) node;
938 nodeHandleViewRule(&(aggref->target), rtable, targetlist,
939 rt_index, modified, sublevels_up);
944 * This has to be done to make queries using groupclauses work
949 GroupClause *group = (GroupClause *) node;
951 nodeHandleViewRule((Node **) (&(group->entry)), rtable, targetlist,
952 rt_index, modified, sublevels_up);
957 Expr *expr = (Expr *) node;
959 nodeHandleViewRule((Node **) (&(expr->args)),
961 rt_index, modified, sublevels_up);
966 Iter *iter = (Iter *) node;
968 nodeHandleViewRule((Node **) (&(iter->iterexpr)),
970 rt_index, modified, sublevels_up);
975 ArrayRef *ref = (ArrayRef *) node;
977 nodeHandleViewRule((Node **) (&(ref->refupperindexpr)),
979 rt_index, modified, sublevels_up);
980 nodeHandleViewRule((Node **) (&(ref->reflowerindexpr)),
982 rt_index, modified, sublevels_up);
983 nodeHandleViewRule((Node **) (&(ref->refexpr)),
985 rt_index, modified, sublevels_up);
986 nodeHandleViewRule((Node **) (&(ref->refassgnexpr)),
988 rt_index, modified, sublevels_up);
993 Var *var = (Var *) node;
994 int this_varno = var->varno;
995 int this_varlevelsup = var->varlevelsup;
998 if (this_varno == rt_index &&
999 this_varlevelsup == sublevels_up)
1001 n = FindMatchingTLEntry(targetlist,
1002 get_attname(getrelid(this_varno,
1006 *nodePtr = make_null(((Var *) node)->vartype);
1011 * This is a hack: The varlevelsup of the orignal
1012 * variable and the new one should be the same.
1013 * Normally we adapt the node by changing a
1014 * pointer to point to a var contained in
1015 * 'targetlist'. In the targetlist all
1016 * varlevelsups are 0 so if we want to change it
1017 * to the original value we have to copy the node
1018 * before! (Maybe this will cause troubles with
1019 * some sophisticated queries on views?)
1021 if (this_varlevelsup > 0)
1022 *nodePtr = copyObject(n);
1026 if (nodeTag(nodePtr) == T_Var)
1027 ((Var *) *nodePtr)->varlevelsup = this_varlevelsup;
1029 nodeHandleViewRule(&n, rtable, targetlist,
1030 rt_index, modified, sublevels_up);
1040 foreach(l, (List *) node)
1042 nodeHandleViewRule((Node **) (&(lfirst(l))),
1044 rt_index, modified, sublevels_up);
1050 SubLink *sublink = (SubLink *) node;
1051 Query *query = (Query *) sublink->subselect;
1056 nodeHandleViewRule((Node **) &(query->qual), rtable, targetlist,
1057 rt_index, modified, sublevels_up + 1);
1060 nodeHandleViewRule((Node **) &(query->havingQual), rtable, targetlist,
1061 rt_index, modified, sublevels_up + 1);
1062 nodeHandleViewRule((Node **) &(query->targetList), rtable, targetlist,
1063 rt_index, modified, sublevels_up + 1);
1067 * We also have to adapt the variables used in
1068 * sublink->lefthand and sublink->oper
1070 nodeHandleViewRule((Node **) &(sublink->lefthand), rtable,
1071 targetlist, rt_index, modified, sublevels_up);
1074 * Make sure the first argument of sublink->oper points to
1075 * the same var as sublink->lefthand does otherwise we
1076 * will run into troubles using aggregates (aggno will not
1079 pfree(lfirst(((Expr *) lfirst(sublink->oper))->args));
1080 lfirst(((Expr *) lfirst(sublink->oper))->args) =
1081 lfirst(sublink->lefthand);
1084 /* INTERSECT want's this - Jan */
1087 * tmp_lefthand = sublink->lefthand; foreach(tmp_oper,
1088 * sublink->oper) { lfirst(((Expr *)
1089 * lfirst(tmp_oper))->args) = lfirst(tmp_lefthand);
1090 * tmp_lefthand = lnext(tmp_lefthand); }
1095 /* ignore the others */
1101 HandleViewRule(Query *parsetree,
1107 nodeHandleViewRule(&parsetree->qual, rtable, targetlist, rt_index,
1109 nodeHandleViewRule((Node **) (&(parsetree->targetList)), rtable, targetlist,
1110 rt_index, modified, 0);
1113 * The variables in the havingQual and groupClause also have to be
1116 nodeHandleViewRule(&parsetree->havingQual, rtable, targetlist, rt_index,
1118 nodeHandleViewRule((Node **) (&(parsetree->groupClause)), rtable, targetlist, rt_index,