OSDN Git Service

Subselects in FROM clause, per ISO syntax: FROM (SELECT ...) [AS] alias.
[pg-rex/syncrep.git] / src / backend / rewrite / rewriteManip.c
1 /*-------------------------------------------------------------------------
2  *
3  * rewriteManip.c
4  *
5  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
6  * Portions Copyright (c) 1994, Regents of the University of California
7  *
8  *
9  * IDENTIFICATION
10  *        $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteManip.c,v 1.49 2000/09/29 18:21:24 tgl Exp $
11  *
12  *-------------------------------------------------------------------------
13  */
14 #include "postgres.h"
15
16 #include "optimizer/clauses.h"
17 #include "optimizer/tlist.h"
18 #include "parser/parsetree.h"
19 #include "parser/parse_clause.h"
20 #include "rewrite/rewriteManip.h"
21 #include "utils/lsyscache.h"
22
23
24 /* macros borrowed from expression_tree_mutator */
25
26 #define FLATCOPY(newnode, node, nodetype)  \
27         ( (newnode) = makeNode(nodetype), \
28           memcpy((newnode), (node), sizeof(nodetype)) )
29
30 #define MUTATE(newfield, oldfield, fieldtype, mutator, context)  \
31                 ( (newfield) = (fieldtype) mutator((Node *) (oldfield), (context)) )
32
33 static bool checkExprHasAggs_walker(Node *node, void *context);
34 static bool checkExprHasSubLink_walker(Node *node, void *context);
35
36
37 /*
38  * checkExprHasAggs -
39  *      Queries marked hasAggs might not have them any longer after
40  *      rewriting. Check it.
41  */
42 bool
43 checkExprHasAggs(Node *node)
44 {
45         /*
46          * If a Query is passed, examine it --- but we will not recurse
47          * into sub-Queries.
48          */
49         if (node && IsA(node, Query))
50                 return query_tree_walker((Query *) node, checkExprHasAggs_walker,
51                                                                  NULL);
52         else
53                 return checkExprHasAggs_walker(node, NULL);
54 }
55
56 static bool
57 checkExprHasAggs_walker(Node *node, void *context)
58 {
59         if (node == NULL)
60                 return false;
61         if (IsA(node, Aggref))
62                 return true;                    /* abort the tree traversal and return
63                                                                  * true */
64         return expression_tree_walker(node, checkExprHasAggs_walker, context);
65 }
66
67 /*
68  * checkExprHasSubLink -
69  *      Queries marked hasSubLinks might not have them any longer after
70  *      rewriting. Check it.
71  */
72 bool
73 checkExprHasSubLink(Node *node)
74 {
75         /*
76          * If a Query is passed, examine it --- but we will not recurse
77          * into sub-Queries.
78          */
79         if (node && IsA(node, Query))
80                 return query_tree_walker((Query *) node, checkExprHasSubLink_walker,
81                                                                  NULL);
82         else
83                 return checkExprHasSubLink_walker(node, NULL);
84 }
85
86 static bool
87 checkExprHasSubLink_walker(Node *node, void *context)
88 {
89         if (node == NULL)
90                 return false;
91         if (IsA(node, SubLink))
92                 return true;                    /* abort the tree traversal and return
93                                                                  * true */
94         return expression_tree_walker(node, checkExprHasSubLink_walker, context);
95 }
96
97
98 /*
99  * OffsetVarNodes - adjust Vars when appending one query's RT to another
100  *
101  * Find all Var nodes in the given tree with varlevelsup == sublevels_up,
102  * and increment their varno fields (rangetable indexes) by 'offset'.
103  * The varnoold fields are adjusted similarly.  Also, RangeTblRef nodes
104  * in join trees are adjusted.
105  *
106  * NOTE: although this has the form of a walker, we cheat and modify the
107  * nodes in-place.      The given expression tree should have been copied
108  * earlier to ensure that no unwanted side-effects occur!
109  */
110
111 typedef struct
112 {
113         int                     offset;
114         int                     sublevels_up;
115 } OffsetVarNodes_context;
116
117 static bool
118 OffsetVarNodes_walker(Node *node, OffsetVarNodes_context *context)
119 {
120         if (node == NULL)
121                 return false;
122         if (IsA(node, Var))
123         {
124                 Var                *var = (Var *) node;
125
126                 if (var->varlevelsup == context->sublevels_up)
127                 {
128                         var->varno += context->offset;
129                         var->varnoold += context->offset;
130                 }
131                 return false;
132         }
133         if (IsA(node, RangeTblRef))
134         {
135                 RangeTblRef        *rtr = (RangeTblRef *) node;
136
137                 if (context->sublevels_up == 0)
138                         rtr->rtindex += context->offset;
139                 return false;
140         }
141         if (IsA(node, Query))
142         {
143                 /* Recurse into subselects */
144                 bool            result;
145
146                 context->sublevels_up++;
147                 result = query_tree_walker((Query *) node, OffsetVarNodes_walker,
148                                                                    (void *) context);
149                 context->sublevels_up--;
150                 return result;
151         }
152         return expression_tree_walker(node, OffsetVarNodes_walker,
153                                                                   (void *) context);
154 }
155
156 void
157 OffsetVarNodes(Node *node, int offset, int sublevels_up)
158 {
159         OffsetVarNodes_context context;
160
161         context.offset = offset;
162         context.sublevels_up = sublevels_up;
163
164         /*
165          * Must be prepared to start with a Query or a bare expression tree;
166          * if it's a Query, go straight to query_tree_walker to make sure that
167          * sublevels_up doesn't get incremented prematurely.
168          */
169         if (node && IsA(node, Query))
170                 query_tree_walker((Query *) node, OffsetVarNodes_walker,
171                                                   (void *) &context);
172         else
173                 OffsetVarNodes_walker(node, &context);
174 }
175
176 /*
177  * ChangeVarNodes - adjust Var nodes for a specific change of RT index
178  *
179  * Find all Var nodes in the given tree belonging to a specific relation
180  * (identified by sublevels_up and rt_index), and change their varno fields
181  * to 'new_index'.      The varnoold fields are changed too.  Also, RangeTblRef
182  * nodes in join trees are adjusted.
183  *
184  * NOTE: although this has the form of a walker, we cheat and modify the
185  * nodes in-place.      The given expression tree should have been copied
186  * earlier to ensure that no unwanted side-effects occur!
187  */
188
189 typedef struct
190 {
191         int                     rt_index;
192         int                     new_index;
193         int                     sublevels_up;
194 } ChangeVarNodes_context;
195
196 static bool
197 ChangeVarNodes_walker(Node *node, ChangeVarNodes_context *context)
198 {
199         if (node == NULL)
200                 return false;
201         if (IsA(node, Var))
202         {
203                 Var                *var = (Var *) node;
204
205                 if (var->varlevelsup == context->sublevels_up &&
206                         var->varno == context->rt_index)
207                 {
208                         var->varno = context->new_index;
209                         var->varnoold = context->new_index;
210                 }
211                 return false;
212         }
213         if (IsA(node, RangeTblRef))
214         {
215                 RangeTblRef        *rtr = (RangeTblRef *) node;
216
217                 if (context->sublevels_up == 0 &&
218                         rtr->rtindex == context->rt_index)
219                         rtr->rtindex = context->new_index;
220                 return false;
221         }
222         if (IsA(node, Query))
223         {
224                 /* Recurse into subselects */
225                 bool            result;
226
227                 context->sublevels_up++;
228                 result = query_tree_walker((Query *) node, ChangeVarNodes_walker,
229                                                                    (void *) context);
230                 context->sublevels_up--;
231                 return result;
232         }
233         return expression_tree_walker(node, ChangeVarNodes_walker,
234                                                                   (void *) context);
235 }
236
237 void
238 ChangeVarNodes(Node *node, int rt_index, int new_index, int sublevels_up)
239 {
240         ChangeVarNodes_context context;
241
242         context.rt_index = rt_index;
243         context.new_index = new_index;
244         context.sublevels_up = sublevels_up;
245
246         /*
247          * Must be prepared to start with a Query or a bare expression tree;
248          * if it's a Query, go straight to query_tree_walker to make sure that
249          * sublevels_up doesn't get incremented prematurely.
250          */
251         if (node && IsA(node, Query))
252                 query_tree_walker((Query *) node, ChangeVarNodes_walker,
253                                                   (void *) &context);
254         else
255                 ChangeVarNodes_walker(node, &context);
256 }
257
258 /*
259  * IncrementVarSublevelsUp - adjust Var nodes when pushing them down in tree
260  *
261  * Find all Var nodes in the given tree having varlevelsup >= min_sublevels_up,
262  * and add delta_sublevels_up to their varlevelsup value.  This is needed when
263  * an expression that's correct for some nesting level is inserted into a
264  * subquery.  Ordinarily the initial call has min_sublevels_up == 0 so that
265  * all Vars are affected.  The point of min_sublevels_up is that we can
266  * increment it when we recurse into a sublink, so that local variables in
267  * that sublink are not affected, only outer references to vars that belong
268  * to the expression's original query level or parents thereof.
269  *
270  * NOTE: although this has the form of a walker, we cheat and modify the
271  * Var nodes in-place.  The given expression tree should have been copied
272  * earlier to ensure that no unwanted side-effects occur!
273  */
274
275 typedef struct
276 {
277         int                     delta_sublevels_up;
278         int                     min_sublevels_up;
279 } IncrementVarSublevelsUp_context;
280
281 static bool
282 IncrementVarSublevelsUp_walker(Node *node,
283                                                            IncrementVarSublevelsUp_context *context)
284 {
285         if (node == NULL)
286                 return false;
287         if (IsA(node, Var))
288         {
289                 Var                *var = (Var *) node;
290
291                 if (var->varlevelsup >= context->min_sublevels_up)
292                         var->varlevelsup += context->delta_sublevels_up;
293                 return false;
294         }
295         if (IsA(node, Query))
296         {
297                 /* Recurse into subselects */
298                 bool            result;
299
300                 context->min_sublevels_up++;
301                 result = query_tree_walker((Query *) node,
302                                                                    IncrementVarSublevelsUp_walker,
303                                                                    (void *) context);
304                 context->min_sublevels_up--;
305                 return result;
306         }
307         return expression_tree_walker(node, IncrementVarSublevelsUp_walker,
308                                                                   (void *) context);
309 }
310
311 void
312 IncrementVarSublevelsUp(Node *node, int delta_sublevels_up,
313                                                 int min_sublevels_up)
314 {
315         IncrementVarSublevelsUp_context context;
316
317         context.delta_sublevels_up = delta_sublevels_up;
318         context.min_sublevels_up = min_sublevels_up;
319
320         /*
321          * Must be prepared to start with a Query or a bare expression tree;
322          * if it's a Query, go straight to query_tree_walker to make sure that
323          * sublevels_up doesn't get incremented prematurely.
324          */
325         if (node && IsA(node, Query))
326                 query_tree_walker((Query *) node, IncrementVarSublevelsUp_walker,
327                                                   (void *) &context);
328         else
329                 IncrementVarSublevelsUp_walker(node, &context);
330 }
331
332
333 /*
334  * rangeTableEntry_used - detect whether an RTE is referenced somewhere
335  *      in var nodes or jointree nodes of a query or expression.
336  */
337
338 typedef struct
339 {
340         int                     rt_index;
341         int                     sublevels_up;
342 } rangeTableEntry_used_context;
343
344 static bool
345 rangeTableEntry_used_walker(Node *node,
346                                                         rangeTableEntry_used_context *context)
347 {
348         if (node == NULL)
349                 return false;
350         if (IsA(node, Var))
351         {
352                 Var                *var = (Var *) node;
353
354                 if (var->varlevelsup == context->sublevels_up &&
355                         var->varno == context->rt_index)
356                         return true;
357                 return false;
358         }
359         if (IsA(node, RangeTblRef))
360         {
361                 RangeTblRef *rtr = (RangeTblRef *) node;
362
363                 if (rtr->rtindex == context->rt_index &&
364                         context->sublevels_up == 0)
365                         return true;
366                 return false;
367         }
368         if (IsA(node, Query))
369         {
370                 /* Recurse into subselects */
371                 bool            result;
372
373                 context->sublevels_up++;
374                 result = query_tree_walker((Query *) node, rangeTableEntry_used_walker,
375                                                                    (void *) context);
376                 context->sublevels_up--;
377                 return result;
378         }
379         return expression_tree_walker(node, rangeTableEntry_used_walker,
380                                                                   (void *) context);
381 }
382
383 bool
384 rangeTableEntry_used(Node *node, int rt_index, int sublevels_up)
385 {
386         rangeTableEntry_used_context context;
387
388         context.rt_index = rt_index;
389         context.sublevels_up = sublevels_up;
390
391         /*
392          * Must be prepared to start with a Query or a bare expression tree;
393          * if it's a Query, go straight to query_tree_walker to make sure that
394          * sublevels_up doesn't get incremented prematurely.
395          */
396         if (node && IsA(node, Query))
397                 return query_tree_walker((Query *) node, rangeTableEntry_used_walker,
398                                                                  (void *) &context);
399         else
400                 return rangeTableEntry_used_walker(node, &context);
401 }
402
403
404 /*
405  * attribute_used -
406  *      Check if a specific attribute number of a RTE is used
407  *      somewhere in the query or expression.
408  */
409
410 typedef struct
411 {
412         int                     rt_index;
413         int                     attno;
414         int                     sublevels_up;
415 } attribute_used_context;
416
417 static bool
418 attribute_used_walker(Node *node,
419                                           attribute_used_context *context)
420 {
421         if (node == NULL)
422                 return false;
423         if (IsA(node, Var))
424         {
425                 Var                *var = (Var *) node;
426
427                 if (var->varlevelsup == context->sublevels_up &&
428                         var->varno == context->rt_index &&
429                         var->varattno == context->attno)
430                         return true;
431                 return false;
432         }
433         if (IsA(node, Query))
434         {
435                 /* Recurse into subselects */
436                 bool            result;
437
438                 context->sublevels_up++;
439                 result = query_tree_walker((Query *) node, attribute_used_walker,
440                                                                    (void *) context);
441                 context->sublevels_up--;
442                 return result;
443         }
444         return expression_tree_walker(node, attribute_used_walker,
445                                                                   (void *) context);
446 }
447
448 bool
449 attribute_used(Node *node, int rt_index, int attno, int sublevels_up)
450 {
451         attribute_used_context context;
452
453         context.rt_index = rt_index;
454         context.attno = attno;
455         context.sublevels_up = sublevels_up;
456
457         /*
458          * Must be prepared to start with a Query or a bare expression tree;
459          * if it's a Query, go straight to query_tree_walker to make sure that
460          * sublevels_up doesn't get incremented prematurely.
461          */
462         if (node && IsA(node, Query))
463                 return query_tree_walker((Query *) node, attribute_used_walker,
464                                                                  (void *) &context);
465         else
466                 return attribute_used_walker(node, &context);
467 }
468
469
470 /*
471  * Add the given qualifier condition to the query's WHERE clause
472  */
473 void
474 AddQual(Query *parsetree, Node *qual)
475 {
476         Node       *copy;
477
478         if (qual == NULL)
479                 return;
480
481         /* INTERSECT want's the original, but we need to copy - Jan */
482         copy = copyObject(qual);
483
484         parsetree->jointree->quals = make_and_qual(parsetree->jointree->quals,
485                                                                                            copy);
486
487         /*
488          * Make sure query is marked correctly if added qual has sublinks or
489          * aggregates (not sure it can ever have aggs, but sublinks
490          * definitely).
491          */
492         parsetree->hasAggs |= checkExprHasAggs(copy);
493         parsetree->hasSubLinks |= checkExprHasSubLink(copy);
494 }
495
496 /*
497  * Add the given havingQual to the one already contained in the parsetree
498  * just as AddQual does for the normal 'where' qual
499  */
500 void
501 AddHavingQual(Query *parsetree, Node *havingQual)
502 {
503         Node       *copy;
504
505         if (havingQual == NULL)
506                 return;
507
508         /* INTERSECT want's the original, but we need to copy - Jan */
509         copy = copyObject(havingQual);
510
511         parsetree->havingQual = make_and_qual(parsetree->havingQual,
512                                                                                   copy);
513
514         /*
515          * Make sure query is marked correctly if added qual has sublinks or
516          * aggregates (not sure it can ever have aggs, but sublinks
517          * definitely).
518          */
519         parsetree->hasAggs |= checkExprHasAggs(copy);
520         parsetree->hasSubLinks |= checkExprHasSubLink(copy);
521 }
522
523 #ifdef NOT_USED
524 void
525 AddNotHavingQual(Query *parsetree, Node *havingQual)
526 {
527         Node       *notqual;
528
529         if (havingQual == NULL)
530                 return;
531
532         /* Need not copy input qual, because AddHavingQual will... */
533         notqual = (Node *) make_notclause((Expr *) havingQual);
534
535         AddHavingQual(parsetree, notqual);
536 }
537
538 #endif
539
540 void
541 AddNotQual(Query *parsetree, Node *qual)
542 {
543         Node       *notqual;
544
545         if (qual == NULL)
546                 return;
547
548         /* Need not copy input qual, because AddQual will... */
549         notqual = (Node *) make_notclause((Expr *) qual);
550
551         AddQual(parsetree, notqual);
552 }
553
554
555 /* Build a NULL constant expression of the given type */
556 static Node *
557 make_null(Oid type)
558 {
559         Const      *c = makeNode(Const);
560
561         c->consttype = type;
562         c->constlen = get_typlen(type);
563         c->constvalue = PointerGetDatum(NULL);
564         c->constisnull = true;
565         c->constbyval = get_typbyval(type);
566         return (Node *) c;
567 }
568
569 /* Find a targetlist entry by resno */
570 static Node *
571 FindMatchingNew(List *tlist, int attno)
572 {
573         List       *i;
574
575         foreach(i, tlist)
576         {
577                 TargetEntry *tle = lfirst(i);
578
579                 if (tle->resdom->resno == attno)
580                         return tle->expr;
581         }
582         return NULL;
583 }
584
585 #ifdef NOT_USED
586
587 /* Find a targetlist entry by resname */
588 static Node *
589 FindMatchingTLEntry(List *tlist, char *e_attname)
590 {
591         List       *i;
592
593         foreach(i, tlist)
594         {
595                 TargetEntry *tle = lfirst(i);
596                 char       *resname;
597
598                 resname = tle->resdom->resname;
599                 if (strcmp(e_attname, resname) == 0)
600                         return tle->expr;
601         }
602         return NULL;
603 }
604
605 #endif
606
607
608 /*
609  * ResolveNew - replace Vars with corresponding items from a targetlist
610  *
611  * Vars matching target_varno and sublevels_up are replaced by the
612  * entry with matching resno from targetlist, if there is one.
613  * If not, we either change the unmatched Var's varno to update_varno
614  * (when event == CMD_UPDATE) or replace it with a constant NULL.
615  */
616
617 typedef struct
618 {
619         int                     target_varno;
620         int                     sublevels_up;
621         List       *targetlist;
622         int                     event;
623         int                     update_varno;
624 } ResolveNew_context;
625
626 static Node *
627 ResolveNew_mutator(Node *node, ResolveNew_context *context)
628 {
629         if (node == NULL)
630                 return NULL;
631         if (IsA(node, Var))
632         {
633                 Var                *var = (Var *) node;
634                 int                     this_varno = (int) var->varno;
635                 int                     this_varlevelsup = (int) var->varlevelsup;
636
637                 if (this_varno == context->target_varno &&
638                         this_varlevelsup == context->sublevels_up)
639                 {
640                         Node       *n = FindMatchingNew(context->targetlist,
641                                                                                         var->varattno);
642
643                         if (n == NULL)
644                         {
645                                 if (context->event == CMD_UPDATE)
646                                 {
647                                         /* For update, just change unmatched var's varno */
648                                         var = (Var *) copyObject(node);
649                                         var->varno = context->update_varno;
650                                         var->varnoold = context->update_varno;
651                                         return (Node *) var;
652                                 }
653                                 else
654                                 {
655                                         /* Otherwise replace unmatched var with a null */
656                                         return make_null(var->vartype);
657                                 }
658                         }
659                         else
660                         {
661                                 /* Make a copy of the tlist item to return */
662                                 n = copyObject(n);
663                                 /* Adjust varlevelsup if tlist item is from higher query */
664                                 if (this_varlevelsup > 0)
665                                         IncrementVarSublevelsUp(n, this_varlevelsup, 0);
666                                 return n;
667                         }
668                 }
669                 /* otherwise fall through to copy the var normally */
670         }
671
672         /*
673          * Since expression_tree_mutator won't touch subselects, we have to
674          * handle them specially.
675          */
676         if (IsA(node, SubLink))
677         {
678                 SubLink    *sublink = (SubLink *) node;
679                 SubLink    *newnode;
680
681                 FLATCOPY(newnode, sublink, SubLink);
682                 MUTATE(newnode->lefthand, sublink->lefthand, List *,
683                            ResolveNew_mutator, context);
684                 context->sublevels_up++;
685                 MUTATE(newnode->subselect, sublink->subselect, Node *,
686                            ResolveNew_mutator, context);
687                 context->sublevels_up--;
688                 return (Node *) newnode;
689         }
690         if (IsA(node, Query))
691         {
692                 Query      *query = (Query *) node;
693                 Query      *newnode;
694
695                 FLATCOPY(newnode, query, Query);
696                 MUTATE(newnode->targetList, query->targetList, List *,
697                            ResolveNew_mutator, context);
698                 MUTATE(newnode->jointree, query->jointree, FromExpr *,
699                            ResolveNew_mutator, context);
700                 MUTATE(newnode->havingQual, query->havingQual, Node *,
701                            ResolveNew_mutator, context);
702                 return (Node *) newnode;
703         }
704         return expression_tree_mutator(node, ResolveNew_mutator,
705                                                                    (void *) context);
706 }
707
708 Node *
709 ResolveNew(Node *node, int target_varno, int sublevels_up,
710                    List *targetlist, int event, int update_varno)
711 {
712         ResolveNew_context context;
713
714         context.target_varno = target_varno;
715         context.sublevels_up = sublevels_up;
716         context.targetlist = targetlist;
717         context.event = event;
718         context.update_varno = update_varno;
719
720         /*
721          * Note: if an entire Query is passed, the right things will happen,
722          * because ResolveNew_mutator increments sublevels_up when it sees
723          * a SubLink, not a Query.
724          */
725         return ResolveNew_mutator(node, &context);
726 }
727
728 /*
729  * Alternate interface to ResolveNew: substitute Vars in info->rule_action
730  * with targetlist items from the parsetree's targetlist.
731  */
732 void
733 FixNew(RewriteInfo *info, Query *parsetree)
734 {
735         ResolveNew_context context;
736
737         context.target_varno = info->new_varno;
738         context.sublevels_up = 0;
739         context.targetlist = parsetree->targetList;
740         context.event = info->event;
741         context.update_varno = info->current_varno;
742
743         info->rule_action->targetList = (List *)
744                 ResolveNew_mutator((Node *) info->rule_action->targetList, &context);
745         info->rule_action->jointree = (FromExpr *)
746                 ResolveNew_mutator((Node *) info->rule_action->jointree, &context);
747         info->rule_action->havingQual =
748                 ResolveNew_mutator(info->rule_action->havingQual, &context);
749 }
750
751
752 #ifdef NOT_USED
753
754 /*
755  * HandleRIRAttributeRule
756  *      Replace Vars matching a given RT index with copies of TL expressions.
757  *
758  * Handles 'on retrieve to relation.attribute
759  *                      do instead retrieve (attribute = expression) w/qual'
760  */
761
762 typedef struct
763 {
764         List       *rtable;
765         List       *targetlist;
766         int                     rt_index;
767         int                     attr_num;
768         int                *modified;
769         int                *badsql;
770         int                     sublevels_up;
771 } HandleRIRAttributeRule_context;
772
773 static Node *
774 HandleRIRAttributeRule_mutator(Node *node,
775                                                            HandleRIRAttributeRule_context *context)
776 {
777         if (node == NULL)
778                 return NULL;
779         if (IsA(node, Var))
780         {
781                 Var                *var = (Var *) node;
782                 int                     this_varno = var->varno;
783                 int                     this_varattno = var->varattno;
784                 int                     this_varlevelsup = var->varlevelsup;
785
786                 if (this_varno == context->rt_index &&
787                         this_varattno == context->attr_num &&
788                         this_varlevelsup == context->sublevels_up)
789                 {
790                         if (var->vartype == 32)
791                         {                                       /* HACK: disallow SET variables */
792                                 *context->modified = TRUE;
793                                 *context->badsql = TRUE;
794                                 return make_null(var->vartype);
795                         }
796                         else
797                         {
798                                 char       *name_to_look_for;
799
800                                 name_to_look_for = get_attname(getrelid(this_varno,
801                                                                                                                 context->rtable),
802                                                                                            this_varattno);
803                                 if (name_to_look_for)
804                                 {
805                                         Node       *n;
806
807                                         *context->modified = TRUE;
808                                         n = FindMatchingTLEntry(context->targetlist,
809                                                                                         name_to_look_for);
810                                         if (n == NULL)
811                                                 return make_null(var->vartype);
812                                         /* Make a copy of the tlist item to return */
813                                         n = copyObject(n);
814
815                                         /*
816                                          * Adjust varlevelsup if tlist item is from higher
817                                          * query
818                                          */
819                                         if (this_varlevelsup > 0)
820                                                 IncrementVarSublevelsUp(n, this_varlevelsup, 0);
821                                         return n;
822                                 }
823                         }
824                 }
825                 /* otherwise fall through to copy the var normally */
826         }
827
828         /*
829          * Since expression_tree_mutator won't touch subselects, we have to
830          * handle them specially.
831          */
832         if (IsA(node, SubLink))
833         {
834                 SubLink    *sublink = (SubLink *) node;
835                 SubLink    *newnode;
836
837                 FLATCOPY(newnode, sublink, SubLink);
838                 MUTATE(newnode->lefthand, sublink->lefthand, List *,
839                            HandleRIRAttributeRule_mutator, context);
840                 context->sublevels_up++;
841                 MUTATE(newnode->subselect, sublink->subselect, Node *,
842                            HandleRIRAttributeRule_mutator, context);
843                 context->sublevels_up--;
844                 return (Node *) newnode;
845         }
846         if (IsA(node, Query))
847         {
848                 Query      *query = (Query *) node;
849                 Query      *newnode;
850
851                 FLATCOPY(newnode, query, Query);
852                 MUTATE(newnode->targetList, query->targetList, List *,
853                            HandleRIRAttributeRule_mutator, context);
854                 MUTATE(newnode->jointree, query->jointree, FromExpr *,
855                            HandleRIRAttributeRule_mutator, context);
856                 MUTATE(newnode->havingQual, query->havingQual, Node *,
857                            HandleRIRAttributeRule_mutator, context);
858
859
860                 return (Node *) newnode;
861         }
862         return expression_tree_mutator(node, HandleRIRAttributeRule_mutator,
863                                                                    (void *) context);
864 }
865
866 void
867 HandleRIRAttributeRule(Query *parsetree,
868                                            List *rtable,
869                                            List *targetlist,
870                                            int rt_index,
871                                            int attr_num,
872                                            int *modified,
873                                            int *badsql)
874 {
875         HandleRIRAttributeRule_context context;
876
877         context.rtable = rtable;
878         context.targetlist = targetlist;
879         context.rt_index = rt_index;
880         context.attr_num = attr_num;
881         context.modified = modified;
882         context.badsql = badsql;
883         context.sublevels_up = 0;
884
885         parsetree->targetList = (List *)
886                 HandleRIRAttributeRule_mutator((Node *) parsetree->targetList,
887                                                                            &context);
888         parsetree->jointree = (FromExpr *)
889                 HandleRIRAttributeRule_mutator((Node *) parsetree->jointree,
890                                                                            &context);
891         parsetree->havingQual =
892                 HandleRIRAttributeRule_mutator(parsetree->havingQual,
893                                                                            &context);
894 }
895
896 #endif /* NOT_USED */