From 3efd251ae3dac657b5576f111f70564ba3d7f289 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 25 Oct 2005 09:00:57 +0300 Subject: [PATCH] Fix for BUG#13832 - Unknown column t1.a in 'on clause'. The cause for the bug is that the priorities of all rules/terminals that process the FROM clause are not fully specified, and the parser generator produces a parser that doesn't always parse the FROM clause so that JOINs are left-associative. As a result the final join tree produced by the parser is incorrect, which is the cause for subsequent name resolution to fail. mysql-test/r/select.result: Test for BUG#13832. mysql-test/t/select.test: Test for BUG#13832. sql/sql_yacc.yy: Fix for BUG#13832 - Unknown column t1.a in 'on clause'. List all join-related operators as having lower priority than the join operands to make the parser process join- related productions from left to right. --- mysql-test/r/select.result | 12 ++++++++++++ mysql-test/t/select.test | 14 ++++++++++++++ sql/sql_yacc.yy | 32 +++++++++++++++++++++++--------- 3 files changed, 49 insertions(+), 9 deletions(-) diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result index abf607dd438..57788800f60 100644 --- a/mysql-test/r/select.result +++ b/mysql-test/r/select.result @@ -3124,3 +3124,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 6fc149e2e1f..3044aa466a2 100644 --- a/mysql-test/t/select.test +++ b/mysql-test/t/select.test @@ -2649,3 +2649,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 14f617b9f8b..f44120ae1a8 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 @@ -5225,14 +5225,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 @@ -5274,6 +5282,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 { @@ -5305,6 +5320,8 @@ join_table: $6->outer_join|=JOIN_TYPE_LEFT; $$=$6; } + +/* RIGHT JOIN variants */ | table_ref RIGHT opt_outer JOIN_SYM table_ref ON { @@ -5342,10 +5359,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 {}