]> granicus.if.org Git - postgresql/blob - src/backend/rewrite/rewriteHandler.c
a8997d5a8ab33089bbd09a8726b9179eeffdf5d6
[postgresql] / src / backend / rewrite / rewriteHandler.c
1 /*-------------------------------------------------------------------------
2  *
3  * rewriteHandler.c--
4  *
5  * Copyright (c) 1994, Regents of the University of California
6  *
7  *
8  * IDENTIFICATION
9  *        $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.27 1998/12/14 00:02:16 thomas Exp $
10  *
11  *-------------------------------------------------------------------------
12  */
13 #include <string.h>
14 #include "postgres.h"
15 #include "miscadmin.h"
16 #include "utils/palloc.h"
17 #include "utils/elog.h"
18 #include "utils/rel.h"
19 #include "nodes/pg_list.h"
20 #include "nodes/primnodes.h"
21 #include "nodes/relation.h"
22
23 #include "parser/parsetree.h"   /* for parsetree manipulation */
24 #include "parser/parse_relation.h"
25 #include "nodes/parsenodes.h"
26
27 #include "rewrite/rewriteSupport.h"
28 #include "rewrite/rewriteHandler.h"
29 #include "rewrite/rewriteManip.h"
30 #include "rewrite/locks.h"
31
32 #include "commands/creatinh.h"
33 #include "access/heapam.h"
34
35 #include "utils/lsyscache.h"
36 #include "utils/syscache.h"
37 #include "utils/acl.h"
38 #include "catalog/pg_shadow.h"
39 #include "catalog/pg_type.h"
40
41
42 static RewriteInfo *gatherRewriteMeta(Query *parsetree,
43                                   Query *rule_action,
44                                   Node *rule_qual,
45                                   int rt_index,
46                                   CmdType event,
47                                   bool *instead_flag);
48 static bool rangeTableEntry_used(Node *node, int rt_index, int sublevels_up);
49 static bool attribute_used(Node *node, int rt_index, int attno, int sublevels_up);
50 static void modifyAggregUplevel(Node *node);
51 static void modifyAggregChangeVarnodes(Node **nodePtr, int rt_index, int new_index, int sublevels_up);
52 static void modifyAggregDropQual(Node **nodePtr, Node *orignode, Expr *expr);
53 static SubLink *modifyAggregMakeSublink(Expr *origexp, Query *parsetree);
54 static void modifyAggregQual(Node **nodePtr, Query *parsetree);
55
56
57 static Query *fireRIRrules(Query *parsetree);
58
59
60 /*
61  * gatherRewriteMeta -
62  *        Gather meta information about parsetree, and rule. Fix rule body
63  *        and qualifier so that they can be mixed with the parsetree and
64  *        maintain semantic validity
65  */
66 static RewriteInfo *
67 gatherRewriteMeta(Query *parsetree,
68                                   Query *rule_action,
69                                   Node *rule_qual,
70                                   int rt_index,
71                                   CmdType event,
72                                   bool *instead_flag)
73 {
74         RewriteInfo *info;
75         int                     rt_length;
76         int                     result_reln;
77
78         info = (RewriteInfo *) palloc(sizeof(RewriteInfo));
79         info->rt_index = rt_index;
80         info->event = event;
81         info->instead_flag = *instead_flag;
82         info->rule_action = (Query *) copyObject(rule_action);
83         info->rule_qual = (Node *) copyObject(rule_qual);
84         if (info->rule_action == NULL)
85                 info->nothing = TRUE;
86         else
87         {
88                 info->nothing = FALSE;
89                 info->action = info->rule_action->commandType;
90                 info->current_varno = rt_index;
91                 info->rt = parsetree->rtable;
92                 rt_length = length(info->rt);
93                 info->rt = append(info->rt, info->rule_action->rtable);
94
95                 info->new_varno = PRS2_NEW_VARNO + rt_length;
96                 OffsetVarNodes(info->rule_action->qual, rt_length, 0);
97                 OffsetVarNodes((Node *) info->rule_action->targetList, rt_length, 0);
98                 OffsetVarNodes(info->rule_qual, rt_length, 0);
99                 ChangeVarNodes((Node *) info->rule_action->qual,
100                                            PRS2_CURRENT_VARNO + rt_length, rt_index, 0);
101                 ChangeVarNodes((Node *) info->rule_action->targetList,
102                                            PRS2_CURRENT_VARNO + rt_length, rt_index, 0);
103                 ChangeVarNodes(info->rule_qual,
104                                            PRS2_CURRENT_VARNO + rt_length, rt_index, 0);
105
106                 /*
107                  * bug here about replace CURRENT  -- sort of replace current is
108                  * deprecated now so this code shouldn't really need to be so
109                  * clutzy but.....
110                  */
111                 if (info->action != CMD_SELECT)
112                 {                                               /* i.e update XXXXX */
113                         int                     new_result_reln = 0;
114
115                         result_reln = info->rule_action->resultRelation;
116                         switch (result_reln)
117                         {
118                                 case PRS2_CURRENT_VARNO:
119                                         new_result_reln = rt_index;
120                                         break;
121                                 case PRS2_NEW_VARNO:    /* XXX */
122                                 default:
123                                         new_result_reln = result_reln + rt_length;
124                                         break;
125                         }
126                         info->rule_action->resultRelation = new_result_reln;
127                 }
128         }
129         return info;
130 }
131
132
133 /*
134  * rangeTableEntry_used -
135  *      we need to process a RTE for RIR rules only if it is
136  *      referenced somewhere in var nodes of the query.
137  */
138 static bool
139 rangeTableEntry_used(Node *node, int rt_index, int sublevels_up)
140 {
141         if (node == NULL)
142                 return FALSE;
143
144         switch(nodeTag(node)) {
145                 case T_TargetEntry:
146                         {
147                                 TargetEntry     *tle = (TargetEntry *)node;
148
149                                 return rangeTableEntry_used(
150                                                 (Node *)(tle->expr),
151                                                 rt_index,
152                                                 sublevels_up);
153                         }
154                         break;
155
156                 case T_Aggreg:
157                         {
158                                 Aggreg  *agg = (Aggreg *)node;
159
160                                 return rangeTableEntry_used(
161                                                 (Node *)(agg->target),
162                                                 rt_index,
163                                                 sublevels_up);
164                         }
165                         break;
166
167                 case T_GroupClause:
168                         {
169                                 GroupClause     *grp = (GroupClause *)node;
170
171                                 return rangeTableEntry_used(
172                                                 (Node *)(grp->entry),
173                                                 rt_index,
174                                                 sublevels_up);
175                         }
176                         break;
177
178                 case T_Expr:
179                         {
180                                 Expr    *exp = (Expr *)node;
181
182                                 return rangeTableEntry_used(
183                                                 (Node *)(exp->args),
184                                                 rt_index,
185                                                 sublevels_up);
186                         }
187                         break;
188
189                 case T_Iter:
190                         {
191                                 Iter    *iter = (Iter *)node;
192
193                                 return rangeTableEntry_used(
194                                                 (Node *)(iter->iterexpr),
195                                                 rt_index,
196                                                 sublevels_up);
197                         }
198                         break;
199
200                 case T_ArrayRef:
201                         {
202                                 ArrayRef        *ref = (ArrayRef *)node;
203
204                                 if (rangeTableEntry_used(
205                                                 (Node *)(ref->refupperindexpr),
206                                                 rt_index,
207                                                 sublevels_up))
208                                         return TRUE;
209                                 
210                                 if (rangeTableEntry_used(
211                                                 (Node *)(ref->reflowerindexpr),
212                                                 rt_index,
213                                                 sublevels_up))
214                                         return TRUE;
215                                 
216                                 if (rangeTableEntry_used(
217                                                 (Node *)(ref->refexpr),
218                                                 rt_index,
219                                                 sublevels_up))
220                                         return TRUE;
221                                 
222                                 if (rangeTableEntry_used(
223                                                 (Node *)(ref->refassgnexpr),
224                                                 rt_index,
225                                                 sublevels_up))
226                                         return TRUE;
227                                 
228                                 return FALSE;
229                         }
230                         break;
231
232                 case T_Var:
233                         {
234                                 Var     *var = (Var *)node;
235
236                                 if (var->varlevelsup == sublevels_up)
237                                         return var->varno == rt_index;
238                                 else
239                                         return FALSE;
240                         }
241                         break;
242
243                 case T_Param:
244                         return FALSE;
245
246                 case T_Const:
247                         return FALSE;
248
249                 case T_List:
250                         {
251                                 List    *l;
252
253                                 foreach (l, (List *)node) {
254                                         if (rangeTableEntry_used(
255                                                         (Node *)lfirst(l),
256                                                         rt_index,
257                                                         sublevels_up))
258                                                 return TRUE;
259                                 }
260                                 return FALSE;
261                         }
262                         break;
263
264                 case T_SubLink:
265                         {
266                                 SubLink *sub = (SubLink *)node;
267
268                                 if (rangeTableEntry_used(
269                                                 (Node *)(sub->lefthand),
270                                                 rt_index,
271                                                 sublevels_up))
272                                         return TRUE;
273
274                                 if (rangeTableEntry_used(
275                                                 (Node *)(sub->subselect),
276                                                 rt_index,
277                                                 sublevels_up + 1))
278                                         return TRUE;
279
280                                 return FALSE;
281                         }
282                         break;
283
284                 case T_CaseExpr:
285                         {
286                                 CaseExpr        *exp = (CaseExpr *)node;
287
288                                 if (rangeTableEntry_used(
289                                                 (Node *)(exp->args),
290                                                 rt_index,
291                                                 sublevels_up))
292                                         return TRUE;
293
294                                 if (rangeTableEntry_used(
295                                                 (Node *)(exp->defresult),
296                                                 rt_index,
297                                                 sublevels_up))
298                                         return TRUE;
299
300                                 return FALSE;
301                         }
302                         break;
303
304                 case T_CaseWhen:
305                         {
306                                 CaseWhen        *when = (CaseWhen *)node;
307
308                                 if (rangeTableEntry_used(
309                                                 (Node *)(when->expr),
310                                                 rt_index,
311                                                 sublevels_up))
312                                         return TRUE;
313
314                                 if (rangeTableEntry_used(
315                                                 (Node *)(when->result),
316                                                 rt_index,
317                                                 sublevels_up))
318                                         return TRUE;
319
320                                 return FALSE;
321                         }
322                         break;
323
324                 case T_Query:
325                         {
326                                 Query   *qry = (Query *)node;
327
328                                 if (rangeTableEntry_used(
329                                                 (Node *)(qry->targetList),
330                                                 rt_index,
331                                                 sublevels_up))
332                                         return TRUE;
333
334                                 if (rangeTableEntry_used(
335                                                 (Node *)(qry->qual),
336                                                 rt_index,
337                                                 sublevels_up))
338                                         return TRUE;
339
340                                 if (rangeTableEntry_used(
341                                                 (Node *)(qry->havingQual),
342                                                 rt_index,
343                                                 sublevels_up))
344                                         return TRUE;
345
346                                 if (rangeTableEntry_used(
347                                                 (Node *)(qry->groupClause),
348                                                 rt_index,
349                                                 sublevels_up))
350                                         return TRUE;
351
352                                 return FALSE;
353                         }
354                         break;
355
356                 default:
357                         elog(NOTICE, "unknown node tag %d in rangeTableEntry_used()", nodeTag(node));
358                         elog(NOTICE, "Node is: %s", nodeToString(node));
359                         break;
360
361
362         }
363
364         return FALSE;
365 }
366
367
368 /*
369  * attribute_used -
370  *      Check if a specific attribute number of a RTE is used
371  *      somewhere in the query
372  */
373 static bool
374 attribute_used(Node *node, int rt_index, int attno, int sublevels_up)
375 {
376         if (node == NULL)
377                 return FALSE;
378
379         switch(nodeTag(node)) {
380                 case T_TargetEntry:
381                         {
382                                 TargetEntry     *tle = (TargetEntry *)node;
383
384                                 return attribute_used(
385                                                 (Node *)(tle->expr),
386                                                 rt_index,
387                                                 attno,
388                                                 sublevels_up);
389                         }
390                         break;
391
392                 case T_Aggreg:
393                         {
394                                 Aggreg  *agg = (Aggreg *)node;
395
396                                 return attribute_used(
397                                                 (Node *)(agg->target),
398                                                 rt_index,
399                                                 attno,
400                                                 sublevels_up);
401                         }
402                         break;
403
404                 case T_GroupClause:
405                         {
406                                 GroupClause     *grp = (GroupClause *)node;
407
408                                 return attribute_used(
409                                                 (Node *)(grp->entry),
410                                                 rt_index,
411                                                 attno,
412                                                 sublevels_up);
413                         }
414                         break;
415
416                 case T_Expr:
417                         {
418                                 Expr    *exp = (Expr *)node;
419
420                                 return attribute_used(
421                                                 (Node *)(exp->args),
422                                                 rt_index,
423                                                 attno,
424                                                 sublevels_up);
425                         }
426                         break;
427
428                 case T_Iter:
429                         {
430                                 Iter    *iter = (Iter *)node;
431
432                                 return attribute_used(
433                                                 (Node *)(iter->iterexpr),
434                                                 rt_index,
435                                                 attno,
436                                                 sublevels_up);
437                         }
438                         break;
439
440                 case T_ArrayRef:
441                         {
442                                 ArrayRef        *ref = (ArrayRef *)node;
443
444                                 if (attribute_used(
445                                                 (Node *)(ref->refupperindexpr),
446                                                 rt_index,
447                                                 attno,
448                                                 sublevels_up))
449                                         return TRUE;
450
451                                 if (attribute_used(
452                                                 (Node *)(ref->reflowerindexpr),
453                                                 rt_index,
454                                                 attno,
455                                                 sublevels_up))
456                                         return TRUE;
457
458                                 if (attribute_used(
459                                                 (Node *)(ref->refexpr),
460                                                 rt_index,
461                                                 attno,
462                                                 sublevels_up))
463                                         return TRUE;
464
465                                 if (attribute_used(
466                                                 (Node *)(ref->refassgnexpr),
467                                                 rt_index,
468                                                 attno,
469                                                 sublevels_up))
470                                         return TRUE;
471
472                                 return FALSE;
473                         }
474                         break;
475
476                 case T_Var:
477                         {
478                                 Var     *var = (Var *)node;
479
480                                 if (var->varlevelsup == sublevels_up)
481                                         return var->varno == rt_index;
482                                 else
483                                         return FALSE;
484                         }
485                         break;
486
487                 case T_Param:
488                         return FALSE;
489
490                 case T_Const:
491                         return FALSE;
492
493                 case T_List:
494                         {
495                                 List    *l;
496
497                                 foreach (l, (List *)node) {
498                                         if (attribute_used(
499                                                         (Node *)lfirst(l),
500                                                         rt_index,
501                                                         attno,
502                                                         sublevels_up))
503                                                 return TRUE;
504                                 }
505                                 return FALSE;
506                         }
507                         break;
508
509                 case T_SubLink:
510                         {
511                                 SubLink *sub = (SubLink *)node;
512
513                                 if (attribute_used(
514                                                 (Node *)(sub->lefthand),
515                                                 rt_index,
516                                                 attno,
517                                                 sublevels_up))
518                                         return TRUE;
519
520                                 if (attribute_used(
521                                                 (Node *)(sub->subselect),
522                                                 rt_index,
523                                                 attno,
524                                                 sublevels_up + 1))
525                                         return TRUE;
526
527                                 return FALSE;
528                         }
529                         break;
530
531                 case T_Query:
532                         {
533                                 Query   *qry = (Query *)node;
534
535                                 if (attribute_used(
536                                                 (Node *)(qry->targetList),
537                                                 rt_index,
538                                                 attno,
539                                                 sublevels_up))
540                                         return TRUE;
541
542                                 if (attribute_used(
543                                                 (Node *)(qry->qual),
544                                                 rt_index,
545                                                 attno,
546                                                 sublevels_up))
547                                         return TRUE;
548
549                                 if (attribute_used(
550                                                 (Node *)(qry->havingQual),
551                                                 rt_index,
552                                                 attno,
553                                                 sublevels_up))
554                                         return TRUE;
555
556                                 if (attribute_used(
557                                                 (Node *)(qry->groupClause),
558                                                 rt_index,
559                                                 attno,
560                                                 sublevels_up))
561                                         return TRUE;
562
563                                 return FALSE;
564                         }
565                         break;
566
567                 default:
568                         elog(NOTICE, "unknown node tag %d in attribute_used()", nodeTag(node));
569                         elog(NOTICE, "Node is: %s", nodeToString(node));
570                         break;
571
572
573         }
574
575         return FALSE;
576 }
577
578
579 /*
580  * modifyAggregUplevel -
581  *      In the newly created sublink for an aggregate column used in
582  *      the qualification, we must adjust the varlevelsup in all the
583  *      var nodes.
584  */
585 static void
586 modifyAggregUplevel(Node *node)
587 {
588         if (node == NULL)
589                 return;
590
591         switch(nodeTag(node)) {
592                 case T_TargetEntry:
593                         {
594                                 TargetEntry     *tle = (TargetEntry *)node;
595
596                                 modifyAggregUplevel(
597                                                 (Node *)(tle->expr));
598                         }
599                         break;
600
601                 case T_Aggreg:
602                         {
603                                 Aggreg  *agg = (Aggreg *)node;
604
605                                 modifyAggregUplevel(
606                                                 (Node *)(agg->target));
607                         }
608                         break;
609
610                 case T_Expr:
611                         {
612                                 Expr    *exp = (Expr *)node;
613
614                                 modifyAggregUplevel(
615                                                 (Node *)(exp->args));
616                         }
617                         break;
618
619                 case T_Iter:
620                         {
621                                 Iter    *iter = (Iter *)node;
622
623                                 modifyAggregUplevel(
624                                                 (Node *)(iter->iterexpr));
625                         }
626                         break;
627
628                 case T_ArrayRef:
629                         {
630                                 ArrayRef        *ref = (ArrayRef *)node;
631
632                                 modifyAggregUplevel(
633                                                 (Node *)(ref->refupperindexpr));
634                                 modifyAggregUplevel(
635                                                 (Node *)(ref->reflowerindexpr));
636                                 modifyAggregUplevel(
637                                                 (Node *)(ref->refexpr));
638                                 modifyAggregUplevel(
639                                                 (Node *)(ref->refassgnexpr));
640                         }
641                         break;
642
643                 case T_Var:
644                         {
645                                 Var     *var = (Var *)node;
646
647                                 var->varlevelsup++;
648                         }
649                         break;
650
651                 case T_Param:
652                         break;
653
654                 case T_Const:
655                         break;
656
657                 case T_List:
658                         {
659                                 List    *l;
660
661                                 foreach (l, (List *)node)
662                                         modifyAggregUplevel(
663                                                         (Node *)lfirst(l));
664                         }
665                         break;
666
667                 case T_SubLink:
668                         {
669                                 SubLink *sub = (SubLink *)node;
670
671                                 modifyAggregUplevel(
672                                                 (Node *)(sub->lefthand));
673
674                                 modifyAggregUplevel(
675                                                 (Node *)(sub->oper));
676
677                                 modifyAggregUplevel(
678                                                 (Node *)(sub->subselect));
679                         }
680                         break;
681
682                 case T_Query:
683                         {
684                                 Query   *qry = (Query *)node;
685
686                                 modifyAggregUplevel(
687                                                 (Node *)(qry->targetList));
688
689                                 modifyAggregUplevel(
690                                                 (Node *)(qry->qual));
691
692                                 modifyAggregUplevel(
693                                                 (Node *)(qry->havingQual));
694
695                                 modifyAggregUplevel(
696                                                 (Node *)(qry->groupClause));
697                         }
698                         break;
699
700                 default:
701                         elog(NOTICE, "unknown node tag %d in modifyAggregUplevel()", nodeTag(node));
702                         elog(NOTICE, "Node is: %s", nodeToString(node));
703                         break;
704
705
706         }
707 }
708
709
710 /*
711  * modifyAggregChangeVarnodes -
712  *      Change the var nodes in a sublink created for an aggregate column
713  *      used in the qualification that is subject of the aggregate
714  *      function to point to the correct local RTE.
715  */
716 static void
717 modifyAggregChangeVarnodes(Node **nodePtr, int rt_index, int new_index, int sublevels_up)
718 {
719         Node    *node = *nodePtr;
720
721         if (node == NULL)
722                 return;
723
724         switch(nodeTag(node)) {
725                 case T_TargetEntry:
726                         {
727                                 TargetEntry     *tle = (TargetEntry *)node;
728
729                                 modifyAggregChangeVarnodes(
730                                                 (Node **)(&(tle->expr)),
731                                                 rt_index,
732                                                 new_index,
733                                                 sublevels_up);
734                         }
735                         break;
736
737                 case T_Aggreg:
738                         {
739                                 Aggreg  *agg = (Aggreg *)node;
740
741                                 modifyAggregChangeVarnodes(
742                                                 (Node **)(&(agg->target)),
743                                                 rt_index,
744                                                 new_index,
745                                                 sublevels_up);
746                         }
747                         break;
748
749                 case T_GroupClause:
750                         {
751                                 GroupClause     *grp = (GroupClause *)node;
752
753                                 modifyAggregChangeVarnodes(
754                                                 (Node **)(&(grp->entry)),
755                                                 rt_index,
756                                                 new_index,
757                                                 sublevels_up);
758                         }
759                         break;
760
761                 case T_Expr:
762                         {
763                                 Expr    *exp = (Expr *)node;
764
765                                 modifyAggregChangeVarnodes(
766                                                 (Node **)(&(exp->args)),
767                                                 rt_index,
768                                                 new_index,
769                                                 sublevels_up);
770                         }
771                         break;
772
773                 case T_Iter:
774                         {
775                                 Iter    *iter = (Iter *)node;
776
777                                 modifyAggregChangeVarnodes(
778                                                 (Node **)(&(iter->iterexpr)),
779                                                 rt_index,
780                                                 new_index,
781                                                 sublevels_up);
782                         }
783                         break;
784
785                 case T_ArrayRef:
786                         {
787                                 ArrayRef        *ref = (ArrayRef *)node;
788
789                                 modifyAggregChangeVarnodes(
790                                                 (Node **)(&(ref->refupperindexpr)),
791                                                 rt_index,
792                                                 new_index,
793                                                 sublevels_up);
794                                 modifyAggregChangeVarnodes(
795                                                 (Node **)(&(ref->reflowerindexpr)),
796                                                 rt_index,
797                                                 new_index,
798                                                 sublevels_up);
799                                 modifyAggregChangeVarnodes(
800                                                 (Node **)(&(ref->refexpr)),
801                                                 rt_index,
802                                                 new_index,
803                                                 sublevels_up);
804                                 modifyAggregChangeVarnodes(
805                                                 (Node **)(&(ref->refassgnexpr)),
806                                                 rt_index,
807                                                 new_index,
808                                                 sublevels_up);
809                         }
810                         break;
811
812                 case T_Var:
813                         {
814                                 Var     *var = (Var *)node;
815
816                                 if (var->varlevelsup == sublevels_up &&
817                                                 var->varno == rt_index) {
818                                         var = copyObject(var);
819                                         var->varno = new_index;
820                                         var->varnoold = new_index;
821                                         var->varlevelsup = 0;
822
823                                         *nodePtr = (Node *)var;
824                                 }
825                         }
826                         break;
827
828                 case T_Param:
829                         break;
830
831                 case T_Const:
832                         break;
833
834                 case T_List:
835                         {
836                                 List    *l;
837
838                                 foreach (l, (List *)node)
839                                         modifyAggregChangeVarnodes(
840                                                         (Node **)(&lfirst(l)),
841                                                         rt_index,
842                                                         new_index,
843                                                         sublevels_up);
844                         }
845                         break;
846
847                 case T_SubLink:
848                         {
849                                 SubLink *sub = (SubLink *)node;
850
851                                 modifyAggregChangeVarnodes(
852                                                 (Node **)(&(sub->lefthand)),
853                                                 rt_index,
854                                                 new_index,
855                                                 sublevels_up);
856
857                                 modifyAggregChangeVarnodes(
858                                                 (Node **)(&(sub->oper)),
859                                                 rt_index,
860                                                 new_index,
861                                                 sublevels_up);
862
863                                 modifyAggregChangeVarnodes(
864                                                 (Node **)(&(sub->subselect)),
865                                                 rt_index,
866                                                 new_index,
867                                                 sublevels_up + 1);
868                         }
869                         break;
870
871                 case T_Query:
872                         {
873                                 Query   *qry = (Query *)node;
874
875                                 modifyAggregChangeVarnodes(
876                                                 (Node **)(&(qry->targetList)),
877                                                 rt_index,
878                                                 new_index,
879                                                 sublevels_up);
880
881                                 modifyAggregChangeVarnodes(
882                                                 (Node **)(&(qry->qual)),
883                                                 rt_index,
884                                                 new_index,
885                                                 sublevels_up);
886
887                                 modifyAggregChangeVarnodes(
888                                                 (Node **)(&(qry->havingQual)),
889                                                 rt_index,
890                                                 new_index,
891                                                 sublevels_up);
892
893                                 modifyAggregChangeVarnodes(
894                                                 (Node **)(&(qry->groupClause)),
895                                                 rt_index,
896                                                 new_index,
897                                                 sublevels_up);
898                         }
899                         break;
900
901                 default:
902                         elog(NOTICE, "unknown node tag %d in modifyAggregChangeVarnodes()", nodeTag(node));
903                         elog(NOTICE, "Node is: %s", nodeToString(node));
904                         break;
905
906
907         }
908 }
909
910
911 /*
912  * modifyAggregDropQual -
913  *      remove the pure aggreg clase from a qualification
914  */
915 static void
916 modifyAggregDropQual(Node **nodePtr, Node *orignode, Expr *expr)
917 {
918         Node    *node = *nodePtr;
919
920         if (node == NULL)
921                 return;
922
923         switch(nodeTag(node)) {
924                 case T_Var:
925                         break;
926
927                 case T_Aggreg:
928                         {
929                                 Aggreg  *agg = (Aggreg *)node;
930                                 Aggreg  *oagg = (Aggreg *)orignode;
931
932                                 modifyAggregDropQual(
933                                                 (Node **)(&(agg->target)),
934                                                 (Node *)(oagg->target),
935                                                 expr);
936                         }
937                         break;
938
939                 case T_Param:
940                         break;
941
942                 case T_Const:
943                         break;
944
945                 case T_GroupClause:
946                         break;
947
948                 case T_Expr:
949                         {
950                                 Expr    *this_expr = (Expr *)node;
951                                 Expr    *orig_expr = (Expr *)orignode;
952
953                                 if (orig_expr == expr) {
954                                         Const   *ctrue;
955
956                                         if (expr->typeOid != BOOLOID)
957                                                 elog(ERROR,
958                                                         "aggregate expression in qualification isn't of type bool");
959                                         ctrue = makeNode(Const);
960                                         ctrue->consttype = BOOLOID;
961                                         ctrue->constlen = 1;
962                                         ctrue->constisnull = FALSE;
963                                         ctrue->constvalue = (Datum)TRUE;
964                                         ctrue->constbyval = TRUE;
965
966                                         *nodePtr = (Node *)ctrue;
967                                 }
968                                 else
969                                         modifyAggregDropQual(
970                                                 (Node **)(&(this_expr->args)),
971                                                 (Node *)(orig_expr->args),
972                                                 expr);
973                         }
974                         break;
975
976                 case T_Iter:
977                         {
978                                 Iter    *iter = (Iter *)node;
979                                 Iter    *oiter = (Iter *)orignode;
980
981                                 modifyAggregDropQual(
982                                                 (Node **)(&(iter->iterexpr)),
983                                                 (Node *)(oiter->iterexpr),
984                                                 expr);
985                         }
986                         break;
987
988                 case T_ArrayRef:
989                         {
990                                 ArrayRef        *ref = (ArrayRef *)node;
991                                 ArrayRef        *oref = (ArrayRef *)orignode;
992
993                                 modifyAggregDropQual(
994                                                 (Node **)(&(ref->refupperindexpr)),
995                                                 (Node *)(oref->refupperindexpr),
996                                                 expr);
997                                 modifyAggregDropQual(
998                                                 (Node **)(&(ref->reflowerindexpr)),
999                                                 (Node *)(oref->reflowerindexpr),
1000                                                 expr);
1001                                 modifyAggregDropQual(
1002                                                 (Node **)(&(ref->refexpr)),
1003                                                 (Node *)(oref->refexpr),
1004                                                 expr);
1005                                 modifyAggregDropQual(
1006                                                 (Node **)(&(ref->refassgnexpr)),
1007                                                 (Node *)(oref->refassgnexpr),
1008                                                 expr);
1009                         }
1010                         break;
1011
1012                 case T_List:
1013                         {
1014                                 List    *l;
1015                                 List    *ol = (List *)orignode;
1016                                 int     li = 0;
1017
1018                                 foreach (l, (List *)node) {
1019                                         modifyAggregDropQual(
1020                                                         (Node **)(&(lfirst(l))),
1021                                                         (Node *)nth(li, ol),
1022                                                         expr);
1023                                         li++;
1024                                 }
1025                         }
1026                         break;
1027
1028                 case T_SubLink:
1029                         {
1030                                 SubLink *sub = (SubLink *)node;
1031                                 SubLink *osub = (SubLink *)orignode;
1032
1033                                 modifyAggregDropQual(
1034                                                 (Node **)(&(sub->subselect)),
1035                                                 (Node *)(osub->subselect),
1036                                                 expr);
1037                         }
1038                         break;
1039
1040                 case T_Query:
1041                         {
1042                                 Query   *qry = (Query *)node;
1043                                 Query   *oqry = (Query *)orignode;
1044
1045                                 modifyAggregDropQual(
1046                                                 (Node **)(&(qry->qual)),
1047                                                 (Node *)(oqry->qual),
1048                                                 expr);
1049
1050                                 modifyAggregDropQual(
1051                                                 (Node **)(&(qry->havingQual)),
1052                                                 (Node *)(oqry->havingQual),
1053                                                 expr);
1054                         }
1055                         break;
1056
1057                 default:
1058                         elog(NOTICE, "unknown node tag %d in modifyAggregDropQual()", nodeTag(node));
1059                         elog(NOTICE, "Node is: %s", nodeToString(node));
1060                         break;
1061
1062
1063         }
1064 }
1065
1066
1067 /*
1068  * modifyAggregMakeSublink -
1069  *      Create a sublink node for a qualification expression that
1070  *      uses an aggregate column of a view
1071  */
1072 static SubLink *
1073 modifyAggregMakeSublink(Expr *origexp, Query *parsetree)
1074 {
1075         SubLink         *sublink;
1076         Query           *subquery;
1077         Node            *subqual;
1078         RangeTblEntry   *rte;
1079         Aggreg          *aggreg;
1080         Var             *target;
1081         TargetEntry     *tle;
1082         Resdom          *resdom;
1083         Expr            *exp = copyObject(origexp);
1084
1085         if (nodeTag(nth(0, exp->args)) == T_Aggreg)
1086         {
1087                 if (nodeTag(nth(1, exp->args)) == T_Aggreg)
1088                         elog(ERROR, "rewrite: comparision of 2 aggregate columns not supported");
1089                 else
1090                         elog(ERROR, "rewrite: aggregate column of view must be at rigth side in qual");
1091         }
1092
1093         aggreg = (Aggreg *)nth(1, exp->args);
1094         target  = (Var *)(aggreg->target);
1095         rte     = (RangeTblEntry *)nth(target->varno - 1, parsetree->rtable);
1096         tle     = makeNode(TargetEntry);
1097         resdom  = makeNode(Resdom);
1098
1099         aggreg->usenulls = TRUE;
1100
1101         resdom->resno   = 1;
1102         resdom->restype = ((Oper *)(exp->oper))->opresulttype;
1103         resdom->restypmod = -1;
1104         resdom->resname = pstrdup("<noname>");
1105         resdom->reskey  = 0;
1106         resdom->reskeyop = 0;
1107         resdom->resjunk = 0;
1108
1109         tle->resdom     = resdom;
1110         tle->expr       = (Node *)aggreg;
1111
1112         subqual = copyObject(parsetree->qual);
1113         modifyAggregDropQual((Node **)&subqual, (Node *)parsetree->qual, origexp);
1114
1115         sublink = makeNode(SubLink);
1116         sublink->subLinkType    = EXPR_SUBLINK;
1117         sublink->useor          = FALSE;
1118         sublink->lefthand       = lappend(NIL, copyObject(lfirst(exp->args)));
1119         sublink->oper           = lappend(NIL, copyObject(exp));
1120         sublink->subselect      = NULL;
1121
1122         subquery                = makeNode(Query);
1123         sublink->subselect      = (Node *)subquery;
1124
1125         subquery->commandType           = CMD_SELECT;
1126         subquery->utilityStmt           = NULL;
1127         subquery->resultRelation        = 0;
1128         subquery->into                  = NULL;
1129         subquery->isPortal              = FALSE;
1130         subquery->isBinary              = FALSE;
1131         subquery->unionall              = FALSE;
1132         subquery->uniqueFlag            = NULL;
1133         subquery->sortClause            = NULL;
1134         subquery->rtable                = lappend(NIL, rte);
1135         subquery->targetList            = lappend(NIL, tle);
1136         subquery->qual                  = subqual;
1137         subquery->groupClause           = NIL;
1138         subquery->havingQual            = NULL;
1139         subquery->hasAggs               = TRUE;
1140         subquery->hasSubLinks           = FALSE;
1141         subquery->unionClause           = NULL;
1142
1143
1144         modifyAggregUplevel((Node *)sublink);
1145
1146         modifyAggregChangeVarnodes((Node **)&(sublink->lefthand), target->varno,
1147                         1, target->varlevelsup);
1148         modifyAggregChangeVarnodes((Node **)&(sublink->oper), target->varno,
1149                         1, target->varlevelsup);
1150         modifyAggregChangeVarnodes((Node **)&(sublink->subselect), target->varno,
1151                         1, target->varlevelsup);
1152
1153         return sublink;
1154 }
1155
1156
1157 /*
1158  * modifyAggregQual -
1159  *      Search for qualification expressions that contain aggregate
1160  *      functions and substiture them by sublinks. These expressions
1161  *      originally come from qualifications that use aggregate columns
1162  *      of a view.
1163  */
1164 static void
1165 modifyAggregQual(Node **nodePtr, Query *parsetree)
1166 {
1167         Node    *node = *nodePtr;
1168
1169         if (node == NULL)
1170                 return;
1171
1172         switch(nodeTag(node)) {
1173                 case T_Var:
1174                         break;
1175
1176                 case T_Param:
1177                         break;
1178
1179                 case T_Const:
1180                         break;
1181
1182                 case T_GroupClause:
1183                         {
1184                                 GroupClause     *grp = (GroupClause *)node;
1185
1186                                 modifyAggregQual(
1187                                                 (Node **)(&(grp->entry)),
1188                                                 parsetree);
1189                         }
1190                         break;
1191
1192                 case T_Expr:
1193                         {
1194                                 Expr    *exp = (Expr *)node;
1195                                 SubLink *sub;
1196
1197
1198                                 if (length(exp->args) != 2) {
1199                                         modifyAggregQual(
1200                                                 (Node **)(&(exp->args)),
1201                                                 parsetree);
1202                                         break;
1203                                 }
1204
1205                                 if (nodeTag(nth(0, exp->args)) != T_Aggreg &&
1206                                         nodeTag(nth(1, exp->args)) != T_Aggreg) {
1207
1208                                         modifyAggregQual(
1209                                                 (Node **)(&(exp->args)),
1210                                                 parsetree);
1211                                         break;
1212                                 }
1213
1214                                 sub = modifyAggregMakeSublink(exp,
1215                                                 parsetree);
1216
1217                                 *nodePtr = (Node *)sub;
1218                                 parsetree->hasSubLinks = TRUE;
1219                         }
1220                         break;
1221
1222                 case T_CaseExpr:
1223                         {
1224                                 /* We're calling recursively,
1225                                  * and this routine knows how to handle lists
1226                                  * so let it do the work to handle the WHEN clauses... */
1227                                 modifyAggregQual(
1228                                                 (Node **)(&(((CaseExpr *)node)->args)),
1229                                                 parsetree);
1230
1231                                 modifyAggregQual(
1232                                                 (Node **)(&(((CaseExpr *)node)->defresult)),
1233                                                 parsetree);
1234                         }
1235                         break;
1236
1237                 case T_CaseWhen:
1238                         {
1239                                 modifyAggregQual(
1240                                                 (Node **)(&(((CaseWhen *)node)->expr)),
1241                                                 parsetree);
1242
1243                                 modifyAggregQual(
1244                                                 (Node **)(&(((CaseWhen *)node)->result)),
1245                                                 parsetree);
1246                         }
1247                         break;
1248
1249                 case T_Iter:
1250                         {
1251                                 Iter    *iter = (Iter *)node;
1252
1253                                 modifyAggregQual(
1254                                                 (Node **)(&(iter->iterexpr)),
1255                                                 parsetree);
1256                         }
1257                         break;
1258
1259                 case T_ArrayRef:
1260                         {
1261                                 ArrayRef        *ref = (ArrayRef *)node;
1262
1263                                 modifyAggregQual(
1264                                                 (Node **)(&(ref->refupperindexpr)),
1265                                                 parsetree);
1266                                 modifyAggregQual(
1267                                                 (Node **)(&(ref->reflowerindexpr)),
1268                                                 parsetree);
1269                                 modifyAggregQual(
1270                                                 (Node **)(&(ref->refexpr)),
1271                                                 parsetree);
1272                                 modifyAggregQual(
1273                                                 (Node **)(&(ref->refassgnexpr)),
1274                                                 parsetree);
1275                         }
1276                         break;
1277
1278                 case T_List:
1279                         {
1280                                 List    *l;
1281
1282                                 foreach (l, (List *)node)
1283                                         modifyAggregQual(
1284                                                         (Node **)(&(lfirst(l))),
1285                                                         parsetree);
1286                         }
1287                         break;
1288
1289                 case T_SubLink:
1290                         {
1291                                 SubLink *sub = (SubLink *)node;
1292
1293                                 modifyAggregQual(
1294                                                 (Node **)(&(sub->subselect)),
1295                                                 (Query *)(sub->subselect));
1296                         }
1297                         break;
1298
1299                 case T_Query:
1300                         {
1301                                 Query   *qry = (Query *)node;
1302
1303                                 modifyAggregQual(
1304                                                 (Node **)(&(qry->qual)),
1305                                                 parsetree);
1306
1307                                 modifyAggregQual(
1308                                                 (Node **)(&(qry->havingQual)),
1309                                                 parsetree);
1310                         }
1311                         break;
1312
1313                 default:
1314                         elog(NOTICE, "unknown node tag %d in modifyAggregQual()", nodeTag(node));
1315                         elog(NOTICE, "Node is: %s", nodeToString(node));
1316                         break;
1317
1318
1319         }
1320 }
1321
1322
1323 static Node *
1324 FindMatchingTLEntry(List *tlist, char *e_attname)
1325 {
1326         List       *i;
1327
1328         foreach(i, tlist)
1329         {
1330                 TargetEntry *tle = lfirst(i);
1331                 char       *resname;
1332
1333                 resname = tle->resdom->resname;
1334                 if (!strcmp(e_attname, resname))
1335                         return (tle->expr);
1336         }
1337         return NULL;
1338 }
1339
1340
1341 static Node *
1342 make_null(Oid type)
1343 {
1344         Const      *c = makeNode(Const);
1345
1346         c->consttype = type;
1347         c->constlen = get_typlen(type);
1348         c->constvalue = PointerGetDatum(NULL);
1349         c->constisnull = true;
1350         c->constbyval = get_typbyval(type);
1351         return (Node *) c;
1352 }
1353
1354
1355 static void 
1356 apply_RIR_adjust_sublevel(Node *node, int sublevels_up)
1357 {
1358         if (node == NULL)
1359                 return;
1360
1361         switch(nodeTag(node)) {
1362                 case T_TargetEntry:
1363                         {
1364                                 TargetEntry     *tle = (TargetEntry *)node;
1365
1366                                 apply_RIR_adjust_sublevel(
1367                                                 (Node *)(tle->expr),
1368                                                 sublevels_up);
1369                         }
1370                         break;
1371
1372                 case T_Aggreg:
1373                         {
1374                                 Aggreg  *agg = (Aggreg *)node;
1375
1376                                 apply_RIR_adjust_sublevel(
1377                                                 (Node *)(agg->target),
1378                                                 sublevels_up);
1379                         }
1380                         break;
1381
1382                 case T_GroupClause:
1383                         {
1384                                 GroupClause     *grp = (GroupClause *)node;
1385
1386                                 apply_RIR_adjust_sublevel(
1387                                                 (Node *)(grp->entry),
1388                                                 sublevels_up);
1389                         }
1390                         break;
1391
1392                 case T_Expr:
1393                         {
1394                                 Expr    *exp = (Expr *)node;
1395
1396                                 apply_RIR_adjust_sublevel(
1397                                                 (Node *)(exp->args),
1398                                                 sublevels_up);
1399                         }
1400                         break;
1401
1402                 case T_Iter:
1403                         {
1404                                 Iter    *iter = (Iter *)node;
1405
1406                                 apply_RIR_adjust_sublevel(
1407                                                 (Node *)(iter->iterexpr),
1408                                                 sublevels_up);
1409                         }
1410                         break;
1411
1412                 case T_ArrayRef:
1413                         {
1414                                 ArrayRef        *ref = (ArrayRef *)node;
1415
1416                                 apply_RIR_adjust_sublevel(
1417                                                 (Node *)(ref->refupperindexpr),
1418                                                 sublevels_up);
1419
1420                                 apply_RIR_adjust_sublevel(
1421                                                 (Node *)(ref->reflowerindexpr),
1422                                                 sublevels_up);
1423
1424                                 apply_RIR_adjust_sublevel(
1425                                                 (Node *)(ref->refexpr),
1426                                                 sublevels_up);
1427
1428                                 apply_RIR_adjust_sublevel(
1429                                                 (Node *)(ref->refassgnexpr),
1430                                                 sublevels_up);
1431                         }
1432                         break;
1433
1434                 case T_Var:
1435                         {
1436                                 Var     *var = (Var *)node;
1437
1438                                 var->varlevelsup = sublevels_up;
1439                         }
1440                         break;
1441
1442                 case T_Param:
1443                         break;
1444
1445                 case T_Const:
1446                         break;
1447
1448                 case T_List:
1449                         {
1450                                 List    *l;
1451
1452                                 foreach (l, (List *)node) {
1453                                         apply_RIR_adjust_sublevel(
1454                                                         (Node *)lfirst(l),
1455                                                         sublevels_up);
1456                                 }
1457                         }
1458                         break;
1459
1460                 case T_CaseExpr:
1461                         {
1462                                 CaseExpr        *exp = (CaseExpr *)node;
1463
1464                                 apply_RIR_adjust_sublevel(
1465                                                 (Node *)(exp->args),
1466                                                 sublevels_up);
1467
1468                                 apply_RIR_adjust_sublevel(
1469                                                 (Node *)(exp->defresult),
1470                                                 sublevels_up);
1471                         }
1472                         break;
1473
1474                 case T_CaseWhen:
1475                         {
1476                                 CaseWhen        *exp = (CaseWhen *)node;
1477
1478                                 apply_RIR_adjust_sublevel(
1479                                                 (Node *)(exp->expr),
1480                                                 sublevels_up);
1481
1482                                 apply_RIR_adjust_sublevel(
1483                                                 (Node *)(exp->result),
1484                                                 sublevels_up);
1485                         }
1486                         break;
1487
1488                 default:
1489                         elog(NOTICE, "unknown node tag %d in attribute_used()", nodeTag(node));
1490                         elog(NOTICE, "Node is: %s", nodeToString(node));
1491                         break;
1492
1493
1494         }
1495 }
1496
1497
1498 static void
1499 apply_RIR_view(Node **nodePtr, int rt_index, RangeTblEntry *rte, List *tlist, int *modified, int sublevels_up)
1500 {
1501         Node    *node = *nodePtr;
1502
1503         if (node == NULL)
1504                 return;
1505
1506         switch(nodeTag(node)) {
1507                 case T_TargetEntry:
1508                         {
1509                                 TargetEntry     *tle = (TargetEntry *)node;
1510
1511                                 apply_RIR_view(
1512                                                 (Node **)(&(tle->expr)),
1513                                                 rt_index,
1514                                                 rte,
1515                                                 tlist,
1516                                                 modified,
1517                                                 sublevels_up);
1518                         }
1519                         break;
1520
1521                 case T_Aggreg:
1522                         {
1523                                 Aggreg  *agg = (Aggreg *)node;
1524
1525                                 apply_RIR_view(
1526                                                 (Node **)(&(agg->target)),
1527                                                 rt_index,
1528                                                 rte,
1529                                                 tlist,
1530                                                 modified,
1531                                                 sublevels_up);
1532                         }
1533                         break;
1534
1535                 case T_GroupClause:
1536                         {
1537                                 GroupClause     *grp = (GroupClause *)node;
1538
1539                                 apply_RIR_view(
1540                                                 (Node **)(&(grp->entry)),
1541                                                 rt_index,
1542                                                 rte,
1543                                                 tlist,
1544                                                 modified,
1545                                                 sublevels_up);
1546                         }
1547                         break;
1548
1549                 case T_Expr:
1550                         {
1551                                 Expr    *exp = (Expr *)node;
1552
1553                                 apply_RIR_view(
1554                                                 (Node **)(&(exp->args)),
1555                                                 rt_index,
1556                                                 rte,
1557                                                 tlist,
1558                                                 modified,
1559                                                 sublevels_up);
1560                         }
1561                         break;
1562
1563                 case T_Iter:
1564                         {
1565                                 Iter    *iter = (Iter *)node;
1566
1567                                 apply_RIR_view(
1568                                                 (Node **)(&(iter->iterexpr)),
1569                                                 rt_index,
1570                                                 rte,
1571                                                 tlist,
1572                                                 modified,
1573                                                 sublevels_up);
1574                         }
1575                         break;
1576
1577                 case T_ArrayRef:
1578                         {
1579                                 ArrayRef        *ref = (ArrayRef *)node;
1580
1581                                 apply_RIR_view(
1582                                                 (Node **)(&(ref->refupperindexpr)),
1583                                                 rt_index,
1584                                                 rte,
1585                                                 tlist,
1586                                                 modified,
1587                                                 sublevels_up);
1588                                 apply_RIR_view(
1589                                                 (Node **)(&(ref->reflowerindexpr)),
1590                                                 rt_index,
1591                                                 rte,
1592                                                 tlist,
1593                                                 modified,
1594                                                 sublevels_up);
1595                                 apply_RIR_view(
1596                                                 (Node **)(&(ref->refexpr)),
1597                                                 rt_index,
1598                                                 rte,
1599                                                 tlist,
1600                                                 modified,
1601                                                 sublevels_up);
1602                                 apply_RIR_view(
1603                                                 (Node **)(&(ref->refassgnexpr)),
1604                                                 rt_index,
1605                                                 rte,
1606                                                 tlist,
1607                                                 modified,
1608                                                 sublevels_up);
1609                         }
1610                         break;
1611
1612                 case T_Var:
1613                         {
1614                                 Var     *var = (Var *)node;
1615
1616                                 if (var->varlevelsup == sublevels_up &&
1617                                                 var->varno == rt_index) {
1618                                         Node            *exp;
1619
1620                                         if (var->varattno < 0)
1621                                                 elog(ERROR, "system column %s not available - %s is a view", get_attname(rte->relid, var->varattno), rte->relname);
1622                                         exp = FindMatchingTLEntry(
1623                                                         tlist,
1624                                                         get_attname(rte->relid,
1625                                                                 var->varattno));
1626
1627                                         if (exp == NULL) {
1628                                                 *nodePtr = make_null(var->vartype);
1629                                                 return;
1630                                         }
1631
1632                                         exp = copyObject(exp);
1633                                         if (var->varlevelsup > 0)
1634                                                 apply_RIR_adjust_sublevel(exp, var->varlevelsup);
1635                                         *nodePtr = exp;
1636                                         *modified = TRUE;
1637                                 }
1638                         }
1639                         break;
1640
1641                 case T_Param:
1642                         break;
1643
1644                 case T_Const:
1645                         break;
1646
1647                 case T_List:
1648                         {
1649                                 List    *l;
1650
1651                                 foreach (l, (List *)node)
1652                                         apply_RIR_view(
1653                                                         (Node **)(&(lfirst(l))),
1654                                                         rt_index,
1655                                                         rte,
1656                                                         tlist,
1657                                                         modified,
1658                                                         sublevels_up);
1659                         }
1660                         break;
1661
1662                 case T_SubLink:
1663                         {
1664                                 SubLink *sub = (SubLink *)node;
1665
1666                                 apply_RIR_view(
1667                                                 (Node **)(&(sub->lefthand)),
1668                                                 rt_index,
1669                                                 rte,
1670                                                 tlist,
1671                                                 modified,
1672                                                 sublevels_up);
1673
1674                                 apply_RIR_view(
1675                                                 (Node **)(&(sub->subselect)),
1676                                                 rt_index,
1677                                                 rte,
1678                                                 tlist,
1679                                                 modified,
1680                                                 sublevels_up + 1);
1681                         }
1682                         break;
1683
1684                 case T_Query:
1685                         {
1686                                 Query   *qry = (Query *)node;
1687
1688                                 apply_RIR_view(
1689                                                 (Node **)(&(qry->targetList)),
1690                                                 rt_index,
1691                                                 rte,
1692                                                 tlist,
1693                                                 modified,
1694                                                 sublevels_up);
1695
1696                                 apply_RIR_view(
1697                                                 (Node **)(&(qry->qual)),
1698                                                 rt_index,
1699                                                 rte,
1700                                                 tlist,
1701                                                 modified,
1702                                                 sublevels_up);
1703
1704                                 apply_RIR_view(
1705                                                 (Node **)(&(qry->havingQual)),
1706                                                 rt_index,
1707                                                 rte,
1708                                                 tlist,
1709                                                 modified,
1710                                                 sublevels_up);
1711
1712                                 apply_RIR_view(
1713                                                 (Node **)(&(qry->groupClause)),
1714                                                 rt_index,
1715                                                 rte,
1716                                                 tlist,
1717                                                 modified,
1718                                                 sublevels_up);
1719                         }
1720                         break;
1721
1722                 case T_CaseExpr:
1723                         {
1724                                 CaseExpr        *exp = (CaseExpr *)node;
1725
1726                                 apply_RIR_view(
1727                                                 (Node **)(&(exp->args)),
1728                                                 rt_index,
1729                                                 rte,
1730                                                 tlist,
1731                                                 modified,
1732                                                 sublevels_up);
1733
1734                                 apply_RIR_view(
1735                                                 (Node **)(&(exp->defresult)),
1736                                                 rt_index,
1737                                                 rte,
1738                                                 tlist,
1739                                                 modified,
1740                                                 sublevels_up);
1741                         }
1742                         break;
1743
1744                 case T_CaseWhen:
1745                         {
1746                                 CaseWhen        *exp = (CaseWhen *)node;
1747
1748                                 apply_RIR_view(
1749                                                 (Node **)(&(exp->expr)),
1750                                                 rt_index,
1751                                                 rte,
1752                                                 tlist,
1753                                                 modified,
1754                                                 sublevels_up);
1755
1756                                 apply_RIR_view(
1757                                                 (Node **)(&(exp->result)),
1758                                                 rt_index,
1759                                                 rte,
1760                                                 tlist,
1761                                                 modified,
1762                                                 sublevels_up);
1763                         }
1764                         break;
1765
1766                 default:
1767                         elog(NOTICE, "unknown node tag %d in apply_RIR_view()", nodeTag(node));
1768                         elog(NOTICE, "Node is: %s", nodeToString(node));
1769                         break;
1770         }
1771 }
1772
1773
1774 static void
1775 ApplyRetrieveRule(Query *parsetree,
1776                                   RewriteRule *rule,
1777                                   int rt_index,
1778                                   int relation_level,
1779                                   Relation relation,
1780                                   int *modified)
1781 {
1782         Query      *rule_action = NULL;
1783         Node       *rule_qual;
1784         List       *rtable,
1785                            *rt;
1786         int                     nothing,
1787                                 rt_length;
1788         int                     badsql = FALSE;
1789
1790         rule_qual = rule->qual;
1791         if (rule->actions)
1792         {
1793                 if (length(rule->actions) > 1)  /* ??? because we don't handle
1794                                                                                  * rules with more than one
1795                                                                                  * action? -ay */
1796
1797                         return;
1798                 rule_action = copyObject(lfirst(rule->actions));
1799                 nothing = FALSE;
1800         }
1801         else
1802                 nothing = TRUE;
1803
1804         rtable = copyObject(parsetree->rtable);
1805         foreach(rt, rtable)
1806         {
1807                 RangeTblEntry *rte = lfirst(rt);
1808
1809                 /*
1810                  * this is to prevent add_missing_vars_to_base_rels() from adding
1811                  * a bogus entry to the new target list.
1812                  */
1813                 rte->inFromCl = false;
1814         }
1815         rt_length = length(rtable);
1816
1817         rtable = nconc(rtable, copyObject(rule_action->rtable));
1818         parsetree->rtable = rtable;
1819
1820         rule_action->rtable = rtable;
1821         OffsetVarNodes((Node *) rule_qual,   rt_length, 0);
1822         OffsetVarNodes((Node *) rule_action, rt_length, 0);
1823
1824         ChangeVarNodes((Node *) rule_qual, 
1825                                    PRS2_CURRENT_VARNO + rt_length, rt_index, 0);
1826         ChangeVarNodes((Node *) rule_action,
1827                                    PRS2_CURRENT_VARNO + rt_length, rt_index, 0);
1828
1829         if (relation_level)
1830         {
1831           apply_RIR_view((Node **) &parsetree, rt_index, 
1832                         (RangeTblEntry *)nth(rt_index - 1, rtable),
1833                         rule_action->targetList, modified, 0);
1834           apply_RIR_view((Node **) &rule_action, rt_index, 
1835                         (RangeTblEntry *)nth(rt_index - 1, rtable),
1836                         rule_action->targetList, modified, 0);
1837         }
1838         else
1839         {
1840           HandleRIRAttributeRule(parsetree, rtable, rule_action->targetList,
1841                                  rt_index, rule->attrno, modified, &badsql);
1842         }
1843         if (*modified && !badsql) {
1844           AddQual(parsetree, rule_action->qual);
1845           /* This will only work if the query made to the view defined by the following
1846            * groupClause groups by the same attributes or does not use group at all! */
1847           if (parsetree->groupClause == NULL)
1848             parsetree->groupClause=rule_action->groupClause;
1849           AddHavingQual(parsetree, rule_action->havingQual);
1850           parsetree->hasAggs = (rule_action->hasAggs || parsetree->hasAggs);
1851           parsetree->hasSubLinks = (rule_action->hasSubLinks ||  parsetree->hasSubLinks);
1852         }       
1853 }
1854
1855
1856 static void
1857 fireRIRonSubselect(Node *node)
1858 {
1859         if (node == NULL)
1860                 return;
1861
1862         switch(nodeTag(node)) {
1863                 case T_TargetEntry:
1864                         {
1865                                 TargetEntry     *tle = (TargetEntry *)node;
1866
1867                                 fireRIRonSubselect(
1868                                                 (Node *)(tle->expr));
1869                         }
1870                         break;
1871
1872                 case T_Aggreg:
1873                         {
1874                                 Aggreg  *agg = (Aggreg *)node;
1875
1876                                 fireRIRonSubselect(
1877                                                 (Node *)(agg->target));
1878                         }
1879                         break;
1880
1881                 case T_GroupClause:
1882                         {
1883                                 GroupClause     *grp = (GroupClause *)node;
1884
1885                                 fireRIRonSubselect(
1886                                                 (Node *)(grp->entry));
1887                         }
1888                         break;
1889
1890                 case T_Expr:
1891                         {
1892                                 Expr    *exp = (Expr *)node;
1893
1894                                 fireRIRonSubselect(
1895                                                 (Node *)(exp->args));
1896                         }
1897                         break;
1898
1899                 case T_Iter:
1900                         {
1901                                 Iter    *iter = (Iter *)node;
1902
1903                                 fireRIRonSubselect(
1904                                                 (Node *)(iter->iterexpr));
1905                         }
1906                         break;
1907
1908                 case T_ArrayRef:
1909                         {
1910                                 ArrayRef        *ref = (ArrayRef *)node;
1911
1912                                 fireRIRonSubselect(
1913                                                 (Node *)(ref->refupperindexpr));
1914                                 fireRIRonSubselect(
1915                                                 (Node *)(ref->reflowerindexpr));
1916                                 fireRIRonSubselect(
1917                                                 (Node *)(ref->refexpr));
1918                                 fireRIRonSubselect(
1919                                                 (Node *)(ref->refassgnexpr));
1920                         }
1921                         break;
1922
1923                 case T_Var:
1924                         break;
1925
1926                 case T_Param:
1927                         break;
1928
1929                 case T_Const:
1930                         break;
1931
1932                 case T_List:
1933                         {
1934                                 List    *l;
1935
1936                                 foreach (l, (List *)node)
1937                                         fireRIRonSubselect(
1938                                                         (Node *)(lfirst(l)));
1939                         }
1940                         break;
1941
1942                 case T_SubLink:
1943                         {
1944                                 SubLink *sub = (SubLink *)node;
1945                                 Query   *qry;
1946
1947                                 fireRIRonSubselect(
1948                                                 (Node *)(sub->lefthand));
1949
1950                                 qry = fireRIRrules((Query *)(sub->subselect));
1951
1952                                 fireRIRonSubselect(
1953                                                 (Node *)qry);
1954
1955                                 sub->subselect = (Node *) qry;
1956                         }
1957                         break;
1958
1959                 case T_CaseExpr:
1960                         {
1961                                 CaseExpr        *exp = (CaseExpr *)node;
1962
1963                                 fireRIRonSubselect(
1964                                                 (Node *)(exp->args));
1965
1966                                 fireRIRonSubselect(
1967                                                 (Node *)(exp->defresult));
1968                         }
1969                         break;
1970
1971                 case T_CaseWhen:
1972                         {
1973                                 CaseWhen        *exp = (CaseWhen *)node;
1974
1975                                 fireRIRonSubselect(
1976                                                 (Node *)(exp->expr));
1977
1978                                 fireRIRonSubselect(
1979                                                 (Node *)(exp->result));
1980                         }
1981                         break;
1982
1983                 case T_Query:
1984                         {
1985                                 Query   *qry = (Query *)node;
1986
1987                                 fireRIRonSubselect(
1988                                                 (Node *)(qry->targetList));
1989
1990                                 fireRIRonSubselect(
1991                                                 (Node *)(qry->qual));
1992
1993                                 fireRIRonSubselect(
1994                                                 (Node *)(qry->havingQual));
1995
1996                                 fireRIRonSubselect(
1997                                                 (Node *)(qry->groupClause));
1998                         }
1999                         break;
2000
2001                 default:
2002                         elog(NOTICE, "unknown node tag %d in fireRIRonSubselect()", nodeTag(node));
2003                         elog(NOTICE, "Node is: %s", nodeToString(node));
2004                         break;
2005
2006
2007         }
2008 }
2009
2010
2011 /*
2012  * fireRIRrules -
2013  *      Apply all RIR rules on each rangetable entry in a query
2014  */
2015 static Query *
2016 fireRIRrules(Query *parsetree)
2017 {
2018         int             rt_index;
2019         RangeTblEntry   *rte;
2020         Relation        rel;
2021         List            *locks;
2022         RuleLock        *rules;
2023         RewriteRule     *rule;
2024         RewriteRule     RIRonly;
2025         int             modified;
2026         int             i;
2027         List            *l;
2028
2029         rt_index = 0;
2030         while(rt_index < length(parsetree->rtable)) {
2031                 ++rt_index;
2032
2033                 if (!rangeTableEntry_used((Node *)parsetree, rt_index, 0))
2034                         continue;
2035                 
2036                 rte = nth(rt_index - 1, parsetree->rtable);
2037                 rel = heap_openr(rte->relname);
2038                 if (rel->rd_rules == NULL) {
2039                         heap_close(rel);
2040                         continue;
2041                 }
2042
2043                 rules = rel->rd_rules;
2044                 locks = NIL;
2045
2046                 /*
2047                  * Collect the RIR rules that we must apply
2048                  */
2049                 for (i = 0; i < rules->numLocks; i++) {
2050                         rule = rules->rules[i];
2051                         if (rule->event != CMD_SELECT)
2052                                 continue;
2053                         
2054                         if (rule->attrno > 0 &&
2055                                         !attribute_used((Node *)parsetree,
2056                                                         rt_index,
2057                                                         rule->attrno, 0))
2058                                 continue;
2059
2060                         locks = lappend(locks, rule);
2061                 }
2062
2063                 /*
2064                  * Check permissions
2065                  */
2066                 checkLockPerms(locks, parsetree, rt_index);
2067
2068                 /*
2069                  * Now apply them
2070                  */
2071                 foreach (l, locks) {
2072                         rule = lfirst(l);
2073
2074                         RIRonly.event   = rule->event;
2075                         RIRonly.attrno  = rule->attrno;
2076                         RIRonly.qual    = rule->qual;
2077                         RIRonly.actions = rule->actions;
2078
2079                         ApplyRetrieveRule(parsetree,
2080                                         &RIRonly,
2081                                         rt_index,
2082                                         RIRonly.attrno == -1,
2083                                         rel,
2084                                         &modified);
2085                 }
2086
2087                 heap_close(rel);
2088         }
2089
2090         fireRIRonSubselect((Node *) parsetree);
2091         modifyAggregQual((Node **) &(parsetree->qual), parsetree);
2092
2093         return parsetree;
2094 }
2095
2096
2097 /*
2098  * idea is to fire regular rules first, then qualified instead
2099  * rules and unqualified instead rules last. Any lemming is counted for.
2100  */
2101 static List *
2102 orderRules(List *locks)
2103 {
2104         List       *regular = NIL;
2105         List       *instead_rules = NIL;
2106         List       *instead_qualified = NIL;
2107         List       *i;
2108
2109         foreach(i, locks)
2110         {
2111                 RewriteRule *rule_lock = (RewriteRule *) lfirst(i);
2112
2113                 if (rule_lock->isInstead)
2114                 {
2115                         if (rule_lock->qual == NULL)
2116                                 instead_rules = lappend(instead_rules, rule_lock);
2117                         else
2118                                 instead_qualified = lappend(instead_qualified, rule_lock);
2119                 }
2120                 else
2121                         regular = lappend(regular, rule_lock);
2122         }
2123         regular = nconc(regular, instead_qualified);
2124         return nconc(regular, instead_rules);
2125 }
2126
2127
2128
2129 static Query *
2130 CopyAndAddQual(Query *parsetree,
2131                            List *actions,
2132                            Node *rule_qual,
2133                            int rt_index,
2134                            CmdType event)
2135 {
2136         Query      *new_tree = (Query *) copyObject(parsetree);
2137         Node       *new_qual = NULL;
2138         Query      *rule_action = NULL;
2139
2140         if (actions)
2141                 rule_action = lfirst(actions);
2142         if (rule_qual != NULL)
2143                 new_qual = (Node *) copyObject(rule_qual);
2144         if (rule_action != NULL)
2145         {
2146                 List       *rtable;
2147                 int                     rt_length;
2148
2149                 rtable = new_tree->rtable;
2150                 rt_length = length(rtable);
2151                 rtable = append(rtable, listCopy(rule_action->rtable));
2152                 new_tree->rtable = rtable;
2153                 OffsetVarNodes(new_qual, rt_length, 0);
2154                 ChangeVarNodes(new_qual, PRS2_CURRENT_VARNO + rt_length, rt_index, 0);
2155         }
2156         /* XXX -- where current doesn't work for instead nothing.... yet */
2157         AddNotQual(new_tree, new_qual);
2158
2159         return new_tree;
2160 }
2161
2162
2163
2164 /*
2165  *      fireRules -
2166  *         Iterate through rule locks applying rules.
2167  *         All rules create their own parsetrees. Instead rules
2168  *         with rule qualification save the original parsetree
2169  *         and add their negated qualification to it. Real instead
2170  *         rules finally throw away the original parsetree.
2171  *
2172  *         remember: reality is for dead birds -- glass
2173  *
2174  */
2175 static List *
2176 fireRules(Query *parsetree,
2177                   int rt_index,
2178                   CmdType event,
2179                   bool *instead_flag,
2180                   List *locks,
2181                   List **qual_products)
2182 {
2183         RewriteInfo *info;
2184         List       *results = NIL;
2185         List       *i;
2186
2187         /* choose rule to fire from list of rules */
2188         if (locks == NIL)
2189         {
2190                 return NIL;
2191         }
2192
2193         locks = orderRules(locks);      /* real instead rules last */
2194         foreach(i, locks)
2195         {
2196                 RewriteRule *rule_lock = (RewriteRule *) lfirst(i);
2197                 Node       *qual,
2198                                    *event_qual;
2199                 List       *actions;
2200                 List       *r;
2201
2202                 /*
2203                  * Instead rules change the resultRelation of the query. So the
2204                  * permission checks on the initial resultRelation would never be
2205                  * done (this is normally done in the executor deep down). So we
2206                  * must do it here. The result relations resulting from earlier
2207                  * rewrites are already checked against the rules eventrelation
2208                  * owner (during matchLocks) and have the skipAcl flag set.
2209                  */
2210                 if (rule_lock->isInstead &&
2211                         parsetree->commandType != CMD_SELECT)
2212                 {
2213                         RangeTblEntry *rte;
2214                         int32           acl_rc;
2215                         int32           reqperm;
2216
2217                         switch (parsetree->commandType)
2218                         {
2219                                 case CMD_INSERT:
2220                                         reqperm = ACL_AP;
2221                                         break;
2222                                 default:
2223                                         reqperm = ACL_WR;
2224                                         break;
2225                         }
2226
2227                         rte = (RangeTblEntry *) nth(parsetree->resultRelation - 1,
2228                                                                                 parsetree->rtable);
2229                         if (!rte->skipAcl)
2230                         {
2231                                 acl_rc = pg_aclcheck(rte->relname,
2232                                                                          GetPgUserName(), reqperm);
2233                                 if (acl_rc != ACLCHECK_OK)
2234                                 {
2235                                         elog(ERROR, "%s: %s",
2236                                                  rte->relname,
2237                                                  aclcheck_error_strings[acl_rc]);
2238                                 }
2239                         }
2240                 }
2241
2242                 /* multiple rule action time */
2243                 *instead_flag = rule_lock->isInstead;
2244                 event_qual = rule_lock->qual;
2245                 actions = rule_lock->actions;
2246                 if (event_qual != NULL && *instead_flag)
2247                 {
2248                         Query      *qual_product;
2249                         RewriteInfo qual_info;
2250
2251                         /* ----------
2252                          * If there are instead rules with qualifications,
2253                          * the original query is still performed. But all
2254                          * the negated rule qualifications of the instead
2255                          * rules are added so it does it's actions only
2256                          * in cases where the rule quals of all instead
2257                          * rules are false. Think of it as the default
2258                          * action in a case. We save this in *qual_products
2259                          * so deepRewriteQuery() can add it to the query
2260                          * list after we mangled it up enough.
2261                          * ----------
2262                          */
2263                         if (*qual_products == NIL)
2264                                 qual_product = parsetree;
2265                         else
2266                                 qual_product = (Query *) nth(0, *qual_products);
2267
2268                         qual_info.event = qual_product->commandType;
2269                         qual_info.new_varno = length(qual_product->rtable) + 2;
2270                         qual_product = CopyAndAddQual(qual_product,
2271                                                                                   actions,
2272                                                                                   event_qual,
2273                                                                                   rt_index,
2274                                                                                   event);
2275
2276                         qual_info.rule_action = qual_product;
2277
2278                         if (event == CMD_INSERT || event == CMD_UPDATE)
2279                                 FixNew(&qual_info, qual_product);
2280
2281                         *qual_products = lappend(NIL, qual_product);
2282                 }
2283
2284                 foreach(r, actions)
2285                 {
2286                         Query      *rule_action = lfirst(r);
2287                         Node       *rule_qual = copyObject(event_qual);
2288
2289                         if (rule_action->commandType == CMD_NOTHING)
2290                                 continue;
2291
2292                         /*--------------------------------------------------
2293                          * We copy the qualifications of the parsetree
2294                          * to the action and vice versa. So force
2295                          * hasSubLinks if one of them has it.
2296                          *
2297                          * As of 6.4 only parsetree qualifications can
2298                          * have sublinks. If this changes, we must make
2299                          * this a node lookup at the end of rewriting.
2300                          *
2301                          * Jan
2302                          *--------------------------------------------------
2303                          */
2304                         if (parsetree->hasSubLinks && !rule_action->hasSubLinks)
2305                         {
2306                                 rule_action = copyObject(rule_action);
2307                                 rule_action->hasSubLinks = TRUE;
2308                         }
2309                         if (!parsetree->hasSubLinks && rule_action->hasSubLinks)
2310                         {
2311                                 parsetree->hasSubLinks = TRUE;
2312                         }
2313
2314                         /*--------------------------------------------------
2315                          * Step 1:
2316                          *        Rewrite current.attribute or current to tuple variable
2317                          *        this appears to be done in parser?
2318                          *--------------------------------------------------
2319                          */
2320                         info = gatherRewriteMeta(parsetree, rule_action, rule_qual,
2321                                                                          rt_index, event, instead_flag);
2322
2323                         /* handle escapable cases, or those handled by other code */
2324                         if (info->nothing)
2325                         {
2326                                 if (*instead_flag)
2327                                         return NIL;
2328                                 else
2329                                         continue;
2330                         }
2331
2332                         if (info->action == info->event &&
2333                                 info->event == CMD_SELECT)
2334                                 continue;
2335
2336                         /*
2337                          * Event Qualification forces copying of parsetree and
2338                          * splitting into two queries one w/rule_qual, one w/NOT
2339                          * rule_qual. Also add user query qual onto rule action
2340                          */
2341                         qual = parsetree->qual;
2342                         AddQual(info->rule_action, qual);
2343
2344                         if (info->rule_qual != NULL)
2345                                 AddQual(info->rule_action, info->rule_qual);
2346
2347                         /*--------------------------------------------------
2348                          * Step 2:
2349                          *        Rewrite new.attribute w/ right hand side of target-list
2350                          *        entry for appropriate field name in insert/update
2351                          *--------------------------------------------------
2352                          */
2353                         if ((info->event == CMD_INSERT) || (info->event == CMD_UPDATE))
2354                                 FixNew(info, parsetree);
2355
2356                         /*--------------------------------------------------
2357                          * Step 3:
2358                          *        rewriting due to retrieve rules
2359                          *--------------------------------------------------
2360                          */
2361                         info->rule_action->rtable = info->rt;
2362                         /*
2363                         ProcessRetrieveQuery(info->rule_action, info->rt,
2364                                                                  &orig_instead_flag, TRUE);
2365                         */
2366
2367                         /*--------------------------------------------------
2368                          * Step 4
2369                          *        Simplify? hey, no algorithm for simplification... let
2370                          *        the planner do it.
2371                          *--------------------------------------------------
2372                          */
2373                         results = lappend(results, info->rule_action);
2374
2375                         pfree(info);
2376                 }
2377
2378                 /* ----------
2379                  * If this was an unqualified instead rule,
2380                  * throw away an eventually saved 'default' parsetree
2381                  * ----------
2382                  */
2383                 if (event_qual == NULL && *instead_flag)
2384                         *qual_products = NIL;
2385         }
2386         return results;
2387 }
2388
2389
2390
2391 static List *
2392 RewriteQuery(Query *parsetree, bool *instead_flag, List **qual_products)
2393 {
2394         CmdType         event;
2395         List            *product_queries = NIL;
2396         int             result_relation = 0;
2397         RangeTblEntry   *rt_entry;
2398         Relation        rt_entry_relation = NULL;
2399         RuleLock        *rt_entry_locks = NULL;
2400
2401         Assert(parsetree != NULL);
2402
2403         event = parsetree->commandType;
2404
2405         /*
2406          * SELECT rules are handled later when we have all the
2407          * queries that should get executed
2408          */
2409         if (event == CMD_SELECT)
2410                 return NIL;
2411
2412         /*
2413          * Utilities aren't rewritten at all - why is this here?
2414          */
2415         if (event == CMD_UTILITY)
2416                 return NIL;
2417
2418         /*
2419          * only for a delete may the targetlist be NULL
2420          */
2421         if (event != CMD_DELETE)
2422                 Assert(parsetree->targetList != NULL);
2423
2424         result_relation = parsetree->resultRelation;
2425
2426         /*
2427          * the statement is an update, insert or delete - fire rules
2428          * on it.
2429          */
2430         rt_entry = rt_fetch(result_relation, parsetree->rtable);
2431         rt_entry_relation = heap_openr(rt_entry->relname);
2432         rt_entry_locks = rt_entry_relation->rd_rules;
2433         heap_close(rt_entry_relation);
2434
2435         if (rt_entry_locks != NULL)
2436         {
2437                 List       *locks =
2438                 matchLocks(event, rt_entry_locks, result_relation, parsetree);
2439
2440                 product_queries =
2441                         fireRules(parsetree,
2442                                           result_relation,
2443                                           event,
2444                                           instead_flag,
2445                                           locks,
2446                                           qual_products);
2447         }
2448
2449         return product_queries;
2450
2451 }
2452
2453
2454 /*
2455  * to avoid infinite recursion, we restrict the number of times a query
2456  * can be rewritten. Detecting cycles is left for the reader as an excercise.
2457  */
2458 #ifndef REWRITE_INVOKE_MAX
2459 #define REWRITE_INVOKE_MAX              10
2460 #endif
2461
2462 static int      numQueryRewriteInvoked = 0;
2463
2464 /*
2465  * deepRewriteQuery -
2466  *        rewrites the query and apply the rules again on the queries rewritten
2467  */
2468 static List *
2469 deepRewriteQuery(Query *parsetree)
2470 {
2471         List       *n;
2472         List       *rewritten = NIL;
2473         List       *result = NIL;
2474         bool            instead;
2475         List       *qual_products = NIL;
2476
2477
2478
2479         if (++numQueryRewriteInvoked > REWRITE_INVOKE_MAX)
2480         {
2481                 elog(ERROR, "query rewritten %d times, may contain cycles",
2482                          numQueryRewriteInvoked - 1);
2483         }
2484
2485         instead = FALSE;
2486         result = RewriteQuery(parsetree, &instead, &qual_products);
2487
2488         foreach(n, result)
2489         {
2490                 Query      *pt = lfirst(n);
2491                 List       *newstuff = NIL;
2492
2493                 newstuff = deepRewriteQuery(pt);
2494                 if (newstuff != NIL)
2495                         rewritten = nconc(rewritten, newstuff);
2496         }
2497
2498         /* ----------
2499          * qual_products are the original query with the negated
2500          * rule qualification of an instead rule
2501          * ----------
2502          */
2503         if (qual_products != NIL)
2504                 rewritten = nconc(rewritten, qual_products);
2505
2506         /* ----------
2507          * The original query is appended last if not instead
2508          * because update and delete rule actions might not do
2509          * anything if they are invoked after the update or
2510          * delete is performed. The command counter increment
2511          * between the query execution makes the deleted (and
2512          * maybe the updated) tuples disappear so the scans
2513          * for them in the rule actions cannot find them.
2514          * ----------
2515          */
2516         if (!instead)
2517                 rewritten = lappend(rewritten, parsetree);
2518
2519         return rewritten;
2520 }
2521
2522
2523 /*
2524  * QueryOneRewrite -
2525  *        rewrite one query
2526  */
2527 static List *
2528 QueryRewriteOne(Query *parsetree)
2529 {
2530         numQueryRewriteInvoked = 0;
2531
2532         /*
2533          * take a deep breath and apply all the rewrite rules - ay
2534          */
2535         return deepRewriteQuery(parsetree);
2536 }
2537
2538
2539 /* ----------
2540  * RewritePreprocessQuery -
2541  *      adjust details in the parsetree, the rule system
2542  *      depends on
2543  * ----------
2544  */
2545 static void
2546 RewritePreprocessQuery(Query *parsetree)
2547 {
2548         /* ----------
2549          * if the query has a resultRelation, reassign the
2550          * result domain numbers to the attribute numbers in the
2551          * target relation. FixNew() depends on it when replacing
2552          * *new* references in a rule action by the expressions
2553          * from the rewritten query.
2554          * ----------
2555          */
2556         if (parsetree->resultRelation > 0)
2557         {
2558                 RangeTblEntry *rte;
2559                 Relation        rd;
2560                 List       *tl;
2561                 TargetEntry *tle;
2562                 int                     resdomno;
2563
2564                 rte = (RangeTblEntry *) nth(parsetree->resultRelation - 1,
2565                                                                         parsetree->rtable);
2566                 rd = heap_openr(rte->relname);
2567
2568                 foreach(tl, parsetree->targetList)
2569                 {
2570                         tle = (TargetEntry *) lfirst(tl);
2571                         resdomno = attnameAttNum(rd, tle->resdom->resname);
2572                         tle->resdom->resno = resdomno;
2573                 }
2574
2575                 heap_close(rd);
2576         }
2577 }
2578
2579
2580 /*
2581  * QueryRewrite -
2582  *        rewrite one query via query rewrite system, possibly returning 0
2583  *        or many queries
2584  */
2585 List *
2586 QueryRewrite(Query *parsetree)
2587 {
2588         List            *querylist;
2589         List            *results = NIL;
2590         List            *l;
2591         Query           *query;
2592
2593         /*
2594          * Step 1
2595          *
2596          * There still seems something broken with the resdom numbers
2597          * so we reassign them first.
2598          */
2599         RewritePreprocessQuery(parsetree);
2600
2601         /*
2602          * Step 2
2603          *
2604          * Apply all non-SELECT rules possibly getting 0 or many queries
2605          */
2606         querylist = QueryRewriteOne(parsetree);
2607
2608         /*
2609          * Step 3
2610          *
2611          * Apply all the RIR rules on each query
2612          */
2613         foreach (l, querylist) {
2614                 query = (Query *)lfirst(l);
2615                 results = lappend(results, fireRIRrules(query));
2616         }
2617
2618         return results;
2619 }
2620
2621