OSDN Git Service

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