1010 *
1111 *
1212 * IDENTIFICATION
13- * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.93 1999/07/17 20:17:21 momjian Exp $
13+ * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.94 1999/07/20 00:18:01 tgl Exp $
1414 *
1515 * HISTORY
1616 * AUTHORDATEMAJOR EVENT
@@ -2468,14 +2468,15 @@ OptimizableStmt: SelectStmt
24682468 *****************************************************************************/
24692469
24702470/* This rule used 'opt_column_list' between 'relation_name' and 'insert_rest'
2471- * originally. When the second rule of 'insert_rest' was changed to use
2472- * the new 'SelectStmt' rule (for INTERSECT and EXCEPT) it produced a shift/reduce
2473- * conflict. So I just changed the rules 'InsertStmt' and 'insert_rest' to accept
2474- * the same statements without any shift/reduce conflicts */
2475- InsertStmt: INSERT INTO relation_name insert_rest
2471+ * originally. When the second rule of 'insert_rest' was changed to use the
2472+ * new 'SelectStmt' rule (for INTERSECT and EXCEPT) it produced a shift/reduce
2473+ * conflict. So I just changed the rules 'InsertStmt' and 'insert_rest' to
2474+ * accept the same statements without any shift/reduce conflicts
2475+ */
2476+ InsertStmt: INSERT INTO relation_name insert_rest
24762477{
24772478 $4->relname = $3;
2478- $$ = (Node *)$4;
2479+ $$ = (Node *) $4;
24792480}
24802481;
24812482
@@ -2503,15 +2504,16 @@ insert_rest: VALUES '(' target_list ')'
25032504$$->unionClause = NIL;
25042505 $$->intersectClause = NIL;
25052506}
2506- /* We want the full power of SelectStatements including INTERSECT and EXCEPT
2507- * for insertion */
2507+ /* We want the full power of SelectStatements including INTERSECT and EXCEPT
2508+ * for insertion. However, we can't support sort or limit clauses.
2509+ */
25082510| SelectStmt
25092511{
2510- SelectStmt *n;
2511-
2512- n = (SelectStmt *)$1 ;
2512+ SelectStmt *n = (SelectStmt *) $1 ;
2513+ if (n->sortClause)
2514+ elog(ERROR, "INSERT ... SELECT can't have ORDER BY") ;
25132515$$ = makeNode(InsertStmt);
2514- $$->cols =NULL ;
2516+ $$->cols =NIL ;
25152517$$->unique = n->unique;
25162518$$->targetList = n->targetList;
25172519$$->fromClause = n->fromClause;
@@ -2520,6 +2522,7 @@ insert_rest: VALUES '(' target_list ')'
25202522$$->havingClause = n->havingClause;
25212523$$->unionClause = n->unionClause;
25222524$$->intersectClause = n->intersectClause;
2525+ $$->unionall = n->unionall;
25232526$$->forUpdate = n->forUpdate;
25242527}
25252528| '(' columnList ')' VALUES '(' target_list ')'
@@ -2537,9 +2540,9 @@ insert_rest: VALUES '(' target_list ')'
25372540}
25382541| '(' columnList ')' SelectStmt
25392542{
2540- SelectStmt *n;
2541-
2542- n = (SelectStmt *)$4 ;
2543+ SelectStmt *n = (SelectStmt *) $4 ;
2544+ if (n->sortClause)
2545+ elog(ERROR, "INSERT ... SELECT can't have ORDER BY") ;
25432546$$ = makeNode(InsertStmt);
25442547$$->cols = $2;
25452548$$->unique = n->unique;
@@ -2550,6 +2553,8 @@ insert_rest: VALUES '(' target_list ')'
25502553$$->havingClause = n->havingClause;
25512554$$->unionClause = n->unionClause;
25522555$$->intersectClause = n->intersectClause;
2556+ $$->unionall = n->unionall;
2557+ $$->forUpdate = n->forUpdate;
25532558}
25542559;
25552560
@@ -2682,103 +2687,115 @@ opt_cursor: BINARY{ $$ = TRUE; }
26822687 *SELECT STATEMENTS
26832688 *
26842689 *****************************************************************************/
2685- /* The new 'SelectStmt' rule adapted for the optional use of INTERSECT EXCEPT and UNION
2686- * accepts the use of '(' and ')' to select an order of set operations.
2690+
2691+ /* A complete SELECT statement looks like this. Note sort, for_update,
2692+ * and limit clauses can only appear once, not in each subselect.
26872693 *
26882694 * The rule returns a SelectStmt Node having the set operations attached to
26892695 * unionClause and intersectClause (NIL if no set operations were present)
26902696 */
26912697
26922698SelectStmt: select_clause sort_clause for_update_clause opt_select_limit
26932699{
2694- /* There were no set operations, so just attach the sortClause */
26952700if IsA($1, SelectStmt)
26962701{
2697- SelectStmt *n = (SelectStmt *)$1;
2698- n->sortClause = $2;
2699- n->forUpdate = $3;
2700- n->limitOffset = nth(0, $4);
2701- n->limitCount = nth(1, $4);
2702- $$ = (Node *)n;
2702+ /* There were no set operations, so just attach the
2703+ * one-time clauses.
2704+ */
2705+ SelectStmt *n = (SelectStmt *) $1;
2706+ n->sortClause = $2;
2707+ n->forUpdate = $3;
2708+ n->limitOffset = nth(0, $4);
2709+ n->limitCount = nth(1, $4);
2710+ $$ = (Node *) n;
27032711 }
2704- /* There were set operations: The root of the operator tree
2705- * is delivered by $1 but we cannot hand back an A_Expr Node.
2706- * So we search for the leftmost 'SelectStmt' in the operator
2707- * tree $1 (which is the first Select Statement in the query
2708- * typed in by the user or where ever it came from).
2709- *
2710- * Then we attach the whole operator tree to 'intersectClause',
2711- * and a list of all 'SelectStmt' Nodes to 'unionClause' and
2712- * hand back the leftmost 'SelectStmt' Node. (We do it this way
2713- * because the following functions (e.g. parse_analyze etc.)
2714- * excpect a SelectStmt node and not an operator tree! The whole
2715- * tree attached to 'intersectClause' won't be touched by
2716- * parse_analyze() etc. until the function
2717- * Except_Intersect_Rewrite() (in rewriteHandler.c) which performs
2718- * the necessary steps to be able create a plan!) */
27192712else
27202713{
2721- List *select_list = NIL;
2722- SelectStmt *first_select;
2723- Node *op = (Node *) $1;
2724- bool intersect_present = FALSE, unionall_present = FALSE;
2725-
2726- /* Take the operator tree as an argument and
2727- * create a list of all SelectStmt Nodes found in the tree.
2728- *
2729- * If one of the SelectStmt Nodes has the 'unionall' flag
2730- * set to true the 'unionall_present' flag is also set to
2731- * true */
2732- create_select_list((Node *)op, &select_list, &unionall_present);
2733-
2734- /* Replace all the A_Expr Nodes in the operator tree by
2735- * Expr Nodes.
2736- *
2737- * If an INTERSECT or an EXCEPT is present, the
2738- * 'intersect_present' flag is set to true */
2739- op = A_Expr_to_Expr(op, &intersect_present);
2740-
2741- /* If both flags are set to true we have a UNION ALL
2742- * statement mixed up with INTERSECT or EXCEPT
2743- * which can not be handled at the moment */
2744- if (intersect_present && unionall_present)
2745- {
2746- elog(ERROR,"UNION ALL not allowed in mixed set operations!");
2747- }
2714+ /* There were set operations. The root of the operator
2715+ * tree is delivered by $1, but we must hand back a
2716+ * SelectStmt node not an A_Expr Node.
2717+ * So we find the leftmost 'SelectStmt' in the operator
2718+ * tree $1 (which is the first Select Statement in the
2719+ * query), which will be the returned node.
2720+ * Then we attach the whole operator tree to that node's
2721+ * 'intersectClause', and a list of all 'SelectStmt' Nodes
2722+ * in the tree to its 'unionClause'. (NOTE that this means
2723+ * the top node has indirect recursive pointers to itself!
2724+ * This would cause trouble if we tried copyObject!!)
2725+ * The intersectClause and unionClause subtrees will be
2726+ * left untouched by the main parser, and will only be
2727+ * processed when control gets to the function
2728+ * Except_Intersect_Rewrite() (in rewriteHandler.c).
2729+ */
2730+ Node *op = (Node *) $1;
2731+ List *select_list = NIL;
2732+ SelectStmt *first_select;
2733+ boolintersect_present = false,
2734+ unionall_present = false;
2735+
2736+ /* Take the operator tree as an argument and create a
2737+ * list of all SelectStmt Nodes found in the tree.
2738+ *
2739+ * If one of the SelectStmt Nodes has the 'unionall' flag
2740+ * set to true the 'unionall_present' flag is also set to
2741+ * true.
2742+ */
2743+ create_select_list(op, &select_list, &unionall_present);
2744+
2745+ /* Replace all the A_Expr Nodes in the operator tree by
2746+ * Expr Nodes.
2747+ *
2748+ * If an INTERSECT or an EXCEPT is present, the
2749+ * 'intersect_present' flag is set to true
2750+ */
2751+ op = A_Expr_to_Expr(op, &intersect_present);
27482752
2749- /* Get the leftmost SeletStmt Node (which automatically
2750- * represents the first Select Statement of the query!) */
2751- first_select = (SelectStmt *)lfirst(select_list);
2753+ /* If both flags are set to true we have a UNION ALL
2754+ * statement mixed up with INTERSECT or EXCEPT
2755+ * which can not be handled at the moment.
2756+ */
2757+ if (intersect_present && unionall_present)
2758+ elog(ERROR, "UNION ALL not allowed in mixed set operations");
2759+
2760+ /* Get the leftmost SeletStmt Node (which automatically
2761+ * represents the first Select Statement of the query!)
2762+ */
2763+ first_select = (SelectStmt *) lfirst(select_list);
27522764
2753- /* Attach the list of all SeletStmt Nodes to unionClause */
2754- first_select->unionClause = select_list;
2765+ /* Attach the list of all SeletStmt Nodes to unionClause */
2766+ first_select->unionClause = select_list;
27552767
2756- /* Attach the whole operator tree to intersectClause */
2757- first_select->intersectClause = (List *) op;
2768+ /* Attach the whole operator tree to intersectClause */
2769+ first_select->intersectClause = (List *) op;
27582770
2759- /* finally attach the sort clause */
2760- first_select->sortClause = $2;
2761- first_select->forUpdate = $3;
2762- $$ = (Node *)first_select;
2771+ /* finally attach the sort clause &etc */
2772+ first_select->sortClause = $2;
2773+ first_select->forUpdate = $3;
2774+ first_select->limitOffset = nth(0, $4);
2775+ first_select->limitCount = nth(1, $4);
2776+ $$ = (Node *) first_select;
27632777}
27642778if (((SelectStmt *)$$)->forUpdate != NULL && QueryIsRule)
27652779elog(ERROR, "SELECT FOR UPDATE is not allowed in RULES");
27662780}
27672781;
27682782
2769- /* This rule parses Select statementsincluding UNION INTERSECT and EXCEPT.
2770- * '(' and ')' can be used to specify the order of the operations
2771- *(UNION EXCEPT INTERSECT). Without theuse of '(' and ')' we want the
2783+ /* This rule parses Select statementsthat can appear within set operations,
2784+ *including UNION, INTERSECT and EXCEPT. '(' and ')' can be used to specify
2785+ *the ordering of theset operations. Without '(' and ')' we want the
27722786 * operations to be left associative.
27732787 *
2774- * The sort_clause is not handled here!
2788+ * Note that sort clauses cannot be included at this level --- a sort clause
2789+ * can only appear at the end of the complete Select, and it will be handled
2790+ * by the topmost SelectStmt rule. Likewise FOR UPDATE and LIMIT.
27752791 *
27762792 * The rule builds up an operator tree using A_Expr Nodes. AND Nodes represent
2777- * INTERSECTs OR Nodes represent UNIONs and AND NOT nodes represent EXCEPTs.
2793+ * INTERSECTs, OR Nodes represent UNIONs, and AND NOT nodes represent EXCEPTs.
27782794 * The SelectStatements to be connected are the left and right arguments to
27792795 * the A_Expr Nodes.
2780- * If no set operations show up in the query the tree consists only of one
2781- * SelectStmt Node */
2796+ * If no set operations appear in the query, the tree consists only of one
2797+ * SelectStmt Node.
2798+ */
27822799select_clause: '(' select_clause ')'
27832800{
27842801$$ = $2;
@@ -2798,6 +2815,12 @@ select_clause: '(' select_clause ')'
27982815 {
27992816 SelectStmt *n = (SelectStmt *)$4;
28002817 n->unionall = $3;
2818+ /* NOTE: if UNION ALL appears with a parenthesized set
2819+ * operation to its right, the ALL is silently discarded.
2820+ * Should we generate an error instead? I think it may
2821+ * be OK since ALL with UNION to its right is ignored
2822+ * anyway...
2823+ */
28012824 }
28022825$$ = (Node *)makeA_Expr(OR,NULL,$1,$4);
28032826}
@@ -2822,7 +2845,8 @@ SubSelect:SELECT opt_unique target_list
28222845 * want to create a new rule 'SubSelect1' including the
28232846 * feature. If it makes troubles we will have to add
28242847 * a new rule and change this to prevent INTOs in
2825- * Subselects again */
2848+ * Subselects again.
2849+ */
28262850n->istemp = (bool) ((Value *) lfirst($4))->val.ival;
28272851n->into = (char *) lnext($4);
28282852