1 /*-------------------------------------------------------------------------
4 * transform the parse tree into a query tree
6 * Copyright (c) 1994, Regents of the University of California
10 * $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.56 1997/12/24 06:06:18 momjian Exp $
12 *-------------------------------------------------------------------------
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"
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);
49 * analyze a list of parse trees and transform them if necessary.
51 * Returns a list of transformed parse trees. Optimizable statements are
52 * all transformed to Query while the rest stays the same.
54 * CALLER is responsible for freeing the QueryTreeList* returned
57 parse_analyze(List *pl)
59 QueryTreeList *result;
63 result = malloc(sizeof(QueryTreeList));
64 result->len = length(pl);
65 result->qtrees = (Query **) malloc(result->len * sizeof(Query *));
69 pstate = make_parsestate();
70 result->qtrees[i++] = transformStmt(pstate, lfirst(pl));
73 result->len += length(extras);
74 result->qtrees = (Query **) realloc(result->qtrees, result->len * sizeof(Query *));
77 result->qtrees[i++] = transformStmt(pstate, lfirst(extras));
78 extras = lnext(extras);
83 if (pstate->p_target_relation != NULL)
84 heap_close(pstate->p_target_relation);
93 * transform a Parse tree. If it is an optimizable statement, turn it
97 transformStmt(ParseState *pstate, Node *parseTree)
101 switch (nodeTag(parseTree))
103 /*------------------------
104 * Non-optimizable statements
105 *------------------------
108 result = transformCreateStmt(pstate, (CreateStmt *) parseTree);
112 result = transformIndexStmt(pstate, (IndexStmt *) parseTree);
116 result = transformExtendStmt(pstate, (ExtendStmt *) parseTree);
120 result = transformRuleStmt(pstate, (RuleStmt *) parseTree);
125 ViewStmt *n = (ViewStmt *) parseTree;
127 n->query = (Query *) transformStmt(pstate, (Node *) n->query);
128 result = makeNode(Query);
129 result->commandType = CMD_UTILITY;
130 result->utilityStmt = (Node *) n;
136 MemoryContext oldcontext;
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
144 oldcontext = MemoryContextSwitchTo(TopMemoryContext);
145 result = makeNode(Query);
146 result->commandType = CMD_UTILITY;
147 result->utilityStmt = (Node *) parseTree;
148 MemoryContextSwitchTo(oldcontext);
154 ExplainStmt *n = (ExplainStmt *) parseTree;
156 result = makeNode(Query);
157 result->commandType = CMD_UTILITY;
158 n->query = transformStmt(pstate, (Node *) n->query);
159 result->utilityStmt = (Node *) parseTree;
163 /*------------------------
164 * Optimizable statements
165 *------------------------
168 result = transformInsertStmt(pstate, (AppendStmt *) parseTree);
172 result = transformDeleteStmt(pstate, (DeleteStmt *) parseTree);
176 result = transformUpdateStmt(pstate, (ReplaceStmt *) parseTree);
180 result = transformCursorStmt(pstate, (CursorStmt *) parseTree);
184 result = transformSelectStmt(pstate, (RetrieveStmt *) parseTree);
190 * other statments don't require any transformation-- just
191 * return the original parsetree
193 result = makeNode(Query);
194 result->commandType = CMD_UTILITY;
195 result->utilityStmt = (Node *) parseTree;
202 * transformDeleteStmt -
203 * transforms a Delete Statement
206 transformDeleteStmt(ParseState *pstate, DeleteStmt *stmt)
208 Query *qry = makeNode(Query);
210 qry->commandType = CMD_DELETE;
212 /* set up a range table */
213 makeRangeTable(pstate, stmt->relname, NULL);
215 qry->uniqueFlag = NULL;
217 /* fix where clause */
218 qry->qual = transformWhereClause(pstate, stmt->whereClause);
220 qry->rtable = pstate->p_rtable;
221 qry->resultRelation = refnameRangeTablePosn(pstate->p_rtable, stmt->relname);
223 /* make sure we don't have aggregates in the where clause */
224 if (pstate->p_numAgg > 0)
225 parseCheckAggregates(pstate, qry);
227 return (Query *) qry;
231 * transformInsertStmt -
232 * transform an Insert Statement
235 transformInsertStmt(ParseState *pstate, AppendStmt *stmt)
237 Query *qry = makeNode(Query); /* make a new query tree */
240 qry->commandType = CMD_INSERT;
241 pstate->p_is_insert = true;
243 /* set up a range table */
244 makeRangeTable(pstate, stmt->relname, stmt->fromClause);
246 qry->uniqueFlag = NULL;
248 /* fix the target list */
249 icolumns = pstate->p_insert_columns = makeTargetNames(pstate, stmt->cols);
251 qry->targetList = transformTargetList(pstate, stmt->targetList);
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)
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;
263 * if stmt->cols == NIL then makeTargetNames returns list of all
264 * attrs: have to shorter icolumns list...
266 if (stmt->cols == NIL)
269 int i = length(qry->targetList);
271 foreach (extrl, icolumns)
276 freeList (lnext(extrl));
286 foreach (tl, icolumns)
288 id = (Ident *) lfirst(tl);
289 if (!namestrcmp(&(att[defval[ndef].adnum - 1]->attname), id->name))
292 if (tl != NIL) /* something given for this attr */
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...
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))),
312 te->expr = (Node *) stringToNode(defval[ndef].adbin);
313 qry->targetList = lappend (qry->targetList, te);
317 /* fix where clause */
318 qry->qual = transformWhereClause(pstate, stmt->whereClause);
320 /* now the range table will not change */
321 qry->rtable = pstate->p_rtable;
322 qry->resultRelation = refnameRangeTablePosn(pstate->p_rtable, stmt->relname);
324 if (pstate->p_numAgg > 0)
325 finalizeAggregates(pstate, qry);
327 return (Query *) qry;
331 * Create a table name from a list of fields.
334 makeTableName(void *elem,...);
337 makeTableName(void *elem,...)
342 char buf[NAMEDATALEN+1];
351 /* not enough room for next part? then return nothing */
352 if ((strlen(buf)+strlen(name)) >= (sizeof(buf)-1))
355 if (strlen(buf) > 0) strcat(buf,"_");
358 name = va_arg(args,void *);
363 name = palloc(strlen(buf)+1);
367 } /* makeTableName() */
370 CreateIndexName(char *tname, char *cname, char *label, List *indices);
373 CreateIndexName(char *tname, char *cname, char *label, List *indices)
379 char name2[NAMEDATALEN+1];
381 /* use working storage, since we might be trying several possibilities */
383 while (iname == NULL)
385 iname = makeTableName(tname, name2, label, NULL);
386 /* unable to make a name at all? then quit */
391 printf("CreateNameIndex- check %s against indices\n",iname);
397 index = lfirst(ilist);
399 printf("CreateNameIndex- compare %s with existing index %s\n",iname,index->idxname);
401 if (strcasecmp(iname,index->idxname) == 0)
404 ilist = lnext(ilist);
406 /* ran through entire list? then no name conflict found so done */
410 /* the last one conflicted, so try a new name component */
414 sprintf(name2, "%s_%d", cname, (pass+1));
418 } /* CreateIndexName() */
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
430 transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
433 int have_pkey = FALSE;
439 List *constraints, *clist;
440 Constraint *constraint;
448 q->commandType = CMD_UTILITY;
450 elements = stmt->tableElts;
451 constraints = stmt->constraints;
455 while (elements != NIL)
457 element = lfirst(elements);
458 switch (nodeTag(element))
461 column = (ColumnDef *) element;
463 printf("transformCreateStmt- found column %s\n",column->colname);
465 columns = lappend(columns,column);
466 if (column->constraints != NIL)
469 printf("transformCreateStmt- found constraint(s) on column %s\n",column->colname);
471 clist = column->constraints;
474 constraint = lfirst(clist);
475 switch (constraint->contype)
479 printf("transformCreateStmt- found NOT NULL constraint on column %s\n",column->colname);
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;
489 printf("transformCreateStmt- found DEFAULT clause on column %s\n",column->colname);
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;
499 printf("transformCreateStmt- found PRIMARY KEY clause on column %s\n",column->colname);
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);
510 printf("transformCreateStmt- found UNIQUE clause on column %s\n",column->colname);
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);
521 printf("transformCreateStmt- found CHECK clause on column %s\n",column->colname);
523 constraints = lappend(constraints, constraint);
524 if (constraint->name == NULL)
525 constraint->name = makeTableName(stmt->relname, column->colname, NULL);
529 elog(WARN,"parser: internal error; unrecognized constraint",NULL);
532 clist = lnext(clist);
538 constraint = (Constraint *) element;
540 printf("transformCreateStmt- found constraint %s\n", ((constraint->name != NULL)? constraint->name: "(unknown)"));
542 switch (constraint->contype)
546 printf("transformCreateStmt- found PRIMARY KEY clause\n");
548 if (constraint->name == NULL)
549 constraint->name = makeTableName(stmt->relname, "pkey", NULL);
550 dlist = lappend(dlist, constraint);
555 printf("transformCreateStmt- found UNIQUE clause\n");
558 if (constraint->name == NULL)
559 constraint->name = makeTableName(stmt->relname, "key", NULL);
561 dlist = lappend(dlist, constraint);
566 printf("transformCreateStmt- found CHECK clause\n");
568 constraints = lappend(constraints, constraint);
573 elog(WARN,"parser: internal error; illegal context for constraint",NULL);
576 elog(WARN,"parser: internal error; unrecognized constraint",NULL);
582 elog(WARN,"parser: internal error; unrecognized node",NULL);
585 elements = lnext(elements);
588 stmt->tableElts = columns;
589 stmt->constraints = constraints;
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.
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
603 constraint = lfirst(dlist);
604 if (nodeTag(constraint) != T_Constraint)
605 elog(WARN,"parser: internal error; unrecognized deferred node",NULL);
608 printf("transformCreateStmt- found deferred constraint %s\n",
609 ((constraint->name != NULL)? constraint->name: "(unknown)"));
612 if (constraint->contype == CONSTR_PRIMARY)
614 elog(WARN,"CREATE TABLE/PRIMARY KEY multiple primary keys"
615 " for table %s are not legal", stmt->relname);
618 else if (constraint->contype != CONSTR_UNIQUE)
619 elog(WARN,"parser: internal error; unrecognized deferred constraint",NULL);
622 printf("transformCreateStmt- found deferred %s clause\n",
623 (constraint->contype == CONSTR_PRIMARY? "PRIMARY KEY": "UNIQUE"));
626 index = makeNode(IndexStmt);
628 index->unique = TRUE;
629 if (constraint->name != NULL)
630 index->idxname = constraint->name;
631 else if (constraint->contype == CONSTR_PRIMARY)
634 elog(WARN,"CREATE TABLE/PRIMARY KEY multiple keys for table %s are not legal", stmt->relname);
637 index->idxname = makeTableName(stmt->relname, "pkey", NULL);
640 index->idxname = NULL;
642 index->relname = stmt->relname;
643 index->accessMethod = "btree";
644 index->indexParams = NIL;
645 index->withClause = NIL;
646 index->whereClause = NULL;
648 keys = constraint->keys;
653 printf("transformCreateStmt- check key %s for column match\n", key->name);
655 columns = stmt->tableElts;
657 while (columns != NIL)
659 column = lfirst(columns);
661 printf("transformCreateStmt- check column %s for key match\n", column->colname);
663 if (strcasecmp(column->colname,key->name) == 0) break;
665 columns = lnext(columns);
668 elog(WARN,"parser: column '%s' in key does not exist",key->name);
670 if (constraint->contype == CONSTR_PRIMARY)
673 printf("transformCreateStmt- mark column %s as NOT NULL\n", column->colname);
675 column->is_not_null = TRUE;
677 iparam = makeNode(IndexElem);
678 iparam->name = strcpy(palloc(strlen(column->colname)+1), column->colname);
680 iparam->class = NULL;
681 iparam->tname = NULL;
682 index->indexParams = lappend(index->indexParams, iparam);
684 if (index->idxname == NULL)
685 index->idxname = CreateIndexName(stmt->relname, iparam->name, "key", ilist);
690 if (index->idxname == NULL)
691 elog(WARN,"parser: unable to construct implicit index for table %s"
692 "; name too long", stmt->relname);
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);
698 ilist = lappend(ilist, index);
699 dlist = lnext(dlist);
702 q->utilityStmt = (Node *) stmt;
706 } /* transformCreateStmt() */
709 * transformIndexStmt -
710 * transforms the qualification of the index statement
713 transformIndexStmt(ParseState *pstate, IndexStmt *stmt)
718 q->commandType = CMD_UTILITY;
720 /* take care of the where clause */
721 stmt->whereClause = transformWhereClause(pstate, stmt->whereClause);
722 stmt->rangetable = pstate->p_rtable;
724 q->utilityStmt = (Node *) stmt;
730 * transformExtendStmt -
731 * transform the qualifications of the Extend Index Statement
735 transformExtendStmt(ParseState *pstate, ExtendStmt *stmt)
740 q->commandType = CMD_UTILITY;
742 /* take care of the where clause */
743 stmt->whereClause = transformWhereClause(pstate, stmt->whereClause);
744 stmt->rangetable = pstate->p_rtable;
746 q->utilityStmt = (Node *) stmt;
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.
756 transformRuleStmt(ParseState *pstate, RuleStmt *stmt)
762 q->commandType = CMD_UTILITY;
764 actions = stmt->actions;
767 * transform each statment, like parse_analyze()
769 while (actions != NIL)
773 * NOTE: 'CURRENT' must always have a varno equal to 1 and 'NEW'
776 addRangeTableEntry(pstate, stmt->object->relname, "*CURRENT*",
778 addRangeTableEntry(pstate, stmt->object->relname, "*NEW*",
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;
786 lfirst(actions) = transformStmt(pstate, lfirst(actions));
787 actions = lnext(actions);
790 /* take care of the where clause */
791 stmt->whereClause = transformWhereClause(pstate, stmt->whereClause);
793 q->utilityStmt = (Node *) stmt;
799 * transformSelectStmt -
800 * transforms a Select Statement
804 transformSelectStmt(ParseState *pstate, RetrieveStmt *stmt)
806 Query *qry = makeNode(Query);
808 qry->commandType = CMD_SELECT;
810 /* set up a range table */
811 makeRangeTable(pstate, NULL, stmt->fromClause);
813 qry->uniqueFlag = stmt->unique;
815 qry->into = stmt->into;
816 qry->isPortal = FALSE;
818 /* fix the target list */
819 qry->targetList = transformTargetList(pstate, stmt->targetList);
821 /* fix where clause */
822 qry->qual = transformWhereClause(pstate, stmt->whereClause);
824 /* check having clause */
825 if (stmt->havingClause)
826 elog(NOTICE, "HAVING not yet supported; ignore clause", NULL);
828 /* fix order clause */
829 qry->sortClause = transformSortClause(pstate,
834 qry->groupClause = transformGroupClause(pstate,
837 qry->rtable = pstate->p_rtable;
839 if (pstate->p_numAgg > 0)
840 finalizeAggregates(pstate, qry);
842 if (stmt->unionClause)
845 QueryTreeList *qlist;
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;
854 qry->unionClause = NULL;
856 return (Query *) qry;
860 * transformUpdateStmt -
861 * transforms an update statement
865 transformUpdateStmt(ParseState *pstate, ReplaceStmt *stmt)
867 Query *qry = makeNode(Query);
869 qry->commandType = CMD_UPDATE;
870 pstate->p_is_update = true;
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.
876 makeRangeTable(pstate, stmt->relname, stmt->fromClause);
878 /* fix the target list */
879 qry->targetList = transformTargetList(pstate, stmt->targetList);
881 /* fix where clause */
882 qry->qual = transformWhereClause(pstate, stmt->whereClause);
884 qry->rtable = pstate->p_rtable;
885 qry->resultRelation = refnameRangeTablePosn(pstate->p_rtable, stmt->relname);
887 /* make sure we don't have aggregates in the where clause */
888 if (pstate->p_numAgg > 0)
889 parseCheckAggregates(pstate, qry);
891 return (Query *) qry;
895 * transformCursorStmt -
896 * transform a Create Cursor Statement
900 transformCursorStmt(ParseState *pstate, CursorStmt *stmt)
902 Query *qry = makeNode(Query);
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.
909 qry->commandType = CMD_SELECT;
911 /* set up a range table */
912 makeRangeTable(pstate, NULL, stmt->fromClause);
914 qry->uniqueFlag = stmt->unique;
916 qry->into = stmt->portalname;
917 qry->isPortal = TRUE;
918 qry->isBinary = stmt->binary; /* internal portal */
920 /* fix the target list */
921 qry->targetList = transformTargetList(pstate, stmt->targetList);
923 /* fix where clause */
924 qry->qual = transformWhereClause(pstate, stmt->whereClause);
926 /* fix order clause */
927 qry->sortClause = transformSortClause(pstate,
931 /* fix group by clause */
932 qry->groupClause = transformGroupClause(pstate,
936 qry->rtable = pstate->p_rtable;
938 if (pstate->p_numAgg > 0)
939 finalizeAggregates(pstate, qry);
941 return (Query *) qry;