mirror of
https://git.postgresql.org/git/postgresql.git
synced 2025-01-06 15:24:56 +08:00
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 o'gorman
This commit is contained in:
parent
3eb9b73718
commit
2f4c9d39fe
@ -11,7 +11,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.198 2000/10/25 18:56:16 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.199 2000/10/28 15:44:04 momjian Exp $
|
||||
*
|
||||
* HISTORY
|
||||
* AUTHOR DATE MAJOR EVENT
|
||||
@ -127,14 +127,15 @@ static void doNegateFloat(Value *v);
|
||||
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,
|
||||
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
|
||||
@ -177,19 +178,20 @@ static void doNegateFloat(Value *v);
|
||||
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
|
||||
@ -2660,7 +2662,7 @@ opt_column: COLUMN { $$ = COLUMN; }
|
||||
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;
|
||||
@ -2673,17 +2675,42 @@ RuleStmt: CREATE RULE name AS
|
||||
}
|
||||
;
|
||||
|
||||
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;
|
||||
}
|
||||
@ -2695,6 +2722,31 @@ RuleActionMulti: RuleActionMulti ';' RuleActionStmtOrEmpty
|
||||
}
|
||||
;
|
||||
|
||||
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
|
||||
@ -3248,7 +3300,12 @@ opt_cursor: BINARY { $$ = TRUE; }
|
||||
* 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);
|
||||
|
||||
@ -3258,34 +3315,35 @@ SelectStmt: select_clause sort_clause for_update_clause opt_select_limit
|
||||
n->limitCount = nth(1, $4);
|
||||
$$ = $1;
|
||||
}
|
||||
;
|
||||
| select_head for_update_clause opt_select_limit
|
||||
{
|
||||
SelectStmt *n = findLeftmostSelect($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 ')'
|
||||
{
|
||||
$$ = $2;
|
||||
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
|
||||
{
|
||||
@ -3300,7 +3358,13 @@ select_subclause: SELECT opt_distinct target_list
|
||||
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;
|
||||
@ -3309,7 +3373,7 @@ select_subclause: SELECT opt_distinct target_list
|
||||
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;
|
||||
@ -3318,7 +3382,7 @@ select_subclause: SELECT opt_distinct target_list
|
||||
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;
|
||||
@ -3383,7 +3447,6 @@ opt_distinct: DISTINCT { $$ = makeList1(NIL); }
|
||||
;
|
||||
|
||||
sort_clause: ORDER BY sortby_list { $$ = $3; }
|
||||
| /*EMPTY*/ { $$ = NIL; }
|
||||
;
|
||||
|
||||
sortby_list: sortby { $$ = makeList1($1); }
|
||||
@ -3405,7 +3468,7 @@ OptUseOp: USING all_Op { $$ = $2; }
|
||||
;
|
||||
|
||||
|
||||
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); }
|
||||
@ -3415,6 +3478,9 @@ opt_select_limit: LIMIT select_limit_value ',' select_offset_value
|
||||
{ $$ = makeList2($2, $4); }
|
||||
| OFFSET select_offset_value
|
||||
{ $$ = makeList2($2, NULL); }
|
||||
;
|
||||
|
||||
opt_select_limit: select_limit { $$ = $1; }
|
||||
| /* EMPTY */
|
||||
{ $$ = makeList2(NULL, NULL); }
|
||||
;
|
||||
@ -3514,6 +3580,9 @@ having_clause: HAVING a_expr
|
||||
|
||||
for_update_clause: FOR UPDATE update_list { $$ = $3; }
|
||||
| FOR READ ONLY { $$ = NULL; }
|
||||
;
|
||||
|
||||
opt_for_update_clause: for_update_clause { $$ = $1; }
|
||||
| /* EMPTY */ { $$ = NULL; }
|
||||
;
|
||||
|
||||
@ -3557,7 +3626,7 @@ table_ref: relation_expr
|
||||
$1->name = $2;
|
||||
$$ = (Node *) $1;
|
||||
}
|
||||
| '(' select_subclause ')' alias_clause
|
||||
| '(' SelectStmt ')' alias_clause
|
||||
{
|
||||
RangeSubselect *n = makeNode(RangeSubselect);
|
||||
n->subquery = $2;
|
||||
@ -4093,7 +4162,7 @@ opt_interval: datetime { $$ = makeList1($1); }
|
||||
* 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;
|
||||
@ -4103,7 +4172,7 @@ row_expr: '(' row_descriptor ')' IN '(' select_subclause ')'
|
||||
n->subselect = $6;
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
| '(' row_descriptor ')' NOT IN '(' select_subclause ')'
|
||||
| '(' row_descriptor ')' NOT IN '(' SelectStmt ')'
|
||||
{
|
||||
SubLink *n = makeNode(SubLink);
|
||||
n->lefthand = $2;
|
||||
@ -4113,7 +4182,7 @@ row_expr: '(' row_descriptor ')' IN '(' select_subclause ')'
|
||||
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;
|
||||
@ -4126,7 +4195,7 @@ row_expr: '(' row_descriptor ')' IN '(' select_subclause ')'
|
||||
n->subselect = $7;
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
| '(' row_descriptor ')' all_Op '(' select_subclause ')'
|
||||
| '(' row_descriptor ')' all_Op '(' SelectStmt ')'
|
||||
{
|
||||
SubLink *n = makeNode(SubLink);
|
||||
n->lefthand = $2;
|
||||
@ -4457,7 +4526,7 @@ a_expr: c_expr
|
||||
$$ = n;
|
||||
}
|
||||
}
|
||||
| a_expr all_Op sub_type '(' select_subclause ')'
|
||||
| a_expr all_Op sub_type '(' SelectStmt ')'
|
||||
{
|
||||
SubLink *n = makeNode(SubLink);
|
||||
n->lefthand = makeList1($1);
|
||||
@ -4853,7 +4922,7 @@ c_expr: attr
|
||||
n->agg_distinct = FALSE;
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
| '(' select_subclause ')'
|
||||
| '(' SelectStmt ')'
|
||||
{
|
||||
SubLink *n = makeNode(SubLink);
|
||||
n->lefthand = NIL;
|
||||
@ -4863,7 +4932,7 @@ c_expr: attr
|
||||
n->subselect = $2;
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
| EXISTS '(' select_subclause ')'
|
||||
| EXISTS '(' SelectStmt ')'
|
||||
{
|
||||
SubLink *n = makeNode(SubLink);
|
||||
n->lefthand = NIL;
|
||||
@ -4962,7 +5031,7 @@ trim_list: a_expr FROM expr_list
|
||||
{ $$ = $1; }
|
||||
;
|
||||
|
||||
in_expr: select_subclause
|
||||
in_expr: SelectStmt
|
||||
{
|
||||
SubLink *n = makeNode(SubLink);
|
||||
n->subselect = $1;
|
||||
|
Loading…
Reference in New Issue
Block a user