OSDN Git Service

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