Okay, here's my attempt at fixing the problems with parentheses in
subqueries.  It passes the normal 'runcheck' tests, and I've tried
a few simple things like 
  select 1 as foo union (((((select 2))))) order by foo;

There are a few things that it doesn't do that have been talked 
about here at least a little:

1) It doesn't allow things like "IN(((select 1)))" -- the select
here has to be at the top level.  This is not new.

2) It does NOT preserve the odd syntax I found when I started looking
at this, where a SELECT statement could begin with parentheses.  Thus,
  (SELECT a from foo) order by a;
fails.

I have preserved the ability, used in the regression tests, to
have a single select statement in what appears to be a RuleActionMulti
(but wasn't -- the parens were part of select_clause syntax).
In my version, this is a special form.

This may cause some discussion: I have differentiated the two kinds
of RuleActionMulti.  Perhaps nobody knew there were two kinds, because
I don't think the second form appears in the regression tests. This
one uses square brackets instead of parentheses, but originally was
otherwise the same as the one in parentheses.  In this version of
gram.y, the square bracket form treats SELECT statements the same
as the other allowed statements.  As discussed before on this list,
psql cannot make sense out of the results of such a thing, but an
application might.  And I have designs on just such an application.

++ kevin



-- 
Kevin O'Gorman  (805) 650-6274  mailto:kogorman@pacbell.net
Permanent e-mail forwarder:  mailto:Kevin.O'Gorman.64@Alum.Dartmouth.org
At school: mailto:kogorman@cs.ucsb.edu
Web: http://www.cs.ucsb.edu/~kogorman/index.html
Web: http://trixie.kosman.via.ayuda.com/~kevin/index.html

"There is a freedom lying beyond circumstance,
derived from the direct intuition that life can
be grounded upon its absorption in what is
changeless amid change" 
   -- Alfred North Whitehead
Fri, 27 Oct 2000 18:11:00 -0700
"Kevin O'Gorman" <kogorman@pacbell.net>
Gram.y patches for better parenthesis handling.
"Kevin O'Gorman" <kogorman@pacbell.net> writes:
> 2) It does NOT preserve the odd syntax I found when I started looking
> at this, where a SELECT statement could begin with parentheses.  Thus,
>   (SELECT a from foo) order by a;
> fails.

Um, as a general rule that's not an acceptable limitation.  Consider

	(SELECT foo EXCEPT SELECT bar) INTERSECT SELECT baz;

Without parens this will mean something quite different, since
INTERSECT has higher precedence than EXCEPT.

Also, a leading paren is clearly legal according to SQL92 --- trace
for example the productions
         <direct select statement: multiple rows>
         <query expression>
         <non-join query expression>
         <non-join query term>
         <non-join query primary> ::=
              <left paren> <non-join query expression> <right paren>

(UNION/EXCEPT structures are <non-join query expression> in this
hierarchy.)

The reason that making this grammar yacc-compatible is so hard is
precisely that leading parens must sometimes be part of the SELECT
structure, whereas extraneous parens need to be kept out of it.

			regards, tom lane

Sat, 28 Oct 2000 00:55:40 -0400
Tom Lane <tgl@sss.pgh.pa.us>
Re: Gram.y patches for better parenthesis handling. 
Applied.   Thanks.


> Okay, here's my attempt at fixing the problems with parentheses in
> subqueries.  It passes the normal 'runcheck' tests, and I've tried
> a few simple things like 
>   select 1 as foo union (((((select 2))))) order by foo;
> 
> There are a few things that it doesn't do that have been talked 
> about here at least a little:
> 
> 1) It doesn't allow things like "IN(((select 1)))" -- the select
> here has to be at the top level.  This is not new.
> 
> 2) It does NOT preserve the odd syntax I found when I started looking
> at this, where a SELECT statement could begin with parentheses.  Thus,
>   (SELECT a from foo) order by a;
> fails.
> 
> I have preserved the ability, used in the regression tests, to
> have a single select statement in what appears to be a RuleActionMulti
> (but wasn't -- the parens were part of select_clause syntax).
> In my version, this is a special form.
> 
> This may cause some discussion: I have differentiated the two kinds
> of RuleActionMulti.  Perhaps nobody knew there were two kinds, because
> I don't think the second form appears in the regression tests. This
> one uses square brackets instead of parentheses, but originally was
> otherwise the same as the one in parentheses.  In this version of
> gram.y, the square bracket form treats SELECT statements the same
> as the other allowed statements.  As discussed before on this list,
> psql cannot make sense out of the results of such a thing, but an
> application might.  And I have designs on just such an application.
> 
> ++ kevin
> 
> 
> 
> -- 
> Kevin O'Gorman  (805) 650-6274  mailto:kogorman@pacbell.net
> Permanent e-mail forwarder:  mailto:Kevin.O'Gorman.64@Alum.Dartmouth.org
> At school: mailto:kogorman@cs.ucsb.edu
> Web: http://www.cs.ucsb.edu/~kogorman/index.html
> Web: http://trixie.kosman.via.ayuda.com/~kevin/index.html
> 
> "There is a freedom lying beyond circumstance,
> derived from the direct intuition that life can
> be grounded upon its absorption in what is
> changeless amid change" 
>    -- Alfred North Whitehead

> --- gram.y.orig	Thu Oct 26 13:13:04 2000
> +++ gram.y	Fri Oct 27 17:37:58 2000
> @@ -124,14 +124,15 @@
>  		DropGroupStmt, DropPLangStmt, DropSchemaStmt, DropStmt, DropTrigStmt,
>  		DropUserStmt, DropdbStmt, ExplainStmt, ExtendStmt, FetchStmt,
>  		GrantStmt, IndexStmt, InsertStmt, ListenStmt, LoadStmt, LockStmt,
> -		NotifyStmt, OptimizableStmt, ProcedureStmt, ReindexStmt,
> +		NotifyStmt, OptimizableStmt, ProcedureStmt
> +		QualifiedSelectStmt, ReindexStmt,
>  		RemoveAggrStmt, RemoveFuncStmt, RemoveOperStmt, RemoveStmt,
>  		RenameStmt, RevokeStmt, RuleActionStmt, RuleActionStmtOrEmpty,
>  		RuleStmt, SelectStmt, SetSessionStmt, TransactionStmt, TruncateStmt,
>  		UnlistenStmt, UpdateStmt, VacuumStmt, VariableResetStmt,
>  		VariableSetStmt, VariableShowStmt, ViewStmt
>  
> -%type <node>	select_clause, select_subclause
> +%type <node>	subquery, simple_select, select_head, set_select
>  
>  %type <list>	SessionList
>  %type <node>	SessionClause
> @@ -174,19 +175,20 @@
>  		result, OptTempTableName, relation_name_list, OptTableElementList,
>  		OptUnder, OptInherit, definition, opt_distinct,
>  		opt_with, func_args, func_args_list, func_as,
> -		oper_argtypes, RuleActionList, RuleActionMulti,
> +		oper_argtypes, RuleActionList, RuleActionMulti, 
> +		RuleActionOrSelectMulti, RuleActions, RuleActionBracket,
>  		opt_column_list, columnList, opt_va_list, va_list,
>  		sort_clause, sortby_list, index_params, index_list, name_list,
>  		from_clause, from_list, opt_array_bounds,
>  		expr_list, attrs, target_list, update_target_list,
>  		def_list, opt_indirection, group_clause, TriggerFuncArgs,
> -		opt_select_limit
> +		opt_select_limit, select_limit
>  
>  %type <typnam>	func_arg, func_return, aggr_argtype
>  
>  %type <boolean>	opt_arg, TriggerForOpt, TriggerForType, OptTemp
>  
> -%type <list>	for_update_clause, update_list
> +%type <list>	opt_for_update_clause, for_update_clause, update_list
>  %type <boolean>	opt_all
>  %type <boolean>	opt_table
>  %type <boolean>	opt_chain, opt_trans
> @@ -2689,7 +2691,7 @@
>  RuleStmt:  CREATE RULE name AS
>  		   { QueryIsRule=TRUE; }
>  		   ON event TO event_object where_clause
> -		   DO opt_instead RuleActionList
> +		   DO opt_instead RuleActions
>  				{
>  					RuleStmt *n = makeNode(RuleStmt);
>  					n->rulename = $3;
> @@ -2702,17 +2704,42 @@
>  				}
>  		;
>  
> -RuleActionList:  NOTHING				{ $$ = NIL; }
> -		| SelectStmt					{ $$ = makeList1($1); }
> -		| RuleActionStmt				{ $$ = makeList1($1); }
> -		| '[' RuleActionMulti ']'		{ $$ = $2; }
> -		| '(' RuleActionMulti ')'		{ $$ = $2; } 
> +RuleActions:  NOTHING				{ $$ = NIL; }
> +		| RuleActionStmt			{ $$ = makeList1($1); }
> +		| SelectStmt				{ $$ = makeList1($1); }
> +		| RuleActionList
> +		| RuleActionBracket
> +		;
> +
> +/* LEGACY: Version 7.0 did not like SELECT statements in these lists,
> + * but because of an oddity in the syntax for select_clause, allowed
> + * certain forms like "DO INSTEAD (select 1)", and this is used in
> + * the regression tests.
> + * Here, we're allowing just one SELECT in parentheses, to preserve
> + * any such expectations, and make the regression tests work.
> + *               ++ KO'G
> + */
> +RuleActionList:		'(' RuleActionMulti ')'		{ $$ = $2; } 
> +		| '(' SelectStmt ')'	{ $$ = makeList1($2); }
> +		;
> +
> +/* An undocumented feature, bracketed lists are allowed to contain
> + * SELECT statements on the same basis as the others.  Before this,
> + * they were the same as parenthesized lists, and did not allow
> + * SelectStmts.  Anybody know why they were here originally?  Or if
> + * they're in the regression tests at all?
> + *               ++ KO'G
> + */
> +RuleActionBracket:	'[' RuleActionOrSelectMulti ']'		{ $$ = $2; } 
>  		;
>  
>  /* the thrashing around here is to discard "empty" statements... */
>  RuleActionMulti:  RuleActionMulti ';' RuleActionStmtOrEmpty
>  				{ if ($3 != (Node *) NULL)
> -					$$ = lappend($1, $3);
> +					if ($1 != NIL)
> +						$$ = lappend($1, $3);
> +					else
> +						$$ = makeList1($3);
>  				  else
>  					$$ = $1;
>  				}
> @@ -2724,6 +2751,31 @@
>  				}
>  		;
>  
> +RuleActionOrSelectMulti: RuleActionOrSelectMulti ';' RuleActionStmtOrEmpty
> +				{ if ($3 != (Node *) NULL)
> +					if ($1 != NIL)
> +						$$ = lappend($1, $3);
> +					else
> +						$$ = makeList1($3);
> +				  else
> +					$$ = $1;
> +				}
> +		| RuleActionOrSelectMulti ';' SelectStmt
> +				{ if ($1 != NIL)
> +						$$ = lappend($1, $3);
> +				  else
> +						$$ = makeList1($3);
> +				}
> +		| RuleActionStmtOrEmpty
> +				{ if ($1 != (Node *) NULL)
> +					$$ = makeList1($1);
> +				  else
> +					$$ = NIL;
> +				}
> +		| SelectStmt		{ $$ = makeList1($1); }
> +		;
> +
> +
>  RuleActionStmt:	InsertStmt
>  		| UpdateStmt
>  		| DeleteStmt
> @@ -3289,7 +3341,12 @@
>   * However, this is not checked by the grammar; parse analysis must check it.
>   */
>  
> -SelectStmt:	  select_clause sort_clause for_update_clause opt_select_limit
> +SelectStmt:	QualifiedSelectStmt
> +		| select_head
> +		;
> +
> +QualifiedSelectStmt:
> +		  select_head sort_clause opt_for_update_clause opt_select_limit
>  			{
>  				SelectStmt *n = findLeftmostSelect($1);
>  
> @@ -3299,34 +3356,35 @@
>  				n->limitCount = nth(1, $4);
>  				$$ = $1;
>  			}
> -		;
> -
> -/* This rule parses Select statements that can appear within set operations,
> - * including UNION, INTERSECT and EXCEPT.  '(' and ')' can be used to specify
> - * the ordering of the set operations.  Without '(' and ')' we want the
> - * operations to be ordered per the precedence specs at the head of this file.
> - *
> - * Since parentheses around SELECTs also appear in the expression grammar,
> - * there is a parse ambiguity if parentheses are allowed at the top level of a
> - * select_clause: are the parens part of the expression or part of the select?
> - * We separate select_clause into two levels to resolve this: select_clause
> - * can have top-level parentheses, select_subclause cannot.
> - *
> - * Note that sort clauses cannot be included at this level --- a sort clause
> - * can only appear at the end of the complete Select, and it will be handled
> - * by the topmost SelectStmt rule.  Likewise FOR UPDATE and LIMIT.
> - */
> -select_clause: '(' select_subclause ')'
> +		| select_head for_update_clause opt_select_limit
>  			{
> -				$$ = $2; 
> +				SelectStmt *n = findLeftmostSelect($1);
> +
> +				n->sortClause = NULL;
> +				n->forUpdate = $2;
> +				n->limitOffset = nth(0, $3);
> +				n->limitCount = nth(1, $3);
> +				$$ = $1;
>  			}
> -		| select_subclause
> +		| select_head select_limit
>  			{
> -				$$ = $1; 
> +				SelectStmt *n = findLeftmostSelect($1);
> +
> +				n->sortClause = NULL;
> +				n->forUpdate = NULL;
> +				n->limitOffset = nth(0, $2);
> +				n->limitCount = nth(1, $2);
> +				$$ = $1;
>  			}
>  		;
>  
> -select_subclause: SELECT opt_distinct target_list
> +subquery:	'(' subquery ')'			{ $$ = $2; }
> +		| '(' QualifiedSelectStmt ')'	{ $$ = $2; }
> +		| '(' set_select ')'			{ $$ = $2; }
> +		| simple_select					{ $$ = $1; }
> +		;
> +
> +simple_select: SELECT opt_distinct target_list
>  			 result from_clause where_clause
>  			 group_clause having_clause
>  				{
> @@ -3341,7 +3399,13 @@
>  					n->havingClause = $8;
>  					$$ = (Node *)n;
>  				}
> -		| select_clause UNION opt_all select_clause
> +		;
> +
> +select_head: simple_select			{ $$ = $1; }
> +		|	set_select				{ $$ = $1; }
> +		;
> +
> +set_select: select_head UNION opt_all subquery
>  			{	
>  				SetOperationStmt *n = makeNode(SetOperationStmt);
>  				n->op = SETOP_UNION;
> @@ -3350,7 +3414,7 @@
>  				n->rarg = $4;
>  				$$ = (Node *) n;
>  			}
> -		| select_clause INTERSECT opt_all select_clause
> +		| select_head INTERSECT opt_all subquery
>  			{
>  				SetOperationStmt *n = makeNode(SetOperationStmt);
>  				n->op = SETOP_INTERSECT;
> @@ -3359,7 +3423,7 @@
>  				n->rarg = $4;
>  				$$ = (Node *) n;
>  			}
> -		| select_clause EXCEPT opt_all select_clause
> +		| select_head EXCEPT opt_all subquery
>  			{
>  				SetOperationStmt *n = makeNode(SetOperationStmt);
>  				n->op = SETOP_EXCEPT;
> @@ -3424,7 +3488,6 @@
>  		;
>  
>  sort_clause:  ORDER BY sortby_list				{ $$ = $3; }
> -		| /*EMPTY*/								{ $$ = NIL; }
>  		;
>  
>  sortby_list:  sortby							{ $$ = makeList1($1); }
> @@ -3446,7 +3509,7 @@
>  		;
>  
>  
> -opt_select_limit:	LIMIT select_limit_value ',' select_offset_value
> +select_limit:	LIMIT select_limit_value ',' select_offset_value
>  			{ $$ = makeList2($4, $2); }
>  		| LIMIT select_limit_value OFFSET select_offset_value
>  			{ $$ = makeList2($4, $2); }
> @@ -3456,6 +3519,9 @@
>  			{ $$ = makeList2($2, $4); }
>  		| OFFSET select_offset_value
>  			{ $$ = makeList2($2, NULL); }
> +		;
> +
> +opt_select_limit: select_limit	{ $$ = $1; }
>  		| /* EMPTY */
>  			{ $$ = makeList2(NULL, NULL); }
>  		;
> @@ -3555,6 +3621,9 @@
>  
>  for_update_clause:  FOR UPDATE update_list		{ $$ = $3; }
>  		| FOR READ ONLY							{ $$ = NULL; }
> +		;
> +
> +opt_for_update_clause:	for_update_clause		{ $$ = $1; }
>  		| /* EMPTY */							{ $$ = NULL; }
>  		;
>  
> @@ -3598,7 +3667,7 @@
>  					$1->name = $2;
>  					$$ = (Node *) $1;
>  				}
> -		| '(' select_subclause ')' alias_clause
> +		| '(' SelectStmt ')' alias_clause
>  				{
>  					RangeSubselect *n = makeNode(RangeSubselect);
>  					n->subquery = $2;
> @@ -4134,7 +4203,7 @@
>   * Define row_descriptor to allow yacc to break the reduce/reduce conflict
>   *  with singleton expressions.
>   */
> -row_expr: '(' row_descriptor ')' IN '(' select_subclause ')'
> +row_expr: '(' row_descriptor ')' IN '(' SelectStmt ')'
>  				{
>  					SubLink *n = makeNode(SubLink);
>  					n->lefthand = $2;
> @@ -4144,7 +4213,7 @@
>  					n->subselect = $6;
>  					$$ = (Node *)n;
>  				}
> -		| '(' row_descriptor ')' NOT IN '(' select_subclause ')'
> +		| '(' row_descriptor ')' NOT IN '(' SelectStmt ')'
>  				{
>  					SubLink *n = makeNode(SubLink);
>  					n->lefthand = $2;
> @@ -4154,7 +4223,7 @@
>  					n->subselect = $7;
>  					$$ = (Node *)n;
>  				}
> -		| '(' row_descriptor ')' all_Op sub_type '(' select_subclause ')'
> +		| '(' row_descriptor ')' all_Op sub_type '(' SelectStmt ')'
>  				{
>  					SubLink *n = makeNode(SubLink);
>  					n->lefthand = $2;
> @@ -4167,7 +4236,7 @@
>  					n->subselect = $7;
>  					$$ = (Node *)n;
>  				}
> -		| '(' row_descriptor ')' all_Op '(' select_subclause ')'
> +		| '(' row_descriptor ')' all_Op '(' SelectStmt ')'
>  				{
>  					SubLink *n = makeNode(SubLink);
>  					n->lefthand = $2;
> @@ -4498,7 +4567,7 @@
>  						$$ = n;
>  					}
>  				}
> -		| a_expr all_Op sub_type '(' select_subclause ')'
> +		| a_expr all_Op sub_type '(' SelectStmt ')'
>  				{
>  					SubLink *n = makeNode(SubLink);
>  					n->lefthand = makeList1($1);
> @@ -4894,7 +4963,7 @@
>  					n->agg_distinct = FALSE;
>  					$$ = (Node *)n;
>  				}
> -		| '(' select_subclause ')'
> +		| '(' SelectStmt ')'
>  				{
>  					SubLink *n = makeNode(SubLink);
>  					n->lefthand = NIL;
> @@ -4904,7 +4973,7 @@
>  					n->subselect = $2;
>  					$$ = (Node *)n;
>  				}
> -		| EXISTS '(' select_subclause ')'
> +		| EXISTS '(' SelectStmt ')'
>  				{
>  					SubLink *n = makeNode(SubLink);
>  					n->lefthand = NIL;
> @@ -5003,7 +5072,7 @@
>  				{ $$ = $1; }
>  		;
>  
> -in_expr:  select_subclause
> +in_expr:  SelectStmt
>  				{
>  					SubLink *n = makeNode(SubLink);
>  					n->subselect = $1;


-- 
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 853-3000
  +  If your life is a hard drive,     |  830 Blythe Avenue
  +  Christ can be your backup.        |  Drexel Hill, Pennsylvania 19026

Sat, 28 Oct 2000 11:44:04 -0400 (EDT)
Bruce Momjian <pgman@candle.pha.pa.us>
Re: Gram.y patches for better parenthesis handling.
Err, with Tom's objections, why was this applied?
* Bruce Momjian <pgman@candle.pha.pa.us> [001028 11:34]:
> Applied.   Thanks.
> 
> 
> > Okay, here's my attempt at fixing the problems with parentheses in
> > subqueries.  It passes the normal 'runcheck' tests, and I've tried
> > a few simple things like 
> >   select 1 as foo union (((((select 2))))) order by foo;
> > 
> > There are a few things that it doesn't do that have been talked 
> > about here at least a little:
> > 
> > 1) It doesn't allow things like "IN(((select 1)))" -- the select
> > here has to be at the top level.  This is not new.
> > 
> > 2) It does NOT preserve the odd syntax I found when I started looking
> > at this, where a SELECT statement could begin with parentheses.  Thus,
> >   (SELECT a from foo) order by a;
> > fails.
> > 
> > I have preserved the ability, used in the regression tests, to
> > have a single select statement in what appears to be a RuleActionMulti
> > (but wasn't -- the parens were part of select_clause syntax).
> > In my version, this is a special form.
> > 
> > This may cause some discussion: I have differentiated the two kinds
> > of RuleActionMulti.  Perhaps nobody knew there were two kinds, because
> > I don't think the second form appears in the regression tests. This
> > one uses square brackets instead of parentheses, but originally was
> > otherwise the same as the one in parentheses.  In this version of
> > gram.y, the square bracket form treats SELECT statements the same
> > as the other allowed statements.  As discussed before on this list,
> > psql cannot make sense out of the results of such a thing, but an
> > application might.  And I have designs on just such an application.
> > 
> > ++ kevin
> > 
> > 
> > 
> > -- 
> > Kevin O'Gorman  (805) 650-6274  mailto:kogorman@pacbell.net
> > Permanent e-mail forwarder:  mailto:Kevin.O'Gorman.64@Alum.Dartmouth.org
> > At school: mailto:kogorman@cs.ucsb.edu
> > Web: http://www.cs.ucsb.edu/~kogorman/index.html
> > Web: http://trixie.kosman.via.ayuda.com/~kevin/index.html
> > 
> > "There is a freedom lying beyond circumstance,
> > derived from the direct intuition that life can
> > be grounded upon its absorption in what is
> > changeless amid change" 
> >    -- Alfred North Whitehead
> 
> > --- gram.y.orig	Thu Oct 26 13:13:04 2000
> > +++ gram.y	Fri Oct 27 17:37:58 2000
> > @@ -124,14 +124,15 @@
> >  		DropGroupStmt, DropPLangStmt, DropSchemaStmt, DropStmt, DropTrigStmt,
> >  		DropUserStmt, DropdbStmt, ExplainStmt, ExtendStmt, FetchStmt,
> >  		GrantStmt, IndexStmt, InsertStmt, ListenStmt, LoadStmt, LockStmt,
> > -		NotifyStmt, OptimizableStmt, ProcedureStmt, ReindexStmt,
> > +		NotifyStmt, OptimizableStmt, ProcedureStmt
> > +		QualifiedSelectStmt, ReindexStmt,
> >  		RemoveAggrStmt, RemoveFuncStmt, RemoveOperStmt, RemoveStmt,
> >  		RenameStmt, RevokeStmt, RuleActionStmt, RuleActionStmtOrEmpty,
> >  		RuleStmt, SelectStmt, SetSessionStmt, TransactionStmt, TruncateStmt,
> >  		UnlistenStmt, UpdateStmt, VacuumStmt, VariableResetStmt,
> >  		VariableSetStmt, VariableShowStmt, ViewStmt
> >  
> > -%type <node>	select_clause, select_subclause
> > +%type <node>	subquery, simple_select, select_head, set_select
> >  
> >  %type <list>	SessionList
> >  %type <node>	SessionClause
> > @@ -174,19 +175,20 @@
> >  		result, OptTempTableName, relation_name_list, OptTableElementList,
> >  		OptUnder, OptInherit, definition, opt_distinct,
> >  		opt_with, func_args, func_args_list, func_as,
> > -		oper_argtypes, RuleActionList, RuleActionMulti,
> > +		oper_argtypes, RuleActionList, RuleActionMulti, 
> > +		RuleActionOrSelectMulti, RuleActions, RuleActionBracket,
> >  		opt_column_list, columnList, opt_va_list, va_list,
> >  		sort_clause, sortby_list, index_params, index_list, name_list,
> >  		from_clause, from_list, opt_array_bounds,
> >  		expr_list, attrs, target_list, update_target_list,
> >  		def_list, opt_indirection, group_clause, TriggerFuncArgs,
> > -		opt_select_limit
> > +		opt_select_limit, select_limit
> >  
> >  %type <typnam>	func_arg, func_return, aggr_argtype
> >  
> >  %type <boolean>	opt_arg, TriggerForOpt, TriggerForType, OptTemp
> >  
> > -%type <list>	for_update_clause, update_list
> > +%type <list>	opt_for_update_clause, for_update_clause, update_list
> >  %type <boolean>	opt_all
> >  %type <boolean>	opt_table
> >  %type <boolean>	opt_chain, opt_trans
> > @@ -2689,7 +2691,7 @@
> >  RuleStmt:  CREATE RULE name AS
> >  		   { QueryIsRule=TRUE; }
> >  		   ON event TO event_object where_clause
> > -		   DO opt_instead RuleActionList
> > +		   DO opt_instead RuleActions
> >  				{
> >  					RuleStmt *n = makeNode(RuleStmt);
> >  					n->rulename = $3;
> > @@ -2702,17 +2704,42 @@
> >  				}
> >  		;
> >  
> > -RuleActionList:  NOTHING				{ $$ = NIL; }
> > -		| SelectStmt					{ $$ = makeList1($1); }
> > -		| RuleActionStmt				{ $$ = makeList1($1); }
> > -		| '[' RuleActionMulti ']'		{ $$ = $2; }
> > -		| '(' RuleActionMulti ')'		{ $$ = $2; } 
> > +RuleActions:  NOTHING				{ $$ = NIL; }
> > +		| RuleActionStmt			{ $$ = makeList1($1); }
> > +		| SelectStmt				{ $$ = makeList1($1); }
> > +		| RuleActionList
> > +		| RuleActionBracket
> > +		;
> > +
> > +/* LEGACY: Version 7.0 did not like SELECT statements in these lists,
> > + * but because of an oddity in the syntax for select_clause, allowed
> > + * certain forms like "DO INSTEAD (select 1)", and this is used in
> > + * the regression tests.
> > + * Here, we're allowing just one SELECT in parentheses, to preserve
> > + * any such expectations, and make the regression tests work.
> > + *               ++ KO'G
> > + */
> > +RuleActionList:		'(' RuleActionMulti ')'		{ $$ = $2; } 
> > +		| '(' SelectStmt ')'	{ $$ = makeList1($2); }
> > +		;
> > +
> > +/* An undocumented feature, bracketed lists are allowed to contain
> > + * SELECT statements on the same basis as the others.  Before this,
> > + * they were the same as parenthesized lists, and did not allow
> > + * SelectStmts.  Anybody know why they were here originally?  Or if
> > + * they're in the regression tests at all?
> > + *               ++ KO'G
> > + */
> > +RuleActionBracket:	'[' RuleActionOrSelectMulti ']'		{ $$ = $2; } 
> >  		;
> >  
> >  /* the thrashing around here is to discard "empty" statements... */
> >  RuleActionMulti:  RuleActionMulti ';' RuleActionStmtOrEmpty
> >  				{ if ($3 != (Node *) NULL)
> > -					$$ = lappend($1, $3);
> > +					if ($1 != NIL)
> > +						$$ = lappend($1, $3);
> > +					else
> > +						$$ = makeList1($3);
> >  				  else
> >  					$$ = $1;
> >  				}
> > @@ -2724,6 +2751,31 @@
> >  				}
> >  		;
> >  
> > +RuleActionOrSelectMulti: RuleActionOrSelectMulti ';' RuleActionStmtOrEmpty
> > +				{ if ($3 != (Node *) NULL)
> > +					if ($1 != NIL)
> > +						$$ = lappend($1, $3);
> > +					else
> > +						$$ = makeList1($3);
> > +				  else
> > +					$$ = $1;
> > +				}
> > +		| RuleActionOrSelectMulti ';' SelectStmt
> > +				{ if ($1 != NIL)
> > +						$$ = lappend($1, $3);
> > +				  else
> > +						$$ = makeList1($3);
> > +				}
> > +		| RuleActionStmtOrEmpty
> > +				{ if ($1 != (Node *) NULL)
> > +					$$ = makeList1($1);
> > +				  else
> > +					$$ = NIL;
> > +				}
> > +		| SelectStmt		{ $$ = makeList1($1); }
> > +		;
> > +
> > +
> >  RuleActionStmt:	InsertStmt
> >  		| UpdateStmt
> >  		| DeleteStmt
> > @@ -3289,7 +3341,12 @@
> >   * However, this is not checked by the grammar; parse analysis must check it.
> >   */
> >  
> > -SelectStmt:	  select_clause sort_clause for_update_clause opt_select_limit
> > +SelectStmt:	QualifiedSelectStmt
> > +		| select_head
> > +		;
> > +
> > +QualifiedSelectStmt:
> > +		  select_head sort_clause opt_for_update_clause opt_select_limit
> >  			{
> >  				SelectStmt *n = findLeftmostSelect($1);
> >  
> > @@ -3299,34 +3356,35 @@
> >  				n->limitCount = nth(1, $4);
> >  				$$ = $1;
> >  			}
> > -		;
> > -
> > -/* This rule parses Select statements that can appear within set operations,
> > - * including UNION, INTERSECT and EXCEPT.  '(' and ')' can be used to specify
> > - * the ordering of the set operations.  Without '(' and ')' we want the
> > - * operations to be ordered per the precedence specs at the head of this file.
> > - *
> > - * Since parentheses around SELECTs also appear in the expression grammar,
> > - * there is a parse ambiguity if parentheses are allowed at the top level of a
> > - * select_clause: are the parens part of the expression or part of the select?
> > - * We separate select_clause into two levels to resolve this: select_clause
> > - * can have top-level parentheses, select_subclause cannot.
> > - *
> > - * Note that sort clauses cannot be included at this level --- a sort clause
> > - * can only appear at the end of the complete Select, and it will be handled
> > - * by the topmost SelectStmt rule.  Likewise FOR UPDATE and LIMIT.
> > - */
> > -select_clause: '(' select_subclause ')'
> > +		| select_head for_update_clause opt_select_limit
> >  			{
> > -				$$ = $2; 
> > +				SelectStmt *n = findLeftmostSelect($1);
> > +
> > +				n->sortClause = NULL;
> > +				n->forUpdate = $2;
> > +				n->limitOffset = nth(0, $3);
> > +				n->limitCount = nth(1, $3);
> > +				$$ = $1;
> >  			}
> > -		| select_subclause
> > +		| select_head select_limit
> >  			{
> > -				$$ = $1; 
> > +				SelectStmt *n = findLeftmostSelect($1);
> > +
> > +				n->sortClause = NULL;
> > +				n->forUpdate = NULL;
> > +				n->limitOffset = nth(0, $2);
> > +				n->limitCount = nth(1, $2);
> > +				$$ = $1;
> >  			}
> >  		;
> >  
> > -select_subclause: SELECT opt_distinct target_list
> > +subquery:	'(' subquery ')'			{ $$ = $2; }
> > +		| '(' QualifiedSelectStmt ')'	{ $$ = $2; }
> > +		| '(' set_select ')'			{ $$ = $2; }
> > +		| simple_select					{ $$ = $1; }
> > +		;
> > +
> > +simple_select: SELECT opt_distinct target_list
> >  			 result from_clause where_clause
> >  			 group_clause having_clause
> >  				{
> > @@ -3341,7 +3399,13 @@
> >  					n->havingClause = $8;
> >  					$$ = (Node *)n;
> >  				}
> > -		| select_clause UNION opt_all select_clause
> > +		;
> > +
> > +select_head: simple_select			{ $$ = $1; }
> > +		|	set_select				{ $$ = $1; }
> > +		;
> > +
> > +set_select: select_head UNION opt_all subquery
> >  			{	
> >  				SetOperationStmt *n = makeNode(SetOperationStmt);
> >  				n->op = SETOP_UNION;
> > @@ -3350,7 +3414,7 @@
> >  				n->rarg = $4;
> >  				$$ = (Node *) n;
> >  			}
> > -		| select_clause INTERSECT opt_all select_clause
> > +		| select_head INTERSECT opt_all subquery
> >  			{
> >  				SetOperationStmt *n = makeNode(SetOperationStmt);
> >  				n->op = SETOP_INTERSECT;
> > @@ -3359,7 +3423,7 @@
> >  				n->rarg = $4;
> >  				$$ = (Node *) n;
> >  			}
> > -		| select_clause EXCEPT opt_all select_clause
> > +		| select_head EXCEPT opt_all subquery
> >  			{
> >  				SetOperationStmt *n = makeNode(SetOperationStmt);
> >  				n->op = SETOP_EXCEPT;
> > @@ -3424,7 +3488,6 @@
> >  		;
> >  
> >  sort_clause:  ORDER BY sortby_list				{ $$ = $3; }
> > -		| /*EMPTY*/								{ $$ = NIL; }
> >  		;
> >  
> >  sortby_list:  sortby							{ $$ = makeList1($1); }
> > @@ -3446,7 +3509,7 @@
> >  		;
> >  
> >  
> > -opt_select_limit:	LIMIT select_limit_value ',' select_offset_value
> > +select_limit:	LIMIT select_limit_value ',' select_offset_value
> >  			{ $$ = makeList2($4, $2); }
> >  		| LIMIT select_limit_value OFFSET select_offset_value
> >  			{ $$ = makeList2($4, $2); }
> > @@ -3456,6 +3519,9 @@
> >  			{ $$ = makeList2($2, $4); }
> >  		| OFFSET select_offset_value
> >  			{ $$ = makeList2($2, NULL); }
> > +		;
> > +
> > +opt_select_limit: select_limit	{ $$ = $1; }
> >  		| /* EMPTY */
> >  			{ $$ = makeList2(NULL, NULL); }
> >  		;
> > @@ -3555,6 +3621,9 @@
> >  
> >  for_update_clause:  FOR UPDATE update_list		{ $$ = $3; }
> >  		| FOR READ ONLY							{ $$ = NULL; }
> > +		;
> > +
> > +opt_for_update_clause:	for_update_clause		{ $$ = $1; }
> >  		| /* EMPTY */							{ $$ = NULL; }
> >  		;
> >  
> > @@ -3598,7 +3667,7 @@
> >  					$1->name = $2;
> >  					$$ = (Node *) $1;
> >  				}
> > -		| '(' select_subclause ')' alias_clause
> > +		| '(' SelectStmt ')' alias_clause
> >  				{
> >  					RangeSubselect *n = makeNode(RangeSubselect);
> >  					n->subquery = $2;
> > @@ -4134,7 +4203,7 @@
> >   * Define row_descriptor to allow yacc to break the reduce/reduce conflict
> >   *  with singleton expressions.
> >   */
> > -row_expr: '(' row_descriptor ')' IN '(' select_subclause ')'
> > +row_expr: '(' row_descriptor ')' IN '(' SelectStmt ')'
> >  				{
> >  					SubLink *n = makeNode(SubLink);
> >  					n->lefthand = $2;
> > @@ -4144,7 +4213,7 @@
> >  					n->subselect = $6;
> >  					$$ = (Node *)n;
> >  				}
> > -		| '(' row_descriptor ')' NOT IN '(' select_subclause ')'
> > +		| '(' row_descriptor ')' NOT IN '(' SelectStmt ')'
> >  				{
> >  					SubLink *n = makeNode(SubLink);
> >  					n->lefthand = $2;
> > @@ -4154,7 +4223,7 @@
> >  					n->subselect = $7;
> >  					$$ = (Node *)n;
> >  				}
> > -		| '(' row_descriptor ')' all_Op sub_type '(' select_subclause ')'
> > +		| '(' row_descriptor ')' all_Op sub_type '(' SelectStmt ')'
> >  				{
> >  					SubLink *n = makeNode(SubLink);
> >  					n->lefthand = $2;
> > @@ -4167,7 +4236,7 @@
> >  					n->subselect = $7;
> >  					$$ = (Node *)n;
> >  				}
> > -		| '(' row_descriptor ')' all_Op '(' select_subclause ')'
> > +		| '(' row_descriptor ')' all_Op '(' SelectStmt ')'
> >  				{
> >  					SubLink *n = makeNode(SubLink);
> >  					n->lefthand = $2;
> > @@ -4498,7 +4567,7 @@
> >  						$$ = n;
> >  					}
> >  				}
> > -		| a_expr all_Op sub_type '(' select_subclause ')'
> > +		| a_expr all_Op sub_type '(' SelectStmt ')'
> >  				{
> >  					SubLink *n = makeNode(SubLink);
> >  					n->lefthand = makeList1($1);
> > @@ -4894,7 +4963,7 @@
> >  					n->agg_distinct = FALSE;
> >  					$$ = (Node *)n;
> >  				}
> > -		| '(' select_subclause ')'
> > +		| '(' SelectStmt ')'
> >  				{
> >  					SubLink *n = makeNode(SubLink);
> >  					n->lefthand = NIL;
> > @@ -4904,7 +4973,7 @@
> >  					n->subselect = $2;
> >  					$$ = (Node *)n;
> >  				}
> > -		| EXISTS '(' select_subclause ')'
> > +		| EXISTS '(' SelectStmt ')'
> >  				{
> >  					SubLink *n = makeNode(SubLink);
> >  					n->lefthand = NIL;
> > @@ -5003,7 +5072,7 @@
> >  				{ $$ = $1; }
> >  		;
> >  
> > -in_expr:  select_subclause
> > +in_expr:  SelectStmt
> >  				{
> >  					SubLink *n = makeNode(SubLink);
> >  					n->subselect = $1;
> 
> 
> -- 
>   Bruce Momjian                        |  http://candle.pha.pa.us
>   pgman@candle.pha.pa.us               |  (610) 853-3000
>   +  If your life is a hard drive,     |  830 Blythe Avenue
>   +  Christ can be your backup.        |  Drexel Hill, Pennsylvania 19026
-- 
Larry Rosenman                      http://www.lerctr.org/~ler
Phone: +1 972-414-9812 (voice) Internet: ler@lerctr.org
US Mail: 1905 Steamboat Springs Drive, Garland, TX 75044-6749

Sat, 28 Oct 2000 11:38:53 -0500
Larry Rosenman <ler@lerctr.org>
Re: Gram.y patches for better parenthesis handling.
Larry Rosenman <ler@lerctr.org> writes:
> Err, with Tom's objections, why was this applied?

> * Bruce Momjian <pgman@candle.pha.pa.us> [001028 11:34]:
>> Applied.   Thanks.

Itchy trigger finger today, Bruce?

Please revert the change --- I'm still discussing it with Kevin offlist,
but I don't feel it's acceptable as-is because it breaks reasonable
(non-redundant) UNION/INTERSECT/EXCEPT constructs that have worked for
several releases past.

			regards, tom lane

Sat, 28 Oct 2000 12:41:19 -0400
Tom Lane <tgl@sss.pgh.pa.us>
Re: Gram.y patches for better parenthesis handling. 
On Sat, 28 Oct 2000, Larry Rosenman wrote:

> Err, with Tom's objections, why was this applied?

was going to ask this too ... someone going patch-happy again? :)


> * Bruce Momjian <pgman@candle.pha.pa.us> [001028 11:34]:
> > Applied.   Thanks.
> > 
> > 
> > > Okay, here's my attempt at fixing the problems with parentheses in
> > > subqueries.  It passes the normal 'runcheck' tests, and I've tried
> > > a few simple things like 
> > >   select 1 as foo union (((((select 2))))) order by foo;
> > > 
> > > There are a few things that it doesn't do that have been talked 
> > > about here at least a little:
> > > 
> > > 1) It doesn't allow things like "IN(((select 1)))" -- the select
> > > here has to be at the top level.  This is not new.
> > > 
> > > 2) It does NOT preserve the odd syntax I found when I started looking
> > > at this, where a SELECT statement could begin with parentheses.  Thus,
> > >   (SELECT a from foo) order by a;
> > > fails.
> > > 
> > > I have preserved the ability, used in the regression tests, to
> > > have a single select statement in what appears to be a RuleActionMulti
> > > (but wasn't -- the parens were part of select_clause syntax).
> > > In my version, this is a special form.
> > > 
> > > This may cause some discussion: I have differentiated the two kinds
> > > of RuleActionMulti.  Perhaps nobody knew there were two kinds, because
> > > I don't think the second form appears in the regression tests. This
> > > one uses square brackets instead of parentheses, but originally was
> > > otherwise the same as the one in parentheses.  In this version of
> > > gram.y, the square bracket form treats SELECT statements the same
> > > as the other allowed statements.  As discussed before on this list,
> > > psql cannot make sense out of the results of such a thing, but an
> > > application might.  And I have designs on just such an application.
> > > 
> > > ++ kevin
> > > 
> > > 
> > > 
> > > -- 
> > > Kevin O'Gorman  (805) 650-6274  mailto:kogorman@pacbell.net
> > > Permanent e-mail forwarder:  mailto:Kevin.O'Gorman.64@Alum.Dartmouth.org
> > > At school: mailto:kogorman@cs.ucsb.edu
> > > Web: http://www.cs.ucsb.edu/~kogorman/index.html
> > > Web: http://trixie.kosman.via.ayuda.com/~kevin/index.html
> > > 
> > > "There is a freedom lying beyond circumstance,
> > > derived from the direct intuition that life can
> > > be grounded upon its absorption in what is
> > > changeless amid change" 
> > >    -- Alfred North Whitehead
> > 
> > > --- gram.y.orig	Thu Oct 26 13:13:04 2000
> > > +++ gram.y	Fri Oct 27 17:37:58 2000
> > > @@ -124,14 +124,15 @@
> > >  		DropGroupStmt, DropPLangStmt, DropSchemaStmt, DropStmt, DropTrigStmt,
> > >  		DropUserStmt, DropdbStmt, ExplainStmt, ExtendStmt, FetchStmt,
> > >  		GrantStmt, IndexStmt, InsertStmt, ListenStmt, LoadStmt, LockStmt,
> > > -		NotifyStmt, OptimizableStmt, ProcedureStmt, ReindexStmt,
> > > +		NotifyStmt, OptimizableStmt, ProcedureStmt
> > > +		QualifiedSelectStmt, ReindexStmt,
> > >  		RemoveAggrStmt, RemoveFuncStmt, RemoveOperStmt, RemoveStmt,
> > >  		RenameStmt, RevokeStmt, RuleActionStmt, RuleActionStmtOrEmpty,
> > >  		RuleStmt, SelectStmt, SetSessionStmt, TransactionStmt, TruncateStmt,
> > >  		UnlistenStmt, UpdateStmt, VacuumStmt, VariableResetStmt,
> > >  		VariableSetStmt, VariableShowStmt, ViewStmt
> > >  
> > > -%type <node>	select_clause, select_subclause
> > > +%type <node>	subquery, simple_select, select_head, set_select
> > >  
> > >  %type <list>	SessionList
> > >  %type <node>	SessionClause
> > > @@ -174,19 +175,20 @@
> > >  		result, OptTempTableName, relation_name_list, OptTableElementList,
> > >  		OptUnder, OptInherit, definition, opt_distinct,
> > >  		opt_with, func_args, func_args_list, func_as,
> > > -		oper_argtypes, RuleActionList, RuleActionMulti,
> > > +		oper_argtypes, RuleActionList, RuleActionMulti, 
> > > +		RuleActionOrSelectMulti, RuleActions, RuleActionBracket,
> > >  		opt_column_list, columnList, opt_va_list, va_list,
> > >  		sort_clause, sortby_list, index_params, index_list, name_list,
> > >  		from_clause, from_list, opt_array_bounds,
> > >  		expr_list, attrs, target_list, update_target_list,
> > >  		def_list, opt_indirection, group_clause, TriggerFuncArgs,
> > > -		opt_select_limit
> > > +		opt_select_limit, select_limit
> > >  
> > >  %type <typnam>	func_arg, func_return, aggr_argtype
> > >  
> > >  %type <boolean>	opt_arg, TriggerForOpt, TriggerForType, OptTemp
> > >  
> > > -%type <list>	for_update_clause, update_list
> > > +%type <list>	opt_for_update_clause, for_update_clause, update_list
> > >  %type <boolean>	opt_all
> > >  %type <boolean>	opt_table
> > >  %type <boolean>	opt_chain, opt_trans
> > > @@ -2689,7 +2691,7 @@
> > >  RuleStmt:  CREATE RULE name AS
> > >  		   { QueryIsRule=TRUE; }
> > >  		   ON event TO event_object where_clause
> > > -		   DO opt_instead RuleActionList
> > > +		   DO opt_instead RuleActions
> > >  				{
> > >  					RuleStmt *n = makeNode(RuleStmt);
> > >  					n->rulename = $3;
> > > @@ -2702,17 +2704,42 @@
> > >  				}
> > >  		;
> > >  
> > > -RuleActionList:  NOTHING				{ $$ = NIL; }
> > > -		| SelectStmt					{ $$ = makeList1($1); }
> > > -		| RuleActionStmt				{ $$ = makeList1($1); }
> > > -		| '[' RuleActionMulti ']'		{ $$ = $2; }
> > > -		| '(' RuleActionMulti ')'		{ $$ = $2; } 
> > > +RuleActions:  NOTHING				{ $$ = NIL; }
> > > +		| RuleActionStmt			{ $$ = makeList1($1); }
> > > +		| SelectStmt				{ $$ = makeList1($1); }
> > > +		| RuleActionList
> > > +		| RuleActionBracket
> > > +		;
> > > +
> > > +/* LEGACY: Version 7.0 did not like SELECT statements in these lists,
> > > + * but because of an oddity in the syntax for select_clause, allowed
> > > + * certain forms like "DO INSTEAD (select 1)", and this is used in
> > > + * the regression tests.
> > > + * Here, we're allowing just one SELECT in parentheses, to preserve
> > > + * any such expectations, and make the regression tests work.
> > > + *               ++ KO'G
> > > + */
> > > +RuleActionList:		'(' RuleActionMulti ')'		{ $$ = $2; } 
> > > +		| '(' SelectStmt ')'	{ $$ = makeList1($2); }
> > > +		;
> > > +
> > > +/* An undocumented feature, bracketed lists are allowed to contain
> > > + * SELECT statements on the same basis as the others.  Before this,
> > > + * they were the same as parenthesized lists, and did not allow
> > > + * SelectStmts.  Anybody know why they were here originally?  Or if
> > > + * they're in the regression tests at all?
> > > + *               ++ KO'G
> > > + */
> > > +RuleActionBracket:	'[' RuleActionOrSelectMulti ']'		{ $$ = $2; } 
> > >  		;
> > >  
> > >  /* the thrashing around here is to discard "empty" statements... */
> > >  RuleActionMulti:  RuleActionMulti ';' RuleActionStmtOrEmpty
> > >  				{ if ($3 != (Node *) NULL)
> > > -					$$ = lappend($1, $3);
> > > +					if ($1 != NIL)
> > > +						$$ = lappend($1, $3);
> > > +					else
> > > +						$$ = makeList1($3);
> > >  				  else
> > >  					$$ = $1;
> > >  				}
> > > @@ -2724,6 +2751,31 @@
> > >  				}
> > >  		;
> > >  
> > > +RuleActionOrSelectMulti: RuleActionOrSelectMulti ';' RuleActionStmtOrEmpty
> > > +				{ if ($3 != (Node *) NULL)
> > > +					if ($1 != NIL)
> > > +						$$ = lappend($1, $3);
> > > +					else
> > > +						$$ = makeList1($3);
> > > +				  else
> > > +					$$ = $1;
> > > +				}
> > > +		| RuleActionOrSelectMulti ';' SelectStmt
> > > +				{ if ($1 != NIL)
> > > +						$$ = lappend($1, $3);
> > > +				  else
> > > +						$$ = makeList1($3);
> > > +				}
> > > +		| RuleActionStmtOrEmpty
> > > +				{ if ($1 != (Node *) NULL)
> > > +					$$ = makeList1($1);
> > > +				  else
> > > +					$$ = NIL;
> > > +				}
> > > +		| SelectStmt		{ $$ = makeList1($1); }
> > > +		;
> > > +
> > > +
> > >  RuleActionStmt:	InsertStmt
> > >  		| UpdateStmt
> > >  		| DeleteStmt
> > > @@ -3289,7 +3341,12 @@
> > >   * However, this is not checked by the grammar; parse analysis must check it.
> > >   */
> > >  
> > > -SelectStmt:	  select_clause sort_clause for_update_clause opt_select_limit
> > > +SelectStmt:	QualifiedSelectStmt
> > > +		| select_head
> > > +		;
> > > +
> > > +QualifiedSelectStmt:
> > > +		  select_head sort_clause opt_for_update_clause opt_select_limit
> > >  			{
> > >  				SelectStmt *n = findLeftmostSelect($1);
> > >  
> > > @@ -3299,34 +3356,35 @@
> > >  				n->limitCount = nth(1, $4);
> > >  				$$ = $1;
> > >  			}
> > > -		;
> > > -
> > > -/* This rule parses Select statements that can appear within set operations,
> > > - * including UNION, INTERSECT and EXCEPT.  '(' and ')' can be used to specify
> > > - * the ordering of the set operations.  Without '(' and ')' we want the
> > > - * operations to be ordered per the precedence specs at the head of this file.
> > > - *
> > > - * Since parentheses around SELECTs also appear in the expression grammar,
> > > - * there is a parse ambiguity if parentheses are allowed at the top level of a
> > > - * select_clause: are the parens part of the expression or part of the select?
> > > - * We separate select_clause into two levels to resolve this: select_clause
> > > - * can have top-level parentheses, select_subclause cannot.
> > > - *
> > > - * Note that sort clauses cannot be included at this level --- a sort clause
> > > - * can only appear at the end of the complete Select, and it will be handled
> > > - * by the topmost SelectStmt rule.  Likewise FOR UPDATE and LIMIT.
> > > - */
> > > -select_clause: '(' select_subclause ')'
> > > +		| select_head for_update_clause opt_select_limit
> > >  			{
> > > -				$$ = $2; 
> > > +				SelectStmt *n = findLeftmostSelect($1);
> > > +
> > > +				n->sortClause = NULL;
> > > +				n->forUpdate = $2;
> > > +				n->limitOffset = nth(0, $3);
> > > +				n->limitCount = nth(1, $3);
> > > +				$$ = $1;
> > >  			}
> > > -		| select_subclause
> > > +		| select_head select_limit
> > >  			{
> > > -				$$ = $1; 
> > > +				SelectStmt *n = findLeftmostSelect($1);
> > > +
> > > +				n->sortClause = NULL;
> > > +				n->forUpdate = NULL;
> > > +				n->limitOffset = nth(0, $2);
> > > +				n->limitCount = nth(1, $2);
> > > +				$$ = $1;
> > >  			}
> > >  		;
> > >  
> > > -select_subclause: SELECT opt_distinct target_list
> > > +subquery:	'(' subquery ')'			{ $$ = $2; }
> > > +		| '(' QualifiedSelectStmt ')'	{ $$ = $2; }
> > > +		| '(' set_select ')'			{ $$ = $2; }
> > > +		| simple_select					{ $$ = $1; }
> > > +		;
> > > +
> > > +simple_select: SELECT opt_distinct target_list
> > >  			 result from_clause where_clause
> > >  			 group_clause having_clause
> > >  				{
> > > @@ -3341,7 +3399,13 @@
> > >  					n->havingClause = $8;
> > >  					$$ = (Node *)n;
> > >  				}
> > > -		| select_clause UNION opt_all select_clause
> > > +		;
> > > +
> > > +select_head: simple_select			{ $$ = $1; }
> > > +		|	set_select				{ $$ = $1; }
> > > +		;
> > > +
> > > +set_select: select_head UNION opt_all subquery
> > >  			{	
> > >  				SetOperationStmt *n = makeNode(SetOperationStmt);
> > >  				n->op = SETOP_UNION;
> > > @@ -3350,7 +3414,7 @@
> > >  				n->rarg = $4;
> > >  				$$ = (Node *) n;
> > >  			}
> > > -		| select_clause INTERSECT opt_all select_clause
> > > +		| select_head INTERSECT opt_all subquery
> > >  			{
> > >  				SetOperationStmt *n = makeNode(SetOperationStmt);
> > >  				n->op = SETOP_INTERSECT;
> > > @@ -3359,7 +3423,7 @@
> > >  				n->rarg = $4;
> > >  				$$ = (Node *) n;
> > >  			}
> > > -		| select_clause EXCEPT opt_all select_clause
> > > +		| select_head EXCEPT opt_all subquery
> > >  			{
> > >  				SetOperationStmt *n = makeNode(SetOperationStmt);
> > >  				n->op = SETOP_EXCEPT;
> > > @@ -3424,7 +3488,6 @@
> > >  		;
> > >  
> > >  sort_clause:  ORDER BY sortby_list				{ $$ = $3; }
> > > -		| /*EMPTY*/								{ $$ = NIL; }
> > >  		;
> > >  
> > >  sortby_list:  sortby							{ $$ = makeList1($1); }
> > > @@ -3446,7 +3509,7 @@
> > >  		;
> > >  
> > >  
> > > -opt_select_limit:	LIMIT select_limit_value ',' select_offset_value
> > > +select_limit:	LIMIT select_limit_value ',' select_offset_value
> > >  			{ $$ = makeList2($4, $2); }
> > >  		| LIMIT select_limit_value OFFSET select_offset_value
> > >  			{ $$ = makeList2($4, $2); }
> > > @@ -3456,6 +3519,9 @@
> > >  			{ $$ = makeList2($2, $4); }
> > >  		| OFFSET select_offset_value
> > >  			{ $$ = makeList2($2, NULL); }
> > > +		;
> > > +
> > > +opt_select_limit: select_limit	{ $$ = $1; }
> > >  		| /* EMPTY */
> > >  			{ $$ = makeList2(NULL, NULL); }
> > >  		;
> > > @@ -3555,6 +3621,9 @@
> > >  
> > >  for_update_clause:  FOR UPDATE update_list		{ $$ = $3; }
> > >  		| FOR READ ONLY							{ $$ = NULL; }
> > > +		;
> > > +
> > > +opt_for_update_clause:	for_update_clause		{ $$ = $1; }
> > >  		| /* EMPTY */							{ $$ = NULL; }
> > >  		;
> > >  
> > > @@ -3598,7 +3667,7 @@
> > >  					$1->name = $2;
> > >  					$$ = (Node *) $1;
> > >  				}
> > > -		| '(' select_subclause ')' alias_clause
> > > +		| '(' SelectStmt ')' alias_clause
> > >  				{
> > >  					RangeSubselect *n = makeNode(RangeSubselect);
> > >  					n->subquery = $2;
> > > @@ -4134,7 +4203,7 @@
> > >   * Define row_descriptor to allow yacc to break the reduce/reduce conflict
> > >   *  with singleton expressions.
> > >   */
> > > -row_expr: '(' row_descriptor ')' IN '(' select_subclause ')'
> > > +row_expr: '(' row_descriptor ')' IN '(' SelectStmt ')'
> > >  				{
> > >  					SubLink *n = makeNode(SubLink);
> > >  					n->lefthand = $2;
> > > @@ -4144,7 +4213,7 @@
> > >  					n->subselect = $6;
> > >  					$$ = (Node *)n;
> > >  				}
> > > -		| '(' row_descriptor ')' NOT IN '(' select_subclause ')'
> > > +		| '(' row_descriptor ')' NOT IN '(' SelectStmt ')'
> > >  				{
> > >  					SubLink *n = makeNode(SubLink);
> > >  					n->lefthand = $2;
> > > @@ -4154,7 +4223,7 @@
> > >  					n->subselect = $7;
> > >  					$$ = (Node *)n;
> > >  				}
> > > -		| '(' row_descriptor ')' all_Op sub_type '(' select_subclause ')'
> > > +		| '(' row_descriptor ')' all_Op sub_type '(' SelectStmt ')'
> > >  				{
> > >  					SubLink *n = makeNode(SubLink);
> > >  					n->lefthand = $2;
> > > @@ -4167,7 +4236,7 @@
> > >  					n->subselect = $7;
> > >  					$$ = (Node *)n;
> > >  				}
> > > -		| '(' row_descriptor ')' all_Op '(' select_subclause ')'
> > > +		| '(' row_descriptor ')' all_Op '(' SelectStmt ')'
> > >  				{
> > >  					SubLink *n = makeNode(SubLink);
> > >  					n->lefthand = $2;
> > > @@ -4498,7 +4567,7 @@
> > >  						$$ = n;
> > >  					}
> > >  				}
> > > -		| a_expr all_Op sub_type '(' select_subclause ')'
> > > +		| a_expr all_Op sub_type '(' SelectStmt ')'
> > >  				{
> > >  					SubLink *n = makeNode(SubLink);
> > >  					n->lefthand = makeList1($1);
> > > @@ -4894,7 +4963,7 @@
> > >  					n->agg_distinct = FALSE;
> > >  					$$ = (Node *)n;
> > >  				}
> > > -		| '(' select_subclause ')'
> > > +		| '(' SelectStmt ')'
> > >  				{
> > >  					SubLink *n = makeNode(SubLink);
> > >  					n->lefthand = NIL;
> > > @@ -4904,7 +4973,7 @@
> > >  					n->subselect = $2;
> > >  					$$ = (Node *)n;
> > >  				}
> > > -		| EXISTS '(' select_subclause ')'
> > > +		| EXISTS '(' SelectStmt ')'
> > >  				{
> > >  					SubLink *n = makeNode(SubLink);
> > >  					n->lefthand = NIL;
> > > @@ -5003,7 +5072,7 @@
> > >  				{ $$ = $1; }
> > >  		;
> > >  
> > > -in_expr:  select_subclause
> > > +in_expr:  SelectStmt
> > >  				{
> > >  					SubLink *n = makeNode(SubLink);
> > >  					n->subselect = $1;
> > 
> > 
> > -- 
> >   Bruce Momjian                        |  http://candle.pha.pa.us
> >   pgman@candle.pha.pa.us               |  (610) 853-3000
> >   +  If your life is a hard drive,     |  830 Blythe Avenue
> >   +  Christ can be your backup.        |  Drexel Hill, Pennsylvania 19026
> -- 
> Larry Rosenman                      http://www.lerctr.org/~ler
> Phone: +1 972-414-9812 (voice) Internet: ler@lerctr.org
> US Mail: 1905 Steamboat Springs Drive, Garland, TX 75044-6749
> 
> 

Marc G. Fournier                   ICQ#7615664               IRC Nick: Scrappy
Systems Administrator @ hub.org 
primary: scrappy@hub.org           secondary: scrappy@{freebsd|postgresql}.org 


Sat, 28 Oct 2000 15:17:38 -0300 (ADT)
The Hermit Hacker <scrappy@hub.org>
Re: Gram.y patches for better parenthesis handling.
> Larry Rosenman <ler@lerctr.org> writes:
> > Err, with Tom's objections, why was this applied?
> 
> > * Bruce Momjian <pgman@candle.pha.pa.us> [001028 11:34]:
> >> Applied.   Thanks.
> 
> Itchy trigger finger today, Bruce?
> 
> Please revert the change --- I'm still discussing it with Kevin offlist,
> but I don't feel it's acceptable as-is because it breaks reasonable
> (non-redundant) UNION/INTERSECT/EXCEPT constructs that have worked for
> several releases past.

Backed out.  I applied it because you said "it was not unacceptible", so
I thought you liked it.

-- 
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 853-3000
  +  If your life is a hard drive,     |  830 Blythe Avenue
  +  Christ can be your backup.        |  Drexel Hill, Pennsylvania 19026

Sat, 28 Oct 2000 15:41:24 -0400 (EDT)
Bruce Momjian <pgman@candle.pha.pa.us>
Re: Gram.y patches for better parenthesis handling.
I've taken another look at this stuff.  I think it's a big improvement, but
we didn't notice that it does NOT do the thing we set out to.  You
still cannot say 
     select foo union (((select bar)))

and as I think about it, there's no way to allow that without unifying
with c_expr.  Consider: yacc is a bottom-up parser, with limited
look-ahead.  So when it sees
   "(((select bar)" and it has just turned it into
   "(((SelectStmt)" what is it going to reduce next?  It has one
char of lookahead, so it can peek out to
   "(((SelectStmt))" but it still doesn't know what to reduce.
It could be that what is wanted is either of
   "((c_expr)" or "((some_select_type)"
and guessing is not allowed.... :-)

I have experimented with unifying c_expr and selects, and it is
all kinds of messy, because to the parser it appears that you're
introducing all sorts of expression tokens into the Select syntax.
Of course we would reject all such strings for other reasons, but
poor yacc has no way of knowing that.

I'm afraid that for now, we should accept the improvements that
have been achieved, and consider a more general treatment of
parentheses later.

What do you think?

++ kevin


On Sun, 29 Oct 2000, Kevin O'Gorman wrote:
> 
> That was very helpful.  And I was able to eliminate most of the
> remaining restrictions by letting a SelectStmt be EITHER
>  a) a simple_select (which has no top-level parens or qualifiers)
> or
>  b) a select_clause with at least one qualifier.
> Option b reintroduces the SORT and LIMIT operations at the
> top level, outside parentheses.
> 
> The remaining restriction that is not SQL92 is that a SelectStmt
> may not have wholly inclusive parens -- there has to be something
> outside of them.  If they're really important, one way to do it would
> be to say an OptimizableStmt can be a c_expr, and check that it
> has a top-level SelectStmt or SetOperationStmt, then treat it as
> a Select Statement.
> 
> I also made mods to put the top-level sort,limit and forUpdate in the
> top-level node of the tree. In order to make this be workable, I also
> modified parsenodes.h so that the structure for SetOperationStmt is a
> synonym for SelectStmt, and merged the fields of the two node
> types.
> 
> I've attached diffs from the current tip of the tree (as of this morning).
> These are still not completely functional until the downstream code
> is changed too, of course.
> 
> 
> On Sat, 28 Oct 2000, you wrote:
> > After some more experimentation, I found that gram.y can be modified
> > per the attached diffs to yield a conflict-free grammar that allows
> > redundant parens and ORDER/LIMIT in subclauses.  The remaining
> > restrictions are:
> > 
> > * To attach ORDER/LIMIT to a member select of a UNION/INTERSECT/EXCEPT,
> > you need to write parens, eg
> > 	(SELECT foo ORDER BY bar) UNION SELECT baz;
> > 	SELECT foo UNION (SELECT bar ORDER BY baz);
> > In the second case the parens are clearly necessary to distinguish the
> > intent from attaching the ORDER BY to the UNION result.  So this seems
> > OK to me.
> > 
> > * Parens cannot separate a select clause from its ORDER/LIMIT clauses.
> > For example, this is not allowed:
> > 	(SELECT foo FROM table) ORDER BY bar;
> > 
> > The latter restriction is pretty annoying, first because SQL92 says
> > it should be legal, and second because we used to accept it.  However,
> > it might be an acceptable tradeoff for allowing ORDER in subselects.
> > Thoughts?
> > 
> > BTW these diffs are just proof-of-concept for the grammar being
> > conflict-free; I haven't changed the output structures, so don't
> > try to run the code!
> > 
> > 			regards, tom lane
> 

-- 
Kevin O'Gorman  (805) 650-6274  mailto:kogorman@pacbell.net
Permanent e-mail forwarder:  mailto:Kevin.O'Gorman.64@Alum.Dartmouth.org
At school: mailto:kogorman@cs.ucsb.edu
Web: http://www.cs.ucsb.edu/~kogorman/index.html
Web: http://trixie.kosman.via.ayuda.com/~kevin/index.html

"There is a freedom lying beyond circumstance,
derived from the direct intuition that life can
be grounded upon its absorption in what is
changeless amid change" 
   -- Alfred North Whitehead

Sun, 29 Oct 2000 17:52:02 -0800
"Kevin O'Gorman" <kevin@trixie.kosman.via.ayuda.com>
Re: I believe it will (was Re: Hmm, will this do?)
At 17:52 29/10/00 -0800, Kevin O'Gorman wrote:
>
>I'm afraid that for now, we should accept the improvements that
>have been achieved, and consider a more general treatment of
>parentheses later.
>
>What do you think?
>

Just to clarify: what is the status of the improvements that are
implemented? Are you saying we have ORDER/LIMIT in subselect, but the only
thing not added is multiple levels of parentheses?


----------------------------------------------------------------
Philip Warner                    |     __---_____
Albatross Consulting Pty. Ltd.   |----/       -  \
(A.B.N. 75 008 659 498)          |          /(@)   ______---_
Tel: (+61) 0500 83 82 81         |                 _________  \
Fax: (+61) 0500 83 82 82         |                 ___________ |
Http://www.rhyme.com.au          |                /           \|
                                 |    --________--
PGP key available upon request,  |  /
and from pgp5.ai.mit.edu:11371   |/

Mon, 30 Oct 2000 14:40:09 +1100
Philip Warner <pjw@rhyme.com.au>
Re: Re: I believe it will (was Re: Hmm, will this
  do?)