summaryrefslogtreecommitdiff
path: root/sql/sql_parse.cc
diff options
context:
space:
mode:
authorIgor Babaev <igor@askmonty.org>2019-08-15 17:27:49 -0700
committerIgor Babaev <igor@askmonty.org>2019-08-19 14:20:41 -0700
commite746f451d57def4be679caafc29976741b3e89f7 (patch)
tree4b56a580b76b9912777fbd0be56d0ebae9e0022f /sql/sql_parse.cc
parentec1f195ecf797fc5f37b0cfdbe4ee76d71a96729 (diff)
downloadmariadb-git-e746f451d57def4be679caafc29976741b3e89f7.tar.gz
MDEV-20265 Unknown column in field list
This patch corrects the fix of the patch for mdev-19421 that resolved the problem of parsing some embedded join expressions such as t1 join t2 left join t3 on t2.a=t3.a on t1.a=t2.a. Yet the patch contained a bug that prevented proper context analysis of the queries where such expressions were used together with comma separated table references in from clauses.
Diffstat (limited to 'sql/sql_parse.cc')
-rw-r--r--sql/sql_parse.cc103
1 files changed, 75 insertions, 28 deletions
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 346f8ad5e8b..ae5a6b4cd35 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -6435,10 +6435,6 @@ TABLE_LIST *st_select_lex::nest_last_join(THD *thd)
TABLE_LIST *head= join_list->head();
if (head->nested_join && head->nested_join->nest_type & REBALANCED_NEST)
{
- List_iterator<TABLE_LIST> li(*join_list);
- li++;
- while (li++)
- li.remove();
DBUG_RETURN(head);
}
@@ -6522,13 +6518,13 @@ void st_select_lex::add_joined_table(TABLE_LIST *table)
context and right-associative in another context.
In this query
- SELECT * FROM t1 JOIN t2 LEFT JOIN t3 ON t2.a=t3.a (Q1)
+ SELECT * FROM t1 JOIN t2 LEFT JOIN t3 ON t2.a=t3.a (Q1)
JOIN is left-associative and the query Q1 is interpreted as
- SELECT * FROM (t1 JOIN t2) LEFT JOIN t3 ON t2.a=t3.a.
+ SELECT * FROM (t1 JOIN t2) LEFT JOIN t3 ON t2.a=t3.a.
While in this query
- SELECT * FROM t1 JOIN t2 LEFT JOIN t3 ON t2.a=t3.a ON t1.b=t2.b (Q2)
+ SELECT * FROM t1 JOIN t2 LEFT JOIN t3 ON t2.a=t3.a ON t1.b=t2.b (Q2)
JOIN is right-associative and the query Q2 is interpreted as
- SELECT * FROM t1 JOIN (t2 LEFT JOIN t3 ON t2.a=t3.a) ON t1.b=t2.b
+ SELECT * FROM t1 JOIN (t2 LEFT JOIN t3 ON t2.a=t3.a) ON t1.b=t2.b
JOIN is right-associative if it is used with ON clause or with USING clause.
Otherwise it is left-associative.
@@ -6574,9 +6570,9 @@ void st_select_lex::add_joined_table(TABLE_LIST *table)
J LJ - ON
/ \ / \
- t1 LJ - ON (TQ3*) => J t2
- / \ / \
- t3 t2 t1 t3
+ t1 LJ - ON (TQ3*) => t3 J
+ / \ / \
+ t3 t2 t1 t2
With several left associative JOINs
SELECT * FROM t1 JOIN t2 JOIN t3 LEFT JOIN t4 ON t3.a=t4.a (Q4)
@@ -6584,15 +6580,15 @@ void st_select_lex::add_joined_table(TABLE_LIST *table)
J1 LJ - ON
/ \ / \
- t1 LJ - ON J2 t4
+ t1 J2 J2 t4
/ \ => / \
- J2 t4 J1 t3
- / \ / \
- t2 t3 t1 t2
+ t2 LJ - ON J1 t3
+ / \ / \
+ t3 t4 t1 t2
- Here's another example:
- SELECT *
- FROM t1 JOIN t2 LEFT JOIN t3 JOIN t4 ON t3.a=t4.a ON t2.b=t3.b (Q5)
+ Here's another example:
+ SELECT *
+ FROM t1 JOIN t2 LEFT JOIN t3 JOIN t4 ON t3.a=t4.a ON t2.b=t3.b (Q5)
J LJ - ON
/ \ / \
@@ -6602,15 +6598,58 @@ void st_select_lex::add_joined_table(TABLE_LIST *table)
/ \
t3 t4
- If the transformed nested join node node is a natural join node like in
- the following query
- SELECT * FROM t1 JOIN t2 LEFT JOIN t3 USING(a) (Q6)
- the transformation additionally has to take care about setting proper
- references in the field natural_join for both operands of the natural
- join operation.
- The function also has to change the name resolution context for ON
- expressions used in the transformed join expression to take into
- account the tables of the left_op node.
+ If the transformed nested join node node is a natural join node like in
+ the following query
+ SELECT * FROM t1 JOIN t2 LEFT JOIN t3 USING(a) (Q6)
+ the transformation additionally has to take care about setting proper
+ references in the field natural_join for both operands of the natural
+ join operation.
+
+ The queries that combine comma syntax for join operation with
+ JOIN expression require a special care. Consider the query
+ SELECT * FROM t1, t2 JOIN t3 LEFT JOIN t4 ON t3.a=t4.a (Q7)
+ This query is equivalent to the query
+ SELECT * FROM (t1, t2) JOIN t3 LEFT JOIN t4 ON t3.a=t4.a
+ The latter is transformed in the same way as query Q1
+
+ J LJ - ON
+ / \ / \
+ (t1,t2) LJ - ON => J t4
+ / \ / \
+ t3 t4 (t1,t2) t3
+
+ A transformation similar to the transformation for Q3 is done for
+ the following query with RIGHT JOIN
+ SELECT * FROM t1, t2 JOIN t3 RIGHT JOIN t4 ON t3.a=t4.a (Q8)
+
+ J LJ - ON
+ / \ / \
+ t3 LJ - ON => t4 J
+ / \ / \
+ t4 (t1,t2) (t1,t2) t3
+
+ The function also has to change the name resolution context for ON
+ expressions used in the transformed join expression to take into
+ account the tables of the left_op node.
+
+ TODO:
+ A more elegant solution would be to implement the transformation that
+ eliminates nests for cross join operations. For Q7 it would work like this:
+
+ J LJ - ON
+ / \ / \
+ (t1,t2) LJ - ON => (t1,t2,t3) t4
+ / \
+ t3 t4
+
+ For Q8 with RIGHT JOIN the transformation would work similarly:
+
+ J LJ - ON
+ / \ / \
+ t3 LJ - ON => t4 (t1,t2,t3)
+ / \
+ t4 (t1,t2)
+
*/
bool st_select_lex::add_cross_joined_table(TABLE_LIST *left_op,
@@ -6633,7 +6672,11 @@ bool st_select_lex::add_cross_joined_table(TABLE_LIST *left_op,
}
TABLE_LIST *tbl;
- List<TABLE_LIST> *jl= &right_op->nested_join->join_list;
+ List<TABLE_LIST> *right_op_jl= right_op->join_list;
+ TABLE_LIST *r_tbl= right_op_jl->pop();
+ DBUG_ASSERT(right_op == r_tbl);
+ TABLE_LIST *l_tbl= right_op_jl->pop();
+ DBUG_ASSERT(left_op == l_tbl);
TABLE_LIST *cj_nest;
/*
@@ -6650,6 +6693,8 @@ bool st_select_lex::add_cross_joined_table(TABLE_LIST *left_op,
List<TABLE_LIST> *cjl= &cj_nest->nested_join->join_list;
cjl->empty();
+ List<TABLE_LIST> *jl= &right_op->nested_join->join_list;
+ DBUG_ASSERT(jl->elements == 2);
/* Look for the left most node tbl of the right_op tree */
for ( ; ; )
{
@@ -6721,6 +6766,8 @@ bool st_select_lex::add_cross_joined_table(TABLE_LIST *left_op,
create a new top level nested join node.
*/
right_op->nested_join->nest_type|= REBALANCED_NEST;
+ if (unlikely(right_op_jl->push_front(right_op)))
+ DBUG_RETURN(true);
DBUG_RETURN(false);
}