Commit 1cf483aa authored by Tor Didriksen's avatar Tor Didriksen

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.
parent 3b52208f
...@@ -176,11 +176,12 @@ SELECT @@session.sql_mode INTO @old_sql_mode; ...@@ -176,11 +176,12 @@ SELECT @@session.sql_mode INTO @old_sql_mode;
SET SESSION sql_mode='ONLY_FULL_GROUP_BY'; SET SESSION sql_mode='ONLY_FULL_GROUP_BY';
EXPLAIN EXTENDED SELECT 1 FROM t1 EXPLAIN EXTENDED SELECT 1 FROM t1
WHERE f1 > ALL( SELECT t.f1 FROM t1,t1 AS t ); 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 id select_type table type possible_keys key key_len ref rows Extra
SHOW WARNINGS; 1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
Level Code Message 2 SUBQUERY t1 system NULL NULL NULL NULL 0 const row not found
Error 1140 Mixing of GROUP columns (MIN(),MAX(),COUNT(),...) with no GROUP columns is illegal if there is no GROUP BY clause 2 SUBQUERY t system NULL NULL NULL NULL 0 const row not found
Note 1003 select 1 AS `1` from `test`.`t1` where <not>(<exists>(...)) Warnings:
Note 1003 select 1 AS `1` from `test`.`t1` where 0
SET SESSION sql_mode=@old_sql_mode; SET SESSION sql_mode=@old_sql_mode;
DROP TABLE t1; DROP TABLE t1;
End of 5.0 tests. End of 5.0 tests.
...@@ -4528,6 +4528,32 @@ pk int_key ...@@ -4528,6 +4528,32 @@ pk int_key
7 3 7 3
DROP TABLE t1,t2; 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;
#
# Bug #52711: Segfault when doing EXPLAIN SELECT with # Bug #52711: Segfault when doing EXPLAIN SELECT with
# union...order by (select... where...) # union...order by (select... where...)
# #
......
# #
# Test of different EXPLAIN's # Test of different EXPLAINs
--disable_warnings --disable_warnings
drop table if exists t1; drop table if exists t1;
...@@ -157,11 +157,12 @@ CREATE TABLE t1 (f1 INT); ...@@ -157,11 +157,12 @@ CREATE TABLE t1 (f1 INT);
SELECT @@session.sql_mode INTO @old_sql_mode; SELECT @@session.sql_mode INTO @old_sql_mode;
SET SESSION sql_mode='ONLY_FULL_GROUP_BY'; SET SESSION sql_mode='ONLY_FULL_GROUP_BY';
# EXPLAIN EXTENDED (with subselect). used to crash. should give NOTICE. # EXPLAIN EXTENDED (with subselect). used to crash.
--error ER_MIX_OF_GROUP_FUNC_AND_FIELDS # 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 EXPLAIN EXTENDED SELECT 1 FROM t1
WHERE f1 > ALL( SELECT t.f1 FROM t1,t1 AS t ); WHERE f1 > ALL( SELECT t.f1 FROM t1,t1 AS t );
SHOW WARNINGS;
SET SESSION sql_mode=@old_sql_mode; SET SESSION sql_mode=@old_sql_mode;
......
...@@ -3506,6 +3506,40 @@ ORDER BY outr.pk; ...@@ -3506,6 +3506,40 @@ ORDER BY outr.pk;
DROP TABLE t1,t2; 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 # --echo #
--echo # Bug #52711: Segfault when doing EXPLAIN SELECT with --echo # Bug #52711: Segfault when doing EXPLAIN SELECT with
--echo # union...order by (select... where...) --echo # union...order by (select... where...)
......
...@@ -4080,14 +4080,14 @@ bool Item_field::fix_fields(THD *thd, Item **reference) ...@@ -4080,14 +4080,14 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
aggregated or not. aggregated or not.
*/ */
if (!thd->lex->in_sum_func) 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 else
{ {
if (outer_fixed) if (outer_fixed)
thd->lex->in_sum_func->outer_fields.push_back(this); thd->lex->in_sum_func->outer_fields.push_back(this);
else if (thd->lex->in_sum_func->nest_level != else if (thd->lex->in_sum_func->nest_level !=
thd->lex->current_select->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; return FALSE;
......
...@@ -936,6 +936,14 @@ Item_in_subselect::single_value_transformer(JOIN *join, ...@@ -936,6 +936,14 @@ Item_in_subselect::single_value_transformer(JOIN *join,
it.replace(item); 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; save_allow_sum_func= thd->lex->allow_sum_func;
thd->lex->allow_sum_func|= 1 << thd->lex->current_select->nest_level; thd->lex->allow_sum_func|= 1 << thd->lex->current_select->nest_level;
/* /*
......
...@@ -246,10 +246,10 @@ bool Item_sum::check_sum_func(THD *thd, Item **ref) ...@@ -246,10 +246,10 @@ bool Item_sum::check_sum_func(THD *thd, Item **ref)
in_sum_func->outer_fields.push_back(field); in_sum_func->outer_fields.push_back(field);
} }
else else
sel->full_group_by_flag|= NON_AGG_FIELD_USED; sel->set_non_agg_field_used(true);
} }
if (sel->nest_level > aggr_level && if (sel->nest_level > aggr_level &&
(sel->full_group_by_flag & SUM_FUNC_USED) && (sel->agg_func_used()) &&
!sel->group_list.elements) !sel->group_list.elements)
{ {
my_message(ER_MIX_OF_GROUP_FUNC_AND_FIELDS, my_message(ER_MIX_OF_GROUP_FUNC_AND_FIELDS,
...@@ -258,7 +258,7 @@ bool Item_sum::check_sum_func(THD *thd, Item **ref) ...@@ -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(); update_used_tables();
thd->lex->in_sum_func= in_sum_func; thd->lex->in_sum_func= in_sum_func;
return FALSE; return FALSE;
......
...@@ -1086,13 +1086,6 @@ SQL_SELECT *make_select(TABLE *head, table_map const_tables, ...@@ -1086,13 +1086,6 @@ SQL_SELECT *make_select(TABLE *head, table_map const_tables,
bool allow_null_cond, int *error); bool allow_null_cond, int *error);
extern Item **not_found_item; 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 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 to return the info on how an item has been resolved against a list
......
...@@ -1232,6 +1232,8 @@ void st_select_lex::init_query() ...@@ -1232,6 +1232,8 @@ void st_select_lex::init_query()
exclude_from_table_unique_test= no_wrap_view_item= FALSE; exclude_from_table_unique_test= no_wrap_view_item= FALSE;
nest_level= 0; nest_level= 0;
link_next= 0; link_next= 0;
m_non_agg_field_used= false;
m_agg_func_used= false;
} }
void st_select_lex::init_select() void st_select_lex::init_select()
...@@ -1266,7 +1268,8 @@ void st_select_lex::init_select() ...@@ -1266,7 +1268,8 @@ void st_select_lex::init_select()
non_agg_fields.empty(); non_agg_fields.empty();
cond_value= having_value= Item::COND_UNDEF; cond_value= having_value= Item::COND_UNDEF;
inner_refs_list.empty(); inner_refs_list.empty();
full_group_by_flag= 0; m_non_agg_field_used= false;
m_agg_func_used= false;
} }
/* /*
......
...@@ -617,16 +617,7 @@ class st_select_lex: public st_select_lex_node ...@@ -617,16 +617,7 @@ class st_select_lex: public st_select_lex_node
joins on the right. joins on the right.
*/ */
List<String> *prev_join_using; 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_query();
void init_select(); void init_select();
st_select_lex_unit* master_unit(); st_select_lex_unit* master_unit();
...@@ -714,6 +705,21 @@ class st_select_lex: public st_select_lex_node ...@@ -714,6 +705,21 @@ class st_select_lex: public st_select_lex_node
select lexes. select lexes.
*/ */
void cleanup_all_joins(bool full); 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; typedef class st_select_lex SELECT_LEX;
......
...@@ -391,19 +391,18 @@ inline int setup_without_group(THD *thd, Item **ref_pointer_array, ...@@ -391,19 +391,18 @@ inline int setup_without_group(THD *thd, Item **ref_pointer_array,
int res; int res;
nesting_map save_allow_sum_func=thd->lex->allow_sum_func ; 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 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"); DBUG_ENTER("setup_without_group");
thd->lex->allow_sum_func&= ~(1 << thd->lex->current_select->nest_level); thd->lex->allow_sum_func&= ~(1 << thd->lex->current_select->nest_level);
res= setup_conds(thd, tables, leaves, conds); res= setup_conds(thd, tables, leaves, conds);
/* it's not wrong to have non-aggregated columns in a WHERE */ /* 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->set_non_agg_field_used(saved_non_agg_field_used);
thd->lex->current_select->full_group_by_flag= saved_flag |
(thd->lex->current_select->full_group_by_flag & ~NON_AGG_FIELD_USED);
thd->lex->allow_sum_func|= 1 << thd->lex->current_select->nest_level; thd->lex->allow_sum_func|= 1 << thd->lex->current_select->nest_level;
res= res || setup_order(thd, ref_pointer_array, tables, fields, all_fields, res= res || setup_order(thd, ref_pointer_array, tables, fields, all_fields,
...@@ -593,7 +592,8 @@ JOIN::prepare(Item ***rref_pointer_array, ...@@ -593,7 +592,8 @@ JOIN::prepare(Item ***rref_pointer_array,
aggregate functions with implicit grouping (there is no GROUP BY). aggregate functions with implicit grouping (there is no GROUP BY).
*/ */
if (thd->variables.sql_mode & MODE_ONLY_FULL_GROUP_BY && !group_list && 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, my_message(ER_MIX_OF_GROUP_FUNC_AND_FIELDS,
ER(ER_MIX_OF_GROUP_FUNC_AND_FIELDS), MYF(0)); ER(ER_MIX_OF_GROUP_FUNC_AND_FIELDS), MYF(0));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment