summaryrefslogtreecommitdiff
path: root/sql/sql_yacc.yy
diff options
context:
space:
mode:
authorIgor Babaev <igor@askmonty.org>2019-06-30 13:16:12 -0700
committerIgor Babaev <igor@askmonty.org>2019-07-11 13:39:21 -0700
commit8540fa83bb34df6a3d489a4e85c77692f36e3e26 (patch)
tree7a56a3d6652d25e7af8a3dafc15cbc7aaee09fab /sql/sql_yacc.yy
parent8997f20f12309d2660988f254415a343d6328835 (diff)
downloadmariadb-git-8540fa83bb34df6a3d489a4e85c77692f36e3e26.tar.gz
MDEV-19421 Basic 3-way join queries are not parsed.
The parser returned a syntax error message for the queries with join expressions like this t1 JOIN t2 [LEFT | RIGHT] JOIN t3 ON ... ON ... when the second operand of the outer JOIN operation with ON clause was another join expression with ON clause. In this expression the JOIN operator is right-associative, i.e. expression has to be parsed as the expression t1 JOIN (t2 [LEFT | RIGHT] JOIN t3 ON ... ) ON ... Such join expressions are hard to parse because the outer JOIN is left-associative if there is no ON clause for the first outer JOIN operator. The patch implements the solution when the JOIN operator is always parsed as right-associative and builds first the right-associative tree. If it happens that there is no corresponding ON clause for this operator the tree is converted to left-associative. The idea of the solution was taken from the patch by Martin Hansson "WL#8083: Fixed the join_table rule" from MySQL-8.0 code line. As the grammar rules related to join expressions in MySQL-8.0 and MariaDB-5.5+ are quite different MariaDB solution could not borrow any code from the MySQL-8.0 solution.
Diffstat (limited to 'sql/sql_yacc.yy')
-rw-r--r--sql/sql_yacc.yy49
1 files changed, 25 insertions, 24 deletions
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 93ac55592bf..a0e9497f217 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -1428,9 +1428,9 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token IMPOSSIBLE_ACTION /* To avoid warning for yyerrlab1 */
-%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 CONDITIONLESS_JOIN
+%left JOIN_SYM INNER_SYM STRAIGHT_JOIN CROSS LEFT RIGHT ON_SYM USING
%left SET_VAR
%left OR_OR_SYM OR_SYM OR2_SYM
%left XOR
@@ -9607,9 +9607,9 @@ join_table_list:
and are ignored.
*/
esc_table_ref:
- table_ref { $$=$1; }
- | '{' ident table_ref '}' { $$=$3; }
- ;
+ table_ref { $$=$1; }
+ | '{' ident table_ref '}' { $$=$3; }
+ ;
/* Equivalent to <table reference list> in the SQL:2003 standard. */
/* Warning - may return NULL in case of incomplete SELECT */
@@ -9622,23 +9622,24 @@ 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.
+ Notice that JOIN can be a left-associative operator in one context and
+ a right-associative operator in another context (see the comment for
+ st_select_lex::add_cross_joined_table).
*/
join_table:
/* INNER JOIN variants */
- /*
- 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 normal_join table_ref %prec TABLE_REF_PRIORITY
- { MYSQL_YYABORT_UNLESS($1 && ($$=$3)); }
- | table_ref STRAIGHT_JOIN table_factor
- { MYSQL_YYABORT_UNLESS($1 && ($$=$3)); $3->straight=1; }
+ table_ref normal_join table_ref %prec CONDITIONLESS_JOIN
+ {
+ MYSQL_YYABORT_UNLESS($1 && ($$=$3));
+ if (unlikely(Select->add_cross_joined_table($1, $3, false)))
+ MYSQL_YYABORT;
+ }
+ | table_ref STRAIGHT_JOIN table_ref %prec CONDITIONLESS_JOIN
+ {
+ MYSQL_YYABORT_UNLESS($1 && ($$=$3));
+ if (unlikely(Select->add_cross_joined_table($1, $3, true)))
+ MYSQL_YYABORT;
+ }
| table_ref normal_join table_ref
ON
{
@@ -9651,10 +9652,10 @@ join_table:
expr
{
add_join_on($3,$6);
- Lex->pop_context();
+ $3->on_context= Lex->pop_context();
Select->parsing_place= NO_MATTER;
}
- | table_ref STRAIGHT_JOIN table_factor
+ | table_ref STRAIGHT_JOIN table_ref
ON
{
MYSQL_YYABORT_UNLESS($1 && $3);
@@ -9667,7 +9668,7 @@ join_table:
{
$3->straight=1;
add_join_on($3,$6);
- Lex->pop_context();
+ $3->on_context= Lex->pop_context();
Select->parsing_place= NO_MATTER;
}
| table_ref normal_join table_ref
@@ -9696,7 +9697,7 @@ join_table:
expr
{
add_join_on($5,$8);
- Lex->pop_context();
+ $5->on_context= Lex->pop_context();
$5->outer_join|=JOIN_TYPE_LEFT;
$$=$5;
Select->parsing_place= NO_MATTER;
@@ -9735,7 +9736,7 @@ join_table:
if (!($$= lex->current_select->convert_right_join()))
MYSQL_YYABORT;
add_join_on($$, $8);
- Lex->pop_context();
+ $1->on_context= Lex->pop_context();
Select->parsing_place= NO_MATTER;
}
| table_ref RIGHT opt_outer JOIN_SYM table_factor