diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result index fb61095cf22..cd7c70b603c 100644 --- a/mysql-test/r/select.result +++ b/mysql-test/r/select.result @@ -3181,3 +3181,15 @@ from t1 inner join (t2 right join t3 on t2.id = t3.b_id) on t1.id = t3.a_id; count(*) 6 drop table t1,t2,t3; +create table t1 (a int); +create table t2 (b int); +create table t3 (c int); +select * from t1 join t2 join t3 on (t1.a=t3.c); +a b c +select * from t1 join t2 left join t3 on (t1.a=t3.c); +a b c +select * from t1 join t2 right join t3 on (t1.a=t3.c); +a b c +select * from t1 join t2 straight_join t3 on (t1.a=t3.c); +a b c +drop table t1, t2 ,t3; diff --git a/mysql-test/t/select.test b/mysql-test/t/select.test index af51a705122..a3d83c531d2 100644 --- a/mysql-test/t/select.test +++ b/mysql-test/t/select.test @@ -2688,3 +2688,17 @@ select count(*) from t1 inner join (t2 right join t3 on t2.id = t3.b_id) on t1.id = t3.a_id; drop table t1,t2,t3; + +# +# Bug #13832 Incorrect parse order of join productions due to unspecified +# operator priorities results in incorrect join tree. +# + +create table t1 (a int); +create table t2 (b int); +create table t3 (c int); +select * from t1 join t2 join t3 on (t1.a=t3.c); +select * from t1 join t2 left join t3 on (t1.a=t3.c); +select * from t1 join t2 right join t3 on (t1.a=t3.c); +select * from t1 join t2 straight_join t3 on (t1.a=t3.c); +drop table t1, t2 ,t3; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 670385dee93..b9cfb4a62f1 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -660,7 +660,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token YEAR_SYM %token ZEROFILL -%left JOIN_SYM +%left JOIN_SYM INNER_SYM STRAIGHT_JOIN CROSS LEFT RIGHT /* A dummy token to force the priority of table_ref production in a join. */ %left TABLE_REF_PRIORITY %left SET_VAR @@ -5227,14 +5227,22 @@ derived_table_list: } ; +/* + Notice that JOIN is a left-associative operation, and it must be parsed + as such, that is, the parser must process first the left join operand + then the right one. Such order of processing ensures that the parser + produces correct join trees which is essential for semantic analysis + and subsequent optimization phases. +*/ join_table: +/* INNER JOIN variants */ /* - Evaluate production 'table_ref' before 'normal_join' so that - [INNER | CROSS] JOIN is properly nested as other left-associative - joins. + Use %prec to evaluate production 'table_ref' before 'normal_join' + so that [INNER | CROSS] JOIN is properly nested as other + left-associative joins. */ table_ref %prec TABLE_REF_PRIORITY normal_join table_ref - { YYERROR_UNLESS($1 && ($$=$3)); } + { YYERROR_UNLESS($1 && ($$=$3)); } | table_ref STRAIGHT_JOIN table_factor { YYERROR_UNLESS($1 && ($$=$3)); $3->straight=1; } | table_ref normal_join table_ref @@ -5276,6 +5284,13 @@ join_table: } '(' using_list ')' { add_join_natural($1,$3,$7); $$=$3; } + | table_ref NATURAL JOIN_SYM table_factor + { + YYERROR_UNLESS($1 && ($$=$4)); + add_join_natural($1,$4,NULL); + } + +/* LEFT JOIN variants */ | table_ref LEFT opt_outer JOIN_SYM table_ref ON { @@ -5307,6 +5322,8 @@ join_table: $6->outer_join|=JOIN_TYPE_LEFT; $$=$6; } + +/* RIGHT JOIN variants */ | table_ref RIGHT opt_outer JOIN_SYM table_ref ON { @@ -5344,10 +5361,7 @@ join_table: LEX *lex= Lex; if (!($$= lex->current_select->convert_right_join())) YYABORT; - } - | table_ref NATURAL JOIN_SYM table_factor - { YYERROR_UNLESS($1 && ($$=$4)); add_join_natural($1,$4,NULL); }; - + }; normal_join: JOIN_SYM {}