OSDN Git Service

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