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.63 1998/01/10 04:29:47 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 = NULL;
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 /* now the range table will not change */
319 qry->rtable = pstate->p_rtable;
320 qry->resultRelation = refnameRangeTablePosn(pstate->p_rtable, stmt->relname);
322 if (pstate->p_numAgg > 0)
323 finalizeAggregates(pstate, qry);
325 return (Query *) qry;
329 * Create a table name from a list of fields.
332 makeTableName(void *elem,...);
335 makeTableName(void *elem,...)
340 char buf[NAMEDATALEN+1];
349 /* not enough room for next part? then return nothing */
350 if ((strlen(buf)+strlen(name)) >= (sizeof(buf)-1))
353 if (strlen(buf) > 0) strcat(buf,"_");
356 name = va_arg(args,void *);
361 name = palloc(strlen(buf)+1);
365 } /* makeTableName() */
368 CreateIndexName(char *tname, char *cname, char *label, List *indices);
371 CreateIndexName(char *tname, char *cname, char *label, List *indices)
377 char name2[NAMEDATALEN+1];
379 /* use working storage, since we might be trying several possibilities */
381 while (iname == NULL)
383 iname = makeTableName(tname, name2, label, NULL);
384 /* unable to make a name at all? then quit */
389 printf("CreateNameIndex- check %s against indices\n",iname);
395 index = lfirst(ilist);
397 printf("CreateNameIndex- compare %s with existing index %s\n",iname,index->idxname);
399 if (strcasecmp(iname,index->idxname) == 0)
402 ilist = lnext(ilist);
404 /* ran through entire list? then no name conflict found so done */
408 /* the last one conflicted, so try a new name component */
412 sprintf(name2, "%s_%d", cname, (pass+1));
416 } /* CreateIndexName() */
419 * transformCreateStmt -
420 * transforms the "create table" statement
421 * SQL92 allows constraints to be scattered all over, so thumb through
422 * the columns and collect all constraints into one place.
423 * If there are any implied indices (e.g. UNIQUE or PRIMARY KEY)
424 * then expand those into multiple IndexStmt blocks.
425 * - thomas 1997-12-02
428 transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
431 int have_pkey = FALSE;
437 List *constraints, *clist;
438 Constraint *constraint;
446 q->commandType = CMD_UTILITY;
448 elements = stmt->tableElts;
449 constraints = stmt->constraints;
453 while (elements != NIL)
455 element = lfirst(elements);
456 switch (nodeTag(element))
459 column = (ColumnDef *) element;
461 printf("transformCreateStmt- found column %s\n",column->colname);
463 columns = lappend(columns,column);
464 if (column->constraints != NIL)
467 printf("transformCreateStmt- found constraint(s) on column %s\n",column->colname);
469 clist = column->constraints;
472 constraint = lfirst(clist);
473 switch (constraint->contype)
477 printf("transformCreateStmt- found NOT NULL constraint on column %s\n",column->colname);
479 if (column->is_not_null)
480 elog(ERROR,"CREATE TABLE/NOT NULL already specified"
481 " for %s.%s", stmt->relname, column->colname);
482 column->is_not_null = TRUE;
487 printf("transformCreateStmt- found DEFAULT clause on column %s\n",column->colname);
489 if (column->defval != NULL)
490 elog(ERROR,"CREATE TABLE/DEFAULT multiple values specified"
491 " for %s.%s", stmt->relname, column->colname);
492 column->defval = constraint->def;
497 printf("transformCreateStmt- found PRIMARY KEY clause on column %s\n",column->colname);
499 if (constraint->name == NULL)
500 constraint->name = makeTableName(stmt->relname, "pkey", NULL);
501 if (constraint->keys == NIL)
502 constraint->keys = lappend(constraint->keys, column);
503 dlist = lappend(dlist, constraint);
508 printf("transformCreateStmt- found UNIQUE clause on column %s\n",column->colname);
510 if (constraint->name == NULL)
511 constraint->name = makeTableName(stmt->relname, column->colname, "key", NULL);
512 if (constraint->keys == NIL)
513 constraint->keys = lappend(constraint->keys, column);
514 dlist = lappend(dlist, constraint);
519 printf("transformCreateStmt- found CHECK clause on column %s\n",column->colname);
521 constraints = lappend(constraints, constraint);
522 if (constraint->name == NULL)
523 constraint->name = makeTableName(stmt->relname, column->colname, NULL);
527 elog(ERROR,"parser: internal error; unrecognized constraint",NULL);
530 clist = lnext(clist);
536 constraint = (Constraint *) element;
538 printf("transformCreateStmt- found constraint %s\n", ((constraint->name != NULL)? constraint->name: "(unknown)"));
540 switch (constraint->contype)
544 printf("transformCreateStmt- found PRIMARY KEY clause\n");
546 if (constraint->name == NULL)
547 constraint->name = makeTableName(stmt->relname, "pkey", NULL);
548 dlist = lappend(dlist, constraint);
553 printf("transformCreateStmt- found UNIQUE clause\n");
556 if (constraint->name == NULL)
557 constraint->name = makeTableName(stmt->relname, "key", NULL);
559 dlist = lappend(dlist, constraint);
564 printf("transformCreateStmt- found CHECK clause\n");
566 constraints = lappend(constraints, constraint);
571 elog(ERROR,"parser: internal error; illegal context for constraint",NULL);
574 elog(ERROR,"parser: internal error; unrecognized constraint",NULL);
580 elog(ERROR,"parser: internal error; unrecognized node",NULL);
583 elements = lnext(elements);
586 stmt->tableElts = columns;
587 stmt->constraints = constraints;
589 /* Now run through the "deferred list" to complete the query transformation.
590 * For PRIMARY KEYs, mark each column as NOT NULL and create an index.
591 * For UNIQUE, create an index as for PRIMARY KEYS, but do not insist on NOT NULL.
593 * Note that this code does not currently look for all possible redundant cases
594 * and either ignore or stop with warning. The create might fail later when
595 * names for indices turn out to be redundant, or a user might have specified
596 * extra useless indices which might hurt performance. - thomas 1997-12-08
601 constraint = lfirst(dlist);
602 if (nodeTag(constraint) != T_Constraint)
603 elog(ERROR,"parser: internal error; unrecognized deferred node",NULL);
606 printf("transformCreateStmt- found deferred constraint %s\n",
607 ((constraint->name != NULL)? constraint->name: "(unknown)"));
610 if (constraint->contype == CONSTR_PRIMARY)
612 elog(ERROR,"CREATE TABLE/PRIMARY KEY multiple primary keys"
613 " for table %s are not legal", stmt->relname);
616 else if (constraint->contype != CONSTR_UNIQUE)
617 elog(ERROR,"parser: internal error; unrecognized deferred constraint",NULL);
620 printf("transformCreateStmt- found deferred %s clause\n",
621 (constraint->contype == CONSTR_PRIMARY? "PRIMARY KEY": "UNIQUE"));
624 index = makeNode(IndexStmt);
626 index->unique = TRUE;
627 if (constraint->name != NULL)
628 index->idxname = constraint->name;
629 else if (constraint->contype == CONSTR_PRIMARY)
632 elog(ERROR,"CREATE TABLE/PRIMARY KEY multiple keys for table %s are not legal", stmt->relname);
635 index->idxname = makeTableName(stmt->relname, "pkey", NULL);
638 index->idxname = NULL;
640 index->relname = stmt->relname;
641 index->accessMethod = "btree";
642 index->indexParams = NIL;
643 index->withClause = NIL;
644 index->whereClause = NULL;
646 keys = constraint->keys;
651 printf("transformCreateStmt- check key %s for column match\n", key->name);
653 columns = stmt->tableElts;
655 while (columns != NIL)
657 column = lfirst(columns);
659 printf("transformCreateStmt- check column %s for key match\n", column->colname);
661 if (strcasecmp(column->colname,key->name) == 0) break;
663 columns = lnext(columns);
666 elog(ERROR,"parser: column '%s' in key does not exist",key->name);
668 if (constraint->contype == CONSTR_PRIMARY)
671 printf("transformCreateStmt- mark column %s as NOT NULL\n", column->colname);
673 column->is_not_null = TRUE;
675 iparam = makeNode(IndexElem);
676 iparam->name = strcpy(palloc(strlen(column->colname)+1), column->colname);
678 iparam->class = NULL;
679 iparam->tname = NULL;
680 index->indexParams = lappend(index->indexParams, iparam);
682 if (index->idxname == NULL)
683 index->idxname = CreateIndexName(stmt->relname, iparam->name, "key", ilist);
688 if (index->idxname == NULL)
689 elog(ERROR,"parser: unable to construct implicit index for table %s"
690 "; name too long", stmt->relname);
692 elog(NOTICE,"CREATE TABLE/%s will create implicit index %s for table %s",
693 ((constraint->contype == CONSTR_PRIMARY)? "PRIMARY KEY": "UNIQUE"),
694 index->idxname, stmt->relname);
696 ilist = lappend(ilist, index);
697 dlist = lnext(dlist);
700 q->utilityStmt = (Node *) stmt;
704 } /* transformCreateStmt() */
707 * transformIndexStmt -
708 * transforms the qualification of the index statement
711 transformIndexStmt(ParseState *pstate, IndexStmt *stmt)
716 q->commandType = CMD_UTILITY;
718 /* take care of the where clause */
719 stmt->whereClause = transformWhereClause(pstate, stmt->whereClause);
720 stmt->rangetable = pstate->p_rtable;
722 q->utilityStmt = (Node *) stmt;
728 * transformExtendStmt -
729 * transform the qualifications of the Extend Index Statement
733 transformExtendStmt(ParseState *pstate, ExtendStmt *stmt)
738 q->commandType = CMD_UTILITY;
740 /* take care of the where clause */
741 stmt->whereClause = transformWhereClause(pstate, stmt->whereClause);
742 stmt->rangetable = pstate->p_rtable;
744 q->utilityStmt = (Node *) stmt;
749 * transformRuleStmt -
750 * transform a Create Rule Statement. The actions is a list of parse
751 * trees which is transformed into a list of query trees.
754 transformRuleStmt(ParseState *pstate, RuleStmt *stmt)
760 q->commandType = CMD_UTILITY;
762 actions = stmt->actions;
765 * transform each statment, like parse_analyze()
767 while (actions != NIL)
771 * NOTE: 'CURRENT' must always have a varno equal to 1 and 'NEW'
774 addRangeTableEntry(pstate, stmt->object->relname, "*CURRENT*",
776 addRangeTableEntry(pstate, stmt->object->relname, "*NEW*",
779 pstate->p_last_resno = 1;
780 pstate->p_is_rule = true; /* for expand all */
781 pstate->p_numAgg = 0;
782 pstate->p_aggs = NULL;
784 lfirst(actions) = transformStmt(pstate, lfirst(actions));
785 actions = lnext(actions);
788 /* take care of the where clause */
789 stmt->whereClause = transformWhereClause(pstate, stmt->whereClause);
791 q->utilityStmt = (Node *) stmt;
797 * transformSelectStmt -
798 * transforms a Select Statement
802 transformSelectStmt(ParseState *pstate, SelectStmt *stmt)
804 Query *qry = makeNode(Query);
806 qry->commandType = CMD_SELECT;
808 /* set up a range table */
809 makeRangeTable(pstate, NULL, stmt->fromClause);
811 qry->uniqueFlag = stmt->unique;
813 qry->into = stmt->into;
814 qry->isPortal = FALSE;
816 /* fix the target list */
817 qry->targetList = transformTargetList(pstate, stmt->targetList);
819 /* fix where clause */
820 qry->qual = transformWhereClause(pstate, stmt->whereClause);
822 /* check having clause */
823 if (stmt->havingClause)
824 elog(NOTICE, "HAVING not yet supported; ignore clause", NULL);
826 /* fix order clause */
827 qry->sortClause = transformSortClause(pstate,
833 qry->groupClause = transformGroupClause(pstate,
836 qry->rtable = pstate->p_rtable;
838 if (pstate->p_numAgg > 0)
839 finalizeAggregates(pstate, qry);
841 qry->unionall = stmt->unionall; /* in child, so unionClause may be false */
842 qry->unionClause = transformUnionClause(stmt->unionClause, qry->targetList);
844 return (Query *) qry;
848 * transformUpdateStmt -
849 * transforms an update statement
853 transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt)
855 Query *qry = makeNode(Query);
857 qry->commandType = CMD_UPDATE;
858 pstate->p_is_update = true;
861 * the FROM clause is non-standard SQL syntax. We used to be able to
862 * do this with REPLACE in POSTQUEL so we keep the feature.
864 makeRangeTable(pstate, stmt->relname, stmt->fromClause);
866 /* fix the target list */
867 qry->targetList = transformTargetList(pstate, stmt->targetList);
869 /* fix where clause */
870 qry->qual = transformWhereClause(pstate, stmt->whereClause);
872 qry->rtable = pstate->p_rtable;
873 qry->resultRelation = refnameRangeTablePosn(pstate->p_rtable, stmt->relname);
875 if (pstate->p_numAgg > 0)
876 finalizeAggregates(pstate, qry);
878 /* make sure we don't have aggregates in the where clause */
879 if (pstate->p_numAgg > 0)
880 parseCheckAggregates(pstate, qry);
882 return (Query *) qry;
886 * transformCursorStmt -
887 * transform a Create Cursor Statement
891 transformCursorStmt(ParseState *pstate, SelectStmt *stmt)
895 qry = transformSelectStmt(pstate, stmt);
897 qry->into = stmt->portalname;
898 qry->isPortal = TRUE;
899 qry->isBinary = stmt->binary; /* internal portal */