1 /*-------------------------------------------------------------------------
4 * transform the parse tree into a query tree
6 * Copyright (c) 1994, Regents of the University of California
8 * $Id: analyze.c,v 1.95 1999/01/25 12:01:05 vadim Exp $
10 *-------------------------------------------------------------------------
19 #include "access/heapam.h"
20 #include "nodes/makefuncs.h"
21 #include "nodes/memnodes.h"
22 #include "nodes/pg_list.h"
23 #include "parser/analyze.h"
24 #include "parser/parse_agg.h"
25 #include "parser/parse_clause.h"
26 #include "parser/parse_node.h"
27 #include "parser/parse_relation.h"
28 #include "parser/parse_target.h"
30 #include "parser/parse_expr.h"
31 #include "catalog/pg_type.h"
34 #include "utils/builtins.h"
35 #include "utils/mcxt.h"
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);
48 static void transformForUpdate(Query *qry, List *forUpdate);
49 void CheckSelectForUpdate(Query *qry);
51 List *extras_before = NIL;
52 List *extras_after = NIL;
56 * analyze a list of parse trees and transform them if necessary.
58 * Returns a list of transformed parse trees. Optimizable statements are
59 * all transformed to Query while the rest stays the same.
63 parse_analyze(List *pl, ParseState *parentParseState)
65 QueryTreeList *result;
70 result = malloc(sizeof(QueryTreeList));
71 result->len = length(pl);
72 result->qtrees = (Query **) malloc(result->len * sizeof(Query *));
76 pstate = make_parsestate(parentParseState);
77 parsetree = transformStmt(pstate, lfirst(pl));
78 if (pstate->p_target_relation != NULL)
79 heap_close(pstate->p_target_relation);
81 if (extras_before != NIL)
83 result->len += length(extras_before);
84 result->qtrees = (Query **) realloc(result->qtrees, result->len * sizeof(Query *));
85 while (extras_before != NIL)
87 result->qtrees[i++] = transformStmt(pstate, lfirst(extras_before));
88 if (pstate->p_target_relation != NULL)
89 heap_close(pstate->p_target_relation);
90 extras_before = lnext(extras_before);
95 result->qtrees[i++] = parsetree;
97 if (extras_after != NIL)
99 result->len += length(extras_after);
100 result->qtrees = (Query **) realloc(result->qtrees, result->len * sizeof(Query *));
101 while (extras_after != NIL)
103 result->qtrees[i++] = transformStmt(pstate, lfirst(extras_after));
104 if (pstate->p_target_relation != NULL)
105 heap_close(pstate->p_target_relation);
106 extras_after = lnext(extras_after);
120 * transform a Parse tree. If it is an optimizable statement, turn it
124 transformStmt(ParseState *pstate, Node *parseTree)
126 Query *result = NULL;
128 switch (nodeTag(parseTree))
130 /*------------------------
131 * Non-optimizable statements
132 *------------------------
135 result = transformCreateStmt(pstate, (CreateStmt *) parseTree);
139 result = transformIndexStmt(pstate, (IndexStmt *) parseTree);
143 result = transformExtendStmt(pstate, (ExtendStmt *) parseTree);
147 result = transformRuleStmt(pstate, (RuleStmt *) parseTree);
152 ViewStmt *n = (ViewStmt *) parseTree;
154 n->query = (Query *) transformStmt(pstate, (Node *) n->query);
155 result = makeNode(Query);
156 result->commandType = CMD_UTILITY;
157 result->utilityStmt = (Node *) n;
163 MemoryContext oldcontext;
166 * make sure that this Query is allocated in TopMemory
167 * context because vacuum spans transactions and we don't
168 * want to lose the vacuum Query due to end-of-transaction
171 oldcontext = MemoryContextSwitchTo(TopMemoryContext);
172 result = makeNode(Query);
173 result->commandType = CMD_UTILITY;
174 result->utilityStmt = (Node *) parseTree;
175 MemoryContextSwitchTo(oldcontext);
181 ExplainStmt *n = (ExplainStmt *) parseTree;
183 result = makeNode(Query);
184 result->commandType = CMD_UTILITY;
185 n->query = transformStmt(pstate, (Node *) n->query);
186 result->utilityStmt = (Node *) parseTree;
190 /*------------------------
191 * Optimizable statements
192 *------------------------
195 result = transformInsertStmt(pstate, (InsertStmt *) parseTree);
199 result = transformDeleteStmt(pstate, (DeleteStmt *) parseTree);
203 result = transformUpdateStmt(pstate, (UpdateStmt *) parseTree);
207 if (!((SelectStmt *) parseTree)->portalname)
208 result = transformSelectStmt(pstate, (SelectStmt *) parseTree);
210 result = transformCursorStmt(pstate, (SelectStmt *) parseTree);
216 * other statments don't require any transformation-- just
217 * return the original parsetree, yea!
219 result = makeNode(Query);
220 result->commandType = CMD_UTILITY;
221 result->utilityStmt = (Node *) parseTree;
228 * transformDeleteStmt -
229 * transforms a Delete Statement
232 transformDeleteStmt(ParseState *pstate, DeleteStmt *stmt)
234 Query *qry = makeNode(Query);
236 qry->commandType = CMD_DELETE;
238 /* set up a range table */
239 makeRangeTable(pstate, stmt->relname, NULL);
241 qry->uniqueFlag = NULL;
243 /* fix where clause */
244 qry->qual = transformWhereClause(pstate, stmt->whereClause);
245 qry->hasSubLinks = pstate->p_hasSubLinks;
247 qry->rtable = pstate->p_rtable;
248 qry->resultRelation = refnameRangeTablePosn(pstate, stmt->relname, NULL);
250 qry->hasAggs = pstate->p_hasAggs;
251 if (pstate->p_hasAggs)
252 parseCheckAggregates(pstate, qry);
254 return (Query *) qry;
258 * transformInsertStmt -
259 * transform an Insert Statement
262 transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
264 Query *qry = makeNode(Query); /* make a new query tree */
267 qry->commandType = CMD_INSERT;
268 pstate->p_is_insert = true;
270 /* set up a range table */
271 makeRangeTable(pstate, stmt->relname, stmt->fromClause);
273 qry->uniqueFlag = stmt->unique;
275 /* fix the target list */
276 icolumns = pstate->p_insert_columns = makeTargetNames(pstate, stmt->cols);
278 qry->targetList = transformTargetList(pstate, stmt->targetList);
280 /* DEFAULT handling */
281 if (length(qry->targetList) < pstate->p_target_relation->rd_att->natts &&
282 pstate->p_target_relation->rd_att->constr &&
283 pstate->p_target_relation->rd_att->constr->num_defval > 0)
285 Form_pg_attribute *att = pstate->p_target_relation->rd_att->attrs;
286 AttrDefault *defval = pstate->p_target_relation->rd_att->constr->defval;
287 int ndef = pstate->p_target_relation->rd_att->constr->num_defval;
290 * if stmt->cols == NIL then makeTargetNames returns list of all attrs.
291 * May have to shorten icolumns list...
293 if (stmt->cols == NIL)
296 int i = length(qry->targetList);
298 foreach(extrl, icolumns)
301 * decrements first, so if we started with zero items
302 * it will now be negative
308 * this an index into the targetList,
309 * so make sure we had one to start...
313 freeList(lnext(extrl));
328 foreach(tl, icolumns)
330 id = (Ident *) lfirst(tl);
331 if (namestrcmp(&(att[defval[ndef].adnum - 1]->attname), id->name) == 0)
334 if (tl != NIL) /* something given for this attr */
338 * Nothing given for this attr with DEFAULT expr, so add new
339 * TargetEntry to qry->targetList. Note, that we set resno to
340 * defval[ndef].adnum: it's what
341 * transformTargetList()->make_targetlist_expr() does for
342 * INSERT ... SELECT. But for INSERT ... VALUES
343 * pstate->p_last_resno is used. It doesn't matter for
344 * "normal" using (planner creates proper target list in
345 * preptlist.c), but may break RULEs in some way. It seems
346 * better to create proper target list here...
348 te = makeTargetEntry(makeResdom(defval[ndef].adnum,
349 att[defval[ndef].adnum - 1]->atttypid,
350 att[defval[ndef].adnum - 1]->atttypmod,
351 pstrdup(nameout(&(att[defval[ndef].adnum - 1]->attname))),
353 (Node *) stringToNode(defval[ndef].adbin));
354 qry->targetList = lappend(qry->targetList, te);
358 /* fix where clause */
359 qry->qual = transformWhereClause(pstate, stmt->whereClause);
362 * The havingQual has a similar meaning as "qual" in the where
363 * statement. So we can easily use the code from the "where clause"
364 * with some additional traversals done in
365 * .../optimizer/plan/planner.c
367 qry->havingQual = transformWhereClause(pstate, stmt->havingClause);
369 qry->hasSubLinks = pstate->p_hasSubLinks;
371 /* now the range table will not change */
372 qry->rtable = pstate->p_rtable;
373 qry->resultRelation = refnameRangeTablePosn(pstate, stmt->relname, NULL);
375 qry->groupClause = transformGroupClause(pstate,
379 /* fix order clause */
380 qry->sortClause = transformSortClause(pstate,
386 qry->hasAggs = pstate->p_hasAggs;
387 if (pstate->p_hasAggs)
388 parseCheckAggregates(pstate, qry);
391 * The INSERT INTO ... SELECT ... could have a UNION in child, so
392 * unionClause may be false
394 qry->unionall = stmt->unionall;
397 /* Just hand through the unionClause and intersectClause.
398 * We will handle it in the function Except_Intersect_Rewrite() */
399 qry->unionClause = stmt->unionClause;
400 qry->intersectClause = stmt->intersectClause;
403 * If there is a havingQual but there are no aggregates, then there is
404 * something wrong with the query because having must contain
405 * aggregates in its expressions! Otherwise the query could have been
406 * formulated using the where clause.
408 if ((qry->hasAggs == false) && (qry->havingQual != NULL))
410 elog(ERROR, "SELECT/HAVING requires aggregates to be valid");
411 return (Query *) NIL;
414 if (stmt->forUpdate != NULL)
415 transformForUpdate(qry, stmt->forUpdate);
417 return (Query *) qry;
422 * Create a table name from a list of fields.
425 makeTableName(void *elem,...)
430 char buf[NAMEDATALEN + 1];
434 va_start(args, elem);
439 /* not enough room for next part? then return nothing */
440 if ((strlen(buf) + strlen(name)) >= (sizeof(buf) - 1))
447 name = va_arg(args, void *);
452 name = palloc(strlen(buf) + 1);
459 CreateIndexName(char *table_name, char *column_name, char *label, List *indices)
465 char name2[NAMEDATALEN + 1];
467 /* use working storage, since we might be trying several possibilities */
468 strcpy(name2, column_name);
469 while (iname == NULL)
471 iname = makeTableName(table_name, name2, label, NULL);
472 /* unable to make a name at all? then quit */
479 index = lfirst(ilist);
480 if (strcasecmp(iname, index->idxname) == 0)
483 ilist = lnext(ilist);
485 /* ran through entire list? then no name conflict found so done */
489 /* the last one conflicted, so try a new name component */
493 sprintf(name2, "%s_%d", column_name, (pass + 1));
500 * transformCreateStmt -
501 * transforms the "create table" statement
502 * SQL92 allows constraints to be scattered all over, so thumb through
503 * the columns and collect all constraints into one place.
504 * If there are any implied indices (e.g. UNIQUE or PRIMARY KEY)
505 * then expand those into multiple IndexStmt blocks.
506 * - thomas 1997-12-02
509 transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
512 int have_pkey = FALSE;
520 Constraint *constraint;
529 q->commandType = CMD_UTILITY;
531 elements = stmt->tableElts;
532 constraints = stmt->constraints;
536 while (elements != NIL)
538 element = lfirst(elements);
539 switch (nodeTag(element))
542 column = (ColumnDef *) element;
543 columns = lappend(columns, column);
545 if (column->is_sequence)
549 CreateSeqStmt *sequence;
551 sname = makeTableName(stmt->relname, column->colname, "seq", NULL);
553 constraint = makeNode(Constraint);
554 constraint->contype = CONSTR_DEFAULT;
555 constraint->name = sname;
556 cstring = palloc(9 + strlen(constraint->name) + 2 + 1);
557 strcpy(cstring, "nextval('");
558 strcat(cstring, constraint->name);
559 strcat(cstring, "')");
560 constraint->def = cstring;
561 constraint->keys = NULL;
563 /* The parser only allows PRIMARY KEY as a constraint for the SERIAL type.
564 * So, if there is a constraint of any kind, assume it is that.
565 * If PRIMARY KEY is specified, then don't need to gin up a UNIQUE constraint
566 * since that will be covered already.
567 * - thomas 1998-09-15
569 if (column->constraints != NIL)
571 column->constraints = lappend(column->constraints, constraint);
575 column->constraints = lcons(constraint, NIL);
577 constraint = makeNode(Constraint);
578 constraint->contype = CONSTR_UNIQUE;
579 constraint->name = makeTableName(stmt->relname, column->colname, "key", NULL);
580 column->constraints = lappend(column->constraints, constraint);
583 sequence = makeNode(CreateSeqStmt);
584 sequence->seqname = pstrdup(sname);
585 sequence->options = NIL;
587 elog(NOTICE, "CREATE TABLE will create implicit sequence %s for SERIAL column %s.%s",
588 sequence->seqname, stmt->relname, column->colname);
590 blist = lcons(sequence, NIL);
593 if (column->constraints != NIL)
595 clist = column->constraints;
598 constraint = lfirst(clist);
599 switch (constraint->contype)
602 if (column->is_not_null)
603 elog(ERROR, "CREATE TABLE/NOT NULL already specified"
604 " for %s.%s", stmt->relname, column->colname);
605 column->is_not_null = TRUE;
609 if (column->defval != NULL)
610 elog(ERROR, "CREATE TABLE/DEFAULT multiple values specified"
611 " for %s.%s", stmt->relname, column->colname);
612 column->defval = constraint->def;
616 if (constraint->name == NULL)
617 constraint->name = makeTableName(stmt->relname, "pkey", NULL);
618 if (constraint->keys == NIL)
619 constraint->keys = lappend(constraint->keys, column);
620 dlist = lappend(dlist, constraint);
624 if (constraint->name == NULL)
625 constraint->name = makeTableName(stmt->relname, column->colname, "key", NULL);
626 if (constraint->keys == NIL)
627 constraint->keys = lappend(constraint->keys, column);
628 dlist = lappend(dlist, constraint);
632 constraints = lappend(constraints, constraint);
633 if (constraint->name == NULL)
634 constraint->name = makeTableName(stmt->relname, column->colname, NULL);
638 elog(ERROR, "parser: unrecognized constraint (internal error)", NULL);
641 clist = lnext(clist);
647 constraint = (Constraint *) element;
648 switch (constraint->contype)
651 if (constraint->name == NULL)
652 constraint->name = makeTableName(stmt->relname, "pkey", NULL);
653 dlist = lappend(dlist, constraint);
658 if (constraint->name == NULL)
659 constraint->name = makeTableName(stmt->relname, "key", NULL);
661 dlist = lappend(dlist, constraint);
665 constraints = lappend(constraints, constraint);
670 elog(ERROR, "parser: illegal context for constraint (internal error)", NULL);
673 elog(ERROR, "parser: unrecognized constraint (internal error)", NULL);
679 elog(ERROR, "parser: unrecognized node (internal error)", NULL);
682 elements = lnext(elements);
685 stmt->tableElts = columns;
686 stmt->constraints = constraints;
688 /* Now run through the "deferred list" to complete the query transformation.
689 * For PRIMARY KEYs, mark each column as NOT NULL and create an index.
690 * For UNIQUE, create an index as for PRIMARY KEYS, but do not insist on NOT NULL.
692 * Note that this code does not currently look for all possible redundant cases
693 * and either ignore or stop with warning. The create might fail later when
694 * names for indices turn out to be redundant, or a user might have specified
695 * extra useless indices which might hurt performance. - thomas 1997-12-08
699 constraint = lfirst(dlist);
700 if (nodeTag(constraint) != T_Constraint)
701 elog(ERROR, "parser: unrecognized deferred node (internal error)", NULL);
703 if (constraint->contype == CONSTR_PRIMARY)
706 elog(ERROR, "CREATE TABLE/PRIMARY KEY multiple primary keys"
707 " for table %s are not legal", stmt->relname);
711 else if (constraint->contype != CONSTR_UNIQUE)
712 elog(ERROR, "parser: unrecognized deferred constraint (internal error)", NULL);
714 index = makeNode(IndexStmt);
716 index->unique = TRUE;
717 if (constraint->name != NULL)
718 index->idxname = constraint->name;
719 else if (constraint->contype == CONSTR_PRIMARY)
722 elog(ERROR, "CREATE TABLE/PRIMARY KEY multiple keys for table %s are not legal", stmt->relname);
725 index->primary = TRUE;
726 index->idxname = makeTableName(stmt->relname, "pkey", NULL);
730 index->primary = FALSE;
731 index->idxname = NULL;
734 index->relname = stmt->relname;
735 index->accessMethod = "btree";
736 index->indexParams = NIL;
737 index->withClause = NIL;
738 index->whereClause = NULL;
740 keys = constraint->keys;
744 columns = stmt->tableElts;
746 while (columns != NIL)
748 column = lfirst(columns);
749 if (strcasecmp(column->colname, key->name) == 0)
753 columns = lnext(columns);
756 elog(ERROR, "CREATE TABLE column '%s' in key does not exist", key->name);
758 if (constraint->contype == CONSTR_PRIMARY)
759 column->is_not_null = TRUE;
760 iparam = makeNode(IndexElem);
761 iparam->name = strcpy(palloc(strlen(column->colname) + 1), column->colname);
763 iparam->class = NULL;
764 iparam->typename = NULL;
765 index->indexParams = lappend(index->indexParams, iparam);
767 if (index->idxname == NULL)
768 index->idxname = CreateIndexName(stmt->relname, iparam->name, "key", ilist);
773 if (index->idxname == NULL)
774 elog(ERROR, "CREATE TABLE unable to construct implicit index for table %s"
775 "; name too long", stmt->relname);
777 elog(NOTICE, "CREATE TABLE/%s will create implicit index %s for table %s",
778 ((constraint->contype == CONSTR_PRIMARY) ? "PRIMARY KEY" : "UNIQUE"),
779 index->idxname, stmt->relname);
781 ilist = lappend(ilist, index);
782 dlist = lnext(dlist);
785 q->utilityStmt = (Node *) stmt;
786 extras_before = blist;
787 extras_after = ilist;
793 * transformIndexStmt -
794 * transforms the qualification of the index statement
797 transformIndexStmt(ParseState *pstate, IndexStmt *stmt)
801 qry = makeNode(Query);
802 qry->commandType = CMD_UTILITY;
804 /* take care of the where clause */
805 stmt->whereClause = transformWhereClause(pstate, stmt->whereClause);
806 qry->hasSubLinks = pstate->p_hasSubLinks;
808 stmt->rangetable = pstate->p_rtable;
810 qry->utilityStmt = (Node *) stmt;
816 * transformExtendStmt -
817 * transform the qualifications of the Extend Index Statement
821 transformExtendStmt(ParseState *pstate, ExtendStmt *stmt)
825 qry = makeNode(Query);
826 qry->commandType = CMD_UTILITY;
828 /* take care of the where clause */
829 stmt->whereClause = transformWhereClause(pstate, stmt->whereClause);
830 qry->hasSubLinks = pstate->p_hasSubLinks;
832 stmt->rangetable = pstate->p_rtable;
834 qry->utilityStmt = (Node *) stmt;
839 * transformRuleStmt -
840 * transform a Create Rule Statement. The actions is a list of parse
841 * trees which is transformed into a list of query trees.
844 transformRuleStmt(ParseState *pstate, RuleStmt *stmt)
850 qry = makeNode(Query);
851 qry->commandType = CMD_UTILITY;
854 * 'instead nothing' rules with a qualification need a query a
855 * rangetable so the rewrite handler can add the negated rule
856 * qualification to the original query. We create a query with the new
857 * command type CMD_NOTHING here that is treated special by the
860 if (stmt->actions == NIL)
862 Query *nothing_qry = makeNode(Query);
864 nothing_qry->commandType = CMD_NOTHING;
866 addRangeTableEntry(pstate, stmt->object->relname, "*CURRENT*",
868 addRangeTableEntry(pstate, stmt->object->relname, "*NEW*",
871 nothing_qry->rtable = pstate->p_rtable;
873 stmt->actions = lappend(NIL, nothing_qry);
876 actions = stmt->actions;
879 * transform each statment, like parse_analyze()
881 while (actions != NIL)
885 * NOTE: 'CURRENT' must always have a varno equal to 1 and 'NEW'
888 addRangeTableEntry(pstate, stmt->object->relname, "*CURRENT*",
890 addRangeTableEntry(pstate, stmt->object->relname, "*NEW*",
893 pstate->p_last_resno = 1;
894 pstate->p_is_rule = true; /* for expand all */
895 pstate->p_hasAggs = false;
897 action = (Query *) lfirst(actions);
898 if (action->commandType != CMD_NOTHING)
899 lfirst(actions) = transformStmt(pstate, lfirst(actions));
900 actions = lnext(actions);
903 /* take care of the where clause */
904 stmt->whereClause = transformWhereClause(pstate, stmt->whereClause);
905 qry->hasSubLinks = pstate->p_hasSubLinks;
907 qry->utilityStmt = (Node *) stmt;
913 * transformSelectStmt -
914 * transforms a Select Statement
918 transformSelectStmt(ParseState *pstate, SelectStmt *stmt)
920 Query *qry = makeNode(Query);
922 qry->commandType = CMD_SELECT;
924 /* set up a range table */
925 makeRangeTable(pstate, NULL, stmt->fromClause);
927 qry->uniqueFlag = stmt->unique;
929 qry->into = stmt->into;
930 qry->isPortal = FALSE;
932 qry->targetList = transformTargetList(pstate, stmt->targetList);
934 qry->qual = transformWhereClause(pstate, stmt->whereClause);
937 * The havingQual has a similar meaning as "qual" in the where
938 * statement. So we can easily use the code from the "where clause"
939 * with some additional traversals done in optimizer/plan/planner.c
941 qry->havingQual = transformWhereClause(pstate, stmt->havingClause);
943 qry->hasSubLinks = pstate->p_hasSubLinks;
945 qry->sortClause = transformSortClause(pstate,
951 qry->groupClause = transformGroupClause(pstate,
954 qry->rtable = pstate->p_rtable;
956 qry->hasAggs = pstate->p_hasAggs;
957 if (pstate->p_hasAggs)
958 parseCheckAggregates(pstate, qry);
961 * The INSERT INTO ... SELECT ... could have a UNION in child, so
962 * unionClause may be false
964 qry->unionall = stmt->unionall;
967 /* Just hand through the unionClause and intersectClause.
968 * We will handle it in the function Except_Intersect_Rewrite() */
969 qry->unionClause = stmt->unionClause;
970 qry->intersectClause = stmt->intersectClause;
973 * If there is a havingQual but there are no aggregates, then there is
974 * something wrong with the query because having must contain
975 * aggregates in its expressions! Otherwise the query could have been
976 * formulated using the where clause.
978 if ((qry->hasAggs == false) && (qry->havingQual != NULL))
980 elog(ERROR, "SELECT/HAVING requires aggregates to be valid");
981 return (Query *) NIL;
984 if (stmt->forUpdate != NULL)
985 transformForUpdate(qry, stmt->forUpdate);
987 return (Query *) qry;
991 * transformUpdateStmt -
992 * transforms an update statement
996 transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt)
998 Query *qry = makeNode(Query);
1000 qry->commandType = CMD_UPDATE;
1001 pstate->p_is_update = true;
1004 * the FROM clause is non-standard SQL syntax. We used to be able to
1005 * do this with REPLACE in POSTQUEL so we keep the feature.
1007 makeRangeTable(pstate, stmt->relname, stmt->fromClause);
1009 qry->targetList = transformTargetList(pstate, stmt->targetList);
1011 qry->qual = transformWhereClause(pstate, stmt->whereClause);
1012 qry->hasSubLinks = pstate->p_hasSubLinks;
1014 qry->rtable = pstate->p_rtable;
1016 qry->resultRelation = refnameRangeTablePosn(pstate, stmt->relname, NULL);
1018 qry->hasAggs = pstate->p_hasAggs;
1019 if (pstate->p_hasAggs)
1020 parseCheckAggregates(pstate, qry);
1022 return (Query *) qry;
1026 * transformCursorStmt -
1027 * transform a Create Cursor Statement
1031 transformCursorStmt(ParseState *pstate, SelectStmt *stmt)
1035 qry = transformSelectStmt(pstate, stmt);
1037 qry->into = stmt->portalname;
1038 qry->isPortal = TRUE;
1039 qry->isBinary = stmt->binary; /* internal portal */
1045 /* This function steps through the tree
1046 * built up by the select_w_o_sort rule
1047 * and builds a list of all SelectStmt Nodes found
1048 * The built up list is handed back in **select_list.
1049 * If one of the SelectStmt Nodes has the 'unionall' flag
1050 * set to true *unionall_present hands back 'true' */
1052 create_select_list(Node *ptr, List **select_list, bool *unionall_present)
1054 if(IsA(ptr, SelectStmt)) {
1055 *select_list = lappend(*select_list, ptr);
1056 if(((SelectStmt *)ptr)->unionall == TRUE) *unionall_present = TRUE;
1060 /* Recursively call for all arguments. A NOT expr has no lexpr! */
1061 if (((A_Expr *)ptr)->lexpr != NULL)
1062 create_select_list(((A_Expr *)ptr)->lexpr, select_list, unionall_present);
1063 create_select_list(((A_Expr *)ptr)->rexpr, select_list, unionall_present);
1066 /* Changes the A_Expr Nodes to Expr Nodes and exchanges ANDs and ORs.
1067 * The reason for the exchange is easy: We implement INTERSECTs and EXCEPTs
1068 * by rewriting these queries to semantically equivalent queries that use
1069 * IN and NOT IN subselects. To be able to use all three operations
1070 * (UNIONs INTERSECTs and EXCEPTs) in one complex query we have to
1071 * translate the queries into Disjunctive Normal Form (DNF). Unfortunately
1072 * there is no function 'dnfify' but there is a function 'cnfify'
1073 * which produces DNF when we exchange ANDs and ORs before calling
1074 * 'cnfify' and exchange them back in the result.
1076 * If an EXCEPT or INTERSECT is present *intersect_present
1077 * hands back 'true' */
1078 Node *A_Expr_to_Expr(Node *ptr, bool *intersect_present)
1082 switch(nodeTag(ptr))
1086 A_Expr *a = (A_Expr *)ptr;
1092 Expr *expr = makeNode(Expr);
1093 Node *lexpr = A_Expr_to_Expr(((A_Expr *)ptr)->lexpr, intersect_present);
1094 Node *rexpr = A_Expr_to_Expr(((A_Expr *)ptr)->rexpr, intersect_present);
1096 *intersect_present = TRUE;
1098 expr->typeOid = BOOLOID;
1099 expr->opType = OR_EXPR;
1100 expr->args = makeList(lexpr, rexpr, -1);
1101 result = (Node *) expr;
1106 Expr *expr = makeNode(Expr);
1107 Node *lexpr = A_Expr_to_Expr(((A_Expr *)ptr)->lexpr, intersect_present);
1108 Node *rexpr = A_Expr_to_Expr(((A_Expr *)ptr)->rexpr, intersect_present);
1110 expr->typeOid = BOOLOID;
1111 expr->opType = AND_EXPR;
1112 expr->args = makeList(lexpr, rexpr, -1);
1113 result = (Node *) expr;
1118 Expr *expr = makeNode(Expr);
1119 Node *rexpr = A_Expr_to_Expr(((A_Expr *)ptr)->rexpr, intersect_present);
1121 expr->typeOid = BOOLOID;
1122 expr->opType = NOT_EXPR;
1123 expr->args = makeList(rexpr, -1);
1124 result = (Node *) expr;
1139 CheckSelectForUpdate(Query *qry)
1141 if (qry->unionClause != NULL)
1142 elog(ERROR, "SELECT FOR UPDATE is not allowed with UNION/INTERSECT/EXCEPT clause");
1143 if (qry->uniqueFlag != NULL)
1144 elog(ERROR, "SELECT FOR UPDATE is not allowed with DISTINCT clause");
1145 if (qry->groupClause != NULL)
1146 elog(ERROR, "SELECT FOR UPDATE is not allowed with GROUP BY clause");
1148 elog(ERROR, "SELECT FOR UPDATE is not allowed with AGGREGATE");
1152 transformForUpdate(Query *qry, List *forUpdate)
1154 List *rowMark = NULL;
1159 CheckSelectForUpdate(qry);
1161 if (lfirst(forUpdate) == NULL) /* all tables */
1164 foreach (l, qry->rtable)
1166 newrm = makeNode(RowMark);
1168 newrm->info = ROW_MARK_FOR_UPDATE|ROW_ACL_FOR_UPDATE;
1169 rowMark = lappend(rowMark, newrm);
1171 qry->rowMark = nconc(qry->rowMark, rowMark);
1175 foreach (l, forUpdate)
1181 foreach (l2, qry->rtable)
1183 if (strcmp(((RangeTblEntry*)lfirst(l2))->refname, lfirst(l)) == 0)
1185 foreach (l3, rowMark)
1187 if (((RowMark*)lfirst(l3))->rti == i) /* duplicate */
1192 newrm = makeNode(RowMark);
1194 newrm->info = ROW_MARK_FOR_UPDATE|ROW_ACL_FOR_UPDATE;
1195 rowMark = lappend(rowMark, newrm);
1202 elog(ERROR, "FOR UPDATE: relation %s not found in FROM clause", lfirst(l));
1205 qry->rowMark = rowMark;