OSDN Git Service

Add Var.varlevelup to code. More parser cleanup.
[pg-rex/syncrep.git] / src / backend / parser / analyze.c
1 /*-------------------------------------------------------------------------
2  *
3  * analyze.c--
4  *        transform the parse tree into a query tree
5  *
6  * Copyright (c) 1994, Regents of the University of California
7  *
8  *
9  * IDENTIFICATION
10  *        $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.68 1998/01/20 22:11:51 momjian Exp $
11  *
12  *-------------------------------------------------------------------------
13  */
14
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <stdarg.h>
18 #include <string.h>
19
20 #include "postgres.h"
21 #include "access/heapam.h"
22 #include "nodes/makefuncs.h"
23 #include "nodes/memnodes.h"
24 #include "nodes/pg_list.h"
25 #include "parser/analyze.h"
26 #include "parser/parse_agg.h"
27 #include "parser/parse_clause.h"
28 #include "parser/parse_node.h"
29 #include "parser/parse_relation.h"
30 #include "parser/parse_target.h"
31 #include "utils/builtins.h"
32 #include "utils/mcxt.h"
33
34 static Query *transformStmt(ParseState *pstate, Node *stmt);
35 static Query *transformDeleteStmt(ParseState *pstate, DeleteStmt *stmt);
36 static Query *transformInsertStmt(ParseState *pstate, InsertStmt *stmt);
37 static Query *transformIndexStmt(ParseState *pstate, IndexStmt *stmt);
38 static Query *transformExtendStmt(ParseState *pstate, ExtendStmt *stmt);
39 static Query *transformRuleStmt(ParseState *query, RuleStmt *stmt);
40 static Query *transformSelectStmt(ParseState *pstate, SelectStmt *stmt);
41 static Query *transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt);
42 static Query *transformCursorStmt(ParseState *pstate, SelectStmt *stmt);
43 static Query *transformCreateStmt(ParseState *pstate, CreateStmt *stmt);
44
45 List   *extras = NIL;
46
47 /*
48  * parse_analyze -
49  *        analyze a list of parse trees and transform them if necessary.
50  *
51  * Returns a list of transformed parse trees. Optimizable statements are
52  * all transformed to Query while the rest stays the same.
53  *
54  */
55 QueryTreeList *
56 parse_analyze(List *pl, ParseState *parentParseState)
57 {
58         QueryTreeList *result;
59         ParseState *pstate;
60         int                     i = 0;
61
62         result = malloc(sizeof(QueryTreeList));
63         result->len = length(pl);
64         result->qtrees = (Query **) malloc(result->len * sizeof(Query *));
65
66         while (pl != NIL)
67         {
68                 pstate = make_parsestate(parentParseState);
69                 result->qtrees[i++] = transformStmt(pstate, lfirst(pl));
70                 if (pstate->p_target_relation != NULL)
71                         heap_close(pstate->p_target_relation);
72
73                 if (extras != NIL)
74                 {
75                         result->len += length(extras);
76                         result->qtrees = (Query **) realloc(result->qtrees, result->len * sizeof(Query *));
77                         while (extras != NIL)
78                         {
79                                 result->qtrees[i++] = transformStmt(pstate, lfirst(extras));
80                                 if (pstate->p_target_relation != NULL)
81                                         heap_close(pstate->p_target_relation);
82                                 extras = lnext(extras);
83                         }
84                 }
85                 extras = NIL;
86                 pl = lnext(pl);
87                 pfree(pstate);
88         }
89
90         return result;
91 }
92
93 /*
94  * transformStmt -
95  *        transform a Parse tree. If it is an optimizable statement, turn it
96  *        into a Query tree.
97  */
98 static Query *
99 transformStmt(ParseState *pstate, Node *parseTree)
100 {
101         Query      *result = NULL;
102
103         switch (nodeTag(parseTree))
104         {
105                 /*------------------------
106                  *      Non-optimizable statements
107                  *------------------------
108                  */
109                 case T_CreateStmt:
110                         result = transformCreateStmt(pstate, (CreateStmt *) parseTree);
111                         break;
112
113                 case T_IndexStmt:
114                         result = transformIndexStmt(pstate, (IndexStmt *) parseTree);
115                         break;
116
117                 case T_ExtendStmt:
118                         result = transformExtendStmt(pstate, (ExtendStmt *) parseTree);
119                         break;
120
121                 case T_RuleStmt:
122                         result = transformRuleStmt(pstate, (RuleStmt *) parseTree);
123                         break;
124
125                 case T_ViewStmt:
126                         {
127                                 ViewStmt   *n = (ViewStmt *) parseTree;
128
129                                 n->query = (Query *) transformStmt(pstate, (Node *) n->query);
130                                 result = makeNode(Query);
131                                 result->commandType = CMD_UTILITY;
132                                 result->utilityStmt = (Node *) n;
133                         }
134                         break;
135
136                 case T_VacuumStmt:
137                         {
138                                 MemoryContext oldcontext;
139
140                                 /*
141                                  * make sure that this Query is allocated in TopMemory
142                                  * context because vacuum spans transactions and we don't
143                                  * want to lose the vacuum Query due to end-of-transaction
144                                  * free'ing
145                                  */
146                                 oldcontext = MemoryContextSwitchTo(TopMemoryContext);
147                                 result = makeNode(Query);
148                                 result->commandType = CMD_UTILITY;
149                                 result->utilityStmt = (Node *) parseTree;
150                                 MemoryContextSwitchTo(oldcontext);
151                                 break;
152
153                         }
154                 case T_ExplainStmt:
155                         {
156                                 ExplainStmt *n = (ExplainStmt *) parseTree;
157
158                                 result = makeNode(Query);
159                                 result->commandType = CMD_UTILITY;
160                                 n->query = transformStmt(pstate, (Node *) n->query);
161                                 result->utilityStmt = (Node *) parseTree;
162                         }
163                         break;
164
165                 /*------------------------
166                  *      Optimizable statements
167                  *------------------------
168                  */
169                 case T_InsertStmt:
170                         result = transformInsertStmt(pstate, (InsertStmt *) parseTree);
171                         break;
172
173                 case T_DeleteStmt:
174                         result = transformDeleteStmt(pstate, (DeleteStmt *) parseTree);
175                         break;
176
177                 case T_UpdateStmt:
178                         result = transformUpdateStmt(pstate, (UpdateStmt *) parseTree);
179                         break;
180
181                 case T_SelectStmt:
182                         if (!((SelectStmt *)parseTree)->portalname)
183                                 result = transformSelectStmt(pstate, (SelectStmt *) parseTree);
184                         else
185                                 result = transformCursorStmt(pstate, (SelectStmt *) parseTree);
186                         break;
187
188                 default:
189
190                         /*
191                          * other statments don't require any transformation-- just
192                          * return the original parsetree, yea!
193                          */
194                         result = makeNode(Query);
195                         result->commandType = CMD_UTILITY;
196                         result->utilityStmt = (Node *) parseTree;
197                         break;
198         }
199         return result;
200 }
201
202 /*
203  * transformDeleteStmt -
204  *        transforms a Delete Statement
205  */
206 static Query *
207 transformDeleteStmt(ParseState *pstate, DeleteStmt *stmt)
208 {
209         Query      *qry = makeNode(Query);
210
211         qry->commandType = CMD_DELETE;
212
213         /* set up a range table */
214         makeRangeTable(pstate, stmt->relname, NULL);
215
216         qry->uniqueFlag = NULL;
217
218         /* fix where clause */
219         qry->qual = transformWhereClause(pstate, stmt->whereClause);
220
221         qry->rtable = pstate->p_rtable;
222         qry->resultRelation = refnameRangeTablePosn(pstate, stmt->relname, NULL);
223
224         qry->hasAggs = pstate->p_hasAggs;
225         if (pstate->p_hasAggs)
226                 parseCheckAggregates(pstate, qry);
227
228         return (Query *) qry;
229 }
230
231 /*
232  * transformInsertStmt -
233  *        transform an Insert Statement
234  */
235 static Query *
236 transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
237 {
238         Query      *qry = makeNode(Query);      /* make a new query tree */
239         List       *icolumns;
240
241         qry->commandType = CMD_INSERT;
242         pstate->p_is_insert = true;
243
244         /* set up a range table */
245         makeRangeTable(pstate, stmt->relname, stmt->fromClause);
246
247         qry->uniqueFlag = stmt->unique;
248
249         /* fix the target list */
250         icolumns = pstate->p_insert_columns = makeTargetNames(pstate, stmt->cols);
251         
252         qry->targetList = transformTargetList(pstate, stmt->targetList);
253         
254         /* DEFAULT handling */
255         if (length(qry->targetList) < pstate->p_target_relation->rd_att->natts &&
256                 pstate->p_target_relation->rd_att->constr &&
257                 pstate->p_target_relation->rd_att->constr->num_defval > 0)
258         {
259                 AttributeTupleForm         *att = pstate->p_target_relation->rd_att->attrs;
260                 AttrDefault                        *defval = pstate->p_target_relation->rd_att->constr->defval;
261                 int                                             ndef = pstate->p_target_relation->rd_att->constr->num_defval;
262                 
263                 /* 
264                  * if stmt->cols == NIL then makeTargetNames returns list of all
265                  * attrs: have to shorter icolumns list...
266                  */
267                 if (stmt->cols == NIL)
268                 {
269                         List   *extrl;
270                         int             i = length(qry->targetList);
271                         
272                         foreach (extrl, icolumns)
273                         {
274                                 if (--i <= 0)
275                                         break;
276                         }
277                         freeList (lnext(extrl));
278                         lnext(extrl) = NIL;
279                 }
280                 
281                 while (ndef-- > 0)
282                 {
283                         List               *tl;
284                         Ident              *id;
285                         TargetEntry        *te;
286                         
287                         foreach (tl, icolumns)
288                         {
289                                 id = (Ident *) lfirst(tl);
290                                 if (!namestrcmp(&(att[defval[ndef].adnum - 1]->attname), id->name))
291                                         break;
292                         }
293                         if (tl != NIL)          /* something given for this attr */
294                                 continue;
295                         /* 
296                          * Nothing given for this attr with DEFAULT expr, so
297                          * add new TargetEntry to qry->targetList. 
298                          * Note, that we set resno to defval[ndef].adnum:
299                          * it's what transformTargetList()->make_targetlist_expr()
300                          * does for INSERT ... SELECT. But for INSERT ... VALUES
301                          * pstate->p_last_resno is used. It doesn't matter for 
302                          * "normal" using (planner creates proper target list
303                          * in preptlist.c), but may break RULEs in some way.
304                          * It seems better to create proper target list here...
305                          */
306                         te = makeNode(TargetEntry);
307                         te->resdom = makeResdom(defval[ndef].adnum,
308                                                                         att[defval[ndef].adnum - 1]->atttypid,
309                                                                         att[defval[ndef].adnum - 1]->attlen,
310                                                                         pstrdup(nameout(&(att[defval[ndef].adnum - 1]->attname))),
311                                                                         0, 0, 0);
312                         te->fjoin = NULL;
313                         te->expr = (Node *) stringToNode(defval[ndef].adbin);
314                         qry->targetList = lappend (qry->targetList, te);
315                 }
316         }
317         
318         /* fix where clause */
319         qry->qual = transformWhereClause(pstate, stmt->whereClause);
320
321         /* now the range table will not change */
322         qry->rtable = pstate->p_rtable;
323         qry->resultRelation = refnameRangeTablePosn(pstate, stmt->relname, NULL);
324
325         qry->groupClause = transformGroupClause(pstate,
326                                                                                         stmt->groupClause,
327                                                                                         qry->targetList);
328
329         /* fix order clause */
330         qry->sortClause = transformSortClause(pstate,
331                                                                                   NIL,
332                                                                                   NIL,
333                                                                                   qry->targetList,
334                                                                                   qry->uniqueFlag);
335
336         qry->hasAggs = pstate->p_hasAggs;
337         if (pstate->p_hasAggs)
338                 parseCheckAggregates(pstate, qry);
339
340         /* The INSERT INTO ... SELECT ... could have a UNION */
341         qry->unionall = stmt->unionall; /* in child, so unionClause may be false */
342         qry->unionClause = transformUnionClause(stmt->unionClause, qry->targetList);
343
344         return (Query *) qry;
345 }
346
347 /*
348  *      makeTableName()
349  *      Create a table name from a list of fields.
350  */
351 static char *
352 makeTableName(void *elem,...)
353 {
354         va_list args;
355
356         char   *name;
357         char    buf[NAMEDATALEN+1];
358
359         buf[0] = '\0';
360
361         va_start(args,elem);
362
363         name = elem;
364         while (name != NULL)
365         {
366                 /* not enough room for next part? then return nothing */
367                 if ((strlen(buf)+strlen(name)) >= (sizeof(buf)-1))
368                         return (NULL);
369
370                 if (strlen(buf) > 0)
371                         strcat(buf,"_");
372                 strcat(buf,name);
373
374                 name = va_arg(args,void *);
375         }
376
377         va_end(args);
378
379         name = palloc(strlen(buf)+1);
380         strcpy(name,buf);
381
382         return (name);
383 }
384
385 static char *
386 CreateIndexName(char *tname, char *cname, char *label, List *indices)
387 {
388         int                     pass = 0;
389         char       *iname = NULL;
390         List       *ilist;
391         IndexStmt  *index;
392         char            name2[NAMEDATALEN+1];
393
394         /* use working storage, since we might be trying several possibilities */
395         strcpy(name2,cname);
396         while (iname == NULL)
397         {
398                 iname = makeTableName(tname, name2, label, NULL);
399                 /* unable to make a name at all? then quit */
400                 if (iname == NULL)
401                         break;
402
403                 ilist = indices;
404                 while (ilist != NIL)
405                 {
406                         index = lfirst(ilist);
407                         if (strcasecmp(iname,index->idxname) == 0)
408                                 break;
409
410                         ilist = lnext(ilist);
411                 }
412                 /* ran through entire list? then no name conflict found so done */
413                 if (ilist == NIL)
414                         break;
415
416                 /* the last one conflicted, so try a new name component */
417                 pfree(iname);
418                 iname = NULL;
419                 pass++;
420                 sprintf(name2, "%s_%d", cname, (pass+1));
421         }
422
423         return (iname);
424 }
425
426 /*
427  * transformCreateStmt -
428  *        transforms the "create table" statement
429  *        SQL92 allows constraints to be scattered all over, so thumb through
430  *         the columns and collect all constraints into one place.
431  *        If there are any implied indices (e.g. UNIQUE or PRIMARY KEY)
432  *         then expand those into multiple IndexStmt blocks.
433  *        - thomas 1997-12-02
434  */
435 static Query *
436 transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
437 {
438         Query      *q;
439         int                     have_pkey = FALSE;
440         List       *elements;
441         Node       *element;
442         List       *columns;
443         List       *dlist;
444         ColumnDef  *column;
445         List       *constraints, *clist;
446         Constraint *constraint;
447         List       *keys;
448         Ident      *key;
449         List       *ilist;
450         IndexStmt  *index;
451         IndexElem  *iparam;
452
453         q = makeNode(Query);
454         q->commandType = CMD_UTILITY;
455
456         elements = stmt->tableElts;
457         constraints = stmt->constraints;
458         columns = NIL;
459         dlist = NIL;
460
461         while (elements != NIL)
462         {
463                 element = lfirst(elements);
464                 switch (nodeTag(element))
465                 {
466                         case T_ColumnDef:
467                                 column = (ColumnDef *) element;
468                                 columns = lappend(columns,column);
469                                 if (column->constraints != NIL)
470                                 {
471                                         clist = column->constraints;
472                                         while (clist != NIL)
473                                         {
474                                                 constraint = lfirst(clist);
475                                                 switch (constraint->contype)
476                                                 {
477                                                         case CONSTR_NOTNULL:
478                                                                 if (column->is_not_null)
479                                                                         elog(ERROR,"CREATE TABLE/NOT NULL already specified"
480                                                                                 " for %s.%s", stmt->relname, column->colname);
481                                                                 column->is_not_null = TRUE;
482                                                                 break;
483
484                                                         case CONSTR_DEFAULT:
485                                                                 if (column->defval != NULL)
486                                                                         elog(ERROR,"CREATE TABLE/DEFAULT multiple values specified"
487                                                                                 " for %s.%s", stmt->relname, column->colname);
488                                                                 column->defval = constraint->def;
489                                                                 break;
490
491                                                         case CONSTR_PRIMARY:
492                                                                 if (constraint->name == NULL)
493                                                                         constraint->name = makeTableName(stmt->relname, "pkey", NULL);
494                                                                 if (constraint->keys == NIL)
495                                                                         constraint->keys = lappend(constraint->keys, column);
496                                                                 dlist = lappend(dlist, constraint);
497                                                                 break;
498
499                                                         case CONSTR_UNIQUE:
500                                                                 if (constraint->name == NULL)
501                                                                         constraint->name = makeTableName(stmt->relname, column->colname, "key", NULL);
502                                                                 if (constraint->keys == NIL)
503                                                                         constraint->keys = lappend(constraint->keys, column);
504                                                                 dlist = lappend(dlist, constraint);
505                                                                 break;
506
507                                                         case CONSTR_CHECK:
508                                                                 constraints = lappend(constraints, constraint);
509                                                                 if (constraint->name == NULL)
510                                                                         constraint->name = makeTableName(stmt->relname, column->colname, NULL);
511                                                                 break;
512
513                                                         default:
514                                                                 elog(ERROR,"parser: internal error; unrecognized constraint",NULL);
515                                                                 break;
516                                                 }
517                                                 clist = lnext(clist);
518                                         }
519                                 }
520                                 break;
521
522                         case T_Constraint:
523                                 constraint = (Constraint *) element;
524                                 switch (constraint->contype)
525                                 {
526                                         case CONSTR_PRIMARY:
527                                                 if (constraint->name == NULL)
528                                                         constraint->name = makeTableName(stmt->relname, "pkey", NULL);
529                                                 dlist = lappend(dlist, constraint);
530                                                 break;
531
532                                         case CONSTR_UNIQUE:
533 #if FALSE
534                                                 if (constraint->name == NULL)
535                                                         constraint->name = makeTableName(stmt->relname, "key", NULL);
536 #endif
537                                                 dlist = lappend(dlist, constraint);
538                                                 break;
539
540                                         case CONSTR_CHECK:
541                                                 constraints = lappend(constraints, constraint);
542                                                 break;
543
544                                         case CONSTR_NOTNULL:
545                                         case CONSTR_DEFAULT:
546                                                 elog(ERROR,"parser: internal error; illegal context for constraint",NULL);
547                                                 break;
548                                         default:
549                                                 elog(ERROR,"parser: internal error; unrecognized constraint",NULL);
550                                                 break;
551                                 }
552                                 break;
553
554                         default:
555                                 elog(ERROR,"parser: internal error; unrecognized node",NULL);
556                 }
557
558                 elements = lnext(elements);
559         }
560
561         stmt->tableElts = columns;
562         stmt->constraints = constraints;
563
564 /* Now run through the "deferred list" to complete the query transformation.
565  * For PRIMARY KEYs, mark each column as NOT NULL and create an index.
566  * For UNIQUE, create an index as for PRIMARY KEYS, but do not insist on NOT NULL.
567  *
568  * Note that this code does not currently look for all possible redundant cases
569  *  and either ignore or stop with warning. The create might fail later when
570  *  names for indices turn out to be redundant, or a user might have specified
571  *  extra useless indices which might hurt performance. - thomas 1997-12-08
572  */
573         ilist = NIL;
574         while (dlist != NIL)
575         {
576                 constraint = lfirst(dlist);
577                 if (nodeTag(constraint) != T_Constraint)
578                         elog(ERROR,"parser: internal error; unrecognized deferred node",NULL);
579
580                 if (constraint->contype == CONSTR_PRIMARY)
581                         if (have_pkey)
582                                 elog(ERROR,"CREATE TABLE/PRIMARY KEY multiple primary keys"
583                                         " for table %s are not legal", stmt->relname);
584                         else 
585                                 have_pkey = TRUE;
586                 else if (constraint->contype != CONSTR_UNIQUE)
587                         elog(ERROR,"parser: internal error; unrecognized deferred constraint",NULL);
588
589                 index = makeNode(IndexStmt);
590
591                 index->unique = TRUE;
592                 if (constraint->name != NULL)
593                         index->idxname = constraint->name;
594                 else if (constraint->contype == CONSTR_PRIMARY)
595                 {
596                         if (have_pkey)
597                                 elog(ERROR,"CREATE TABLE/PRIMARY KEY multiple keys for table %s are not legal", stmt->relname);
598
599                         have_pkey = TRUE;
600                         index->idxname = makeTableName(stmt->relname, "pkey", NULL);
601                 }
602                 else
603                         index->idxname = NULL;
604
605                 index->relname = stmt->relname;
606                 index->accessMethod = "btree";
607                 index->indexParams = NIL;
608                 index->withClause = NIL;
609                 index->whereClause = NULL;
610  
611                 keys = constraint->keys;
612                 while (keys != NIL)
613                 {
614                         key = lfirst(keys);
615                         columns = stmt->tableElts;
616                         column = NULL;
617                         while (columns != NIL)
618                         {
619                                 column = lfirst(columns);
620                                 if (strcasecmp(column->colname,key->name) == 0) break;
621                                 else column = NULL;
622                                 columns = lnext(columns);
623                         }
624                         if (column == NULL)
625                                 elog(ERROR,"parser: column '%s' in key does not exist",key->name);
626
627                         if (constraint->contype == CONSTR_PRIMARY)
628                                 column->is_not_null = TRUE;
629                         iparam = makeNode(IndexElem);
630                         iparam->name = strcpy(palloc(strlen(column->colname)+1), column->colname);
631                         iparam->args = NIL;
632                         iparam->class = NULL;
633                         iparam->tname = NULL;
634                         index->indexParams = lappend(index->indexParams, iparam);
635
636                         if (index->idxname == NULL)
637                                 index->idxname = CreateIndexName(stmt->relname, iparam->name, "key", ilist);
638
639                         keys = lnext(keys);
640                 }
641
642                 if (index->idxname == NULL)
643                         elog(ERROR,"parser: unable to construct implicit index for table %s"
644                                 "; name too long", stmt->relname);
645                 else
646                         elog(NOTICE,"CREATE TABLE/%s will create implicit index %s for table %s",
647                                 ((constraint->contype == CONSTR_PRIMARY)? "PRIMARY KEY": "UNIQUE"),
648                                 index->idxname, stmt->relname);
649
650                 ilist = lappend(ilist, index);
651                 dlist = lnext(dlist);
652         }
653
654         q->utilityStmt = (Node *) stmt;
655         extras = ilist;
656
657         return q;
658 }
659
660 /*
661  * transformIndexStmt -
662  *        transforms the qualification of the index statement
663  */
664 static Query *
665 transformIndexStmt(ParseState *pstate, IndexStmt *stmt)
666 {
667         Query      *q;
668
669         q = makeNode(Query);
670         q->commandType = CMD_UTILITY;
671
672         /* take care of the where clause */
673         stmt->whereClause = transformWhereClause(pstate, stmt->whereClause);
674         stmt->rangetable = pstate->p_rtable;
675
676         q->utilityStmt = (Node *) stmt;
677
678         return q;
679 }
680
681 /*
682  * transformExtendStmt -
683  *        transform the qualifications of the Extend Index Statement
684  *
685  */
686 static Query *
687 transformExtendStmt(ParseState *pstate, ExtendStmt *stmt)
688 {
689         Query      *q;
690
691         q = makeNode(Query);
692         q->commandType = CMD_UTILITY;
693
694         /* take care of the where clause */
695         stmt->whereClause = transformWhereClause(pstate, stmt->whereClause);
696         stmt->rangetable = pstate->p_rtable;
697
698         q->utilityStmt = (Node *) stmt;
699         return q;
700 }
701
702 /*
703  * transformRuleStmt -
704  *        transform a Create Rule Statement. The actions is a list of parse
705  *        trees which is transformed into a list of query trees.
706  */
707 static Query *
708 transformRuleStmt(ParseState *pstate, RuleStmt *stmt)
709 {
710         Query      *q;
711         List       *actions;
712
713         q = makeNode(Query);
714         q->commandType = CMD_UTILITY;
715
716         actions = stmt->actions;
717
718         /*
719          * transform each statment, like parse_analyze()
720          */
721         while (actions != NIL)
722         {
723
724                 /*
725                  * NOTE: 'CURRENT' must always have a varno equal to 1 and 'NEW'
726                  * equal to 2.
727                  */
728                 addRangeTableEntry(pstate, stmt->object->relname, "*CURRENT*",
729                                                    FALSE, FALSE);
730                 addRangeTableEntry(pstate, stmt->object->relname, "*NEW*",
731                                                    FALSE, FALSE);
732
733                 pstate->p_last_resno = 1;
734                 pstate->p_is_rule = true;               /* for expand all */
735                 pstate->p_hasAggs = false;
736
737                 lfirst(actions) = transformStmt(pstate, lfirst(actions));
738                 actions = lnext(actions);
739         }
740
741         /* take care of the where clause */
742         stmt->whereClause = transformWhereClause(pstate, stmt->whereClause);
743
744         q->utilityStmt = (Node *) stmt;
745         return q;
746 }
747
748
749 /*
750  * transformSelectStmt -
751  *        transforms a Select Statement
752  *
753  */
754 static Query *
755 transformSelectStmt(ParseState *pstate, SelectStmt *stmt)
756 {
757         Query      *qry = makeNode(Query);
758
759         qry->commandType = CMD_SELECT;
760
761         /* set up a range table */
762         makeRangeTable(pstate, NULL, stmt->fromClause);
763
764         qry->uniqueFlag = stmt->unique;
765
766         qry->into = stmt->into;
767         qry->isPortal = FALSE;
768
769         qry->targetList = transformTargetList(pstate, stmt->targetList);
770
771         qry->qual = transformWhereClause(pstate, stmt->whereClause);
772
773         qry->sortClause = transformSortClause(pstate,
774                                                                                   stmt->sortClause,
775                                                                                   NIL,
776                                                                                   qry->targetList,
777                                                                                   qry->uniqueFlag);
778
779         qry->groupClause = transformGroupClause(pstate,
780                                                                                         stmt->groupClause,
781                                                                                         qry->targetList);
782         qry->rtable = pstate->p_rtable;
783
784         qry->hasAggs = pstate->p_hasAggs;
785         if (pstate->p_hasAggs)
786                 parseCheckAggregates(pstate, qry);
787
788         qry->unionall = stmt->unionall; /* in child, so unionClause may be false */
789         qry->unionClause = transformUnionClause(stmt->unionClause, qry->targetList);
790
791         return (Query *) qry;
792 }
793
794 /*
795  * transformUpdateStmt -
796  *        transforms an update statement
797  *
798  */
799 static Query *
800 transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt)
801 {
802         Query      *qry = makeNode(Query);
803
804         qry->commandType = CMD_UPDATE;
805         pstate->p_is_update = true;
806
807         /*
808          * the FROM clause is non-standard SQL syntax. We used to be able to
809          * do this with REPLACE in POSTQUEL so we keep the feature.
810          */
811         makeRangeTable(pstate, stmt->relname, stmt->fromClause);
812
813         qry->targetList = transformTargetList(pstate, stmt->targetList);
814
815         qry->qual = transformWhereClause(pstate, stmt->whereClause);
816
817         qry->rtable = pstate->p_rtable;
818
819         qry->resultRelation = refnameRangeTablePosn(pstate, stmt->relname, NULL);
820
821         qry->hasAggs = pstate->p_hasAggs;
822         if (pstate->p_hasAggs)
823                 parseCheckAggregates(pstate, qry);
824
825         return (Query *) qry;
826 }
827
828 /*
829  * transformCursorStmt -
830  *        transform a Create Cursor Statement
831  *
832  */
833 static Query *
834 transformCursorStmt(ParseState *pstate, SelectStmt *stmt)
835 {
836         Query      *qry;
837
838         qry = transformSelectStmt(pstate, stmt);
839
840         qry->into = stmt->portalname;
841         qry->isPortal = TRUE;
842         qry->isBinary = stmt->binary;           /* internal portal */
843
844         return qry;
845 }