OSDN Git Service

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