1 /*-------------------------------------------------------------------------
5 * Copyright (c) 1994, Regents of the University of California
9 * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteManip.c,v 1.32 1999/05/26 12:55:48 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))
48 TargetEntry *tle = (TargetEntry *) node;
59 Aggref *aggref = (Aggref *) node;
62 (Node *) (aggref->target),
73 Expr *exp = (Expr *) node;
84 Iter *iter = (Iter *) node;
87 (Node *) (iter->iterexpr),
95 ArrayRef *ref = (ArrayRef *) node;
98 (Node *) (ref->refupperindexpr),
102 (Node *) (ref->reflowerindexpr),
106 (Node *) (ref->refexpr),
110 (Node *) (ref->refassgnexpr),
118 Var *var = (Var *) node;
120 if (var->varlevelsup == sublevels_up)
122 var->varno += offset;
123 var->varnoold += offset;
138 foreach(l, (List *) node)
148 SubLink *sub = (SubLink *) node;
153 * We also have to adapt the variables used in
154 * sub->lefthand and sub->oper
157 (Node *) (sub->lefthand),
162 (Node *) (sub->subselect),
169 * Make sure the first argument of sub->oper points to the
170 * same var as sub->lefthand does otherwise we will run
171 * into troubles using aggregates (aggno will not be set
174 tmp_lefthand = sub->lefthand;
175 foreach(tmp_oper, sub->oper)
177 lfirst(((Expr *) lfirst(tmp_oper))->args) =
178 lfirst(tmp_lefthand);
179 tmp_lefthand = lnext(tmp_lefthand);
186 Query *qry = (Query *) node;
189 (Node *) (qry->targetList),
194 (Node *) (qry->qual),
199 (Node *) (qry->havingQual),
207 CaseExpr *exp = (CaseExpr *) node;
210 (Node *) (exp->args),
215 (Node *) (exp->defresult),
223 CaseWhen *exp = (CaseWhen *) node;
226 (Node *) (exp->expr),
231 (Node *) (exp->result),
238 elog(NOTICE, "unknown node tag %d in OffsetVarNodes()", nodeTag(node));
239 elog(NOTICE, "Node is: %s", nodeToString(node));
251 ChangeVarNodes(Node *node, int rt_index, int new_index, int sublevels_up)
256 switch (nodeTag(node))
260 TargetEntry *tle = (TargetEntry *) node;
263 (Node *) (tle->expr),
272 Aggref *aggref = (Aggref *) node;
275 (Node *) (aggref->target),
287 Expr *exp = (Expr *) node;
290 (Node *) (exp->args),
299 Iter *iter = (Iter *) node;
302 (Node *) (iter->iterexpr),
311 ArrayRef *ref = (ArrayRef *) node;
314 (Node *) (ref->refupperindexpr),
319 (Node *) (ref->reflowerindexpr),
324 (Node *) (ref->refexpr),
329 (Node *) (ref->refassgnexpr),
338 Var *var = (Var *) node;
340 if (var->varlevelsup == sublevels_up &&
341 var->varno == rt_index)
343 var->varno = new_index;
344 var->varnoold = new_index;
359 foreach(l, (List *) node)
370 SubLink *sub = (SubLink *) node;
375 (Node *) (sub->lefthand),
381 (Node *) (sub->subselect),
389 * Make sure the first argument of sub->oper points to the
390 * same var as sub->lefthand does otherwise we will run
391 * into troubles using aggregates (aggno will not be set
394 tmp_lefthand = sub->lefthand;
395 foreach(tmp_oper, sub->oper)
397 lfirst(((Expr *) lfirst(tmp_oper))->args) =
398 lfirst(tmp_lefthand);
399 tmp_lefthand = lnext(tmp_lefthand);
406 Query *qry = (Query *) node;
409 (Node *) (qry->targetList),
415 (Node *) (qry->qual),
421 (Node *) (qry->havingQual),
430 CaseExpr *exp = (CaseExpr *) node;
433 (Node *) (exp->args),
439 (Node *) (exp->defresult),
448 CaseWhen *exp = (CaseWhen *) node;
451 (Node *) (exp->expr),
457 (Node *) (exp->result),
465 elog(NOTICE, "unknown node tag %d in ChangeVarNodes()", nodeTag(node));
466 elog(NOTICE, "Node is: %s", nodeToString(node));
476 AddQual(Query *parsetree, Node *qual)
485 /* INTERSECT want's the original, but we need to copy - Jan */
487 copy = copyObject(qual);
489 old = parsetree->qual;
491 parsetree->qual = copy;
493 parsetree->qual = (Node *) make_andclause(makeList(parsetree->qual, copy, -1));
496 /* Adds the given havingQual to the one already contained in the parsetree just as
497 * AddQual does for the normal 'where' qual */
499 AddHavingQual(Query *parsetree, Node *havingQual)
504 if (havingQual == NULL)
508 /* INTERSECT want's the original, but we need to copy - Jan */
509 /* copy = havingQual; */
510 copy = copyObject(havingQual);
512 old = parsetree->havingQual;
514 parsetree->havingQual = copy;
516 parsetree->havingQual = (Node *) make_andclause(makeList(parsetree->havingQual, copy, -1));
521 AddNotHavingQual(Query *parsetree, Node *havingQual)
525 if (havingQual == NULL)
529 /* INTERSECT want's the original, but we need to copy - Jan */
530 /* copy = (Node *) make_notclause((Expr *)havingQual); */
531 copy = (Node *) make_notclause((Expr *) copyObject(havingQual));
533 AddHavingQual(parsetree, copy);
538 AddNotQual(Query *parsetree, Node *qual)
546 /* INTERSECT want's the original, but we need to copy - Jan */
547 /* copy = (Node *) make_notclause((Expr *)qual); */
548 copy = (Node *) make_notclause((Expr *) copyObject(qual));
550 AddQual(parsetree, copy);
555 AddGroupClause(Query *parsetree, List *group_by, List *tlist)
559 GroupClause *groupclause;
563 new_resno = length(parsetree->targetList);
567 groupclause = (GroupClause *) copyObject(lfirst(l));
571 if (((TargetEntry *) lfirst(tl))->resdom->resgroupref ==
572 groupclause->tleGroupref)
574 tle = (TargetEntry *) copyObject(lfirst(tl));
579 elog(ERROR, "AddGroupClause(): GROUP BY entry not found in rules targetlist");
581 tle->resdom->resno = ++new_resno;
582 tle->resdom->resjunk = true;
583 tle->resdom->resgroupref = length(parsetree->groupClause) + 1;
584 groupclause->tleGroupref = tle->resdom->resgroupref;
586 parsetree->targetList = lappend(parsetree->targetList, tle);
587 parsetree->groupClause = lappend(parsetree->groupClause, groupclause);
594 Const *c = makeNode(Const);
597 c->constlen = get_typlen(type);
598 c->constvalue = PointerGetDatum(NULL);
599 c->constisnull = true;
600 c->constbyval = get_typbyval(type);
606 FixResdomTypes(List *tlist)
612 TargetEntry *tle = lfirst(i);
614 if (nodeTag(tle->expr) == T_Var)
616 Var *var = (Var *) tle->expr;
618 tle->resdom->restype = var->vartype;
619 tle->resdom->restypmod = var->vartypmod;
627 FindMatchingNew(List *tlist, int attno)
633 TargetEntry *tle = lfirst(i);
635 if (tle->resdom->resno == attno)
642 FindMatchingTLEntry(List *tlist, char *e_attname)
648 TargetEntry *tle = lfirst(i);
651 resname = tle->resdom->resname;
652 if (!strcmp(e_attname, resname))
659 ResolveNew(RewriteInfo *info, List *targetlist, Node **nodePtr,
662 Node *node = *nodePtr;
667 switch (nodeTag(node))
670 ResolveNew(info, targetlist, &((TargetEntry *) node)->expr,
674 ResolveNew(info, targetlist, &((Aggref *) node)->target,
678 ResolveNew(info, targetlist, (Node **) (&(((Expr *) node)->args)),
682 ResolveNew(info, targetlist, (Node **) (&(((Iter *) node)->iterexpr)),
686 ResolveNew(info, targetlist, (Node **) (&(((ArrayRef *) node)->refupperindexpr)),
688 ResolveNew(info, targetlist, (Node **) (&(((ArrayRef *) node)->reflowerindexpr)),
690 ResolveNew(info, targetlist, (Node **) (&(((ArrayRef *) node)->refexpr)),
692 ResolveNew(info, targetlist, (Node **) (&(((ArrayRef *) node)->refassgnexpr)),
697 int this_varno = (int) ((Var *) node)->varno;
698 int this_varlevelsup = (int) ((Var *) node)->varlevelsup;
701 if (this_varno == info->new_varno &&
702 this_varlevelsup == sublevels_up)
704 n = FindMatchingNew(targetlist,
705 ((Var *) node)->varattno);
708 if (info->event == CMD_UPDATE)
710 *nodePtr = n = copyObject(node);
711 ((Var *) n)->varno = info->current_varno;
712 ((Var *) n)->varnoold = info->current_varno;
715 *nodePtr = make_null(((Var *) node)->vartype);
719 *nodePtr = copyObject(n);
720 ((Var *) *nodePtr)->varlevelsup = this_varlevelsup;
729 foreach(l, (List *) node)
730 ResolveNew(info, targetlist, (Node **) &(lfirst(l)),
736 SubLink *sublink = (SubLink *) node;
737 Query *query = (Query *) sublink->subselect;
739 ResolveNew(info, targetlist, (Node **) &(query->qual), sublevels_up + 1);
745 /* ignore the others */
751 FixNew(RewriteInfo *info, Query *parsetree)
753 ResolveNew(info, parsetree->targetList,
754 (Node **) &(info->rule_action->targetList), 0);
755 ResolveNew(info, parsetree->targetList,
756 (Node **) &info->rule_action->qual, 0);
757 ResolveNew(info, parsetree->targetList,
758 (Node **) &(info->rule_action->groupClause), 0);
762 nodeHandleRIRAttributeRule(Node **nodePtr,
771 Node *node = *nodePtr;
775 switch (nodeTag(node))
779 TargetEntry *tle = (TargetEntry *) node;
781 nodeHandleRIRAttributeRule(&tle->expr, rtable, targetlist,
782 rt_index, attr_num, modified, badsql,
788 Aggref *aggref = (Aggref *) node;
790 nodeHandleRIRAttributeRule(&aggref->target, rtable, targetlist,
791 rt_index, attr_num, modified, badsql,
797 Expr *expr = (Expr *) node;
799 nodeHandleRIRAttributeRule((Node **) (&(expr->args)), rtable,
800 targetlist, rt_index, attr_num,
807 Iter *iter = (Iter *) node;
809 nodeHandleRIRAttributeRule((Node **) (&(iter->iterexpr)), rtable,
810 targetlist, rt_index, attr_num,
817 ArrayRef *ref = (ArrayRef *) node;
819 nodeHandleRIRAttributeRule((Node **) (&(ref->refupperindexpr)), rtable,
820 targetlist, rt_index, attr_num,
823 nodeHandleRIRAttributeRule((Node **) (&(ref->reflowerindexpr)), rtable,
824 targetlist, rt_index, attr_num,
827 nodeHandleRIRAttributeRule((Node **) (&(ref->refexpr)), rtable,
828 targetlist, rt_index, attr_num,
831 nodeHandleRIRAttributeRule((Node **) (&(ref->refassgnexpr)), rtable,
832 targetlist, rt_index, attr_num,
839 int this_varno = ((Var *) node)->varno;
840 int this_varattno = ((Var *) node)->varattno;
841 int this_varlevelsup = ((Var *) node)->varlevelsup;
843 if (this_varno == rt_index &&
844 this_varattno == attr_num &&
845 this_varlevelsup == sublevels_up)
847 if (((Var *) node)->vartype == 32)
849 *nodePtr = make_null(((Var *) node)->vartype);
856 NameData name_to_look_for;
858 name_to_look_for.data[0] = '\0';
859 namestrcpy(&name_to_look_for,
860 (char *) get_attname(getrelid(this_varno,
863 if (name_to_look_for.data[0])
867 n = FindMatchingTLEntry(targetlist, (char *) &name_to_look_for);
869 *nodePtr = make_null(((Var *) node)->vartype);
882 foreach(i, (List *) node)
884 nodeHandleRIRAttributeRule((Node **) (&(lfirst(i))), rtable,
885 targetlist, rt_index, attr_num,
886 modified, badsql, sublevels_up);
892 SubLink *sublink = (SubLink *) node;
893 Query *query = (Query *) sublink->subselect;
895 nodeHandleRIRAttributeRule((Node **) &(query->qual), rtable, targetlist,
896 rt_index, attr_num, modified, badsql,
901 /* ignore the others */
907 * Handles 'on retrieve to relation.attribute
908 * do instead retrieve (attribute = expression) w/qual'
911 HandleRIRAttributeRule(Query *parsetree,
920 nodeHandleRIRAttributeRule((Node **) (&(parsetree->targetList)), rtable,
921 targetlist, rt_index, attr_num,
922 modified, badsql, 0);
923 nodeHandleRIRAttributeRule(&parsetree->qual, rtable, targetlist,
924 rt_index, attr_num, modified, badsql, 0);
929 nodeHandleViewRule(Node **nodePtr,
936 Node *node = *nodePtr;
941 switch (nodeTag(node))
945 TargetEntry *tle = (TargetEntry *) node;
947 nodeHandleViewRule(&(tle->expr), rtable, targetlist,
948 rt_index, modified, sublevels_up);
953 Aggref *aggref = (Aggref *) node;
955 nodeHandleViewRule(&(aggref->target), rtable, targetlist,
956 rt_index, modified, sublevels_up);
961 * This has to be done to make queries using groupclauses work
966 GroupClause *group = (GroupClause *) node;
968 nodeHandleViewRule((Node **) (&(group->entry)), rtable, targetlist,
969 rt_index, modified, sublevels_up);
974 Expr *expr = (Expr *) node;
976 nodeHandleViewRule((Node **) (&(expr->args)),
978 rt_index, modified, sublevels_up);
983 Iter *iter = (Iter *) node;
985 nodeHandleViewRule((Node **) (&(iter->iterexpr)),
987 rt_index, modified, sublevels_up);
992 ArrayRef *ref = (ArrayRef *) node;
994 nodeHandleViewRule((Node **) (&(ref->refupperindexpr)),
996 rt_index, modified, sublevels_up);
997 nodeHandleViewRule((Node **) (&(ref->reflowerindexpr)),
999 rt_index, modified, sublevels_up);
1000 nodeHandleViewRule((Node **) (&(ref->refexpr)),
1002 rt_index, modified, sublevels_up);
1003 nodeHandleViewRule((Node **) (&(ref->refassgnexpr)),
1005 rt_index, modified, sublevels_up);
1010 Var *var = (Var *) node;
1011 int this_varno = var->varno;
1012 int this_varlevelsup = var->varlevelsup;
1015 if (this_varno == rt_index &&
1016 this_varlevelsup == sublevels_up)
1018 n = FindMatchingTLEntry(targetlist,
1019 get_attname(getrelid(this_varno,
1023 *nodePtr = make_null(((Var *) node)->vartype);
1028 * This is a hack: The varlevelsup of the orignal
1029 * variable and the new one should be the same.
1030 * Normally we adapt the node by changing a
1031 * pointer to point to a var contained in
1032 * 'targetlist'. In the targetlist all
1033 * varlevelsups are 0 so if we want to change it
1034 * to the original value we have to copy the node
1035 * before! (Maybe this will cause troubles with
1036 * some sophisticated queries on views?)
1038 if (this_varlevelsup > 0)
1039 *nodePtr = copyObject(n);
1043 if (nodeTag(nodePtr) == T_Var)
1044 ((Var *) *nodePtr)->varlevelsup = this_varlevelsup;
1046 nodeHandleViewRule(&n, rtable, targetlist,
1047 rt_index, modified, sublevels_up);
1057 foreach(l, (List *) node)
1059 nodeHandleViewRule((Node **) (&(lfirst(l))),
1061 rt_index, modified, sublevels_up);
1067 SubLink *sublink = (SubLink *) node;
1068 Query *query = (Query *) sublink->subselect;
1073 nodeHandleViewRule((Node **) &(query->qual), rtable, targetlist,
1074 rt_index, modified, sublevels_up + 1);
1077 nodeHandleViewRule((Node **) &(query->havingQual), rtable, targetlist,
1078 rt_index, modified, sublevels_up + 1);
1079 nodeHandleViewRule((Node **) &(query->targetList), rtable, targetlist,
1080 rt_index, modified, sublevels_up + 1);
1084 * We also have to adapt the variables used in
1085 * sublink->lefthand and sublink->oper
1087 nodeHandleViewRule((Node **) &(sublink->lefthand), rtable,
1088 targetlist, rt_index, modified, sublevels_up);
1091 * Make sure the first argument of sublink->oper points to
1092 * the same var as sublink->lefthand does otherwise we
1093 * will run into troubles using aggregates (aggno will not
1096 pfree(lfirst(((Expr *) lfirst(sublink->oper))->args));
1097 lfirst(((Expr *) lfirst(sublink->oper))->args) =
1098 lfirst(sublink->lefthand);
1102 /* INTERSECT want's this - Jan */
1105 * tmp_lefthand = sublink->lefthand; foreach(tmp_oper,
1106 * sublink->oper) { lfirst(((Expr *)
1107 * lfirst(tmp_oper))->args) = lfirst(tmp_lefthand);
1108 * tmp_lefthand = lnext(tmp_lefthand); }
1113 /* ignore the others */
1119 HandleViewRule(Query *parsetree,
1125 nodeHandleViewRule(&parsetree->qual, rtable, targetlist, rt_index,
1127 nodeHandleViewRule((Node **) (&(parsetree->targetList)), rtable, targetlist,
1128 rt_index, modified, 0);
1131 * The variables in the havingQual and groupClause also have to be
1134 nodeHandleViewRule(&parsetree->havingQual, rtable, targetlist, rt_index,
1136 nodeHandleViewRule((Node **) (&(parsetree->groupClause)), rtable, targetlist, rt_index,