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.64 1998/01/11 03:41:35 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, 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);
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.
56 parse_analyze(List *pl)
58 QueryTreeList *result;
62 result = malloc(sizeof(QueryTreeList));
63 result->len = length(pl);
64 result->qtrees = (Query **) malloc(result->len * sizeof(Query *));
68 pstate = make_parsestate();
69 result->qtrees[i++] = transformStmt(pstate, lfirst(pl));
72 result->len += length(extras);
73 result->qtrees = (Query **) realloc(result->qtrees, result->len * sizeof(Query *));
76 result->qtrees[i++] = transformStmt(pstate, lfirst(extras));
77 extras = lnext(extras);
82 if (pstate->p_target_relation != NULL)
83 heap_close(pstate->p_target_relation);
92 * transform a Parse tree. If it is an optimizable statement, turn it
96 transformStmt(ParseState *pstate, Node *parseTree)
100 switch (nodeTag(parseTree))
102 /*------------------------
103 * Non-optimizable statements
104 *------------------------
107 result = transformCreateStmt(pstate, (CreateStmt *) parseTree);
111 result = transformIndexStmt(pstate, (IndexStmt *) parseTree);
115 result = transformExtendStmt(pstate, (ExtendStmt *) parseTree);
119 result = transformRuleStmt(pstate, (RuleStmt *) parseTree);
124 ViewStmt *n = (ViewStmt *) parseTree;
126 n->query = (Query *) transformStmt(pstate, (Node *) n->query);
127 result = makeNode(Query);
128 result->commandType = CMD_UTILITY;
129 result->utilityStmt = (Node *) n;
135 MemoryContext oldcontext;
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
143 oldcontext = MemoryContextSwitchTo(TopMemoryContext);
144 result = makeNode(Query);
145 result->commandType = CMD_UTILITY;
146 result->utilityStmt = (Node *) parseTree;
147 MemoryContextSwitchTo(oldcontext);
153 ExplainStmt *n = (ExplainStmt *) parseTree;
155 result = makeNode(Query);
156 result->commandType = CMD_UTILITY;
157 n->query = transformStmt(pstate, (Node *) n->query);
158 result->utilityStmt = (Node *) parseTree;
162 /*------------------------
163 * Optimizable statements
164 *------------------------
167 result = transformInsertStmt(pstate, (InsertStmt *) parseTree);
171 result = transformDeleteStmt(pstate, (DeleteStmt *) parseTree);
175 result = transformUpdateStmt(pstate, (UpdateStmt *) parseTree);
179 if (!((SelectStmt *)parseTree)->portalname)
180 result = transformSelectStmt(pstate, (SelectStmt *) parseTree);
182 result = transformCursorStmt(pstate, (SelectStmt *) parseTree);
188 * other statments don't require any transformation-- just
189 * return the original parsetree
191 result = makeNode(Query);
192 result->commandType = CMD_UTILITY;
193 result->utilityStmt = (Node *) parseTree;
200 * transformDeleteStmt -
201 * transforms a Delete Statement
204 transformDeleteStmt(ParseState *pstate, DeleteStmt *stmt)
206 Query *qry = makeNode(Query);
208 qry->commandType = CMD_DELETE;
210 /* set up a range table */
211 makeRangeTable(pstate, stmt->relname, NULL);
213 qry->uniqueFlag = NULL;
215 /* fix where clause */
216 qry->qual = transformWhereClause(pstate, stmt->whereClause);
218 qry->rtable = pstate->p_rtable;
219 qry->resultRelation = refnameRangeTablePosn(pstate->p_rtable, stmt->relname);
221 /* make sure we don't have aggregates in the where clause */
222 if (pstate->p_numAgg > 0)
223 parseCheckAggregates(pstate, qry);
225 return (Query *) qry;
229 * transformInsertStmt -
230 * transform an Insert Statement
233 transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
235 Query *qry = makeNode(Query); /* make a new query tree */
238 qry->commandType = CMD_INSERT;
239 pstate->p_is_insert = true;
241 /* set up a range table */
242 makeRangeTable(pstate, stmt->relname, stmt->fromClause);
244 qry->uniqueFlag = stmt->unique;
246 /* fix the target list */
247 icolumns = pstate->p_insert_columns = makeTargetNames(pstate, stmt->cols);
249 qry->targetList = transformTargetList(pstate, stmt->targetList);
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)
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;
261 * if stmt->cols == NIL then makeTargetNames returns list of all
262 * attrs: have to shorter icolumns list...
264 if (stmt->cols == NIL)
267 int i = length(qry->targetList);
269 foreach (extrl, icolumns)
274 freeList (lnext(extrl));
284 foreach (tl, icolumns)
286 id = (Ident *) lfirst(tl);
287 if (!namestrcmp(&(att[defval[ndef].adnum - 1]->attname), id->name))
290 if (tl != NIL) /* something given for this attr */
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...
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))),
310 te->expr = (Node *) stringToNode(defval[ndef].adbin);
311 qry->targetList = lappend (qry->targetList, te);
315 /* fix where clause */
316 qry->qual = transformWhereClause(pstate, stmt->whereClause);
318 /* check having clause */
319 if (stmt->havingClause)
320 elog(NOTICE, "HAVING not yet supported; ignore clause", NULL);
322 /* now the range table will not change */
323 qry->rtable = pstate->p_rtable;
324 qry->resultRelation = refnameRangeTablePosn(pstate->p_rtable, stmt->relname);
326 qry->groupClause = transformGroupClause(pstate,
330 /* fix order clause */
331 qry->sortClause = transformSortClause(pstate,
337 if (pstate->p_numAgg > 0)
338 finalizeAggregates(pstate, qry);
340 qry->unionall = stmt->unionall; /* in child, so unionClause may be false */
341 qry->unionClause = transformUnionClause(stmt->unionClause, qry->targetList);
343 return (Query *) qry;
347 * Create a table name from a list of fields.
350 makeTableName(void *elem,...);
353 makeTableName(void *elem,...)
358 char buf[NAMEDATALEN+1];
367 /* not enough room for next part? then return nothing */
368 if ((strlen(buf)+strlen(name)) >= (sizeof(buf)-1))
371 if (strlen(buf) > 0) strcat(buf,"_");
374 name = va_arg(args,void *);
379 name = palloc(strlen(buf)+1);
383 } /* makeTableName() */
386 CreateIndexName(char *tname, char *cname, char *label, List *indices);
389 CreateIndexName(char *tname, char *cname, char *label, List *indices)
395 char name2[NAMEDATALEN+1];
397 /* use working storage, since we might be trying several possibilities */
399 while (iname == NULL)
401 iname = makeTableName(tname, name2, label, NULL);
402 /* unable to make a name at all? then quit */
407 printf("CreateNameIndex- check %s against indices\n",iname);
413 index = lfirst(ilist);
415 printf("CreateNameIndex- compare %s with existing index %s\n",iname,index->idxname);
417 if (strcasecmp(iname,index->idxname) == 0)
420 ilist = lnext(ilist);
422 /* ran through entire list? then no name conflict found so done */
426 /* the last one conflicted, so try a new name component */
430 sprintf(name2, "%s_%d", cname, (pass+1));
434 } /* CreateIndexName() */
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
446 transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
449 int have_pkey = FALSE;
455 List *constraints, *clist;
456 Constraint *constraint;
464 q->commandType = CMD_UTILITY;
466 elements = stmt->tableElts;
467 constraints = stmt->constraints;
471 while (elements != NIL)
473 element = lfirst(elements);
474 switch (nodeTag(element))
477 column = (ColumnDef *) element;
479 printf("transformCreateStmt- found column %s\n",column->colname);
481 columns = lappend(columns,column);
482 if (column->constraints != NIL)
485 printf("transformCreateStmt- found constraint(s) on column %s\n",column->colname);
487 clist = column->constraints;
490 constraint = lfirst(clist);
491 switch (constraint->contype)
495 printf("transformCreateStmt- found NOT NULL constraint on column %s\n",column->colname);
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;
505 printf("transformCreateStmt- found DEFAULT clause on column %s\n",column->colname);
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;
515 printf("transformCreateStmt- found PRIMARY KEY clause on column %s\n",column->colname);
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);
526 printf("transformCreateStmt- found UNIQUE clause on column %s\n",column->colname);
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);
537 printf("transformCreateStmt- found CHECK clause on column %s\n",column->colname);
539 constraints = lappend(constraints, constraint);
540 if (constraint->name == NULL)
541 constraint->name = makeTableName(stmt->relname, column->colname, NULL);
545 elog(ERROR,"parser: internal error; unrecognized constraint",NULL);
548 clist = lnext(clist);
554 constraint = (Constraint *) element;
556 printf("transformCreateStmt- found constraint %s\n", ((constraint->name != NULL)? constraint->name: "(unknown)"));
558 switch (constraint->contype)
562 printf("transformCreateStmt- found PRIMARY KEY clause\n");
564 if (constraint->name == NULL)
565 constraint->name = makeTableName(stmt->relname, "pkey", NULL);
566 dlist = lappend(dlist, constraint);
571 printf("transformCreateStmt- found UNIQUE clause\n");
574 if (constraint->name == NULL)
575 constraint->name = makeTableName(stmt->relname, "key", NULL);
577 dlist = lappend(dlist, constraint);
582 printf("transformCreateStmt- found CHECK clause\n");
584 constraints = lappend(constraints, constraint);
589 elog(ERROR,"parser: internal error; illegal context for constraint",NULL);
592 elog(ERROR,"parser: internal error; unrecognized constraint",NULL);
598 elog(ERROR,"parser: internal error; unrecognized node",NULL);
601 elements = lnext(elements);
604 stmt->tableElts = columns;
605 stmt->constraints = constraints;
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.
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
619 constraint = lfirst(dlist);
620 if (nodeTag(constraint) != T_Constraint)
621 elog(ERROR,"parser: internal error; unrecognized deferred node",NULL);
624 printf("transformCreateStmt- found deferred constraint %s\n",
625 ((constraint->name != NULL)? constraint->name: "(unknown)"));
628 if (constraint->contype == CONSTR_PRIMARY)
630 elog(ERROR,"CREATE TABLE/PRIMARY KEY multiple primary keys"
631 " for table %s are not legal", stmt->relname);
634 else if (constraint->contype != CONSTR_UNIQUE)
635 elog(ERROR,"parser: internal error; unrecognized deferred constraint",NULL);
638 printf("transformCreateStmt- found deferred %s clause\n",
639 (constraint->contype == CONSTR_PRIMARY? "PRIMARY KEY": "UNIQUE"));
642 index = makeNode(IndexStmt);
644 index->unique = TRUE;
645 if (constraint->name != NULL)
646 index->idxname = constraint->name;
647 else if (constraint->contype == CONSTR_PRIMARY)
650 elog(ERROR,"CREATE TABLE/PRIMARY KEY multiple keys for table %s are not legal", stmt->relname);
653 index->idxname = makeTableName(stmt->relname, "pkey", NULL);
656 index->idxname = NULL;
658 index->relname = stmt->relname;
659 index->accessMethod = "btree";
660 index->indexParams = NIL;
661 index->withClause = NIL;
662 index->whereClause = NULL;
664 keys = constraint->keys;
669 printf("transformCreateStmt- check key %s for column match\n", key->name);
671 columns = stmt->tableElts;
673 while (columns != NIL)
675 column = lfirst(columns);
677 printf("transformCreateStmt- check column %s for key match\n", column->colname);
679 if (strcasecmp(column->colname,key->name) == 0) break;
681 columns = lnext(columns);
684 elog(ERROR,"parser: column '%s' in key does not exist",key->name);
686 if (constraint->contype == CONSTR_PRIMARY)
689 printf("transformCreateStmt- mark column %s as NOT NULL\n", column->colname);
691 column->is_not_null = TRUE;
693 iparam = makeNode(IndexElem);
694 iparam->name = strcpy(palloc(strlen(column->colname)+1), column->colname);
696 iparam->class = NULL;
697 iparam->tname = NULL;
698 index->indexParams = lappend(index->indexParams, iparam);
700 if (index->idxname == NULL)
701 index->idxname = CreateIndexName(stmt->relname, iparam->name, "key", ilist);
706 if (index->idxname == NULL)
707 elog(ERROR,"parser: unable to construct implicit index for table %s"
708 "; name too long", stmt->relname);
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);
714 ilist = lappend(ilist, index);
715 dlist = lnext(dlist);
718 q->utilityStmt = (Node *) stmt;
722 } /* transformCreateStmt() */
725 * transformIndexStmt -
726 * transforms the qualification of the index statement
729 transformIndexStmt(ParseState *pstate, IndexStmt *stmt)
734 q->commandType = CMD_UTILITY;
736 /* take care of the where clause */
737 stmt->whereClause = transformWhereClause(pstate, stmt->whereClause);
738 stmt->rangetable = pstate->p_rtable;
740 q->utilityStmt = (Node *) stmt;
746 * transformExtendStmt -
747 * transform the qualifications of the Extend Index Statement
751 transformExtendStmt(ParseState *pstate, ExtendStmt *stmt)
756 q->commandType = CMD_UTILITY;
758 /* take care of the where clause */
759 stmt->whereClause = transformWhereClause(pstate, stmt->whereClause);
760 stmt->rangetable = pstate->p_rtable;
762 q->utilityStmt = (Node *) stmt;
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.
772 transformRuleStmt(ParseState *pstate, RuleStmt *stmt)
778 q->commandType = CMD_UTILITY;
780 actions = stmt->actions;
783 * transform each statment, like parse_analyze()
785 while (actions != NIL)
789 * NOTE: 'CURRENT' must always have a varno equal to 1 and 'NEW'
792 addRangeTableEntry(pstate, stmt->object->relname, "*CURRENT*",
794 addRangeTableEntry(pstate, stmt->object->relname, "*NEW*",
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;
802 lfirst(actions) = transformStmt(pstate, lfirst(actions));
803 actions = lnext(actions);
806 /* take care of the where clause */
807 stmt->whereClause = transformWhereClause(pstate, stmt->whereClause);
809 q->utilityStmt = (Node *) stmt;
815 * transformSelectStmt -
816 * transforms a Select Statement
820 transformSelectStmt(ParseState *pstate, SelectStmt *stmt)
822 Query *qry = makeNode(Query);
824 qry->commandType = CMD_SELECT;
826 /* set up a range table */
827 makeRangeTable(pstate, NULL, stmt->fromClause);
829 qry->uniqueFlag = stmt->unique;
831 qry->into = stmt->into;
832 qry->isPortal = FALSE;
834 /* fix the target list */
835 qry->targetList = transformTargetList(pstate, stmt->targetList);
837 /* fix where clause */
838 qry->qual = transformWhereClause(pstate, stmt->whereClause);
840 /* check having clause */
841 if (stmt->havingClause)
842 elog(NOTICE, "HAVING not yet supported; ignore clause", NULL);
844 /* fix order clause */
845 qry->sortClause = transformSortClause(pstate,
851 qry->groupClause = transformGroupClause(pstate,
854 qry->rtable = pstate->p_rtable;
856 if (pstate->p_numAgg > 0)
857 finalizeAggregates(pstate, qry);
859 qry->unionall = stmt->unionall; /* in child, so unionClause may be false */
860 qry->unionClause = transformUnionClause(stmt->unionClause, qry->targetList);
862 return (Query *) qry;
866 * transformUpdateStmt -
867 * transforms an update statement
871 transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt)
873 Query *qry = makeNode(Query);
875 qry->commandType = CMD_UPDATE;
876 pstate->p_is_update = true;
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.
882 makeRangeTable(pstate, stmt->relname, stmt->fromClause);
884 /* fix the target list */
885 qry->targetList = transformTargetList(pstate, stmt->targetList);
887 /* fix where clause */
888 qry->qual = transformWhereClause(pstate, stmt->whereClause);
890 qry->rtable = pstate->p_rtable;
891 qry->resultRelation = refnameRangeTablePosn(pstate->p_rtable, stmt->relname);
893 if (pstate->p_numAgg > 0)
894 finalizeAggregates(pstate, qry);
896 /* make sure we don't have aggregates in the where clause */
897 if (pstate->p_numAgg > 0)
898 parseCheckAggregates(pstate, qry);
900 return (Query *) qry;
904 * transformCursorStmt -
905 * transform a Create Cursor Statement
909 transformCursorStmt(ParseState *pstate, SelectStmt *stmt)
913 qry = transformSelectStmt(pstate, stmt);
915 qry->into = stmt->portalname;
916 qry->isPortal = TRUE;
917 qry->isBinary = stmt->binary; /* internal portal */