diff options
author | Tor Didriksen <tor.didriksen@oracle.com> | 2011-05-04 17:12:45 +0200 |
---|---|---|
committer | Tor Didriksen <tor.didriksen@oracle.com> | 2011-05-04 17:12:45 +0200 |
commit | 9baf84e99a6d7edd36c777593a90671d02aacbc9 (patch) | |
tree | 4b2a82480afbf07a0e4ba4447dbf4f3a51761bbe | |
parent | c00c350f147173bf20c35c8787cdf0d840653e96 (diff) | |
parent | a32df762d43c29545718e8a78a1721a9a7a1a35f (diff) | |
download | mariadb-git-9baf84e99a6d7edd36c777593a90671d02aacbc9.tar.gz |
merge 5.0 => 5.1 : Bug#12329653
-rw-r--r-- | mysql-test/r/explain.result | 11 | ||||
-rw-r--r-- | mysql-test/r/subselect.result | 26 | ||||
-rw-r--r-- | mysql-test/t/explain.test | 9 | ||||
-rw-r--r-- | mysql-test/t/subselect.test | 33 | ||||
-rw-r--r-- | sql/item.cc | 4 | ||||
-rw-r--r-- | sql/item_subselect.cc | 8 | ||||
-rw-r--r-- | sql/item_sum.cc | 6 | ||||
-rw-r--r-- | sql/mysql_priv.h | 7 | ||||
-rw-r--r-- | sql/sql_lex.cc | 5 | ||||
-rw-r--r-- | sql/sql_lex.h | 28 | ||||
-rw-r--r-- | sql/sql_partition.cc | 36 | ||||
-rw-r--r-- | sql/sql_select.cc | 12 |
12 files changed, 128 insertions, 57 deletions
diff --git a/mysql-test/r/explain.result b/mysql-test/r/explain.result index 4bc6c0409f3..4a815549ba9 100644 --- a/mysql-test/r/explain.result +++ b/mysql-test/r/explain.result @@ -176,11 +176,12 @@ SELECT @@session.sql_mode INTO @old_sql_mode; SET SESSION sql_mode='ONLY_FULL_GROUP_BY'; EXPLAIN EXTENDED SELECT 1 FROM t1 WHERE f1 > ALL( SELECT t.f1 FROM t1,t1 AS t ); -ERROR 42000: Mixing of GROUP columns (MIN(),MAX(),COUNT(),...) with no GROUP columns is illegal if there is no GROUP BY clause -SHOW WARNINGS; -Level Code Message -Error 1140 Mixing of GROUP columns (MIN(),MAX(),COUNT(),...) with no GROUP columns is illegal if there is no GROUP BY clause -Note 1003 select 1 AS `1` from `test`.`t1` where <not>(<exists>(...)) +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +2 SUBQUERY t1 system NULL NULL NULL NULL 0 0.00 const row not found +2 SUBQUERY t system NULL NULL NULL NULL 0 0.00 const row not found +Warnings: +Note 1003 select 1 AS `1` from `test`.`t1` where 0 SET SESSION sql_mode=@old_sql_mode; DROP TABLE t1; End of 5.0 tests. diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index dc40e42275b..cebdba6bb06 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -4435,6 +4435,32 @@ pk int_key 3 3 7 3 DROP TABLE t1,t2; +# +# Bug#12329653 +# EXPLAIN, UNION, PREPARED STATEMENT, CRASH, SQL_FULL_GROUP_BY +# +CREATE TABLE t1(a1 int); +INSERT INTO t1 VALUES (1),(2); +SELECT @@session.sql_mode INTO @old_sql_mode; +SET SESSION sql_mode='ONLY_FULL_GROUP_BY'; +SELECT 1 FROM t1 WHERE 1 < SOME (SELECT a1 FROM t1); +1 +1 +1 +PREPARE stmt FROM +'SELECT 1 UNION ALL +SELECT 1 FROM t1 +ORDER BY +(SELECT 1 FROM t1 AS t1_0 + WHERE 1 < SOME (SELECT a1 FROM t1) +)' ; +EXECUTE stmt ; +ERROR 21000: Subquery returns more than 1 row +EXECUTE stmt ; +ERROR 21000: Subquery returns more than 1 row +SET SESSION sql_mode=@old_sql_mode; +DEALLOCATE PREPARE stmt; +DROP TABLE t1; End of 5.0 tests. CREATE TABLE t1 (a INT, b INT); INSERT INTO t1 VALUES (2,22),(1,11),(2,22); diff --git a/mysql-test/t/explain.test b/mysql-test/t/explain.test index c6c30b58341..e764ee80578 100644 --- a/mysql-test/t/explain.test +++ b/mysql-test/t/explain.test @@ -1,5 +1,5 @@ # -# Test of different EXPLAIN's +# Test of different EXPLAINs --disable_warnings drop table if exists t1; @@ -157,11 +157,12 @@ CREATE TABLE t1 (f1 INT); SELECT @@session.sql_mode INTO @old_sql_mode; SET SESSION sql_mode='ONLY_FULL_GROUP_BY'; -# EXPLAIN EXTENDED (with subselect). used to crash. should give NOTICE. ---error ER_MIX_OF_GROUP_FUNC_AND_FIELDS +# EXPLAIN EXTENDED (with subselect). used to crash. +# This is actually a valid query for this sql_mode, +# but it was transformed in such a way that it failed, see +# Bug#12329653 - EXPLAIN, UNION, PREPARED STATEMENT, CRASH, SQL_FULL_GROUP_BY EXPLAIN EXTENDED SELECT 1 FROM t1 WHERE f1 > ALL( SELECT t.f1 FROM t1,t1 AS t ); -SHOW WARNINGS; SET SESSION sql_mode=@old_sql_mode; diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index 1f471b46c4e..e8748710f16 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -3393,6 +3393,39 @@ ORDER BY outr.pk; DROP TABLE t1,t2; +--echo # +--echo # Bug#12329653 +--echo # EXPLAIN, UNION, PREPARED STATEMENT, CRASH, SQL_FULL_GROUP_BY +--echo # + +CREATE TABLE t1(a1 int); +INSERT INTO t1 VALUES (1),(2); + +SELECT @@session.sql_mode INTO @old_sql_mode; +SET SESSION sql_mode='ONLY_FULL_GROUP_BY'; + +## First a simpler query, illustrating the transformation +## '1 < some (...)' => '1 < max(...)' +SELECT 1 FROM t1 WHERE 1 < SOME (SELECT a1 FROM t1); + +## The query which made the server crash. +PREPARE stmt FROM +'SELECT 1 UNION ALL +SELECT 1 FROM t1 +ORDER BY +(SELECT 1 FROM t1 AS t1_0 + WHERE 1 < SOME (SELECT a1 FROM t1) +)' ; + +--error ER_SUBQUERY_NO_1_ROW +EXECUTE stmt ; +--error ER_SUBQUERY_NO_1_ROW +EXECUTE stmt ; + +SET SESSION sql_mode=@old_sql_mode; + +DEALLOCATE PREPARE stmt; +DROP TABLE t1; --echo End of 5.0 tests. diff --git a/sql/item.cc b/sql/item.cc index 40be8b205bd..d569f2b2080 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -4464,14 +4464,14 @@ mark_non_agg_field: SELECT_LEX *select_lex= cached_table ? cached_table->select_lex : context->select_lex; if (!thd->lex->in_sum_func) - select_lex->full_group_by_flag|= NON_AGG_FIELD_USED; + select_lex->set_non_agg_field_used(true); else { if (outer_fixed) thd->lex->in_sum_func->outer_fields.push_back(this); else if (thd->lex->in_sum_func->nest_level != thd->lex->current_select->nest_level) - select_lex->full_group_by_flag|= NON_AGG_FIELD_USED; + select_lex->set_non_agg_field_used(true); } } return FALSE; diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 53d4ac2d0a8..10dd6c93717 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -1016,6 +1016,14 @@ Item_in_subselect::single_value_transformer(JOIN *join, it.replace(item); } + DBUG_EXECUTE("where", + print_where(item, "rewrite with MIN/MAX", QT_ORDINARY);); + if (thd->variables.sql_mode & MODE_ONLY_FULL_GROUP_BY) + { + DBUG_ASSERT(select_lex->non_agg_field_used()); + select_lex->set_non_agg_field_used(false); + } + save_allow_sum_func= thd->lex->allow_sum_func; thd->lex->allow_sum_func|= 1 << thd->lex->current_select->nest_level; /* diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 2a8aea68f7a..f177c98bf65 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -247,10 +247,10 @@ bool Item_sum::check_sum_func(THD *thd, Item **ref) in_sum_func->outer_fields.push_back(field); } else - sel->full_group_by_flag|= NON_AGG_FIELD_USED; + sel->set_non_agg_field_used(true); } if (sel->nest_level > aggr_level && - (sel->full_group_by_flag & SUM_FUNC_USED) && + (sel->agg_func_used()) && !sel->group_list.elements) { my_message(ER_MIX_OF_GROUP_FUNC_AND_FIELDS, @@ -259,7 +259,7 @@ bool Item_sum::check_sum_func(THD *thd, Item **ref) } } } - aggr_sel->full_group_by_flag|= SUM_FUNC_USED; + aggr_sel->set_agg_func_used(true); update_used_tables(); thd->lex->in_sum_func= in_sum_func; return FALSE; diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 8f9a9080d12..f482754baaa 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1470,13 +1470,6 @@ SQL_SELECT *make_select(TABLE *head, table_map const_tables, extern Item **not_found_item; /* - A set of constants used for checking non aggregated fields and sum - functions mixture in the ONLY_FULL_GROUP_BY_MODE. -*/ -#define NON_AGG_FIELD_USED 1 -#define SUM_FUNC_USED 2 - -/* This enumeration type is used only by the function find_item_in_list to return the info on how an item has been resolved against a list of possibly aliased items. diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 9ea144df9bc..346217937fe 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -1621,6 +1621,8 @@ void st_select_lex::init_query() nest_level= 0; link_next= 0; lock_option= TL_READ_DEFAULT; + m_non_agg_field_used= false; + m_agg_func_used= false; } void st_select_lex::init_select() @@ -1651,7 +1653,8 @@ void st_select_lex::init_select() non_agg_fields.empty(); cond_value= having_value= Item::COND_UNDEF; inner_refs_list.empty(); - full_group_by_flag= 0; + m_non_agg_field_used= false; + m_agg_func_used= false; } /* diff --git a/sql/sql_lex.h b/sql/sql_lex.h index b1f30b07824..26818025126 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -713,16 +713,7 @@ public: joins on the right. */ List<String> *prev_join_using; - /* - Bitmap used in the ONLY_FULL_GROUP_BY_MODE to prevent mixture of aggregate - functions and non aggregated fields when GROUP BY list is absent. - Bits: - 0 - non aggregated fields are used in this select, - defined as NON_AGG_FIELD_USED. - 1 - aggregate functions are used in this select, - defined as SUM_FUNC_USED. - */ - uint8 full_group_by_flag; + void init_query(); void init_select(); st_select_lex_unit* master_unit(); @@ -830,7 +821,22 @@ public: void clear_index_hints(void) { index_hints= NULL; } -private: + /* + For MODE_ONLY_FULL_GROUP_BY we need to maintain two flags: + - Non-aggregated fields are used in this select. + - Aggregate functions are used in this select. + In MODE_ONLY_FULL_GROUP_BY only one of these may be true. + */ + bool non_agg_field_used() const { return m_non_agg_field_used; } + bool agg_func_used() const { return m_agg_func_used; } + + void set_non_agg_field_used(bool val) { m_non_agg_field_used= val; } + void set_agg_func_used(bool val) { m_agg_func_used= val; } + +private: + bool m_non_agg_field_used; + bool m_agg_func_used; + /* current index hint kind. used in filling up index_hints */ enum index_hint_type current_index_hint_type; index_clause_map current_index_hint_clause; diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index d10f695f535..30bfa9eb35f 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -930,9 +930,6 @@ static bool fix_fields_part_func(THD *thd, Item* func_expr, TABLE *table, const char *save_where; char* db_name; char db_name_string[FN_REFLEN]; - bool save_use_only_table_context; - uint8 saved_full_group_by_flag; - nesting_map saved_allow_sum_func; DBUG_ENTER("fix_fields_part_func"); if (part_info->fixed) @@ -999,23 +996,26 @@ static bool fix_fields_part_func(THD *thd, Item* func_expr, TABLE *table, of interesting side effects, both desirable and undesirable. */ - save_use_only_table_context= thd->lex->use_only_table_context; - thd->lex->use_only_table_context= TRUE; - thd->lex->current_select->cur_pos_in_select_list= UNDEF_POS; - saved_full_group_by_flag= thd->lex->current_select->full_group_by_flag; - saved_allow_sum_func= thd->lex->allow_sum_func; - thd->lex->allow_sum_func= 0; + { + const bool save_use_only_table_context= thd->lex->use_only_table_context; + thd->lex->use_only_table_context= TRUE; + thd->lex->current_select->cur_pos_in_select_list= UNDEF_POS; + const bool save_agg_field= thd->lex->current_select->non_agg_field_used(); + const bool save_agg_func= thd->lex->current_select->agg_func_used(); + const nesting_map saved_allow_sum_func= thd->lex->allow_sum_func; + thd->lex->allow_sum_func= 0; - error= func_expr->fix_fields(thd, (Item**)&func_expr); - - /* - Restore full_group_by_flag and allow_sum_func, - fix_fields should not affect mysql_select later, see Bug#46923. - */ - thd->lex->current_select->full_group_by_flag= saved_full_group_by_flag; - thd->lex->allow_sum_func= saved_allow_sum_func; + error= func_expr->fix_fields(thd, (Item**)&func_expr); - thd->lex->use_only_table_context= save_use_only_table_context; + /* + Restore agg_field/agg_func and allow_sum_func, + fix_fields should not affect mysql_select later, see Bug#46923. + */ + thd->lex->current_select->set_non_agg_field_used(save_agg_field); + thd->lex->current_select->set_agg_func_used(save_agg_func); + thd->lex->allow_sum_func= saved_allow_sum_func; + thd->lex->use_only_table_context= save_use_only_table_context; + } context->table_list= save_table_list; context->first_name_resolution_table= save_first_table; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index eb2559fc600..b58152d6c38 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -426,19 +426,18 @@ inline int setup_without_group(THD *thd, Item **ref_pointer_array, int res; nesting_map save_allow_sum_func=thd->lex->allow_sum_func ; /* - Need to save the value, so we can turn off only the new NON_AGG_FIELD + Need to save the value, so we can turn off only any new non_agg_field_used additions coming from the WHERE */ - uint8 saved_flag= thd->lex->current_select->full_group_by_flag; + const bool saved_non_agg_field_used= + thd->lex->current_select->non_agg_field_used(); DBUG_ENTER("setup_without_group"); thd->lex->allow_sum_func&= ~(1 << thd->lex->current_select->nest_level); res= setup_conds(thd, tables, leaves, conds); /* it's not wrong to have non-aggregated columns in a WHERE */ - if (thd->variables.sql_mode & MODE_ONLY_FULL_GROUP_BY) - thd->lex->current_select->full_group_by_flag= saved_flag | - (thd->lex->current_select->full_group_by_flag & ~NON_AGG_FIELD_USED); + thd->lex->current_select->set_non_agg_field_used(saved_non_agg_field_used); thd->lex->allow_sum_func|= 1 << thd->lex->current_select->nest_level; res= res || setup_order(thd, ref_pointer_array, tables, fields, all_fields, @@ -644,7 +643,8 @@ JOIN::prepare(Item ***rref_pointer_array, aggregate functions with implicit grouping (there is no GROUP BY). */ if (thd->variables.sql_mode & MODE_ONLY_FULL_GROUP_BY && !group_list && - select_lex->full_group_by_flag == (NON_AGG_FIELD_USED | SUM_FUNC_USED)) + select_lex->non_agg_field_used() && + select_lex->agg_func_used()) { my_message(ER_MIX_OF_GROUP_FUNC_AND_FIELDS, ER(ER_MIX_OF_GROUP_FUNC_AND_FIELDS), MYF(0)); |