OSDN Git Service

Final cleanup.
[pg-rex/syncrep.git] / src / backend / rewrite / rewriteManip.c
1 /*-------------------------------------------------------------------------
2  *
3  * rewriteManip.c
4  *
5  * Copyright (c) 1994, Regents of the University of California
6  *
7  *
8  * IDENTIFICATION
9  *        $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteManip.c,v 1.37 1999/07/16 04:59:40 momjian Exp $
10  *
11  *-------------------------------------------------------------------------
12  */
13 #include <string.h>
14 #include "postgres.h"
15
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"
21
22 static void ResolveNew(RewriteInfo *info, List *targetlist,
23                    Node **node, int sublevels_up);
24
25
26 /*
27  * OffsetVarnodes -
28  */
29 void
30 OffsetVarNodes(Node *node, int offset, int sublevels_up)
31 {
32         if (node == NULL)
33                 return;
34
35         switch (nodeTag(node))
36         {
37                 case T_TargetEntry:
38                         {
39                                 TargetEntry *tle = (TargetEntry *) node;
40
41                                 OffsetVarNodes(
42                                                            (Node *) (tle->expr),
43                                                            offset,
44                                                            sublevels_up);
45                         }
46                         break;
47
48                 case T_Aggref:
49                         {
50                                 Aggref     *aggref = (Aggref *) node;
51
52                                 OffsetVarNodes(
53                                                            (Node *) (aggref->target),
54                                                            offset,
55                                                            sublevels_up);
56                         }
57                         break;
58
59                 case T_GroupClause:
60                         break;
61
62                 case T_Expr:
63                         {
64                                 Expr       *exp = (Expr *) node;
65
66                                 OffsetVarNodes(
67                                                            (Node *) (exp->args),
68                                                            offset,
69                                                            sublevels_up);
70                         }
71                         break;
72
73                 case T_Iter:
74                         {
75                                 Iter       *iter = (Iter *) node;
76
77                                 OffsetVarNodes(
78                                                            (Node *) (iter->iterexpr),
79                                                            offset,
80                                                            sublevels_up);
81                         }
82                         break;
83
84                 case T_ArrayRef:
85                         {
86                                 ArrayRef   *ref = (ArrayRef *) node;
87
88                                 OffsetVarNodes(
89                                                            (Node *) (ref->refupperindexpr),
90                                                            offset,
91                                                            sublevels_up);
92                                 OffsetVarNodes(
93                                                            (Node *) (ref->reflowerindexpr),
94                                                            offset,
95                                                            sublevels_up);
96                                 OffsetVarNodes(
97                                                            (Node *) (ref->refexpr),
98                                                            offset,
99                                                            sublevels_up);
100                                 OffsetVarNodes(
101                                                            (Node *) (ref->refassgnexpr),
102                                                            offset,
103                                                            sublevels_up);
104                         }
105                         break;
106
107                 case T_Var:
108                         {
109                                 Var                *var = (Var *) node;
110
111                                 if (var->varlevelsup == sublevels_up)
112                                 {
113                                         var->varno += offset;
114                                         var->varnoold += offset;
115                                 }
116                         }
117                         break;
118
119                 case T_Param:
120                         break;
121
122                 case T_Const:
123                         break;
124
125                 case T_List:
126                         {
127                                 List       *l;
128
129                                 foreach(l, (List *) node)
130                                         OffsetVarNodes(
131                                                                    (Node *) lfirst(l),
132                                                                    offset,
133                                                                    sublevels_up);
134                         }
135                         break;
136
137                 case T_SubLink:
138                         {
139                                 SubLink    *sub = (SubLink *) node;
140                                 List       *tmp_oper,
141                                                    *tmp_lefthand;
142
143                                 /*
144                                  * We also have to adapt the variables used in
145                                  * sub->lefthand and sub->oper
146                                  */
147                                 OffsetVarNodes(
148                                                            (Node *) (sub->lefthand),
149                                                            offset,
150                                                            sublevels_up);
151
152                                 OffsetVarNodes(
153                                                            (Node *) (sub->subselect),
154                                                            offset,
155                                                            sublevels_up + 1);
156
157                                 /*
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
161                                  * correctly)
162                                  */
163                                 tmp_lefthand = sub->lefthand;
164                                 foreach(tmp_oper, sub->oper)
165                                 {
166                                         lfirst(((Expr *) lfirst(tmp_oper))->args) =
167                                                 lfirst(tmp_lefthand);
168                                         tmp_lefthand = lnext(tmp_lefthand);
169                                 }
170                         }
171                         break;
172
173                 case T_Query:
174                         {
175                                 Query      *qry = (Query *) node;
176
177                                 OffsetVarNodes(
178                                                            (Node *) (qry->targetList),
179                                                            offset,
180                                                            sublevels_up);
181
182                                 OffsetVarNodes(
183                                                            (Node *) (qry->qual),
184                                                            offset,
185                                                            sublevels_up);
186
187                                 OffsetVarNodes(
188                                                            (Node *) (qry->havingQual),
189                                                            offset,
190                                                            sublevels_up);
191                         }
192                         break;
193
194                 case T_CaseExpr:
195                         {
196                                 CaseExpr   *exp = (CaseExpr *) node;
197
198                                 OffsetVarNodes(
199                                                            (Node *) (exp->args),
200                                                            offset,
201                                                            sublevels_up);
202
203                                 OffsetVarNodes(
204                                                            (Node *) (exp->defresult),
205                                                            offset,
206                                                            sublevels_up);
207                         }
208                         break;
209
210                 case T_CaseWhen:
211                         {
212                                 CaseWhen   *exp = (CaseWhen *) node;
213
214                                 OffsetVarNodes(
215                                                            (Node *) (exp->expr),
216                                                            offset,
217                                                            sublevels_up);
218
219                                 OffsetVarNodes(
220                                                            (Node *) (exp->result),
221                                                            offset,
222                                                            sublevels_up);
223                         }
224                         break;
225
226                 default:
227                         elog(NOTICE, "unknown node tag %d in OffsetVarNodes()", nodeTag(node));
228                         elog(NOTICE, "Node is: %s", nodeToString(node));
229                         break;
230
231
232         }
233 }
234
235
236 /*
237  * ChangeVarNodes -
238  */
239 void
240 ChangeVarNodes(Node *node, int rt_index, int new_index, int sublevels_up)
241 {
242         if (node == NULL)
243                 return;
244
245         switch (nodeTag(node))
246         {
247                 case T_TargetEntry:
248                         {
249                                 TargetEntry *tle = (TargetEntry *) node;
250
251                                 ChangeVarNodes(
252                                                            (Node *) (tle->expr),
253                                                            rt_index,
254                                                            new_index,
255                                                            sublevels_up);
256                         }
257                         break;
258
259                 case T_Aggref:
260                         {
261                                 Aggref     *aggref = (Aggref *) node;
262
263                                 ChangeVarNodes(
264                                                            (Node *) (aggref->target),
265                                                            rt_index,
266                                                            new_index,
267                                                            sublevels_up);
268                         }
269                         break;
270
271                 case T_GroupClause:
272                         break;
273
274                 case T_Expr:
275                         {
276                                 Expr       *exp = (Expr *) node;
277
278                                 ChangeVarNodes(
279                                                            (Node *) (exp->args),
280                                                            rt_index,
281                                                            new_index,
282                                                            sublevels_up);
283                         }
284                         break;
285
286                 case T_Iter:
287                         {
288                                 Iter       *iter = (Iter *) node;
289
290                                 ChangeVarNodes(
291                                                            (Node *) (iter->iterexpr),
292                                                            rt_index,
293                                                            new_index,
294                                                            sublevels_up);
295                         }
296                         break;
297
298                 case T_ArrayRef:
299                         {
300                                 ArrayRef   *ref = (ArrayRef *) node;
301
302                                 ChangeVarNodes(
303                                                            (Node *) (ref->refupperindexpr),
304                                                            rt_index,
305                                                            new_index,
306                                                            sublevels_up);
307                                 ChangeVarNodes(
308                                                            (Node *) (ref->reflowerindexpr),
309                                                            rt_index,
310                                                            new_index,
311                                                            sublevels_up);
312                                 ChangeVarNodes(
313                                                            (Node *) (ref->refexpr),
314                                                            rt_index,
315                                                            new_index,
316                                                            sublevels_up);
317                                 ChangeVarNodes(
318                                                            (Node *) (ref->refassgnexpr),
319                                                            rt_index,
320                                                            new_index,
321                                                            sublevels_up);
322                         }
323                         break;
324
325                 case T_Var:
326                         {
327                                 Var                *var = (Var *) node;
328
329                                 if (var->varlevelsup == sublevels_up &&
330                                         var->varno == rt_index)
331                                 {
332                                         var->varno = new_index;
333                                         var->varnoold = new_index;
334                                 }
335                         }
336                         break;
337
338                 case T_Param:
339                         break;
340
341                 case T_Const:
342                         break;
343
344                 case T_List:
345                         {
346                                 List       *l;
347
348                                 foreach(l, (List *) node)
349                                         ChangeVarNodes(
350                                                                    (Node *) lfirst(l),
351                                                                    rt_index,
352                                                                    new_index,
353                                                                    sublevels_up);
354                         }
355                         break;
356
357                 case T_SubLink:
358                         {
359                                 SubLink    *sub = (SubLink *) node;
360                                 List       *tmp_oper,
361                                                    *tmp_lefthand;
362
363                                 ChangeVarNodes(
364                                                            (Node *) (sub->lefthand),
365                                                            rt_index,
366                                                            new_index,
367                                                            sublevels_up);
368
369                                 ChangeVarNodes(
370                                                            (Node *) (sub->subselect),
371                                                            rt_index,
372                                                            new_index,
373                                                            sublevels_up + 1);
374
375                                 /*
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
379                                  * correctly)
380                                  */
381                                 tmp_lefthand = sub->lefthand;
382                                 foreach(tmp_oper, sub->oper)
383                                 {
384                                         lfirst(((Expr *) lfirst(tmp_oper))->args) =
385                                                 lfirst(tmp_lefthand);
386                                         tmp_lefthand = lnext(tmp_lefthand);
387                                 }
388                         }
389                         break;
390
391                 case T_Query:
392                         {
393                                 Query      *qry = (Query *) node;
394
395                                 ChangeVarNodes(
396                                                            (Node *) (qry->targetList),
397                                                            rt_index,
398                                                            new_index,
399                                                            sublevels_up);
400
401                                 ChangeVarNodes(
402                                                            (Node *) (qry->qual),
403                                                            rt_index,
404                                                            new_index,
405                                                            sublevels_up);
406
407                                 ChangeVarNodes(
408                                                            (Node *) (qry->havingQual),
409                                                            rt_index,
410                                                            new_index,
411                                                            sublevels_up);
412                         }
413                         break;
414
415                 case T_CaseExpr:
416                         {
417                                 CaseExpr   *exp = (CaseExpr *) node;
418
419                                 ChangeVarNodes(
420                                                            (Node *) (exp->args),
421                                                            rt_index,
422                                                            new_index,
423                                                            sublevels_up);
424
425                                 ChangeVarNodes(
426                                                            (Node *) (exp->defresult),
427                                                            rt_index,
428                                                            new_index,
429                                                            sublevels_up);
430                         }
431                         break;
432
433                 case T_CaseWhen:
434                         {
435                                 CaseWhen   *exp = (CaseWhen *) node;
436
437                                 ChangeVarNodes(
438                                                            (Node *) (exp->expr),
439                                                            rt_index,
440                                                            new_index,
441                                                            sublevels_up);
442
443                                 ChangeVarNodes(
444                                                            (Node *) (exp->result),
445                                                            rt_index,
446                                                            new_index,
447                                                            sublevels_up);
448                         }
449                         break;
450
451                 default:
452                         elog(NOTICE, "unknown node tag %d in ChangeVarNodes()", nodeTag(node));
453                         elog(NOTICE, "Node is: %s", nodeToString(node));
454                         break;
455
456
457         }
458 }
459
460
461
462 void
463 AddQual(Query *parsetree, Node *qual)
464 {
465         Node       *copy,
466                            *old;
467
468         if (qual == NULL)
469                 return;
470
471         /* INTERSECT want's the original, but we need to copy - Jan */
472         /* copy = qual; */
473         copy = copyObject(qual);
474
475         old = parsetree->qual;
476         if (old == NULL)
477                 parsetree->qual = copy;
478         else
479                 parsetree->qual = (Node *) make_andclause(makeList(parsetree->qual, copy, -1));
480 }
481
482 /* Adds the given havingQual to the one already contained in the parsetree just as
483  * AddQual does for the normal 'where' qual */
484 void
485 AddHavingQual(Query *parsetree, Node *havingQual)
486 {
487         Node       *copy,
488                            *old;
489
490         if (havingQual == NULL)
491                 return;
492
493         /* INTERSECT want's the original, but we need to copy - Jan */
494         /* copy = havingQual; */
495         copy = copyObject(havingQual);
496
497         old = parsetree->havingQual;
498         if (old == NULL)
499                 parsetree->havingQual = copy;
500         else
501                 parsetree->havingQual = (Node *) make_andclause(makeList(parsetree->havingQual, copy, -1));
502 }
503
504 #ifdef NOT_USED
505 void
506 AddNotHavingQual(Query *parsetree, Node *havingQual)
507 {
508         Node       *copy;
509
510         if (havingQual == NULL)
511                 return;
512
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));
516
517         AddHavingQual(parsetree, copy);
518 }
519 #endif
520
521 void
522 AddNotQual(Query *parsetree, Node *qual)
523 {
524         Node       *copy;
525
526         if (qual == NULL)
527                 return;
528
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));
532
533         AddQual(parsetree, copy);
534 }
535
536
537 void
538 AddGroupClause(Query *parsetree, List *group_by, List *tlist)
539 {
540         List       *l;
541         List       *tl;
542         GroupClause *groupclause;
543         TargetEntry *tle;
544         int                     new_resno;
545
546         new_resno = length(parsetree->targetList);
547
548         foreach(l, group_by)
549         {
550                 groupclause = (GroupClause *) copyObject(lfirst(l));
551                 tle = NULL;
552                 foreach(tl, tlist)
553                 {
554                         if (((TargetEntry *) lfirst(tl))->resdom->resgroupref ==
555                                 groupclause->tleGroupref)
556                         {
557                                 tle = (TargetEntry *) copyObject(lfirst(tl));
558                                 break;
559                         }
560                 }
561                 if (tle == NULL)
562                         elog(ERROR, "AddGroupClause(): GROUP BY entry not found in rules targetlist");
563
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;
568
569                 parsetree->targetList = lappend(parsetree->targetList, tle);
570                 parsetree->groupClause = lappend(parsetree->groupClause, groupclause);
571         }
572 }
573
574 static Node *
575 make_null(Oid type)
576 {
577         Const      *c = makeNode(Const);
578
579         c->consttype = type;
580         c->constlen = get_typlen(type);
581         c->constvalue = PointerGetDatum(NULL);
582         c->constisnull = true;
583         c->constbyval = get_typbyval(type);
584         return (Node *) c;
585 }
586
587 #ifdef NOT_USED
588 void
589 FixResdomTypes(List *tlist)
590 {
591         List       *i;
592
593         foreach(i, tlist)
594         {
595                 TargetEntry *tle = lfirst(i);
596
597                 if (nodeTag(tle->expr) == T_Var)
598                 {
599                         Var                *var = (Var *) tle->expr;
600
601                         tle->resdom->restype = var->vartype;
602                         tle->resdom->restypmod = var->vartypmod;
603                 }
604         }
605 }
606
607 #endif
608
609 static Node *
610 FindMatchingNew(List *tlist, int attno)
611 {
612         List       *i;
613
614         foreach(i, tlist)
615         {
616                 TargetEntry *tle = lfirst(i);
617
618                 if (tle->resdom->resno == attno)
619                         return tle->expr;
620         }
621         return NULL;
622 }
623
624 static Node *
625 FindMatchingTLEntry(List *tlist, char *e_attname)
626 {
627         List       *i;
628
629         foreach(i, tlist)
630         {
631                 TargetEntry *tle = lfirst(i);
632                 char       *resname;
633
634                 resname = tle->resdom->resname;
635                 if (!strcmp(e_attname, resname))
636                         return tle->expr;
637         }
638         return NULL;
639 }
640
641 static void
642 ResolveNew(RewriteInfo *info, List *targetlist, Node **nodePtr,
643                    int sublevels_up)
644 {
645         Node       *node = *nodePtr;
646
647         if (node == NULL)
648                 return;
649
650         switch (nodeTag(node))
651         {
652                 case T_TargetEntry:
653                         ResolveNew(info, targetlist, &((TargetEntry *) node)->expr,
654                                            sublevels_up);
655                         break;
656                 case T_Aggref:
657                         ResolveNew(info, targetlist, &((Aggref *) node)->target,
658                                            sublevels_up);
659                         break;
660                 case T_Expr:
661                         ResolveNew(info, targetlist, (Node **) (&(((Expr *) node)->args)),
662                                            sublevels_up);
663                         break;
664                 case T_Iter:
665                         ResolveNew(info, targetlist, (Node **) (&(((Iter *) node)->iterexpr)),
666                                            sublevels_up);
667                         break;
668                 case T_ArrayRef:
669                         ResolveNew(info, targetlist, (Node **) (&(((ArrayRef *) node)->refupperindexpr)),
670                                            sublevels_up);
671                         ResolveNew(info, targetlist, (Node **) (&(((ArrayRef *) node)->reflowerindexpr)),
672                                            sublevels_up);
673                         ResolveNew(info, targetlist, (Node **) (&(((ArrayRef *) node)->refexpr)),
674                                            sublevels_up);
675                         ResolveNew(info, targetlist, (Node **) (&(((ArrayRef *) node)->refassgnexpr)),
676                                            sublevels_up);
677                         break;
678                 case T_Var:
679                         {
680                                 int                     this_varno = (int) ((Var *) node)->varno;
681                                 int                     this_varlevelsup = (int) ((Var *) node)->varlevelsup;
682                                 Node       *n;
683
684                                 if (this_varno == info->new_varno &&
685                                         this_varlevelsup == sublevels_up)
686                                 {
687                                         n = FindMatchingNew(targetlist,
688                                                                                 ((Var *) node)->varattno);
689                                         if (n == NULL)
690                                         {
691                                                 if (info->event == CMD_UPDATE)
692                                                 {
693                                                         *nodePtr = n = copyObject(node);
694                                                         ((Var *) n)->varno = info->current_varno;
695                                                         ((Var *) n)->varnoold = info->current_varno;
696                                                 }
697                                                 else
698                                                         *nodePtr = make_null(((Var *) node)->vartype);
699                                         }
700                                         else
701                                         {
702                                                 *nodePtr = copyObject(n);
703                                                 ((Var *) *nodePtr)->varlevelsup = this_varlevelsup;
704                                         }
705                                 }
706                                 break;
707                         }
708                 case T_List:
709                         {
710                                 List       *l;
711
712                                 foreach(l, (List *) node)
713                                         ResolveNew(info, targetlist, (Node **) &(lfirst(l)),
714                                                            sublevels_up);
715                                 break;
716                         }
717                 case T_SubLink:
718                         {
719                                 SubLink    *sublink = (SubLink *) node;
720                                 Query      *query = (Query *) sublink->subselect;
721
722                                 ResolveNew(info, targetlist, (Node **) &(query->qual), sublevels_up + 1);
723                         }
724                         break;
725                 case T_GroupClause:
726                         break;
727                 default:
728                         /* ignore the others */
729                         break;
730         }
731 }
732
733 void
734 FixNew(RewriteInfo *info, Query *parsetree)
735 {
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);
742 }
743
744 static void
745 nodeHandleRIRAttributeRule(Node **nodePtr,
746                                                    List *rtable,
747                                                    List *targetlist,
748                                                    int rt_index,
749                                                    int attr_num,
750                                                    int *modified,
751                                                    int *badsql,
752                                                    int sublevels_up)
753 {
754         Node       *node = *nodePtr;
755
756         if (node == NULL)
757                 return;
758         switch (nodeTag(node))
759         {
760                 case T_TargetEntry:
761                         {
762                                 TargetEntry *tle = (TargetEntry *) node;
763
764                                 nodeHandleRIRAttributeRule(&tle->expr, rtable, targetlist,
765                                                                         rt_index, attr_num, modified, badsql,
766                                                                                    sublevels_up);
767                         }
768                         break;
769                 case T_Aggref:
770                         {
771                                 Aggref     *aggref = (Aggref *) node;
772
773                                 nodeHandleRIRAttributeRule(&aggref->target, rtable, targetlist,
774                                                                         rt_index, attr_num, modified, badsql,
775                                                                                    sublevels_up);
776                         }
777                         break;
778                 case T_Expr:
779                         {
780                                 Expr       *expr = (Expr *) node;
781
782                                 nodeHandleRIRAttributeRule((Node **) (&(expr->args)), rtable,
783                                                                                    targetlist, rt_index, attr_num,
784                                                                                    modified, badsql,
785                                                                                    sublevels_up);
786                         }
787                         break;
788                 case T_Iter:
789                         {
790                                 Iter       *iter = (Iter *) node;
791
792                                 nodeHandleRIRAttributeRule((Node **) (&(iter->iterexpr)), rtable,
793                                                                                    targetlist, rt_index, attr_num,
794                                                                                    modified, badsql,
795                                                                                    sublevels_up);
796                         }
797                         break;
798                 case T_ArrayRef:
799                         {
800                                 ArrayRef   *ref = (ArrayRef *) node;
801
802                                 nodeHandleRIRAttributeRule((Node **) (&(ref->refupperindexpr)), rtable,
803                                                                                    targetlist, rt_index, attr_num,
804                                                                                    modified, badsql,
805                                                                                    sublevels_up);
806                                 nodeHandleRIRAttributeRule((Node **) (&(ref->reflowerindexpr)), rtable,
807                                                                                    targetlist, rt_index, attr_num,
808                                                                                    modified, badsql,
809                                                                                    sublevels_up);
810                                 nodeHandleRIRAttributeRule((Node **) (&(ref->refexpr)), rtable,
811                                                                                    targetlist, rt_index, attr_num,
812                                                                                    modified, badsql,
813                                                                                    sublevels_up);
814                                 nodeHandleRIRAttributeRule((Node **) (&(ref->refassgnexpr)), rtable,
815                                                                                    targetlist, rt_index, attr_num,
816                                                                                    modified, badsql,
817                                                                                    sublevels_up);
818                         }
819                         break;
820                 case T_Var:
821                         {
822                                 int                     this_varno = ((Var *) node)->varno;
823                                 int                     this_varattno = ((Var *) node)->varattno;
824                                 int                     this_varlevelsup = ((Var *) node)->varlevelsup;
825
826                                 if (this_varno == rt_index &&
827                                         this_varattno == attr_num &&
828                                         this_varlevelsup == sublevels_up)
829                                 {
830                                         if (((Var *) node)->vartype == 32)
831                                         {                       /* HACK */
832                                                 *nodePtr = make_null(((Var *) node)->vartype);
833                                                 *modified = TRUE;
834                                                 *badsql = TRUE;
835                                                 break;
836                                         }
837                                         else
838                                         {
839                                                 NameData        name_to_look_for;
840
841                                                 name_to_look_for.data[0] = '\0';
842                                                 namestrcpy(&name_to_look_for,
843                                                                 (char *) get_attname(getrelid(this_varno,
844                                                                                                                           rtable),
845                                                                                                          attr_num));
846                                                 if (name_to_look_for.data[0])
847                                                 {
848                                                         Node       *n;
849
850                                                         n = FindMatchingTLEntry(targetlist, (char *) &name_to_look_for);
851                                                         if (n == NULL)
852                                                                 *nodePtr = make_null(((Var *) node)->vartype);
853                                                         else
854                                                                 *nodePtr = n;
855                                                         *modified = TRUE;
856                                                 }
857                                         }
858                                 }
859                         }
860                         break;
861                 case T_List:
862                         {
863                                 List       *i;
864
865                                 foreach(i, (List *) node)
866                                 {
867                                         nodeHandleRIRAttributeRule((Node **) (&(lfirst(i))), rtable,
868                                                                                   targetlist, rt_index, attr_num,
869                                                                                  modified, badsql, sublevels_up);
870                                 }
871                         }
872                         break;
873                 case T_SubLink:
874                         {
875                                 SubLink    *sublink = (SubLink *) node;
876                                 Query      *query = (Query *) sublink->subselect;
877
878                                 nodeHandleRIRAttributeRule((Node **) &(query->qual), rtable, targetlist,
879                                                                         rt_index, attr_num, modified, badsql,
880                                                                                    sublevels_up + 1);
881                         }
882                         break;
883                 default:
884                         /* ignore the others */
885                         break;
886         }
887 }
888
889 /*
890  * Handles 'on retrieve to relation.attribute
891  *                      do instead retrieve (attribute = expression) w/qual'
892  */
893 void
894 HandleRIRAttributeRule(Query *parsetree,
895                                            List *rtable,
896                                            List *targetlist,
897                                            int rt_index,
898                                            int attr_num,
899                                            int *modified,
900                                            int *badsql)
901 {
902
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);
908 }
909
910 #ifdef NOT_USED
911 static void
912 nodeHandleViewRule(Node **nodePtr,
913                                    List *rtable,
914                                    List *targetlist,
915                                    int rt_index,
916                                    int *modified,
917                                    int sublevels_up)
918 {
919         Node       *node = *nodePtr;
920
921         if (node == NULL)
922                 return;
923
924         switch (nodeTag(node))
925         {
926                 case T_TargetEntry:
927                         {
928                                 TargetEntry *tle = (TargetEntry *) node;
929
930                                 nodeHandleViewRule(&(tle->expr), rtable, targetlist,
931                                                                    rt_index, modified, sublevels_up);
932                         }
933                         break;
934                 case T_Aggref:
935                         {
936                                 Aggref     *aggref = (Aggref *) node;
937
938                                 nodeHandleViewRule(&(aggref->target), rtable, targetlist,
939                                                                    rt_index, modified, sublevels_up);
940                         }
941                         break;
942
943                         /*
944                          * This has to be done to make queries using groupclauses work
945                          * on views
946                          */
947                 case T_GroupClause:
948                         {
949                                 GroupClause *group = (GroupClause *) node;
950
951                                 nodeHandleViewRule((Node **) (&(group->entry)), rtable, targetlist,
952                                                                    rt_index, modified, sublevels_up);
953                         }
954                         break;
955                 case T_Expr:
956                         {
957                                 Expr       *expr = (Expr *) node;
958
959                                 nodeHandleViewRule((Node **) (&(expr->args)),
960                                                                    rtable, targetlist,
961                                                                    rt_index, modified, sublevels_up);
962                         }
963                         break;
964                 case T_Iter:
965                         {
966                                 Iter       *iter = (Iter *) node;
967
968                                 nodeHandleViewRule((Node **) (&(iter->iterexpr)),
969                                                                    rtable, targetlist,
970                                                                    rt_index, modified, sublevels_up);
971                         }
972                         break;
973                 case T_ArrayRef:
974                         {
975                                 ArrayRef   *ref = (ArrayRef *) node;
976
977                                 nodeHandleViewRule((Node **) (&(ref->refupperindexpr)),
978                                                                    rtable, targetlist,
979                                                                    rt_index, modified, sublevels_up);
980                                 nodeHandleViewRule((Node **) (&(ref->reflowerindexpr)),
981                                                                    rtable, targetlist,
982                                                                    rt_index, modified, sublevels_up);
983                                 nodeHandleViewRule((Node **) (&(ref->refexpr)),
984                                                                    rtable, targetlist,
985                                                                    rt_index, modified, sublevels_up);
986                                 nodeHandleViewRule((Node **) (&(ref->refassgnexpr)),
987                                                                    rtable, targetlist,
988                                                                    rt_index, modified, sublevels_up);
989                         }
990                         break;
991                 case T_Var:
992                         {
993                                 Var                *var = (Var *) node;
994                                 int                     this_varno = var->varno;
995                                 int                     this_varlevelsup = var->varlevelsup;
996                                 Node       *n;
997
998                                 if (this_varno == rt_index &&
999                                         this_varlevelsup == sublevels_up)
1000                                 {
1001                                         n = FindMatchingTLEntry(targetlist,
1002                                                                                  get_attname(getrelid(this_varno,
1003                                                                                                                           rtable),
1004                                                                                                          var->varattno));
1005                                         if (n == NULL)
1006                                                 *nodePtr = make_null(((Var *) node)->vartype);
1007                                         else
1008                                         {
1009
1010                                                 /*
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?)
1020                                                  */
1021                                                 if (this_varlevelsup > 0)
1022                                                         *nodePtr = copyObject(n);
1023                                                 else
1024                                                         *nodePtr = n;
1025
1026                                                 if (nodeTag(nodePtr) == T_Var)
1027                                                         ((Var *) *nodePtr)->varlevelsup = this_varlevelsup;
1028                                                 else
1029                                                         nodeHandleViewRule(&n, rtable, targetlist,
1030                                                                            rt_index, modified, sublevels_up);
1031                                         }
1032                                         *modified = TRUE;
1033                                 }
1034                                 break;
1035                         }
1036                 case T_List:
1037                         {
1038                                 List       *l;
1039
1040                                 foreach(l, (List *) node)
1041                                 {
1042                                         nodeHandleViewRule((Node **) (&(lfirst(l))),
1043                                                                            rtable, targetlist,
1044                                                                            rt_index, modified, sublevels_up);
1045                                 }
1046                         }
1047                         break;
1048                 case T_SubLink:
1049                         {
1050                                 SubLink    *sublink = (SubLink *) node;
1051                                 Query      *query = (Query *) sublink->subselect;
1052                                 List       *tmp_lefthand,
1053                                                    *tmp_oper;
1054
1055
1056                                 nodeHandleViewRule((Node **) &(query->qual), rtable, targetlist,
1057                                                                    rt_index, modified, sublevels_up + 1);
1058
1059                                 /***S*H*D***/
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);
1064
1065
1066                                 /*
1067                                  * We also have to adapt the variables used in
1068                                  * sublink->lefthand and sublink->oper
1069                                  */
1070                                 nodeHandleViewRule((Node **) &(sublink->lefthand), rtable,
1071                                                    targetlist, rt_index, modified, sublevels_up);
1072
1073                                 /*
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
1077                                  * be set correctly
1078                                  */
1079                                 pfree(lfirst(((Expr *) lfirst(sublink->oper))->args));
1080                                 lfirst(((Expr *) lfirst(sublink->oper))->args) =
1081                                         lfirst(sublink->lefthand);
1082
1083
1084                                 /* INTERSECT want's this - Jan */
1085
1086                                 /*
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); }
1091                                  */
1092                         }
1093                         break;
1094                 default:
1095                         /* ignore the others */
1096                         break;
1097         }
1098 }
1099
1100 void
1101 HandleViewRule(Query *parsetree,
1102                            List *rtable,
1103                            List *targetlist,
1104                            int rt_index,
1105                            int *modified)
1106 {
1107         nodeHandleViewRule(&parsetree->qual, rtable, targetlist, rt_index,
1108                                            modified, 0);
1109         nodeHandleViewRule((Node **) (&(parsetree->targetList)), rtable, targetlist,
1110                                            rt_index, modified, 0);
1111
1112         /*
1113          * The variables in the havingQual and groupClause also have to be
1114          * adapted
1115          */
1116         nodeHandleViewRule(&parsetree->havingQual, rtable, targetlist, rt_index,
1117                                            modified, 0);
1118         nodeHandleViewRule((Node **) (&(parsetree->groupClause)), rtable, targetlist, rt_index,
1119                                            modified, 0);
1120 }
1121
1122 #endif