diff --git a/mysql-test/r/delete.result b/mysql-test/r/delete.result index ba4e9386312..4bdf1c770d3 100644 --- a/mysql-test/r/delete.result +++ b/mysql-test/r/delete.result @@ -214,3 +214,12 @@ select count(*) from t1; count(*) 0 drop table t1; +CREATE TABLE t1 (a INT); +INSERT INTO t1 VALUES (1); +DELETE FROM t1 ORDER BY x; +ERROR 42S22: Unknown column 'x' in 'order clause' +DELETE FROM t1 ORDER BY t2.x; +ERROR 42S22: Unknown column 't2.x' in 'order clause' +DELETE FROM t1 ORDER BY (SELECT x); +ERROR 42S22: Unknown column 'x' in 'field list' +DROP TABLE t1; diff --git a/mysql-test/r/gis.result b/mysql-test/r/gis.result index 8f81c7c4b66..418affc50a2 100644 --- a/mysql-test/r/gis.result +++ b/mysql-test/r/gis.result @@ -730,6 +730,12 @@ point(b, b) IS NULL linestring(b) IS NULL polygon(b) IS NULL multipoint(b) IS NU 1 1 1 1 1 1 1 0 1 1 1 1 1 1 drop table t1; +CREATE TABLE t1(a POINT) ENGINE=MyISAM; +INSERT INTO t1 VALUES (NULL); +SELECT * FROM t1; +a +NULL +DROP TABLE t1; End of 4.1 tests create table t1 (s1 geometry not null,s2 char(100)); create trigger t1_bu before update on t1 for each row set new.s1 = null; diff --git a/mysql-test/r/group_by.result b/mysql-test/r/group_by.result index 5cff5fec7ed..c7464bb21d2 100644 --- a/mysql-test/r/group_by.result +++ b/mysql-test/r/group_by.result @@ -1141,4 +1141,9 @@ EXPLAIN SELECT 1 FROM t2 WHERE a IN id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t2 index NULL a 5 NULL 4 Using where; Using index 2 DEPENDENT SUBQUERY t1 ALL NULL NULL NULL NULL 256 Using where +SHOW VARIABLES LIKE 'old'; +Variable_name Value +old OFF +SET @@old = off; +ERROR HY000: Variable 'old' is a read only variable DROP TABLE t1, t2; diff --git a/mysql-test/r/range.result b/mysql-test/r/range.result index 5cd7e3ebfbd..21b127da412 100644 --- a/mysql-test/r/range.result +++ b/mysql-test/r/range.result @@ -717,6 +717,34 @@ d8c4177d225791924.30714720 d8c4177d2380fc201.39666693 d8c4177d24ccef970.14957924 DROP TABLE t1; +create table t1 ( +c1 char(10), c2 char(10), c3 char(10), c4 char(10), +c5 char(10), c6 char(10), c7 char(10), c8 char(10), +c9 char(10), c10 char(10), c11 char(10), c12 char(10), +c13 char(10), c14 char(10), c15 char(10), c16 char(10), +index(c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12,c13,c14,c15,c16) +); +insert into t1 (c1) values ('1'),('1'),('1'),('1'); +select * from t1 where +c1 in ("abcdefgh", "123456789", "qwertyuio", "asddfgh") +and c2 in ("abcdefgh", "123456789", "qwertyuio", "asddfgh") +and c3 in ("abcdefgh", "123456789", "qwertyuio", "asddfgh") +and c4 in ("abcdefgh", "123456789", "qwertyuio", "asddfgh") +and c5 in ("abcdefgh", "123456789", "qwertyuio", "asddfgh") +and c6 in ("abcdefgh", "123456789", "qwertyuio", "asddfgh") +and c7 in ("abcdefgh", "123456789", "qwertyuio", "asddfgh") +and c8 in ("abcdefgh", "123456789", "qwertyuio", "asddfgh") +and c9 in ("abcdefgh", "123456789", "qwertyuio", "asddfgh") +and c10 in ("abcdefgh", "123456789", "qwertyuio", "asddfgh") +and c11 in ("abcdefgh", "123456789", "qwertyuio", "asddfgh") +and c12 in ("abcdefgh", "123456789", "qwertyuio", "asddfgh") +and c13 in ("abcdefgh", "123456789", "qwertyuio", "asddfgh") +and c14 in ("abcdefgh", "123456789", "qwertyuio", "asddfgh") +and c15 in ("abcdefgh", "123456789", "qwertyuio", "asddfgh") +and c16 in ("abcdefgh", "123456789", "qwertyuio", "asddfgh") +; +c1 c2 c3 c4 c5 c6 c7 c8 c9 c10 c11 c12 c13 c14 c15 c16 +drop table t1; End of 4.1 tests CREATE TABLE t1 ( id int(11) NOT NULL auto_increment, diff --git a/mysql-test/r/sp-code.result b/mysql-test/r/sp-code.result index 67b030f87a4..588f4329368 100644 --- a/mysql-test/r/sp-code.result +++ b/mysql-test/r/sp-code.result @@ -621,3 +621,20 @@ Pos Instruction 0 stmt 2 "CREATE INDEX idx ON t1 (c1)" DROP PROCEDURE p1; End of 5.0 tests. +CREATE PROCEDURE p1() +BEGIN +DECLARE dummy int default 0; +CASE 12 +WHEN 12 +THEN SET dummy = 0; +END CASE; +END// +SHOW PROCEDURE CODE p1; +Pos Instruction +0 set dummy@0 0 +1 set_case_expr (6) 0 12 +2 jump_if_not 5(6) (case_expr@0 = 12) +3 set dummy@0 0 +4 jump 6 +5 error 1339 +DROP PROCEDURE p1; diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index 8bc9350bd6c..089fb10aaae 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -3905,6 +3905,48 @@ COUNT(*) a 2 2 3 3 DROP TABLE t1,t2; +CREATE TABLE t1 (a int, b int); +CREATE TABLE t2 (m int, n int); +INSERT INTO t1 VALUES (2,2), (2,2), (3,3), (3,3), (3,3), (4,4); +INSERT INTO t2 VALUES (1,11), (2,22), (3,32), (4,44), (4,44); +SELECT COUNT(*) c, a, +(SELECT GROUP_CONCAT(COUNT(a)) FROM t2 WHERE m = a) +FROM t1 GROUP BY a; +c a (SELECT GROUP_CONCAT(COUNT(a)) FROM t2 WHERE m = a) +2 2 2 +3 3 3 +1 4 1,1 +SELECT COUNT(*) c, a, +(SELECT GROUP_CONCAT(COUNT(a)+1) FROM t2 WHERE m = a) +FROM t1 GROUP BY a; +c a (SELECT GROUP_CONCAT(COUNT(a)+1) FROM t2 WHERE m = a) +2 2 3 +3 3 4 +1 4 2,2 +DROP table t1,t2; +CREATE TABLE t1 (a int, b int); +INSERT INTO t1 VALUES (2,22),(1,11),(2,22); +SELECT a FROM t1 WHERE (SELECT COUNT(b) FROM DUAL) > 0 GROUP BY a; +a +1 +2 +SELECT a FROM t1 WHERE (SELECT COUNT(b) FROM DUAL) > 1 GROUP BY a; +a +SELECT a FROM t1 t0 +WHERE (SELECT COUNT(t0.b) FROM t1 t WHERE t.b>20) GROUP BY a; +a +1 +2 +SET @@sql_mode='ansi'; +SELECT a FROM t1 WHERE (SELECT COUNT(b) FROM DUAL) > 0 GROUP BY a; +ERROR HY000: Invalid use of group function +SELECT a FROM t1 WHERE (SELECT COUNT(b) FROM DUAL) > 1 GROUP BY a; +ERROR HY000: Invalid use of group function +SELECT a FROM t1 t0 +WHERE (SELECT COUNT(t0.b) FROM t1 t WHERE t.b>20) GROUP BY a; +ERROR HY000: Invalid use of group function +SET @@sql_mode=default; +DROP TABLE t1; CREATE TABLE t1 (s1 char(1)); INSERT INTO t1 VALUES ('a'); SELECT * FROM t1 WHERE _utf8'a' = ANY (SELECT s1 FROM t1); diff --git a/mysql-test/t/delete.test b/mysql-test/t/delete.test index 306447dbd5a..36d627209db 100644 --- a/mysql-test/t/delete.test +++ b/mysql-test/t/delete.test @@ -203,3 +203,21 @@ select * from t1 where a is null; delete from t1 where a is null; select count(*) from t1; drop table t1; + +# +# Bug #26186: delete order by, sometimes accept unknown column +# +CREATE TABLE t1 (a INT); INSERT INTO t1 VALUES (1); + +--error ER_BAD_FIELD_ERROR +DELETE FROM t1 ORDER BY x; + +# even columns from a table not used in query (and not even existing) +--error ER_BAD_FIELD_ERROR +DELETE FROM t1 ORDER BY t2.x; + +# subquery (as long as the subquery from is valid or DUAL) +--error ER_BAD_FIELD_ERROR +DELETE FROM t1 ORDER BY (SELECT x); + +DROP TABLE t1; diff --git a/mysql-test/t/gis.test b/mysql-test/t/gis.test index 9cf42070f2f..dd9be6a8085 100644 --- a/mysql-test/t/gis.test +++ b/mysql-test/t/gis.test @@ -424,6 +424,14 @@ from t1; drop table t1; +# +# Bug #27164: Crash when mixing InnoDB and MyISAM Geospatial tables +# +CREATE TABLE t1(a POINT) ENGINE=MyISAM; +INSERT INTO t1 VALUES (NULL); +SELECT * FROM t1; +DROP TABLE t1; + --echo End of 4.1 tests # diff --git a/mysql-test/t/group_by.test b/mysql-test/t/group_by.test index a3318745764..fb9c09d4763 100644 --- a/mysql-test/t/group_by.test +++ b/mysql-test/t/group_by.test @@ -755,7 +755,8 @@ SET SQL_MODE = ''; # # Bug #21174: Index degrades sort performance and -# optimizer does not honor IGNORE INDEX +# optimizer does not honor IGNORE INDEX. +# a.k.a WL3527. # CREATE TABLE t1 (a INT, b INT, PRIMARY KEY (a), @@ -819,4 +820,8 @@ EXPLAIN SELECT a, SUM(b) FROM t2 IGNORE INDEX (a) GROUP BY a LIMIT 2; EXPLAIN SELECT 1 FROM t2 WHERE a IN (SELECT a FROM t1 USE INDEX (i2) IGNORE INDEX (i2)); +SHOW VARIABLES LIKE 'old'; +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +SET @@old = off; + DROP TABLE t1, t2; diff --git a/mysql-test/t/range.test b/mysql-test/t/range.test index b1cec049ab2..68bab0c50a2 100644 --- a/mysql-test/t/range.test +++ b/mysql-test/t/range.test @@ -568,6 +568,38 @@ SELECT s.oxid FROM t1 v, t1 s DROP TABLE t1; +# BUG#26624 high mem usage (crash) in range optimizer (depends on order of fields in where) +create table t1 ( + c1 char(10), c2 char(10), c3 char(10), c4 char(10), + c5 char(10), c6 char(10), c7 char(10), c8 char(10), + c9 char(10), c10 char(10), c11 char(10), c12 char(10), + c13 char(10), c14 char(10), c15 char(10), c16 char(10), + index(c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12,c13,c14,c15,c16) +); + +insert into t1 (c1) values ('1'),('1'),('1'),('1'); + +# This must run without crash and fast: +select * from t1 where + c1 in ("abcdefgh", "123456789", "qwertyuio", "asddfgh") + and c2 in ("abcdefgh", "123456789", "qwertyuio", "asddfgh") + and c3 in ("abcdefgh", "123456789", "qwertyuio", "asddfgh") + and c4 in ("abcdefgh", "123456789", "qwertyuio", "asddfgh") + and c5 in ("abcdefgh", "123456789", "qwertyuio", "asddfgh") + and c6 in ("abcdefgh", "123456789", "qwertyuio", "asddfgh") + and c7 in ("abcdefgh", "123456789", "qwertyuio", "asddfgh") + and c8 in ("abcdefgh", "123456789", "qwertyuio", "asddfgh") + and c9 in ("abcdefgh", "123456789", "qwertyuio", "asddfgh") + and c10 in ("abcdefgh", "123456789", "qwertyuio", "asddfgh") + and c11 in ("abcdefgh", "123456789", "qwertyuio", "asddfgh") + and c12 in ("abcdefgh", "123456789", "qwertyuio", "asddfgh") + and c13 in ("abcdefgh", "123456789", "qwertyuio", "asddfgh") + and c14 in ("abcdefgh", "123456789", "qwertyuio", "asddfgh") + and c15 in ("abcdefgh", "123456789", "qwertyuio", "asddfgh") + and c16 in ("abcdefgh", "123456789", "qwertyuio", "asddfgh") +; +drop table t1; + --echo End of 4.1 tests # diff --git a/mysql-test/t/sp-code.test b/mysql-test/t/sp-code.test index 97bc29fcad2..1b33680cfaf 100644 --- a/mysql-test/t/sp-code.test +++ b/mysql-test/t/sp-code.test @@ -447,3 +447,21 @@ DROP PROCEDURE p1; --echo End of 5.0 tests. + +# +# Bug #26303: reserve() not called before qs_append() may lead to buffer +# overflow +# +DELIMITER //; +CREATE PROCEDURE p1() +BEGIN + DECLARE dummy int default 0; + + CASE 12 + WHEN 12 + THEN SET dummy = 0; + END CASE; +END// +DELIMITER ;// +SHOW PROCEDURE CODE p1; +DROP PROCEDURE p1; diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index 0f42b3e06a5..88c34bdb9b9 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -2765,6 +2765,50 @@ SELECT COUNT(*), a DROP TABLE t1,t2; # +# Bug #27229: GROUP_CONCAT in subselect with COUNT() as an argument +# + +CREATE TABLE t1 (a int, b int); +CREATE TABLE t2 (m int, n int); +INSERT INTO t1 VALUES (2,2), (2,2), (3,3), (3,3), (3,3), (4,4); +INSERT INTO t2 VALUES (1,11), (2,22), (3,32), (4,44), (4,44); + +SELECT COUNT(*) c, a, + (SELECT GROUP_CONCAT(COUNT(a)) FROM t2 WHERE m = a) + FROM t1 GROUP BY a; + +SELECT COUNT(*) c, a, + (SELECT GROUP_CONCAT(COUNT(a)+1) FROM t2 WHERE m = a) + FROM t1 GROUP BY a; + +DROP table t1,t2; + +# +# Bug #27348: SET FUNCTION used in a subquery from WHERE condition +# + +CREATE TABLE t1 (a int, b int); +INSERT INTO t1 VALUES (2,22),(1,11),(2,22); + +SELECT a FROM t1 WHERE (SELECT COUNT(b) FROM DUAL) > 0 GROUP BY a; +SELECT a FROM t1 WHERE (SELECT COUNT(b) FROM DUAL) > 1 GROUP BY a; + +SELECT a FROM t1 t0 + WHERE (SELECT COUNT(t0.b) FROM t1 t WHERE t.b>20) GROUP BY a; + +SET @@sql_mode='ansi'; +--error 1111 +SELECT a FROM t1 WHERE (SELECT COUNT(b) FROM DUAL) > 0 GROUP BY a; +--error 1111 +SELECT a FROM t1 WHERE (SELECT COUNT(b) FROM DUAL) > 1 GROUP BY a; + +--error 1111 +SELECT a FROM t1 t0 + WHERE (SELECT COUNT(t0.b) FROM t1 t WHERE t.b>20) GROUP BY a; + +SET @@sql_mode=default; +DROP TABLE t1; + # Bug#20835 (literal string with =any values) # CREATE TABLE t1 (s1 char(1)); diff --git a/sql/field.h b/sql/field.h index b96be208e41..12f94adcc0e 100644 --- a/sql/field.h +++ b/sql/field.h @@ -1353,7 +1353,7 @@ public: int store_decimal(const my_decimal *); void get_key_image(char *buff,uint length,imagetype type); uint size_of() const { return sizeof(*this); } - int reset(void) { return !maybe_null(); } + int reset(void) { return !maybe_null() || Field_blob::reset(); } }; #endif /*HAVE_SPATIAL*/ diff --git a/sql/item.cc b/sql/item.cc index c7935607130..1482d39b6ba 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -1088,7 +1088,7 @@ bool Item_splocal::set_value(THD *thd, sp_rcontext *ctx, Item **it) Item_case_expr methods *****************************************************************************/ -Item_case_expr::Item_case_expr(int case_expr_id) +Item_case_expr::Item_case_expr(uint case_expr_id) :Item_sp_variable( C_STRING_WITH_LEN("case_expr")), m_case_expr_id(case_expr_id) { @@ -1125,6 +1125,8 @@ Item_case_expr::this_item_addr(THD *thd, Item **) void Item_case_expr::print(String *str) { + if (str->reserve(MAX_INT_WIDTH + sizeof("case_expr@"))) + return; /* purecov: inspected */ VOID(str->append(STRING_WITH_LEN("case_expr@"))); str->qs_append(m_case_expr_id); } @@ -1289,15 +1291,18 @@ void Item::split_sum_func2(THD *thd, Item **ref_pointer_array, Exception is Item_direct_view_ref which we need to convert to Item_ref to allow fields from view being stored in tmp table. */ + Item_aggregate_ref *item_ref; uint el= fields.elements; - Item *new_item, *real_itm= real_item(); + Item *real_itm= real_item(); ref_pointer_array[el]= real_itm; - if (!(new_item= new Item_aggregate_ref(&thd->lex->current_select->context, + if (!(item_ref= new Item_aggregate_ref(&thd->lex->current_select->context, ref_pointer_array + el, 0, name))) return; // fatal_error is set + if (type() == SUM_FUNC_ITEM) + item_ref->depended_from= ((Item_sum *) this)->depended_from(); fields.push_front(real_itm); - thd->change_item_tree(ref, new_item); + thd->change_item_tree(ref, item_ref); } } diff --git a/sql/item.h b/sql/item.h index 87380b53bfb..bf662b98732 100644 --- a/sql/item.h +++ b/sql/item.h @@ -1116,7 +1116,7 @@ inline Item_result Item_splocal::result_type() const class Item_case_expr :public Item_sp_variable { public: - Item_case_expr(int case_expr_id); + Item_case_expr(uint case_expr_id); public: Item *this_item(); @@ -1135,7 +1135,7 @@ public: void print(String *str); private: - int m_case_expr_id; + uint m_case_expr_id; }; /***************************************************************************** diff --git a/sql/item_sum.cc b/sql/item_sum.cc index cd67f83af17..7d7662f06f7 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -61,9 +61,9 @@ bool Item_sum::init_sum_func_check(THD *thd) /* Save a pointer to object to be used in items for nested set functions */ thd->lex->in_sum_func= this; nest_level= thd->lex->current_select->nest_level; - nest_level_tables_count= thd->lex->current_select->join->tables; ref_by= 0; aggr_level= -1; + aggr_sel= NULL; max_arg_level= -1; max_sum_func_level= -1; return FALSE; @@ -149,9 +149,14 @@ bool Item_sum::check_sum_func(THD *thd, Item **ref) if (register_sum_func(thd, ref)) return TRUE; invalid= aggr_level < 0 && !(allow_sum_func & (1 << nest_level)); + if (!invalid && thd->variables.sql_mode & MODE_ANSI) + invalid= aggr_level < 0 && max_arg_level < nest_level; } if (!invalid && aggr_level < 0) + { aggr_level= nest_level; + aggr_sel= thd->lex->current_select; + } /* By this moment we either found a subquery where the set function is to be aggregated and assigned a value that is >= 0 to aggr_level, @@ -161,8 +166,9 @@ bool Item_sum::check_sum_func(THD *thd, Item **ref) Additionally we have to check whether possible nested set functions are acceptable here: they are not, if the level of aggregation of some of them is less than aggr_level. - */ - invalid= aggr_level <= max_sum_func_level; + */ + if (!invalid) + invalid= aggr_level <= max_sum_func_level; if (invalid) { my_message(ER_INVALID_GROUP_FUNC_USE, ER(ER_INVALID_GROUP_FUNC_USE), @@ -212,7 +218,6 @@ bool Item_sum::check_sum_func(THD *thd, Item **ref) bool Item_sum::register_sum_func(THD *thd, Item **ref) { SELECT_LEX *sl; - SELECT_LEX *aggr_sl= NULL; nesting_map allow_sum_func= thd->lex->allow_sum_func; for (sl= thd->lex->current_select->master_unit()->outer_select() ; sl && sl->nest_level > max_arg_level; @@ -222,7 +227,7 @@ bool Item_sum::register_sum_func(THD *thd, Item **ref) { /* Found the most nested subquery where the function can be aggregated */ aggr_level= sl->nest_level; - aggr_sl= sl; + aggr_sel= sl; } } if (sl && (allow_sum_func & (1 << sl->nest_level))) @@ -233,21 +238,22 @@ bool Item_sum::register_sum_func(THD *thd, Item **ref) The set function will be aggregated in this subquery. */ aggr_level= sl->nest_level; - aggr_sl= sl; + aggr_sel= sl; + } if (aggr_level >= 0) { ref_by= ref; - /* Add the object to the list of registered objects assigned to aggr_sl */ - if (!aggr_sl->inner_sum_func_list) + /* Add the object to the list of registered objects assigned to aggr_sel */ + if (!aggr_sel->inner_sum_func_list) next= this; else { - next= aggr_sl->inner_sum_func_list->next; - aggr_sl->inner_sum_func_list->next= this; + next= aggr_sel->inner_sum_func_list->next; + aggr_sel->inner_sum_func_list->next= this; } - aggr_sl->inner_sum_func_list= this; - aggr_sl->with_sum_func= 1; + aggr_sel->inner_sum_func_list= this; + aggr_sel->with_sum_func= 1; /* Mark Item_subselect(s) as containing aggregate function all the way up @@ -265,11 +271,11 @@ bool Item_sum::register_sum_func(THD *thd, Item **ref) has aggregate functions directly referenced (i.e. not through a sub-select). */ for (sl= thd->lex->current_select; - sl && sl != aggr_sl && sl->master_unit()->item; + sl && sl != aggr_sel && sl->master_unit()->item; sl= sl->master_unit()->outer_select() ) sl->master_unit()->item->with_sum_func= 1; } - thd->lex->current_select->mark_as_dependent(aggr_sl); + thd->lex->current_select->mark_as_dependent(aggr_sel); return FALSE; } @@ -299,10 +305,10 @@ Item_sum::Item_sum(List &list) :arg_count(list.elements), Item_sum::Item_sum(THD *thd, Item_sum *item): Item_result_field(thd, item), arg_count(item->arg_count), + aggr_sel(item->aggr_sel), nest_level(item->nest_level), aggr_level(item->aggr_level), quick_group(item->quick_group), used_tables_cache(item->used_tables_cache), - forced_const(item->forced_const), - nest_level_tables_count(item->nest_level_tables_count) + forced_const(item->forced_const) { if (arg_count <= 2) args=tmp_args; @@ -449,8 +455,7 @@ void Item_sum::update_used_tables () used_tables_cache&= PSEUDO_TABLE_BITS; /* the aggregate function is aggregated into its local context */ - if (aggr_level == nest_level) - used_tables_cache |= (1 << nest_level_tables_count) - 1; + used_tables_cache |= (1 << aggr_sel->join->tables) - 1; } } diff --git a/sql/item_sum.h b/sql/item_sum.h index 5756402c1b1..5cf4f93af0e 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -233,6 +233,7 @@ public: Item_sum *next; /* next in the circular chain of registered objects */ uint arg_count; Item_sum *in_sum_func; /* embedding set function if any */ + st_select_lex * aggr_sel; /* select where the function is aggregated */ int8 nest_level; /* number of the nesting level of the set function */ int8 aggr_level; /* nesting level of the aggregating subquery */ int8 max_arg_level; /* max level of unbound column references */ @@ -242,7 +243,6 @@ public: protected: table_map used_tables_cache; bool forced_const; - byte nest_level_tables_count; public: @@ -365,6 +365,8 @@ public: bool init_sum_func_check(THD *thd); bool check_sum_func(THD *thd, Item **ref); bool register_sum_func(THD *thd, Item **ref); + st_select_lex *depended_from() + { return (nest_level == aggr_level ? 0 : aggr_sel); } }; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 51feb197713..cd94dba30ec 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -6271,7 +6271,7 @@ The minimum value for this variable is 4096.", (gptr*) &global_system_variables.net_write_timeout, (gptr*) &max_system_variables.net_write_timeout, 0, GET_ULONG, REQUIRED_ARG, NET_WRITE_TIMEOUT, 1, LONG_TIMEOUT, 0, 1, 0}, - { "old_mode", OPT_OLD_MODE, "Use compatible behaviour.", + { "old", OPT_OLD_MODE, "Use compatible behavior.", (gptr*) &global_system_variables.old_mode, (gptr*) &max_system_variables.old_mode, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 03d97a294ad..88e0eb27d80 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -84,7 +84,7 @@ static int sel_cmp(Field *f,char *a,char *b,uint8 a_flag,uint8 b_flag); static char is_null_string[2]= {1,0}; - +class RANGE_OPT_PARAM; /* A construction block of the SEL_ARG-graph. @@ -170,6 +170,89 @@ static char is_null_string[2]= {1,0}; - get_quick_select() - Walk the SEL_ARG, materialize the key intervals, and create QUICK_RANGE_SELECT object that will read records within these intervals. + + 4. SPACE COMPLEXITY NOTES + + SEL_ARG graph is a representation of an ordered disjoint sequence of + intervals over the ordered set of index tuple values. + + For multi-part keys, one can construct a WHERE expression such that its + list of intervals will be of combinatorial size. Here is an example: + + (keypart1 IN (1,2, ..., n1)) AND + (keypart2 IN (1,2, ..., n2)) AND + (keypart3 IN (1,2, ..., n3)) + + For this WHERE clause the list of intervals will have n1*n2*n3 intervals + of form + + (keypart1, keypart2, keypart3) = (k1, k2, k3), where 1 <= k{i} <= n{i} + + SEL_ARG graph structure aims to reduce the amount of required space by + "sharing" the elementary intervals when possible (the pic at the + beginning of this comment has examples of such sharing). The sharing may + prevent combinatorial blowup: + + There are WHERE clauses that have combinatorial-size interval lists but + will be represented by a compact SEL_ARG graph. + Example: + (keypartN IN (1,2, ..., n1)) AND + ... + (keypart2 IN (1,2, ..., n2)) AND + (keypart1 IN (1,2, ..., n3)) + + but not in all cases: + + - There are WHERE clauses that do have a compact SEL_ARG-graph + representation but get_mm_tree() and its callees will construct a + graph of combinatorial size. + Example: + (keypart1 IN (1,2, ..., n1)) AND + (keypart2 IN (1,2, ..., n2)) AND + ... + (keypartN IN (1,2, ..., n3)) + + - There are WHERE clauses for which the minimal possible SEL_ARG graph + representation will have combinatorial size. + Example: + By induction: Let's take any interval on some keypart in the middle: + + kp15=c0 + + Then let's AND it with this interval 'structure' from preceding and + following keyparts: + + (kp14=c1 AND kp16=c3) OR keypart14=c2) (*) + + We will obtain this SEL_ARG graph: + + kp14 $ kp15 $ kp16 + $ $ + +---------+ $ +---------+ $ +---------+ + | kp14=c1 |--$-->| kp15=c0 |--$-->| kp16=c3 | + +---------+ $ +---------+ $ +---------+ + | $ $ + +---------+ $ +---------+ $ + | kp14=c2 |--$-->| kp15=c0 | $ + +---------+ $ +---------+ $ + $ $ + + Note that we had to duplicate "kp15=c0" and there was no way to avoid + that. + The induction step: AND the obtained expression with another "wrapping" + expression like (*). + When the process ends because of the limit on max. number of keyparts + we'll have: + + WHERE clause length is O(3*#max_keyparts) + SEL_ARG graph size is O(2^(#max_keyparts/2)) + + (it is also possible to construct a case where instead of 2 in 2^n we + have a bigger constant, e.g. 4, and get a graph with 4^(31/2)= 2^31 + nodes) + + We avoid consuming too much memory by setting a limit on the number of + SEL_ARG object we can construct during one range analysis invocation. */ class SEL_ARG :public Sql_alloc @@ -200,6 +283,8 @@ public: enum leaf_color { BLACK,RED } color; enum Type { IMPOSSIBLE, MAYBE, MAYBE_KEY, KEY_RANGE } type; + enum { MAX_SEL_ARGS = 64000 }; + SEL_ARG() {} SEL_ARG(SEL_ARG &); SEL_ARG(Field *,const char *,const char *); @@ -271,7 +356,7 @@ public: return new SEL_ARG(field, part, min_value, arg->max_value, min_flag, arg->max_flag, maybe_flag | arg->maybe_flag); } - SEL_ARG *clone(SEL_ARG *new_parent,SEL_ARG **next); + SEL_ARG *clone(RANGE_OPT_PARAM *param, SEL_ARG *new_parent, SEL_ARG **next); bool copy_min(SEL_ARG* arg) { // Get overlapping range @@ -423,7 +508,6 @@ public: { return parent->left == this ? &parent->left : &parent->right; } - SEL_ARG *clone_tree(); /* @@ -466,6 +550,7 @@ public: } return !field->key_cmp(min_val, max_val); } + SEL_ARG *clone_tree(RANGE_OPT_PARAM *param); }; class SEL_IMERGE; @@ -545,6 +630,8 @@ public: using_real_indexes==TRUE */ uint real_keynr[MAX_KEY]; + /* Number of SEL_ARG objects allocated by SEL_ARG::clone_tree operations */ + uint alloced_sel_args; }; class PARAM : public RANGE_OPT_PARAM @@ -634,8 +721,9 @@ static void print_quick(QUICK_SELECT_I *quick, const key_map *needed_reg); static SEL_TREE *tree_and(RANGE_OPT_PARAM *param,SEL_TREE *tree1,SEL_TREE *tree2); static SEL_TREE *tree_or(RANGE_OPT_PARAM *param,SEL_TREE *tree1,SEL_TREE *tree2); static SEL_ARG *sel_add(SEL_ARG *key1,SEL_ARG *key2); -static SEL_ARG *key_or(SEL_ARG *key1,SEL_ARG *key2); -static SEL_ARG *key_and(SEL_ARG *key1,SEL_ARG *key2,uint clone_flag); +static SEL_ARG *key_or(RANGE_OPT_PARAM *param, SEL_ARG *key1, SEL_ARG *key2); +static SEL_ARG *key_and(RANGE_OPT_PARAM *param, SEL_ARG *key1, SEL_ARG *key2, + uint clone_flag); static bool get_range(SEL_ARG **e1,SEL_ARG **e2,SEL_ARG *root1); bool get_quick_keys(PARAM *param,QUICK_RANGE_SELECT *quick,KEY_PART *key, SEL_ARG *key_tree,char *min_key,uint min_key_flag, @@ -860,6 +948,7 @@ int imerge_list_or_tree(RANGE_OPT_PARAM *param, return im1->is_empty(); } + /*************************************************************************** ** Basic functions for SQL_SELECT and QUICK_RANGE_SELECT ***************************************************************************/ @@ -1510,12 +1599,18 @@ SEL_ARG::SEL_ARG(Field *field_,uint8 part_,char *min_value_,char *max_value_, left=right= &null_element; } -SEL_ARG *SEL_ARG::clone(SEL_ARG *new_parent,SEL_ARG **next_arg) +SEL_ARG *SEL_ARG::clone(RANGE_OPT_PARAM *param, SEL_ARG *new_parent, + SEL_ARG **next_arg) { SEL_ARG *tmp; + + /* Bail out if we have already generated too many SEL_ARGs */ + if (++param->alloced_sel_args > MAX_SEL_ARGS) + return 0; + if (type != KEY_RANGE) { - if (!(tmp= new SEL_ARG(type))) + if (!(tmp= new (param->mem_root) SEL_ARG(type))) return 0; // out of memory tmp->prev= *next_arg; // Link into next/prev chain (*next_arg)->next=tmp; @@ -1523,20 +1618,21 @@ SEL_ARG *SEL_ARG::clone(SEL_ARG *new_parent,SEL_ARG **next_arg) } else { - if (!(tmp= new SEL_ARG(field,part, min_value,max_value, - min_flag, max_flag, maybe_flag))) + if (!(tmp= new (param->mem_root) SEL_ARG(field,part, min_value,max_value, + min_flag, max_flag, maybe_flag))) return 0; // OOM tmp->parent=new_parent; tmp->next_key_part=next_key_part; if (left != &null_element) - tmp->left=left->clone(tmp,next_arg); + if (!(tmp->left=left->clone(param, tmp, next_arg))) + return 0; // OOM tmp->prev= *next_arg; // Link into next/prev chain (*next_arg)->next=tmp; (*next_arg)= tmp; if (right != &null_element) - if (!(tmp->right= right->clone(tmp,next_arg))) + if (!(tmp->right= right->clone(param, tmp, next_arg))) return 0; // OOM } increment_use_count(1); @@ -1614,11 +1710,12 @@ static int sel_cmp(Field *field, char *a,char *b,uint8 a_flag,uint8 b_flag) } -SEL_ARG *SEL_ARG::clone_tree() +SEL_ARG *SEL_ARG::clone_tree(RANGE_OPT_PARAM *param) { SEL_ARG tmp_link,*next_arg,*root; next_arg= &tmp_link; - root= clone((SEL_ARG *) 0, &next_arg); + if (!(root= clone(param, (SEL_ARG *) 0, &next_arg))) + return 0; next_arg->next=0; // Fix last link tmp_link.next->prev=0; // Fix first link if (root) // If not OOM @@ -2120,6 +2217,7 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use, param.real_keynr[param.keys++]=idx; } param.key_parts_end=key_parts; + param.alloced_sel_args= 0; /* Calculate cost of full index read for the shortest covering index */ if (!head->covering_keys.is_clear_all()) @@ -2512,6 +2610,7 @@ bool prune_partitions(THD *thd, TABLE *table, Item *pprune_cond) range_par->using_real_indexes= FALSE; range_par->remove_jump_scans= FALSE; range_par->real_keynr[0]= 0; + range_par->alloced_sel_args= 0; thd->no_errors=1; // Don't warn about NULL thd->mem_root=&alloc; @@ -5242,7 +5341,8 @@ static SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param,COND *cond) while ((item=li++)) { SEL_TREE *new_tree=get_mm_tree(param,item); - if (param->thd->is_fatal_error) + if (param->thd->is_fatal_error || + param->alloced_sel_args > SEL_ARG::MAX_SEL_ARGS) DBUG_RETURN(0); // out of memory tree=tree_and(param,tree,new_tree); if (tree && tree->type == SEL_TREE::IMPOSSIBLE) @@ -5818,9 +5918,9 @@ tree_and(RANGE_OPT_PARAM *param,SEL_TREE *tree1,SEL_TREE *tree2) tree1->type=SEL_TREE::KEY_SMALLER; DBUG_RETURN(tree1); } - key_map result_keys; result_keys.clear_all(); + /* Join the trees key per key */ SEL_ARG **key1,**key2,**end; for (key1= tree1->keys,key2= tree2->keys,end=key1+param->keys ; @@ -5833,7 +5933,7 @@ tree_and(RANGE_OPT_PARAM *param,SEL_TREE *tree1,SEL_TREE *tree2) flag|=CLONE_KEY1_MAYBE; if (*key2 && !(*key2)->simple_key()) flag|=CLONE_KEY2_MAYBE; - *key1=key_and(*key1,*key2,flag); + *key1=key_and(param, *key1, *key2, flag); if (*key1 && (*key1)->type == SEL_ARG::IMPOSSIBLE) { tree1->type= SEL_TREE::IMPOSSIBLE; @@ -5994,7 +6094,7 @@ tree_or(RANGE_OPT_PARAM *param,SEL_TREE *tree1,SEL_TREE *tree2) for (key1= tree1->keys,key2= tree2->keys,end= key1+param->keys ; key1 != end ; key1++,key2++) { - *key1=key_or(*key1,*key2); + *key1=key_or(param, *key1, *key2); if (*key1) { result=tree1; // Added to tree1 @@ -6058,14 +6158,15 @@ tree_or(RANGE_OPT_PARAM *param,SEL_TREE *tree1,SEL_TREE *tree2) /* And key trees where key1->part < key2 -> part */ static SEL_ARG * -and_all_keys(SEL_ARG *key1,SEL_ARG *key2,uint clone_flag) +and_all_keys(RANGE_OPT_PARAM *param, SEL_ARG *key1, SEL_ARG *key2, + uint clone_flag) { SEL_ARG *next; ulong use_count=key1->use_count; if (key1->elements != 1) { - key2->use_count+=key1->elements-1; + key2->use_count+=key1->elements-1; //psergey: why we don't count that key1 has n-k-p? key2->increment_use_count((int) key1->elements-1); } if (key1->type == SEL_ARG::MAYBE_KEY) @@ -6077,7 +6178,7 @@ and_all_keys(SEL_ARG *key1,SEL_ARG *key2,uint clone_flag) { if (next->next_key_part) { - SEL_ARG *tmp=key_and(next->next_key_part,key2,clone_flag); + SEL_ARG *tmp= key_and(param, next->next_key_part, key2, clone_flag); if (tmp && tmp->type == SEL_ARG::IMPOSSIBLE) { key1=key1->tree_delete(next); @@ -6086,6 +6187,8 @@ and_all_keys(SEL_ARG *key1,SEL_ARG *key2,uint clone_flag) next->next_key_part=tmp; if (use_count) next->increment_use_count(use_count); + if (param->alloced_sel_args > SEL_ARG::MAX_SEL_ARGS) + break; } else next->next_key_part=key2; @@ -6102,8 +6205,10 @@ and_all_keys(SEL_ARG *key1,SEL_ARG *key2,uint clone_flag) SYNOPSIS key_and() - key1 First argument, root of its RB-tree - key2 Second argument, root of its RB-tree + param Range analysis context (needed to track if we have allocated + too many SEL_ARGs) + key1 First argument, root of its RB-tree + key2 Second argument, root of its RB-tree RETURN RB-tree root of the resulting SEL_ARG graph. @@ -6111,7 +6216,7 @@ and_all_keys(SEL_ARG *key1,SEL_ARG *key2,uint clone_flag) */ static SEL_ARG * -key_and(SEL_ARG *key1, SEL_ARG *key2, uint clone_flag) +key_and(RANGE_OPT_PARAM *param, SEL_ARG *key1, SEL_ARG *key2, uint clone_flag) { if (!key1) return key2; @@ -6127,9 +6232,9 @@ key_and(SEL_ARG *key1, SEL_ARG *key2, uint clone_flag) // key1->part < key2->part key1->use_count--; if (key1->use_count > 0) - if (!(key1= key1->clone_tree())) + if (!(key1= key1->clone_tree(param))) return 0; // OOM - return and_all_keys(key1,key2,clone_flag); + return and_all_keys(param, key1, key2, clone_flag); } if (((clone_flag & CLONE_KEY2_MAYBE) && @@ -6147,14 +6252,14 @@ key_and(SEL_ARG *key1, SEL_ARG *key2, uint clone_flag) if (key1->use_count > 1) { key1->use_count--; - if (!(key1=key1->clone_tree())) + if (!(key1=key1->clone_tree(param))) return 0; // OOM key1->use_count++; } if (key1->type == SEL_ARG::MAYBE_KEY) { // Both are maybe key - key1->next_key_part=key_and(key1->next_key_part,key2->next_key_part, - clone_flag); + key1->next_key_part=key_and(param, key1->next_key_part, + key2->next_key_part, clone_flag); if (key1->next_key_part && key1->next_key_part->type == SEL_ARG::IMPOSSIBLE) return key1; @@ -6165,7 +6270,7 @@ key_and(SEL_ARG *key1, SEL_ARG *key2, uint clone_flag) if (key2->next_key_part) { key1->use_count--; // Incremented in and_all_keys - return and_all_keys(key1,key2,clone_flag); + return and_all_keys(param, key1, key2, clone_flag); } key2->use_count--; // Key2 doesn't have a tree } @@ -6201,7 +6306,8 @@ key_and(SEL_ARG *key1, SEL_ARG *key2, uint clone_flag) } else if (get_range(&e2,&e1,key2)) continue; - SEL_ARG *next=key_and(e1->next_key_part,e2->next_key_part,clone_flag); + SEL_ARG *next=key_and(param, e1->next_key_part, e2->next_key_part, + clone_flag); e1->increment_use_count(1); e2->increment_use_count(1); if (!next || next->type != SEL_ARG::IMPOSSIBLE) @@ -6249,7 +6355,7 @@ get_range(SEL_ARG **e1,SEL_ARG **e2,SEL_ARG *root1) static SEL_ARG * -key_or(SEL_ARG *key1,SEL_ARG *key2) +key_or(RANGE_OPT_PARAM *param, SEL_ARG *key1,SEL_ARG *key2) { if (!key1) { @@ -6297,7 +6403,7 @@ key_or(SEL_ARG *key1,SEL_ARG *key2) { swap_variables(SEL_ARG *,key1,key2); } - if (key1->use_count > 0 || !(key1=key1->clone_tree())) + if (key1->use_count > 0 || !(key1=key1->clone_tree(param))) return 0; // OOM } @@ -6441,7 +6547,7 @@ key_or(SEL_ARG *key1,SEL_ARG *key2) { // tmp.min. <= x <= tmp.max tmp->maybe_flag|= key.maybe_flag; key.increment_use_count(key1->use_count+1); - tmp->next_key_part=key_or(tmp->next_key_part,key.next_key_part); + tmp->next_key_part= key_or(param, tmp->next_key_part, key.next_key_part); if (!cmp) // Key2 is ready break; key.copy_max_to_min(tmp); @@ -6472,7 +6578,7 @@ key_or(SEL_ARG *key1,SEL_ARG *key2) tmp->increment_use_count(key1->use_count+1); /* Increment key count as it may be used for next loop */ key.increment_use_count(1); - new_arg->next_key_part=key_or(tmp->next_key_part,key.next_key_part); + new_arg->next_key_part= key_or(param, tmp->next_key_part, key.next_key_part); key1=key1->insert(new_arg); break; } diff --git a/sql/set_var.cc b/sql/set_var.cc index fef6fccfd06..7f55556c134 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -356,6 +356,8 @@ sys_var_thd_ulong sys_net_retry_count("net_retry_count", &SV::net_retry_count, 0, fix_net_retry_count); sys_var_thd_bool sys_new_mode("new", &SV::new_mode); +sys_var_bool_ptr_readonly sys_old_mode("old", + &global_system_variables.old_mode); sys_var_thd_bool sys_old_alter_table("old_alter_table", &SV::old_alter_table); sys_var_thd_bool sys_old_passwords("old_passwords", &SV::old_passwords); @@ -942,6 +944,7 @@ SHOW_VAR init_vars[]= { {sys_net_retry_count.name, (char*) &sys_net_retry_count, SHOW_SYS}, {sys_net_write_timeout.name,(char*) &sys_net_write_timeout, SHOW_SYS}, {sys_new_mode.name, (char*) &sys_new_mode, SHOW_SYS}, + {sys_old_mode.name, (char*) &sys_old_mode, SHOW_SYS}, {sys_old_alter_table.name, (char*) &sys_old_alter_table, SHOW_SYS}, {sys_old_passwords.name, (char*) &sys_old_passwords, SHOW_SYS}, {"open_files_limit", (char*) &open_files_limit, SHOW_LONG}, diff --git a/sql/set_var.h b/sql/set_var.h index 8887d91ec69..eac03fce610 100644 --- a/sql/set_var.h +++ b/sql/set_var.h @@ -169,6 +169,16 @@ public: }; +class sys_var_bool_ptr_readonly :public sys_var_bool_ptr +{ +public: + sys_var_bool_ptr_readonly(const char *name_arg, my_bool *value_arg) + :sys_var_bool_ptr(name_arg, value_arg) + {} + bool is_readonly() const { return 1; } +}; + + class sys_var_str :public sys_var { public: diff --git a/sql/sql_base.cc b/sql/sql_base.cc index f01f539ec51..516ca573cb3 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -5838,7 +5838,6 @@ bool setup_tables_and_check_access(THD *thd, TABLE_LIST *leaves_tmp= NULL; bool first_table= true; - thd->leaf_count= 0; if (setup_tables(thd, context, from_clause, tables, &leaves_tmp, select_insert)) return TRUE; @@ -5856,7 +5855,6 @@ bool setup_tables_and_check_access(THD *thd, return TRUE; } first_table= 0; - thd->leaf_count++; } return FALSE; } diff --git a/sql/sql_class.h b/sql/sql_class.h index a9915fce4ef..d4868cc1934 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1412,9 +1412,6 @@ public: partition_info *work_part_info; #endif - /* pass up the count of "leaf" tables in a JOIN out of setup_tables() */ - byte leaf_count; - THD(); ~THD(); diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 0ff5c4e5b50..d300edd6e18 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -54,6 +54,27 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, if (mysql_prepare_delete(thd, table_list, &conds)) DBUG_RETURN(TRUE); + /* check ORDER BY even if it can be ignored */ + if (order && order->elements) + { + TABLE_LIST tables; + List fields; + List all_fields; + + bzero((char*) &tables,sizeof(tables)); + tables.table = table; + tables.alias = table_list->alias; + + if (select_lex->setup_ref_array(thd, order->elements) || + setup_order(thd, select_lex->ref_pointer_array, &tables, + fields, all_fields, (ORDER*) order->first)) + { + delete select; + free_underlaid_joins(thd, &thd->lex->select_lex); + DBUG_RETURN(TRUE); + } + } + const_cond= (!conds || conds->const_item()); safe_update=test(thd->options & OPTION_SAFE_UPDATES); if (safe_update && const_cond) @@ -155,23 +176,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, { uint length= 0; SORT_FIELD *sortorder; - TABLE_LIST tables; - List fields; - List all_fields; ha_rows examined_rows; - - bzero((char*) &tables,sizeof(tables)); - tables.table = table; - tables.alias = table_list->alias; - - if (select_lex->setup_ref_array(thd, order->elements) || - setup_order(thd, select_lex->ref_pointer_array, &tables, - fields, all_fields, (ORDER*) order->first)) - { - delete select; - free_underlaid_joins(thd, &thd->lex->select_lex); - DBUG_RETURN(TRUE); - } if ((!select || table->quick_keys.is_clear_all()) && limit != HA_POS_ERROR) usable_index= get_index_for_order(table, (ORDER*)(order->first), limit); diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 773383c2c2d..d24230eb379 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -2466,14 +2466,12 @@ bool mysql_insert_select_prepare(THD *thd) DBUG_ASSERT(select_lex->leaf_tables != 0); lex->leaf_tables_insert= select_lex->leaf_tables; /* skip all leaf tables belonged to view where we are insert */ - for (first_select_leaf_table= select_lex->leaf_tables->next_leaf, - thd->leaf_count --; + for (first_select_leaf_table= select_lex->leaf_tables->next_leaf; first_select_leaf_table && first_select_leaf_table->belong_to_view && first_select_leaf_table->belong_to_view == lex->leaf_tables_insert->belong_to_view; - first_select_leaf_table= first_select_leaf_table->next_leaf, - thd->leaf_count --) + first_select_leaf_table= first_select_leaf_table->next_leaf) {} select_lex->leaf_tables= first_select_leaf_table; DBUG_RETURN(FALSE); diff --git a/sql/sql_list.h b/sql/sql_list.h index af30cbe0d6a..ba61a931e04 100644 --- a/sql/sql_list.h +++ b/sql/sql_list.h @@ -23,7 +23,7 @@ class Sql_alloc { public: - static void *operator new(size_t size) + static void *operator new(size_t size) throw () { return (void*) sql_alloc((uint) size); } @@ -31,9 +31,9 @@ public: { return (void*) sql_alloc((uint) size); } - static void *operator new[](size_t size, MEM_ROOT *mem_root) + static void *operator new[](size_t size, MEM_ROOT *mem_root) throw () { return (void*) alloc_root(mem_root, (uint) size); } - static void *operator new(size_t size, MEM_ROOT *mem_root) + static void *operator new(size_t size, MEM_ROOT *mem_root) throw () { return (void*) alloc_root(mem_root, (uint) size); } static void operator delete(void *ptr, size_t size) { TRASH(ptr, size); } static void operator delete(void *ptr, MEM_ROOT *mem_root) diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 582df11c8c1..f2555e7f3f9 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -413,7 +413,12 @@ JOIN::prepare(Item ***rref_pointer_array, tables_list, &select_lex->leaf_tables, FALSE, SELECT_ACL, SELECT_ACL)) DBUG_RETURN(-1); - tables= thd->leaf_count; + + TABLE_LIST *table_ptr; + for (table_ptr= select_lex->leaf_tables; + table_ptr; + table_ptr= table_ptr->next_leaf) + tables++; if (setup_wild(thd, tables_list, fields_list, &all_fields, wild_num) || select_lex->setup_ref_array(thd, og_num) || @@ -9417,13 +9422,19 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List &fields, { if (item->with_sum_func && type != Item::SUM_FUNC_ITEM) { - /* - Mark that the we have ignored an item that refers to a summary - function. We need to know this if someone is going to use - DISTINCT on the result. - */ - param->using_indirect_summary_function=1; - continue; + if (item->used_tables() & OUTER_REF_TABLE_BIT) + item->update_used_tables(); + if (type == Item::SUBSELECT_ITEM || + (item->used_tables() & ~OUTER_REF_TABLE_BIT)) + { + /* + Mark that the we have ignored an item that refers to a summary + function. We need to know this if someone is going to use + DISTINCT on the result. + */ + param->using_indirect_summary_function=1; + continue; + } } if (item->const_item() && (int) hidden_field_count <= 0) continue; // We don't have to store this @@ -9608,6 +9619,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List &fields, share->default_values= table->record[1]+alloc_length; } copy_func[0]=0; // End marker + param->func_count= copy_func - param->items_to_copy; setup_tmp_table_column_bitmaps(table, bitmaps); @@ -13824,6 +13836,7 @@ count_field_types(TMP_TABLE_PARAM *param, List &fields, if (!sum_item->quick_group) param->quick_group=0; // UDF SUM function param->sum_func_count++; + param->func_count++; for (uint i=0 ; i < sum_item->arg_count ; i++) {