Loading mysql-test/r/join_nested.result +28 −0 Original line number Diff line number Diff line Loading @@ -1605,3 +1605,31 @@ WHERE t1.id='5'; id ct pc nm 5 NULL NULL NULL DROP TABLE t1,t2,t3,t4; CREATE TABLE t1 (a INT, b INT); CREATE TABLE t2 (a INT); CREATE TABLE t3 (a INT, c INT); CREATE TABLE t4 (a INT, c INT); CREATE TABLE t5 (a INT, c INT); SELECT b FROM t1 JOIN (t2 LEFT JOIN t3 USING (a) LEFT JOIN t4 USING (a) LEFT JOIN t5 USING (a)) USING (a); b SELECT c FROM t1 JOIN (t2 LEFT JOIN t3 USING (a) LEFT JOIN t4 USING (a) LEFT JOIN t5 USING (a)) USING (a); ERROR 23000: Column 'c' in field list is ambiguous SELECT b FROM t1 JOIN (t2 JOIN t3 USING (a) JOIN t4 USING (a) JOIN t5 USING (a)) USING (a); b SELECT c FROM t1 JOIN (t2 JOIN t3 USING (a) JOIN t4 USING (a) JOIN t5 USING (a)) USING (a); ERROR 23000: Column 'c' in field list is ambiguous DROP TABLE t1,t2,t3,t4,t5; CREATE TABLE t1 (a INT, b INT); CREATE TABLE t2 (a INT, b INT); CREATE TABLE t3 (a INT, b INT); INSERT INTO t1 VALUES (1,1); INSERT INTO t2 VALUES (1,1); INSERT INTO t3 VALUES (1,1); SELECT * FROM t1 JOIN (t2 JOIN t3 USING (b)) USING (a); ERROR 23000: Column 'a' in from clause is ambiguous DROP TABLE t1,t2,t3; End of 5.0 tests mysql-test/t/join_nested.test +39 −0 Original line number Diff line number Diff line Loading @@ -1045,3 +1045,42 @@ SELECT t1.*, t4.nm WHERE t1.id='5'; DROP TABLE t1,t2,t3,t4; # # BUG#25575: ERROR 1052 (Column in from clause is ambiguous) with sub-join # CREATE TABLE t1 (a INT, b INT); CREATE TABLE t2 (a INT); CREATE TABLE t3 (a INT, c INT); CREATE TABLE t4 (a INT, c INT); CREATE TABLE t5 (a INT, c INT); SELECT b FROM t1 JOIN (t2 LEFT JOIN t3 USING (a) LEFT JOIN t4 USING (a) LEFT JOIN t5 USING (a)) USING (a); --error ER_NON_UNIQ_ERROR SELECT c FROM t1 JOIN (t2 LEFT JOIN t3 USING (a) LEFT JOIN t4 USING (a) LEFT JOIN t5 USING (a)) USING (a); SELECT b FROM t1 JOIN (t2 JOIN t3 USING (a) JOIN t4 USING (a) JOIN t5 USING (a)) USING (a); --error ER_NON_UNIQ_ERROR SELECT c FROM t1 JOIN (t2 JOIN t3 USING (a) JOIN t4 USING (a) JOIN t5 USING (a)) USING (a); DROP TABLE t1,t2,t3,t4,t5; CREATE TABLE t1 (a INT, b INT); CREATE TABLE t2 (a INT, b INT); CREATE TABLE t3 (a INT, b INT); INSERT INTO t1 VALUES (1,1); INSERT INTO t2 VALUES (1,1); INSERT INTO t3 VALUES (1,1); --error ER_NON_UNIQ_ERROR SELECT * FROM t1 JOIN (t2 JOIN t3 USING (b)) USING (a); DROP TABLE t1,t2,t3; --echo End of 5.0 tests sql/mysql_priv.h +2 −1 Original line number Diff line number Diff line Loading @@ -985,7 +985,8 @@ bool push_new_name_resolution_context(THD *thd, TABLE_LIST *left_op, TABLE_LIST *right_op); void add_join_on(TABLE_LIST *b,Item *expr); void add_join_natural(TABLE_LIST *a,TABLE_LIST *b,List<String> *using_fields); void add_join_natural(TABLE_LIST *a,TABLE_LIST *b,List<String> *using_fields, SELECT_LEX *lex); bool add_proc_to_list(THD *thd, Item *item); TABLE *unlink_open_table(THD *thd,TABLE *list,TABLE *find); void update_non_unique_table_error(TABLE_LIST *update, Loading sql/sql_base.cc +40 −11 Original line number Diff line number Diff line Loading @@ -2945,7 +2945,7 @@ find_field_in_natural_join(THD *thd, TABLE_LIST *table_ref, const char *name, { List_iterator_fast<Natural_join_column> field_it(*(table_ref->join_columns)); Natural_join_column *nj_col; Natural_join_column *nj_col, *curr_nj_col; Field *found_field; Query_arena *arena, backup; DBUG_ENTER("find_field_in_natural_join"); Loading @@ -2956,14 +2956,21 @@ find_field_in_natural_join(THD *thd, TABLE_LIST *table_ref, const char *name, LINT_INIT(found_field); for (;;) for (nj_col= NULL, curr_nj_col= field_it++; curr_nj_col; curr_nj_col= field_it++) { if (!my_strcasecmp(system_charset_info, curr_nj_col->name(), name)) { if (!(nj_col= field_it++)) if (nj_col) { my_error(ER_NON_UNIQ_ERROR, MYF(0), name, thd->where); DBUG_RETURN(NULL); if (!my_strcasecmp(system_charset_info, nj_col->name(), name)) break; } nj_col= curr_nj_col; } } if (!nj_col) DBUG_RETURN(NULL); if (nj_col->view_field) { Loading Loading @@ -3774,9 +3781,16 @@ mark_common_columns(THD *thd, TABLE_LIST *table_ref_1, TABLE_LIST *table_ref_2, { bool found= FALSE; const char *field_name_1; /* true if field_name_1 is a member of using_fields */ bool is_using_column_1; if (!(nj_col_1= it_1.get_or_create_column_ref(leaf_1))) goto err; field_name_1= nj_col_1->name(); is_using_column_1= using_fields && test_if_string_in_list(field_name_1, using_fields); DBUG_PRINT ("info", ("field_name_1=%s.%s", nj_col_1->table_name() ? nj_col_1->table_name() : "", field_name_1)); /* Find a field with the same name in table_ref_2. Loading @@ -3793,6 +3807,10 @@ mark_common_columns(THD *thd, TABLE_LIST *table_ref_1, TABLE_LIST *table_ref_2, if (!(cur_nj_col_2= it_2.get_or_create_column_ref(leaf_2))) goto err; cur_field_name_2= cur_nj_col_2->name(); DBUG_PRINT ("info", ("cur_field_name_2=%s.%s", cur_nj_col_2->table_name() ? cur_nj_col_2->table_name() : "", cur_field_name_2)); /* Compare the two columns and check for duplicate common fields. Loading @@ -3800,10 +3818,16 @@ mark_common_columns(THD *thd, TABLE_LIST *table_ref_1, TABLE_LIST *table_ref_2, table_ref_2 (then found == TRUE), or if a field in table_ref_2 was already matched by some previous field in table_ref_1 (then cur_nj_col_2->is_common == TRUE). Note that it is too early to check the columns outside of the USING list for ambiguity because they are not actually "referenced" here. These columns must be checked only on unqualified reference by name (e.g. in SELECT list). */ if (!my_strcasecmp(system_charset_info, field_name_1, cur_field_name_2)) { if (found || cur_nj_col_2->is_common) DBUG_PRINT ("info", ("match c1.is_common=%d", nj_col_1->is_common)); if (cur_nj_col_2->is_common || (found && (!using_fields || is_using_column_1))) { my_error(ER_NON_UNIQ_ERROR, MYF(0), field_name_1, thd->where); goto err; Loading @@ -3829,9 +3853,7 @@ mark_common_columns(THD *thd, TABLE_LIST *table_ref_1, TABLE_LIST *table_ref_2, clause (if present), mark them as common fields, and add a new equi-join condition to the ON clause. */ if (nj_col_2 && (!using_fields || test_if_string_in_list(field_name_1, using_fields))) if (nj_col_2 && (!using_fields ||is_using_column_1)) { Item *item_1= nj_col_1->create_item(thd); Item *item_2= nj_col_2->create_item(thd); Loading Loading @@ -3886,6 +3908,13 @@ mark_common_columns(THD *thd, TABLE_LIST *table_ref_1, TABLE_LIST *table_ref_2, eq_cond); nj_col_1->is_common= nj_col_2->is_common= TRUE; DBUG_PRINT ("info", ("%s.%s and %s.%s are common", nj_col_1->table_name() ? nj_col_1->table_name() : "", nj_col_1->name(), nj_col_2->table_name() ? nj_col_2->table_name() : "", nj_col_2->name())); if (field_1) { Loading sql/sql_lex.h +14 −0 Original line number Diff line number Diff line Loading @@ -586,6 +586,20 @@ class st_select_lex: public st_select_lex_node int cur_pos_in_select_list; List<udf_func> udf_list; /* udf function calls stack */ /* This is a copy of the original JOIN USING list that comes from the parser. The parser : 1. Sets the natural_join of the second TABLE_LIST in the join and the st_select_lex::prev_join_using. 2. Makes a parent TABLE_LIST and sets its is_natural_join/ join_using_fields members. 3. Uses the wrapper TABLE_LIST as a table in the upper level. We cannot assign directly to join_using_fields in the parser because at stage (1.) the parent TABLE_LIST is not constructed yet and the assignment will override the JOIN USING fields of the lower level joins on the right. */ List<String> *prev_join_using; void init_query(); void init_select(); Loading Loading
mysql-test/r/join_nested.result +28 −0 Original line number Diff line number Diff line Loading @@ -1605,3 +1605,31 @@ WHERE t1.id='5'; id ct pc nm 5 NULL NULL NULL DROP TABLE t1,t2,t3,t4; CREATE TABLE t1 (a INT, b INT); CREATE TABLE t2 (a INT); CREATE TABLE t3 (a INT, c INT); CREATE TABLE t4 (a INT, c INT); CREATE TABLE t5 (a INT, c INT); SELECT b FROM t1 JOIN (t2 LEFT JOIN t3 USING (a) LEFT JOIN t4 USING (a) LEFT JOIN t5 USING (a)) USING (a); b SELECT c FROM t1 JOIN (t2 LEFT JOIN t3 USING (a) LEFT JOIN t4 USING (a) LEFT JOIN t5 USING (a)) USING (a); ERROR 23000: Column 'c' in field list is ambiguous SELECT b FROM t1 JOIN (t2 JOIN t3 USING (a) JOIN t4 USING (a) JOIN t5 USING (a)) USING (a); b SELECT c FROM t1 JOIN (t2 JOIN t3 USING (a) JOIN t4 USING (a) JOIN t5 USING (a)) USING (a); ERROR 23000: Column 'c' in field list is ambiguous DROP TABLE t1,t2,t3,t4,t5; CREATE TABLE t1 (a INT, b INT); CREATE TABLE t2 (a INT, b INT); CREATE TABLE t3 (a INT, b INT); INSERT INTO t1 VALUES (1,1); INSERT INTO t2 VALUES (1,1); INSERT INTO t3 VALUES (1,1); SELECT * FROM t1 JOIN (t2 JOIN t3 USING (b)) USING (a); ERROR 23000: Column 'a' in from clause is ambiguous DROP TABLE t1,t2,t3; End of 5.0 tests
mysql-test/t/join_nested.test +39 −0 Original line number Diff line number Diff line Loading @@ -1045,3 +1045,42 @@ SELECT t1.*, t4.nm WHERE t1.id='5'; DROP TABLE t1,t2,t3,t4; # # BUG#25575: ERROR 1052 (Column in from clause is ambiguous) with sub-join # CREATE TABLE t1 (a INT, b INT); CREATE TABLE t2 (a INT); CREATE TABLE t3 (a INT, c INT); CREATE TABLE t4 (a INT, c INT); CREATE TABLE t5 (a INT, c INT); SELECT b FROM t1 JOIN (t2 LEFT JOIN t3 USING (a) LEFT JOIN t4 USING (a) LEFT JOIN t5 USING (a)) USING (a); --error ER_NON_UNIQ_ERROR SELECT c FROM t1 JOIN (t2 LEFT JOIN t3 USING (a) LEFT JOIN t4 USING (a) LEFT JOIN t5 USING (a)) USING (a); SELECT b FROM t1 JOIN (t2 JOIN t3 USING (a) JOIN t4 USING (a) JOIN t5 USING (a)) USING (a); --error ER_NON_UNIQ_ERROR SELECT c FROM t1 JOIN (t2 JOIN t3 USING (a) JOIN t4 USING (a) JOIN t5 USING (a)) USING (a); DROP TABLE t1,t2,t3,t4,t5; CREATE TABLE t1 (a INT, b INT); CREATE TABLE t2 (a INT, b INT); CREATE TABLE t3 (a INT, b INT); INSERT INTO t1 VALUES (1,1); INSERT INTO t2 VALUES (1,1); INSERT INTO t3 VALUES (1,1); --error ER_NON_UNIQ_ERROR SELECT * FROM t1 JOIN (t2 JOIN t3 USING (b)) USING (a); DROP TABLE t1,t2,t3; --echo End of 5.0 tests
sql/mysql_priv.h +2 −1 Original line number Diff line number Diff line Loading @@ -985,7 +985,8 @@ bool push_new_name_resolution_context(THD *thd, TABLE_LIST *left_op, TABLE_LIST *right_op); void add_join_on(TABLE_LIST *b,Item *expr); void add_join_natural(TABLE_LIST *a,TABLE_LIST *b,List<String> *using_fields); void add_join_natural(TABLE_LIST *a,TABLE_LIST *b,List<String> *using_fields, SELECT_LEX *lex); bool add_proc_to_list(THD *thd, Item *item); TABLE *unlink_open_table(THD *thd,TABLE *list,TABLE *find); void update_non_unique_table_error(TABLE_LIST *update, Loading
sql/sql_base.cc +40 −11 Original line number Diff line number Diff line Loading @@ -2945,7 +2945,7 @@ find_field_in_natural_join(THD *thd, TABLE_LIST *table_ref, const char *name, { List_iterator_fast<Natural_join_column> field_it(*(table_ref->join_columns)); Natural_join_column *nj_col; Natural_join_column *nj_col, *curr_nj_col; Field *found_field; Query_arena *arena, backup; DBUG_ENTER("find_field_in_natural_join"); Loading @@ -2956,14 +2956,21 @@ find_field_in_natural_join(THD *thd, TABLE_LIST *table_ref, const char *name, LINT_INIT(found_field); for (;;) for (nj_col= NULL, curr_nj_col= field_it++; curr_nj_col; curr_nj_col= field_it++) { if (!my_strcasecmp(system_charset_info, curr_nj_col->name(), name)) { if (!(nj_col= field_it++)) if (nj_col) { my_error(ER_NON_UNIQ_ERROR, MYF(0), name, thd->where); DBUG_RETURN(NULL); if (!my_strcasecmp(system_charset_info, nj_col->name(), name)) break; } nj_col= curr_nj_col; } } if (!nj_col) DBUG_RETURN(NULL); if (nj_col->view_field) { Loading Loading @@ -3774,9 +3781,16 @@ mark_common_columns(THD *thd, TABLE_LIST *table_ref_1, TABLE_LIST *table_ref_2, { bool found= FALSE; const char *field_name_1; /* true if field_name_1 is a member of using_fields */ bool is_using_column_1; if (!(nj_col_1= it_1.get_or_create_column_ref(leaf_1))) goto err; field_name_1= nj_col_1->name(); is_using_column_1= using_fields && test_if_string_in_list(field_name_1, using_fields); DBUG_PRINT ("info", ("field_name_1=%s.%s", nj_col_1->table_name() ? nj_col_1->table_name() : "", field_name_1)); /* Find a field with the same name in table_ref_2. Loading @@ -3793,6 +3807,10 @@ mark_common_columns(THD *thd, TABLE_LIST *table_ref_1, TABLE_LIST *table_ref_2, if (!(cur_nj_col_2= it_2.get_or_create_column_ref(leaf_2))) goto err; cur_field_name_2= cur_nj_col_2->name(); DBUG_PRINT ("info", ("cur_field_name_2=%s.%s", cur_nj_col_2->table_name() ? cur_nj_col_2->table_name() : "", cur_field_name_2)); /* Compare the two columns and check for duplicate common fields. Loading @@ -3800,10 +3818,16 @@ mark_common_columns(THD *thd, TABLE_LIST *table_ref_1, TABLE_LIST *table_ref_2, table_ref_2 (then found == TRUE), or if a field in table_ref_2 was already matched by some previous field in table_ref_1 (then cur_nj_col_2->is_common == TRUE). Note that it is too early to check the columns outside of the USING list for ambiguity because they are not actually "referenced" here. These columns must be checked only on unqualified reference by name (e.g. in SELECT list). */ if (!my_strcasecmp(system_charset_info, field_name_1, cur_field_name_2)) { if (found || cur_nj_col_2->is_common) DBUG_PRINT ("info", ("match c1.is_common=%d", nj_col_1->is_common)); if (cur_nj_col_2->is_common || (found && (!using_fields || is_using_column_1))) { my_error(ER_NON_UNIQ_ERROR, MYF(0), field_name_1, thd->where); goto err; Loading @@ -3829,9 +3853,7 @@ mark_common_columns(THD *thd, TABLE_LIST *table_ref_1, TABLE_LIST *table_ref_2, clause (if present), mark them as common fields, and add a new equi-join condition to the ON clause. */ if (nj_col_2 && (!using_fields || test_if_string_in_list(field_name_1, using_fields))) if (nj_col_2 && (!using_fields ||is_using_column_1)) { Item *item_1= nj_col_1->create_item(thd); Item *item_2= nj_col_2->create_item(thd); Loading Loading @@ -3886,6 +3908,13 @@ mark_common_columns(THD *thd, TABLE_LIST *table_ref_1, TABLE_LIST *table_ref_2, eq_cond); nj_col_1->is_common= nj_col_2->is_common= TRUE; DBUG_PRINT ("info", ("%s.%s and %s.%s are common", nj_col_1->table_name() ? nj_col_1->table_name() : "", nj_col_1->name(), nj_col_2->table_name() ? nj_col_2->table_name() : "", nj_col_2->name())); if (field_1) { Loading
sql/sql_lex.h +14 −0 Original line number Diff line number Diff line Loading @@ -586,6 +586,20 @@ class st_select_lex: public st_select_lex_node int cur_pos_in_select_list; List<udf_func> udf_list; /* udf function calls stack */ /* This is a copy of the original JOIN USING list that comes from the parser. The parser : 1. Sets the natural_join of the second TABLE_LIST in the join and the st_select_lex::prev_join_using. 2. Makes a parent TABLE_LIST and sets its is_natural_join/ join_using_fields members. 3. Uses the wrapper TABLE_LIST as a table in the upper level. We cannot assign directly to join_using_fields in the parser because at stage (1.) the parent TABLE_LIST is not constructed yet and the assignment will override the JOIN USING fields of the lower level joins on the right. */ List<String> *prev_join_using; void init_query(); void init_select(); Loading