diff options
author | Tor Didriksen <tor.didriksen@oracle.com> | 2011-05-04 16:18:21 +0200 |
---|---|---|
committer | Tor Didriksen <tor.didriksen@oracle.com> | 2011-05-04 16:18:21 +0200 |
commit | 1cf483aa588cf47383af49db6d7304b911ee92db (patch) | |
tree | 8b8da64e29eab722f4e1e80a9fed11a4a210a882 /sql | |
parent | 3b52208fe1f4eb62c26870a1263b1f955ffea1da (diff) | |
download | mariadb-git-1cf483aa588cf47383af49db6d7304b911ee92db.tar.gz |
Bug#12329653 - EXPLAIN, UNION, PREPARED STATEMENT, CRASH, SQL_FULL_GROUP_BY
The query was re-written *after* we had tagged it with NON_AGG_FIELD_USED.
Remove the flag before continuing.
mysql-test/r/explain.result:
Update test case for Bug#48295.
mysql-test/r/subselect.result:
New test case.
mysql-test/t/explain.test:
Update test case for Bug#48295.
mysql-test/t/subselect.test:
New test case.
sql/item.cc:
Use accessor functions for non_agg_field_used/agg_func_used.
sql/item_subselect.cc:
Remove non_agg_field_used when we rewrite query '1 < some (...)' => '1 < max(...)'
sql/item_sum.cc:
Use accessor functions for non_agg_field_used/agg_func_used.
sql/mysql_priv.h:
Remove unused #defines.
sql/sql_lex.cc:
Initialize new member variables.
sql/sql_lex.h:
Replace full_group_by_flag with two boolean flags,
and itroduce accessors for manipulating them.
sql/sql_select.cc:
Use accessor functions for non_agg_field_used/agg_func_used.
Diffstat (limited to 'sql')
-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 | 26 | ||||
-rw-r--r-- | sql/sql_select.cc | 12 |
7 files changed, 39 insertions, 29 deletions
diff --git a/sql/item.cc b/sql/item.cc index 03d752a85d9..aaeb21f9948 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -4080,14 +4080,14 @@ mark_non_agg_field: aggregated or not. */ if (!thd->lex->in_sum_func) - cached_table->select_lex->full_group_by_flag|= NON_AGG_FIELD_USED; + cached_table->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) - cached_table->select_lex->full_group_by_flag|= NON_AGG_FIELD_USED; + cached_table->select_lex->set_non_agg_field_used(true); } } return FALSE; diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 44d1378839b..6666525a270 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -936,6 +936,14 @@ Item_in_subselect::single_value_transformer(JOIN *join, it.replace(item); } + DBUG_EXECUTE("where", + print_where(item, "rewrite with MIN/MAX");); + 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 43102213b9b..9942ae199cb 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -246,10 +246,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, @@ -258,7 +258,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 a811bbafdb6..97cad9e4b19 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1087,13 +1087,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 97d9fe99eb3..87916b201d2 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -1232,6 +1232,8 @@ void st_select_lex::init_query() exclude_from_table_unique_test= no_wrap_view_item= FALSE; nest_level= 0; link_next= 0; + m_non_agg_field_used= false; + m_agg_func_used= false; } void st_select_lex::init_select() @@ -1266,7 +1268,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 b3822f91afe..7b2227a9678 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -617,16 +617,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(); @@ -714,6 +705,21 @@ public: select lexes. */ void cleanup_all_joins(bool full); + /* + 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; }; typedef class st_select_lex SELECT_LEX; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index cb7add3a874..0d19dcb576b 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -391,19 +391,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, @@ -593,7 +592,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)); |