summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTor Didriksen <tor.didriksen@oracle.com>2011-05-04 17:12:45 +0200
committerTor Didriksen <tor.didriksen@oracle.com>2011-05-04 17:12:45 +0200
commit9baf84e99a6d7edd36c777593a90671d02aacbc9 (patch)
tree4b2a82480afbf07a0e4ba4447dbf4f3a51761bbe
parentc00c350f147173bf20c35c8787cdf0d840653e96 (diff)
parenta32df762d43c29545718e8a78a1721a9a7a1a35f (diff)
downloadmariadb-git-9baf84e99a6d7edd36c777593a90671d02aacbc9.tar.gz
merge 5.0 => 5.1 : Bug#12329653
-rw-r--r--mysql-test/r/explain.result11
-rw-r--r--mysql-test/r/subselect.result26
-rw-r--r--mysql-test/t/explain.test9
-rw-r--r--mysql-test/t/subselect.test33
-rw-r--r--sql/item.cc4
-rw-r--r--sql/item_subselect.cc8
-rw-r--r--sql/item_sum.cc6
-rw-r--r--sql/mysql_priv.h7
-rw-r--r--sql/sql_lex.cc5
-rw-r--r--sql/sql_lex.h28
-rw-r--r--sql/sql_partition.cc36
-rw-r--r--sql/sql_select.cc12
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));