From 6ec7976df97d5c9ced3f2e50339c74f19cda32fd Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 19 Jul 2006 12:36:55 -0700 Subject: [PATCH 01/21] Fixed bug #17526: incorrect print method for class Item_func_trim. For 4.1 it caused wrong output for EXPLAIN EXTENDED commands if expressions with the TRIM function of two arguments were used. For 5.0 it caused an error message when trying to select from a view with the TRIM function of two arguments. This unexpected error message was due to the fact that the print method for the class Item_func_trim was inherited from the class Item_func. Yet the TRIM function does not take a list of its arguments. Rather it takes the arguments in the form: [{BOTH | LEADING | TRAILING} [remstr] FROM] str) | [remstr FROM] str mysql-test/r/func_str.result: Added a test case for bug #17526: uncorrect print method for class Item_func_trim. mysql-test/t/func_str.test: Added a test case for bug #17526: incorrect print method for class Item_func_trim. sql/item_strfunc.cc: Fixed bug #17526: incorrect print method for class Item_func_trim. Added an implementation for the virtual function print in the class Item_func_trim. The implementation takes into account the fact the TRIM function takes the arguments in the following forms: [{BOTH | LEADING | TRAILING} [remstr] FROM] str) | [remstr FROM] str sql/item_strfunc.h: Fixed bug #17526: incorrect print method for class Item_func_trim. Added an implementation for the virtual function print in the class Item_func_trim. Declared a virtual method to return the mode of the TRIM function: LEADING, TRAILING or BOTH. Added implementations of this method for Item_func_trim and its descendants Item_func_ltrim and Item_func_rtrim. --- mysql-test/r/func_str.result | 28 ++++++++++++++++++++++++++++ mysql-test/t/func_str.test | 15 +++++++++++++++ sql/item_strfunc.cc | 17 +++++++++++++++++ sql/item_strfunc.h | 4 ++++ 4 files changed, 64 insertions(+) diff --git a/mysql-test/r/func_str.result b/mysql-test/r/func_str.result index 61a77c211d7..2c15e5581e8 100644 --- a/mysql-test/r/func_str.result +++ b/mysql-test/r/func_str.result @@ -1036,4 +1036,32 @@ a c abc abc abc xyz xyz xyz DROP TABLE t1; +CREATE TABLE t1 (s varchar(10)); +INSERT INTO t1 VALUES ('yadda'), ('yaddy'); +EXPLAIN EXTENDED SELECT s FROM t1 WHERE TRIM(s) > 'ab'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 2 Using where +Warnings: +Note 1003 select test.t1.s AS `s` from test.t1 where (trim(test.t1.s) > _latin1'ab') +EXPLAIN EXTENDED SELECT s FROM t1 WHERE TRIM('y' FROM s) > 'ab'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 2 Using where +Warnings: +Note 1003 select test.t1.s AS `s` from test.t1 where (trim(both _latin1'y' from test.t1.s) > _latin1'ab') +EXPLAIN EXTENDED SELECT s FROM t1 WHERE TRIM(LEADING 'y' FROM s) > 'ab'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 2 Using where +Warnings: +Note 1003 select test.t1.s AS `s` from test.t1 where (trim(leading _latin1'y' from test.t1.s) > _latin1'ab') +EXPLAIN EXTENDED SELECT s FROM t1 WHERE TRIM(TRAILING 'y' FROM s) > 'ab'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 2 Using where +Warnings: +Note 1003 select test.t1.s AS `s` from test.t1 where (trim(trailing _latin1'y' from test.t1.s) > _latin1'ab') +EXPLAIN EXTENDED SELECT s FROM t1 WHERE TRIM(BOTH 'y' FROM s) > 'ab'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 2 Using where +Warnings: +Note 1003 select test.t1.s AS `s` from test.t1 where (trim(both _latin1'y' from test.t1.s) > _latin1'ab') +DROP TABLE t1; End of 4.1 tests diff --git a/mysql-test/t/func_str.test b/mysql-test/t/func_str.test index 9a1c75a8dc0..3c855a32eed 100644 --- a/mysql-test/t/func_str.test +++ b/mysql-test/t/func_str.test @@ -697,5 +697,20 @@ SELECT a, CONCAT(a,' ',a) AS c FROM t1 INSTR(REVERSE(CONCAT(a,' ',a))," ")) = a; DROP TABLE t1; + +# +# Bug#17526: WRONG PRINT for TRIM FUNCTION with two arguments +# + +CREATE TABLE t1 (s varchar(10)); +INSERT INTO t1 VALUES ('yadda'), ('yaddy'); + +EXPLAIN EXTENDED SELECT s FROM t1 WHERE TRIM(s) > 'ab'; +EXPLAIN EXTENDED SELECT s FROM t1 WHERE TRIM('y' FROM s) > 'ab'; +EXPLAIN EXTENDED SELECT s FROM t1 WHERE TRIM(LEADING 'y' FROM s) > 'ab'; +EXPLAIN EXTENDED SELECT s FROM t1 WHERE TRIM(TRAILING 'y' FROM s) > 'ab'; +EXPLAIN EXTENDED SELECT s FROM t1 WHERE TRIM(BOTH 'y' FROM s) > 'ab'; + +DROP TABLE t1; --echo End of 4.1 tests diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 7bc7956283b..1c5b947cb2b 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -1444,6 +1444,23 @@ void Item_func_trim::fix_length_and_dec() } } +void Item_func_trim::print(String *str) +{ + if (arg_count == 1) + { + Item_func::print(str); + return; + } + str->append(Item_func_trim::func_name()); + str->append('('); + str->append(mode_name()); + str->append(' '); + args[1]->print(str); + str->append(" from ",6); + args[0]->print(str); + str->append(')'); +} + /* Item_func_password */ diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index f800c17182b..880a19242ca 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -218,6 +218,8 @@ public: String *val_str(String *); void fix_length_and_dec(); const char *func_name() const { return "trim"; } + void print(String *str); + virtual const char *mode_name() const { return "both"; } }; @@ -228,6 +230,7 @@ public: Item_func_ltrim(Item *a) :Item_func_trim(a) {} String *val_str(String *); const char *func_name() const { return "ltrim"; } + const char *mode_name() const { return "leading"; } }; @@ -238,6 +241,7 @@ public: Item_func_rtrim(Item *a) :Item_func_trim(a) {} String *val_str(String *); const char *func_name() const { return "rtrim"; } + const char *mode_name() const { return "trailing"; } }; From f8dda7bfb928c0eaee550db57f5288e0575ea378 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 19 Jul 2006 16:42:19 -0700 Subject: [PATCH 02/21] Added a test case with views for bug #17526. mysql-test/r/func_str.result: Adjusted results for the test case of bug 17526. sql/item_strfunc.cc: Post-merge modification --- mysql-test/r/func_str.result | 10 +++++----- mysql-test/r/view.result | 33 +++++++++++++++++++++++++++++++++ mysql-test/t/view.test | 24 ++++++++++++++++++++++++ sql/item_strfunc.cc | 2 +- 4 files changed, 63 insertions(+), 6 deletions(-) diff --git a/mysql-test/r/func_str.result b/mysql-test/r/func_str.result index ae62010f118..a857f5055a2 100644 --- a/mysql-test/r/func_str.result +++ b/mysql-test/r/func_str.result @@ -1059,27 +1059,27 @@ EXPLAIN EXTENDED SELECT s FROM t1 WHERE TRIM(s) > 'ab'; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 Using where Warnings: -Note 1003 select test.t1.s AS `s` from test.t1 where (trim(test.t1.s) > _latin1'ab') +Note 1003 select `test`.`t1`.`s` AS `s` from `test`.`t1` where (trim(`test`.`t1`.`s`) > _latin1'ab') EXPLAIN EXTENDED SELECT s FROM t1 WHERE TRIM('y' FROM s) > 'ab'; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 Using where Warnings: -Note 1003 select test.t1.s AS `s` from test.t1 where (trim(both _latin1'y' from test.t1.s) > _latin1'ab') +Note 1003 select `test`.`t1`.`s` AS `s` from `test`.`t1` where (trim(both _latin1'y' from `test`.`t1`.`s`) > _latin1'ab') EXPLAIN EXTENDED SELECT s FROM t1 WHERE TRIM(LEADING 'y' FROM s) > 'ab'; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 Using where Warnings: -Note 1003 select test.t1.s AS `s` from test.t1 where (trim(leading _latin1'y' from test.t1.s) > _latin1'ab') +Note 1003 select `test`.`t1`.`s` AS `s` from `test`.`t1` where (trim(leading _latin1'y' from `test`.`t1`.`s`) > _latin1'ab') EXPLAIN EXTENDED SELECT s FROM t1 WHERE TRIM(TRAILING 'y' FROM s) > 'ab'; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 Using where Warnings: -Note 1003 select test.t1.s AS `s` from test.t1 where (trim(trailing _latin1'y' from test.t1.s) > _latin1'ab') +Note 1003 select `test`.`t1`.`s` AS `s` from `test`.`t1` where (trim(trailing _latin1'y' from `test`.`t1`.`s`) > _latin1'ab') EXPLAIN EXTENDED SELECT s FROM t1 WHERE TRIM(BOTH 'y' FROM s) > 'ab'; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 2 Using where Warnings: -Note 1003 select test.t1.s AS `s` from test.t1 where (trim(both _latin1'y' from test.t1.s) > _latin1'ab') +Note 1003 select `test`.`t1`.`s` AS `s` from `test`.`t1` where (trim(both _latin1'y' from `test`.`t1`.`s`) > _latin1'ab') DROP TABLE t1; End of 4.1 tests create table t1 (d decimal default null); diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index 7d2ab63ca77..c8a673e2209 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -2774,3 +2774,36 @@ Field Type Null Key Default Extra COALESCE(i,j) int(11) YES NULL DROP VIEW v1; DROP TABLE t1,t2; +CREATE TABLE t1 (s varchar(10)); +INSERT INTO t1 VALUES ('yadda'), ('yady'); +SELECT TRIM(BOTH 'y' FROM s) FROM t1; +TRIM(BOTH 'y' FROM s) +adda +ad +CREATE VIEW v1 AS SELECT TRIM(BOTH 'y' FROM s) FROM t1; +SELECT * FROM v1; +TRIM(BOTH 'y' FROM s) +adda +ad +DROP VIEW v1; +SELECT TRIM(LEADING 'y' FROM s) FROM t1; +TRIM(LEADING 'y' FROM s) +adda +ady +CREATE VIEW v1 AS SELECT TRIM(LEADING 'y' FROM s) FROM t1; +SELECT * FROM v1; +TRIM(LEADING 'y' FROM s) +adda +ady +DROP VIEW v1; +SELECT TRIM(TRAILING 'y' FROM s) FROM t1; +TRIM(TRAILING 'y' FROM s) +yadda +yad +CREATE VIEW v1 AS SELECT TRIM(TRAILING 'y' FROM s) FROM t1; +SELECT * FROM v1; +TRIM(TRAILING 'y' FROM s) +yadda +yad +DROP VIEW v1; +DROP TABLE t1; diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index 88a4d489039..6399cef9086 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -2643,3 +2643,27 @@ DESCRIBE t2; DROP VIEW v1; DROP TABLE t1,t2; + +# +# Bug #17526: views with TRIM functions +# + +CREATE TABLE t1 (s varchar(10)); +INSERT INTO t1 VALUES ('yadda'), ('yady'); + +SELECT TRIM(BOTH 'y' FROM s) FROM t1; +CREATE VIEW v1 AS SELECT TRIM(BOTH 'y' FROM s) FROM t1; +SELECT * FROM v1; +DROP VIEW v1; + +SELECT TRIM(LEADING 'y' FROM s) FROM t1; +CREATE VIEW v1 AS SELECT TRIM(LEADING 'y' FROM s) FROM t1; +SELECT * FROM v1; +DROP VIEW v1; + +SELECT TRIM(TRAILING 'y' FROM s) FROM t1; +CREATE VIEW v1 AS SELECT TRIM(TRAILING 'y' FROM s) FROM t1; +SELECT * FROM v1; +DROP VIEW v1; + +DROP TABLE t1; diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 7289c17f996..58ddb331b2e 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -1515,7 +1515,7 @@ void Item_func_trim::print(String *str) str->append(mode_name()); str->append(' '); args[1]->print(str); - str->append(" from ",6); + str->append(STRING_WITH_LEN(" from ")); args[0]->print(str); str->append(')'); } From 68698c04abfbcbee1b67b5daca6695ada679ac4f Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 21 Jul 2006 03:04:04 +0400 Subject: [PATCH 03/21] BUG#20975: Incorrect query result for NOT (subquery): Add implementations of Item_func_{nop,not}_all::neg_transformer mysql-test/r/subselect.result: BUG#20975: testcase mysql-test/t/subselect.test: BUG#20975: testcase sql/mysql_priv.h: Make chooser_compare_func_creator visible in item.h --- mysql-test/r/subselect.result | 26 ++++++++++++++++++++++++++ mysql-test/t/subselect.test | 16 ++++++++++++++++ sql/item_cmpfunc.cc | 22 ++++++++++++++++++++++ sql/item_cmpfunc.h | 2 ++ sql/item_subselect.cc | 6 +++--- sql/item_subselect.h | 9 ++++----- sql/mysql_priv.h | 3 ++- sql/sql_parse.cc | 2 +- 8 files changed, 76 insertions(+), 10 deletions(-) diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index c78f0951469..595d80f1218 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -2868,3 +2868,29 @@ select 1 from dual where 1 < any (select 2 from dual); select 1 from dual where 1 < all (select 2 from dual where 1!=1); 1 1 +create table t1 (s1 char); +insert into t1 values (1),(2); +select * from t1 where (s1 < any (select s1 from t1)); +s1 +1 +select * from t1 where not (s1 < any (select s1 from t1)); +s1 +2 +select * from t1 where (s1 < ALL (select s1+1 from t1)); +s1 +1 +select * from t1 where not(s1 < ALL (select s1+1 from t1)); +s1 +2 +select * from t1 where (s1+1 = ANY (select s1 from t1)); +s1 +1 +select * from t1 where NOT(s1+1 = ANY (select s1 from t1)); +s1 +2 +select * from t1 where (s1 = ALL (select s1/s1 from t1)); +s1 +1 +select * from t1 where NOT(s1 = ALL (select s1/s1 from t1)); +s1 +2 diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index e01310bba45..1bcd37dd7d7 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -1844,4 +1844,20 @@ select 1 from dual where 2 > any (select 1); select 1 from dual where 2 > all (select 1); select 1 from dual where 1 < any (select 2 from dual); select 1 from dual where 1 < all (select 2 from dual where 1!=1); + +# BUG#20975 Wrong query results for subqueries within NOT +create table t1 (s1 char); +insert into t1 values (1),(2); + +select * from t1 where (s1 < any (select s1 from t1)); +select * from t1 where not (s1 < any (select s1 from t1)); + +select * from t1 where (s1 < ALL (select s1+1 from t1)); +select * from t1 where not(s1 < ALL (select s1+1 from t1)); + +select * from t1 where (s1+1 = ANY (select s1 from t1)); +select * from t1 where NOT(s1+1 = ANY (select s1 from t1)); + +select * from t1 where (s1 = ALL (select s1/s1 from t1)); +select * from t1 where NOT(s1 = ALL (select s1/s1 from t1)); # End of 4.1 tests diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index f14efc7187b..a32bd0a7337 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -3099,6 +3099,28 @@ Item *Item_cond_or::neg_transformer(THD *thd) /* NOT(a OR b OR ...) -> */ } +Item *Item_func_nop_all::neg_transformer(THD *thd) +{ + /* "NOT (e $cmp$ ANY (SELECT ...)) -> e $rev_cmp$" ALL (SELECT ...) */ + Item_func_not_all *new_item= new Item_func_not_all(args[0]); + Item_allany_subselect *allany= (Item_allany_subselect*)args[0]; + allany->func= allany->func_creator(FALSE); + allany->all= !allany->all; + allany->upper_item= new_item; + return new_item; +} + +Item *Item_func_not_all::neg_transformer(THD *thd) +{ + /* "NOT (e $cmp$ ALL (SELECT ...)) -> e $rev_cmp$" ANY (SELECT ...) */ + Item_func_nop_all *new_item= new Item_func_nop_all(args[0]); + Item_allany_subselect *allany= (Item_allany_subselect*)args[0]; + allany->all= !allany->all; + allany->func= allany->func_creator(TRUE); + allany->upper_item= new_item; + return new_item; +} + Item *Item_func_eq::negated_item() /* a = b -> a != b */ { return new Item_func_ne(args[0], args[1]); diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 73abe208d9e..0e157fd412c 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -268,6 +268,7 @@ public: void set_sum_test(Item_sum_hybrid *item) { test_sum_item= item; }; void set_sub_test(Item_maxmin_subselect *item) { test_sub_item= item; }; bool empty_underlying_subquery(); + Item *neg_transformer(THD *thd); }; @@ -278,6 +279,7 @@ public: Item_func_nop_all(Item *a) :Item_func_not_all(a) {} longlong val_int(); const char *func_name() const { return ""; } + Item *neg_transformer(THD *thd); }; diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index f6f8eec9af5..c95a91de13e 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -542,14 +542,14 @@ Item_in_subselect::Item_in_subselect(Item * left_exp, } Item_allany_subselect::Item_allany_subselect(Item * left_exp, - Comp_creator *fn, + chooser_compare_func_creator fc, st_select_lex *select_lex, bool all_arg) - :Item_in_subselect(), all(all_arg) + :Item_in_subselect(), all(all_arg), func_creator(fc) { DBUG_ENTER("Item_in_subselect::Item_in_subselect"); left_expr= left_exp; - func= fn; + func= func_creator(all_arg); init(select_lex, new select_exists_subselect(this)); max_columns= 1; abort_on_null= 0; diff --git a/sql/item_subselect.h b/sql/item_subselect.h index dec32398a80..93171ad64a1 100644 --- a/sql/item_subselect.h +++ b/sql/item_subselect.h @@ -251,14 +251,13 @@ public: /* ALL/ANY/SOME subselect */ class Item_allany_subselect :public Item_in_subselect { -protected: - Comp_creator *func; - public: + chooser_compare_func_creator func_creator; + Comp_creator *func; bool all; - Item_allany_subselect(Item * left_expr, Comp_creator *f, - st_select_lex *select_lex, bool all); + Item_allany_subselect(Item * left_expr, chooser_compare_func_creator fc, + st_select_lex *select_lex, bool all); // only ALL subquery has upper not subs_type substype() { return all?ALL_SUBS:ANY_SUBS; } diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index d231942bb7a..d03c6acac7c 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -387,8 +387,9 @@ enum enum_var_type OPT_DEFAULT, OPT_SESSION, OPT_GLOBAL }; class sys_var; -#include "item.h" +class Comp_creator; typedef Comp_creator* (*chooser_compare_func_creator)(bool invert); +#include "item.h" /* sql_parse.cc */ void free_items(Item *item); void cleanup_items(Item *item); diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index fbe36bfdc4a..660c77e81e4 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -5436,7 +5436,7 @@ Item * all_any_subquery_creator(Item *left_expr, return new Item_func_not(new Item_in_subselect(left_expr, select_lex)); Item_allany_subselect *it= - new Item_allany_subselect(left_expr, (*cmp)(all), select_lex, all); + new Item_allany_subselect(left_expr, cmp, select_lex, all); if (all) return it->upper_item= new Item_func_not_all(it); /* ALL */ From 4e59d30dc9ef76c79c8e8c92bfad9b394d4d5c9b Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 21 Jul 2006 11:59:46 +0300 Subject: [PATCH 04/21] Fix for BUG#21007. The problem was that store_top_level_join_columns() incorrectly assumed that the left/right neighbor of a nested join table reference can be only at the same level in the join tree. The fix checks if the current nested join table reference has no immediate left/right neighbor, and if so chooses the left/right neighbors of the nearest upper level, where these references are != NULL. mysql-test/r/group_min_max.result: Test for BUG#21007. mysql-test/t/group_min_max.test: Test for BUG#21007. sql/sql_base.cc: After computing and materializing the columns of all NATURAL joins in a FROM clause, the procedure store_top_level_join_columns() has to change the current natural join into a leaf table reference for name resolution. For this it needs to make the left neighbor point to the natural join table reference, and the natural join itself point to its left neighbor. This fix correctly determines the left/right neighbors of a table reference, even if the neghbors are at higher levels in the nested join tree. The rule is that if a table reference has no immediate left/right neighbors, we recursively pick the left/right neighbor of the level(s) above. --- mysql-test/r/group_min_max.result | 43 +++++++++++++++++++++++++++ mysql-test/t/group_min_max.test | 48 +++++++++++++++++++++++++++++++ sql/sql_base.cc | 38 +++++++++++++++--------- 3 files changed, 116 insertions(+), 13 deletions(-) diff --git a/mysql-test/r/group_min_max.result b/mysql-test/r/group_min_max.result index d62586dba85..fe6f7c4ca55 100644 --- a/mysql-test/r/group_min_max.result +++ b/mysql-test/r/group_min_max.result @@ -2099,3 +2099,46 @@ SOUTH EAST SOUTH EAST SOUTH WEST SOUTH WEST WESTERN WESTERN DROP TABLE t1; +CREATE TABLE t1 (id1 INT, id2 INT); +CREATE TABLE t2 (id2 INT, id3 INT, id5 INT); +CREATE TABLE t3 (id3 INT, id4 INT); +CREATE TABLE t4 (id4 INT); +CREATE TABLE t5 (id5 INT, id6 INT); +CREATE TABLE t6 (id6 INT); +INSERT INTO t1 VALUES(1,1); +INSERT INTO t2 VALUES(1,1,1); +INSERT INTO t3 VALUES(1,1); +INSERT INTO t4 VALUES(1); +INSERT INTO t5 VALUES(1,1); +INSERT INTO t6 VALUES(1); +SELECT * FROM +t1 +NATURAL JOIN +(t2 JOIN (t3 NATURAL JOIN t4, t5 NATURAL JOIN t6) +ON (t3.id3 = t2.id3 AND t5.id5 = t2.id5)); +id2 id1 id3 id5 id4 id3 id6 id5 +1 1 1 1 1 1 1 1 +SELECT * FROM +t1 +NATURAL JOIN +(((t3 NATURAL JOIN t4) join (t5 NATURAL JOIN t6) on t3.id4 = t5.id5) JOIN t2 +ON (t3.id3 = t2.id3 AND t5.id5 = t2.id5)); +id2 id1 id4 id3 id6 id5 id3 id5 +1 1 1 1 1 1 1 1 +SELECT * FROM t1 NATURAL JOIN ((t3 join (t5 NATURAL JOIN t6)) JOIN t2); +id2 id1 id3 id4 id6 id5 id3 id5 +1 1 1 1 1 1 1 1 +SELECT * FROM +(t2 JOIN (t3 NATURAL JOIN t4, t5 NATURAL JOIN t6) +ON (t3.id3 = t2.id3 AND t5.id5 = t2.id5)) +NATURAL JOIN +t1; +id2 id3 id5 id4 id3 id6 id5 id1 +1 1 1 1 1 1 1 1 +SELECT * FROM +(t2 JOIN ((t3 NATURAL JOIN t4) join (t5 NATURAL JOIN t6))) +NATURAL JOIN +t1; +id2 id3 id5 id4 id3 id6 id5 id1 +1 1 1 1 1 1 1 1 +DROP TABLE t1,t2,t3,t4,t5,t6; diff --git a/mysql-test/t/group_min_max.test b/mysql-test/t/group_min_max.test index 874f3cd1a80..5427727a8f4 100644 --- a/mysql-test/t/group_min_max.test +++ b/mysql-test/t/group_min_max.test @@ -746,3 +746,51 @@ EXPLAIN SELECT DISTINCT a,a FROM t1 ORDER BY a; SELECT DISTINCT a,a FROM t1 ORDER BY a; DROP TABLE t1; + +# +# Bug #21007: NATURAL JOIN (any JOIN (2 x NATURAL JOIN)) crashes the server +# + +CREATE TABLE t1 (id1 INT, id2 INT); +CREATE TABLE t2 (id2 INT, id3 INT, id5 INT); +CREATE TABLE t3 (id3 INT, id4 INT); +CREATE TABLE t4 (id4 INT); +CREATE TABLE t5 (id5 INT, id6 INT); +CREATE TABLE t6 (id6 INT); + +INSERT INTO t1 VALUES(1,1); +INSERT INTO t2 VALUES(1,1,1); +INSERT INTO t3 VALUES(1,1); +INSERT INTO t4 VALUES(1); +INSERT INTO t5 VALUES(1,1); +INSERT INTO t6 VALUES(1); + +-- original bug query +SELECT * FROM +t1 + NATURAL JOIN +(t2 JOIN (t3 NATURAL JOIN t4, t5 NATURAL JOIN t6) + ON (t3.id3 = t2.id3 AND t5.id5 = t2.id5)); + +-- inner join swapped +SELECT * FROM +t1 + NATURAL JOIN +(((t3 NATURAL JOIN t4) join (t5 NATURAL JOIN t6) on t3.id4 = t5.id5) JOIN t2 + ON (t3.id3 = t2.id3 AND t5.id5 = t2.id5)); + +-- one join less, no ON cond +SELECT * FROM t1 NATURAL JOIN ((t3 join (t5 NATURAL JOIN t6)) JOIN t2); + +-- wrong error message: 'id2' - ambiguous column +SELECT * FROM +(t2 JOIN (t3 NATURAL JOIN t4, t5 NATURAL JOIN t6) + ON (t3.id3 = t2.id3 AND t5.id5 = t2.id5)) + NATURAL JOIN +t1; +SELECT * FROM +(t2 JOIN ((t3 NATURAL JOIN t4) join (t5 NATURAL JOIN t6))) + NATURAL JOIN +t1; + +DROP TABLE t1,t2,t3,t4,t5,t6; diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 5383bb52aaa..7f9076bb46e 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -4041,36 +4041,48 @@ store_top_level_join_columns(THD *thd, TABLE_LIST *table_ref, if (table_ref->nested_join) { List_iterator_fast nested_it(table_ref->nested_join->join_list); - TABLE_LIST *cur_left_neighbor= nested_it++; - TABLE_LIST *cur_right_neighbor= NULL; + TABLE_LIST *same_level_left_neighbor= nested_it++; + TABLE_LIST *same_level_right_neighbor= NULL; + /* Left/right-most neighbors, possibly at higher levels in the join tree. */ + TABLE_LIST *real_left_neighbor, *real_right_neighbor; - while (cur_left_neighbor) + while (same_level_left_neighbor) { - TABLE_LIST *cur_table_ref= cur_left_neighbor; - cur_left_neighbor= nested_it++; + TABLE_LIST *cur_table_ref= same_level_left_neighbor; + same_level_left_neighbor= nested_it++; /* The order of RIGHT JOIN operands is reversed in 'join list' to transform it into a LEFT JOIN. However, in this procedure we need the join operands in their lexical order, so below we reverse the - join operands. Notice that this happens only in the first loop, and - not in the second one, as in the second loop cur_left_neighbor == NULL. - This is the correct behavior, because the second loop - sets cur_table_ref reference correctly after the join operands are + join operands. Notice that this happens only in the first loop, + and not in the second one, as in the second loop + same_level_left_neighbor == NULL. + This is the correct behavior, because the second loop sets + cur_table_ref reference correctly after the join operands are swapped in the first loop. */ - if (cur_left_neighbor && + if (same_level_left_neighbor && cur_table_ref->outer_join & JOIN_TYPE_RIGHT) { /* This can happen only for JOIN ... ON. */ DBUG_ASSERT(table_ref->nested_join->join_list.elements == 2); - swap_variables(TABLE_LIST*, cur_left_neighbor, cur_table_ref); + swap_variables(TABLE_LIST*, same_level_left_neighbor, cur_table_ref); } + /* + Pick the parent's left and right neighbors if there are no immediate + neighbors at the same level. + */ + real_left_neighbor= (same_level_left_neighbor) ? + same_level_left_neighbor : left_neighbor; + real_right_neighbor= (same_level_right_neighbor) ? + same_level_right_neighbor : right_neighbor; + if (cur_table_ref->nested_join && store_top_level_join_columns(thd, cur_table_ref, - cur_left_neighbor, cur_right_neighbor)) + real_left_neighbor, real_right_neighbor)) goto err; - cur_right_neighbor= cur_table_ref; + same_level_right_neighbor= cur_table_ref; } } From 8024aabb76ffa8d1ea6105ca071b2109766ea2cb Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 21 Jul 2006 17:59:52 +0300 Subject: [PATCH 05/21] Bug #20868: Client connection is broken on SQL query error An aggregate function reference was resolved incorrectly and caused a crash in count_field_types. Must use real_item() to get to the real Item instance through the reference mysql-test/r/func_group.result: Bug #20868: Client connection is broken on SQL query error * test case for the bug mysql-test/t/func_group.test: Bug #20868: Client connection is broken on SQL query error * test case for the bug sql/sql_select.cc: Bug #20868: Client connection is broken on SQL query error * correctly resolve aggregate function references. --- mysql-test/r/func_group.result | 11 +++++++++++ mysql-test/t/func_group.test | 15 +++++++++++++++ sql/sql_select.cc | 2 +- 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/func_group.result b/mysql-test/r/func_group.result index f693c6190d5..896b79297f8 100644 --- a/mysql-test/r/func_group.result +++ b/mysql-test/r/func_group.result @@ -988,3 +988,14 @@ SUM(a) 6 DROP TABLE t1; set div_precision_increment= @sav_dpi; +CREATE TABLE t1 (a INT PRIMARY KEY, b INT); +INSERT INTO t1 VALUES (1,1), (2,2); +CREATE TABLE t2 (a INT PRIMARY KEY, b INT); +INSERT INTO t2 VALUES (1,1), (3,3); +SELECT SQL_NO_CACHE +(SELECT SUM(c.a) FROM t1 ttt, t2 ccc +WHERE ttt.a = ccc.b AND ttt.a = t.a GROUP BY ttt.a) AS minid +FROM t1 t, t2 c WHERE t.a = c.b; +minid +NULL +DROP TABLE t1,t2; diff --git a/mysql-test/t/func_group.test b/mysql-test/t/func_group.test index e8c5fa18a25..f28ce234b73 100644 --- a/mysql-test/t/func_group.test +++ b/mysql-test/t/func_group.test @@ -660,3 +660,18 @@ SELECT SUM(a) FROM t1 GROUP BY b/c; DROP TABLE t1; set div_precision_increment= @sav_dpi; +# +# Bug #20868: Client connection is broken on SQL query error +# +CREATE TABLE t1 (a INT PRIMARY KEY, b INT); +INSERT INTO t1 VALUES (1,1), (2,2); + +CREATE TABLE t2 (a INT PRIMARY KEY, b INT); +INSERT INTO t2 VALUES (1,1), (3,3); + +SELECT SQL_NO_CACHE + (SELECT SUM(c.a) FROM t1 ttt, t2 ccc + WHERE ttt.a = ccc.b AND ttt.a = t.a GROUP BY ttt.a) AS minid +FROM t1 t, t2 c WHERE t.a = c.b; + +DROP TABLE t1,t2; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index a7158960ed0..c31d9d9902b 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -12806,7 +12806,7 @@ count_field_types(TMP_TABLE_PARAM *param, List &fields, { if (! field->const_item()) { - Item_sum *sum_item=(Item_sum*) field; + Item_sum *sum_item=(Item_sum*) field->real_item(); if (!sum_item->quick_group) param->quick_group=0; // UDF SUM function param->sum_func_count++; From 7118c2523c2b8d127ae0e3f2a08f28ee11c1c712 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 21 Jul 2006 20:44:35 +0300 Subject: [PATCH 06/21] Bug #20466: a view is mixing data when there's a trigger on the table When making a place to store field values at the start of each group the real item (not the reference) must be used when deciding which column to copy. mysql-test/r/group_by.result: Bug #20466: a view is mixing data when there's a trigger on the table - test suite for the bug mysql-test/t/group_by.test: Bug #20466: a view is mixing data when there's a trigger on the table - test suite for the bug sql/sql_select.cc: Bug #20466: a view is mixing data when there's a trigger on the table - deal correctly with references --- mysql-test/r/group_by.result | 25 +++++++++++++++++++++++++ mysql-test/t/group_by.test | 23 +++++++++++++++++++++++ sql/sql_select.cc | 16 +++++++++------- 3 files changed, 57 insertions(+), 7 deletions(-) diff --git a/mysql-test/r/group_by.result b/mysql-test/r/group_by.result index 7bc886022cc..e5c177503fa 100644 --- a/mysql-test/r/group_by.result +++ b/mysql-test/r/group_by.result @@ -796,3 +796,28 @@ aaa show warnings; Level Code Message drop table t1, t2; +CREATE TABLE t1 (a tinyint(3), b varchar(255), PRIMARY KEY (a)); +INSERT INTO t1 VALUES (1,'-----'), (6,'Allemagne'), (17,'Autriche'), +(25,'Belgique'), (54,'Danemark'), (62,'Espagne'), (68,'France'); +CREATE TABLE t2 (a tinyint(3), b tinyint(3), PRIMARY KEY (a), KEY b (b)); +INSERT INTO t2 VALUES (1,1), (2,1), (6,6), (18,17), (15,25), (16,25), +(17,25), (10,54), (5,62),(3,68); +CREATE VIEW v1 AS select t1.a, concat(t1.b,'') AS b, t1.b as real_b from t1; +explain +SELECT straight_join sql_no_cache v1.a, v1.b, v1.real_b from t2, v1 +where t2.b=v1.a GROUP BY t2.b; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t2 index b b 2 NULL 10 Using index +1 PRIMARY t1 eq_ref PRIMARY PRIMARY 1 test.t2.b 1 +SELECT straight_join sql_no_cache v1.a, v1.b, v1.real_b from t2, v1 +where t2.b=v1.a GROUP BY t2.b; +a b real_b +1 ----- ----- +6 Allemagne Allemagne +17 Autriche Autriche +25 Belgique Belgique +54 Danemark Danemark +62 Espagne Espagne +68 France France +DROP VIEW v1; +DROP TABLE t1,t2; diff --git a/mysql-test/t/group_by.test b/mysql-test/t/group_by.test index fb9835c5d7f..ce1e4e59600 100644 --- a/mysql-test/t/group_by.test +++ b/mysql-test/t/group_by.test @@ -632,3 +632,26 @@ group by t1.c1; show warnings; drop table t1, t2; +# +# Bug #20466: a view is mixing data when there's a trigger on the table +# +CREATE TABLE t1 (a tinyint(3), b varchar(255), PRIMARY KEY (a)); + +INSERT INTO t1 VALUES (1,'-----'), (6,'Allemagne'), (17,'Autriche'), + (25,'Belgique'), (54,'Danemark'), (62,'Espagne'), (68,'France'); + +CREATE TABLE t2 (a tinyint(3), b tinyint(3), PRIMARY KEY (a), KEY b (b)); + +INSERT INTO t2 VALUES (1,1), (2,1), (6,6), (18,17), (15,25), (16,25), + (17,25), (10,54), (5,62),(3,68); + +CREATE VIEW v1 AS select t1.a, concat(t1.b,'') AS b, t1.b as real_b from t1; + +explain +SELECT straight_join sql_no_cache v1.a, v1.b, v1.real_b from t2, v1 +where t2.b=v1.a GROUP BY t2.b; +SELECT straight_join sql_no_cache v1.a, v1.b, v1.real_b from t2, v1 +where t2.b=v1.a GROUP BY t2.b; + +DROP VIEW v1; +DROP TABLE t1,t2; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index a7158960ed0..39f5b43b05e 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -13066,10 +13066,11 @@ setup_copy_fields(THD *thd, TMP_TABLE_PARAM *param, param->copy_funcs.empty(); for (i= 0; (pos= li++); i++) { - if (pos->real_item()->type() == Item::FIELD_ITEM) + Item *real_pos= pos->real_item(); + if (real_pos->type() == Item::FIELD_ITEM) { Item_field *item; - pos= pos->real_item(); + pos= real_pos; if (!(item= new Item_field(thd, ((Item_field*) pos)))) goto err; pos= item; @@ -13108,12 +13109,13 @@ setup_copy_fields(THD *thd, TMP_TABLE_PARAM *param, } } } - else if ((pos->type() == Item::FUNC_ITEM || - pos->type() == Item::SUBSELECT_ITEM || - pos->type() == Item::CACHE_ITEM || - pos->type() == Item::COND_ITEM) && - !pos->with_sum_func) + else if ((real_pos->type() == Item::FUNC_ITEM || + real_pos->type() == Item::SUBSELECT_ITEM || + real_pos->type() == Item::CACHE_ITEM || + real_pos->type() == Item::COND_ITEM) && + !real_pos->with_sum_func) { // Save for send fields + pos= real_pos; /* TODO: In most cases this result will be sent to the user. This should be changed to use copy_int or copy_real depending From 35209c68eab3137bf40ca1657a2404006c2aa392 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 22 Jul 2006 02:08:00 +0400 Subject: [PATCH 07/21] Fixed bug#12185: Data type aggregation may produce wrong result The Item::tmp_table_field_from_field_type() function creates Field_datetime object instead of Field_timestamp object for timestamp field thus always changing data type is a tmp table is used. The Field_blob object constructor which is used in the Item::tmp_table_field_from_field_type() is always setting packlength field of newly created blob to 4. This leads to changing fields data type for example from the blob to the longblob if a temporary table is used. The Item::make_string_field() function always converts Field_string objects to Field_varstring objects. This leads to changing data type from the char/binary to varchar/varbinary. Added appropriate Field_timestamp object constructor for using in the Item::tmp_table_field_from_field_type() function. Added Field_blob object constructor which sets pack length according to max_length argument. The Item::tmp_table_field_from_field_type() function now creates Field_timestamp object for a timestamp field. The Item_type_holder::display_length() now returns correct NULL length NULL length. The Item::make_string_field() function now doesn't change Field_string to Field_varstring in the case of Item_type_holder. The Item::tmp_table_field_from_field_type() function now uses the Field_blob constructor which sets packlength according to max_length. mysql-test/t/union.test: Added test case for bug#12185: Data type aggregation may produce wrong result Corrected test case after fix for bug#12185 mysql-test/t/innodb.test: Corrected test case after fix for bug#12185 mysql-test/r/union.result: Added test case for bug#12185: Data type aggregation may produce wrong result Corrected test case after fix for bug#12185 mysql-test/r/innodb.result: Corrected test case after fix for bug#12185 mysql-test/r/create.result: Corrected the test case after fixing bug#12185 sql/field.h: Fixed bug#12185: Data type aggregation may produce wrong result Added Field_blob object constructor which sets packlength according to max_length argument. sql/item.cc: Fixed bug#12185: Data type aggregation may produce wrong result The Item::make_string_field() function now doesn't change Field_string to Field_varstring in the case of Item_type_holder. The Item::tmp_table_field_from_field_type() function now creates Field_timestamp object for a timestamp field. The Item::tmp_table_field_from_field_type() function now uses the Field_blob constructor which sets packlength according to max_length. The Item_type_holder::display_length() now returns correct NULL length NULL length. sql/field.cc: Fixed bug#12185: Data type aggregation may produce wrong result Added appropriate Field_timestamp object constructor for using in the Item::tmp_table_field_from_field_type() function. --- mysql-test/r/create.result | 2 +- mysql-test/r/innodb.result | 4 ++-- mysql-test/r/union.result | 31 +++++++++++++++++++++++-------- mysql-test/t/innodb.test | 2 +- mysql-test/t/union.test | 12 ++++++++++-- sql/field.cc | 18 ++++++++++++++++++ sql/field.h | 17 +++++++++++++++++ sql/item.cc | 13 ++++++++++--- 8 files changed, 82 insertions(+), 17 deletions(-) diff --git a/mysql-test/r/create.result b/mysql-test/r/create.result index 27a6c8a9d03..0bc5ec32086 100644 --- a/mysql-test/r/create.result +++ b/mysql-test/r/create.result @@ -452,7 +452,7 @@ t2 CREATE TABLE `t2` ( `ifnull(h,h)` decimal(5,4) default NULL, `ifnull(i,i)` year(4) default NULL, `ifnull(j,j)` date default NULL, - `ifnull(k,k)` datetime NOT NULL default '0000-00-00 00:00:00', + `ifnull(k,k)` timestamp NOT NULL default '0000-00-00 00:00:00', `ifnull(l,l)` datetime default NULL, `ifnull(m,m)` varchar(1) default NULL, `ifnull(n,n)` varchar(3) default NULL, diff --git a/mysql-test/r/innodb.result b/mysql-test/r/innodb.result index 77046cc1fd1..1d1f26e4b01 100644 --- a/mysql-test/r/innodb.result +++ b/mysql-test/r/innodb.result @@ -1473,8 +1473,8 @@ Error 1146 Table 'test.t4' doesn't exist drop table t1,t2,t3; create table t1 (id int, name char(10) not null, name2 char(10) not null) engine=innodb; insert into t1 values(1,'first','fff'),(2,'second','sss'),(3,'third','ttt'); -select name2 from t1 union all select name from t1 union all select id from t1; -name2 +select trim(name2) from t1 union all select trim(name) from t1 union all select trim(id) from t1; +trim(name2) fff sss ttt diff --git a/mysql-test/r/union.result b/mysql-test/r/union.result index eb9e10aa58d..6ef5363d90f 100644 --- a/mysql-test/r/union.result +++ b/mysql-test/r/union.result @@ -691,9 +691,9 @@ t1 CREATE TABLE `t1` ( `da` datetime default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1; -create table t1 SELECT dt from t2 UNION select sc from t2; -select * from t1; -dt +create table t1 SELECT dt from t2 UNION select trim(sc) from t2; +select trim(dt) from t1; +trim(dt) 1972-10-22 11:50:00 testc show create table t1; @@ -732,7 +732,7 @@ tetetetetest show create table t1; Table Create Table t1 CREATE TABLE `t1` ( - `dt` longblob + `dt` blob ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1; create table t1 SELECT sv from t2 UNION select b from t2; @@ -743,7 +743,7 @@ tetetetetest show create table t1; Table Create Table t1 CREATE TABLE `t1` ( - `sv` longblob + `sv` blob ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1; create table t1 SELECT i from t2 UNION select d from t2 UNION select b from t2; @@ -755,7 +755,7 @@ tetetetetest show create table t1; Table Create Table t1 CREATE TABLE `t1` ( - `i` longblob + `i` blob ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1; create table t1 SELECT sv from t2 UNION select tx from t2; @@ -766,7 +766,7 @@ teeeeeeeeeeeest show create table t1; Table Create Table t1 CREATE TABLE `t1` ( - `sv` longtext + `sv` text ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1; create table t1 SELECT b from t2 UNION select tx from t2; @@ -777,7 +777,7 @@ teeeeeeeeeeeest show create table t1; Table Create Table t1 CREATE TABLE `t1` ( - `b` longblob + `b` blob ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1,t2; create table t1 select 1 union select -1; @@ -1306,3 +1306,18 @@ id 5 99 drop table t1; +create table t1(f1 char(1), f2 char(5), f3 binary(1), f4 binary(5), f5 timestamp, f6 varchar(1) character set utf8 collate utf8_general_ci, f7 text); +create table t2 as select *, f6 as f8 from t1 union select *, f7 from t1; +show create table t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `f1` char(1) default NULL, + `f2` char(5) default NULL, + `f3` binary(1) default NULL, + `f4` binary(5) default NULL, + `f5` timestamp NOT NULL default '0000-00-00 00:00:00', + `f6` varchar(1) character set utf8 default NULL, + `f7` text, + `f8` text character set utf8 +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t1, t2; diff --git a/mysql-test/t/innodb.test b/mysql-test/t/innodb.test index e4c8bf89cca..4ebfef3504e 100644 --- a/mysql-test/t/innodb.test +++ b/mysql-test/t/innodb.test @@ -1079,7 +1079,7 @@ drop table t1,t2,t3; # create table t1 (id int, name char(10) not null, name2 char(10) not null) engine=innodb; insert into t1 values(1,'first','fff'),(2,'second','sss'),(3,'third','ttt'); -select name2 from t1 union all select name from t1 union all select id from t1; +select trim(name2) from t1 union all select trim(name) from t1 union all select trim(id) from t1; drop table t1; # diff --git a/mysql-test/t/union.test b/mysql-test/t/union.test index 692f1f509fa..516bc6d4818 100644 --- a/mysql-test/t/union.test +++ b/mysql-test/t/union.test @@ -390,8 +390,8 @@ create table t1 SELECT da from t2 UNION select dt from t2; select * from t1; show create table t1; drop table t1; -create table t1 SELECT dt from t2 UNION select sc from t2; -select * from t1; +create table t1 SELECT dt from t2 UNION select trim(sc) from t2; +select trim(dt) from t1; show create table t1; drop table t1; create table t1 SELECT dt from t2 UNION select sv from t2; @@ -793,3 +793,11 @@ select id from t1 union all select 99 order by 1; drop table t1; # End of 4.1 tests + +# +# Bug#12185: Data type aggregation may produce wrong result +# +create table t1(f1 char(1), f2 char(5), f3 binary(1), f4 binary(5), f5 timestamp, f6 varchar(1) character set utf8 collate utf8_general_ci, f7 text); +create table t2 as select *, f6 as f8 from t1 union select *, f7 from t1; +show create table t2; +drop table t1, t2; diff --git a/sql/field.cc b/sql/field.cc index a920d6d91b1..163822fe712 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -4484,6 +4484,24 @@ Field_timestamp::Field_timestamp(char *ptr_arg, uint32 len_arg, } +Field_timestamp::Field_timestamp(bool maybe_null_arg, + const char *field_name_arg, + struct st_table *table_arg, CHARSET_INFO *cs) + :Field_str((char*) 0, 19, maybe_null_arg ? (uchar*) "": 0, 0, + NONE, field_name_arg, table_arg, cs) +{ + /* For 4.0 MYD and 4.0 InnoDB compatibility */ + flags|= ZEROFILL_FLAG | UNSIGNED_FLAG; + if (table && !table->timestamp_field && + unireg_check != NONE) + { + /* This timestamp has auto-update */ + table->timestamp_field= this; + flags|=TIMESTAMP_FLAG; + } +} + + /* Get auto-set type for TIMESTAMP field. diff --git a/sql/field.h b/sql/field.h index f4d27e46877..3aeb5e03259 100644 --- a/sql/field.h +++ b/sql/field.h @@ -781,6 +781,8 @@ public: enum utype unireg_check_arg, const char *field_name_arg, struct st_table *table_arg, CHARSET_INFO *cs); + Field_timestamp(bool maybe_null_arg, const char *field_name_arg, + struct st_table *table_arg, CHARSET_INFO *cs); enum_field_types type() const { return FIELD_TYPE_TIMESTAMP;} enum ha_base_keytype key_type() const { return HA_KEYTYPE_ULONG_INT; } enum Item_result cmp_type () const { return INT_RESULT; } @@ -1129,6 +1131,21 @@ public: { flags|= BLOB_FLAG; } + Field_blob(uint32 len_arg,bool maybe_null_arg, const char *field_name_arg, + struct st_table *table_arg, CHARSET_INFO *cs, bool set_packlength) + :Field_longstr((char*) 0,len_arg, maybe_null_arg ? (uchar*) "": 0, 0, + NONE, field_name_arg, table_arg, cs) + { + flags|= BLOB_FLAG; + packlength= 4; + if (set_packlength) + { + uint32 char_lengt= len_arg/cs->mbmaxlen; + packlength= char_length <= 255 ? 1 : + char_length <= 65535 ? 2 : + char_length <= 16777215 ? 3 : 4; + } + } enum_field_types type() const { return FIELD_TYPE_BLOB;} enum ha_base_keytype key_type() const { return binary() ? HA_KEYTYPE_VARBINARY2 : HA_KEYTYPE_VARTEXT2; } diff --git a/sql/item.cc b/sql/item.cc index 24efc1f106f..c7208a3af64 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -3874,7 +3874,9 @@ Field *Item::make_string_field(TABLE *table) if (max_length/collation.collation->mbmaxlen > CONVERT_IF_BIGGER_TO_BLOB) return new Field_blob(max_length, maybe_null, name, table, collation.collation); - if (max_length > 0) + /* Item_type_holder holds the exact type, do not change it */ + if (max_length > 0 && + (type() != Item::TYPE_HOLDER || field_type() != MYSQL_TYPE_STRING)) return new Field_varstring(max_length, maybe_null, name, table, collation.collation); return new Field_string(max_length, maybe_null, name, table, @@ -3938,6 +3940,7 @@ Field *Item::tmp_table_field_from_field_type(TABLE *table) case MYSQL_TYPE_TIME: return new Field_time(maybe_null, name, table, &my_charset_bin); case MYSQL_TYPE_TIMESTAMP: + return new Field_timestamp(maybe_null, name, table, &my_charset_bin); case MYSQL_TYPE_DATETIME: return new Field_datetime(maybe_null, name, table, &my_charset_bin); case MYSQL_TYPE_YEAR: @@ -3961,7 +3964,11 @@ Field *Item::tmp_table_field_from_field_type(TABLE *table) case MYSQL_TYPE_LONG_BLOB: case MYSQL_TYPE_BLOB: case MYSQL_TYPE_GEOMETRY: - return new Field_blob(max_length, maybe_null, name, table, + if (this->type() == Item::TYPE_HOLDER) + return new Field_blob(max_length, maybe_null, name, table, + collation.collation, 1); + else + return new Field_blob(max_length, maybe_null, name, table, collation.collation); break; // Blob handled outside of case } @@ -6117,7 +6124,7 @@ uint32 Item_type_holder::display_length(Item *item) case MYSQL_TYPE_DOUBLE: return 53; case MYSQL_TYPE_NULL: - return 4; + return 0; case MYSQL_TYPE_LONGLONG: return 20; case MYSQL_TYPE_INT24: From 9d432f0dae740bcaa89b61a9b8fced23030d5a13 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 22 Jul 2006 02:36:17 +0400 Subject: [PATCH 08/21] Add missing "DROP TABLE" clause --- mysql-test/r/subselect.result | 1 + mysql-test/t/subselect.test | 1 + 2 files changed, 2 insertions(+) diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index 595d80f1218..a2a88be8c42 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -2894,3 +2894,4 @@ s1 select * from t1 where NOT(s1 = ALL (select s1/s1 from t1)); s1 2 +drop table t1; diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index 1bcd37dd7d7..fc97d22cbb1 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -1860,4 +1860,5 @@ select * from t1 where NOT(s1+1 = ANY (select s1 from t1)); select * from t1 where (s1 = ALL (select s1/s1 from t1)); select * from t1 where NOT(s1 = ALL (select s1/s1 from t1)); +drop table t1; # End of 4.1 tests From 5a3a1c98a42fbb045303f766f53bfdd033ed795c Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 22 Jul 2006 05:52:37 +0400 Subject: [PATCH 09/21] field.h: Fixed typo. sql/field.h: Fixed typo. --- sql/field.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/field.h b/sql/field.h index 0bbcd1099a0..d89d8bb3965 100644 --- a/sql/field.h +++ b/sql/field.h @@ -1141,7 +1141,7 @@ public: packlength= 4; if (set_packlength) { - uint32 char_lengt= len_arg/cs->mbmaxlen; + uint32 char_length= len_arg/cs->mbmaxlen; packlength= char_length <= 255 ? 1 : char_length <= 65535 ? 2 : char_length <= 16777215 ? 3 : 4; From 0f5797f57697750a6177e4dbe3c04a4fefcdae41 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 22 Jul 2006 16:18:28 +0400 Subject: [PATCH 10/21] Post-merge fixes --- sql/item_subselect.cc | 2 +- sql/mysql_priv.h | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 3c279d827b2..6675c9e7b25 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -575,7 +575,7 @@ Item_allany_subselect::Item_allany_subselect(Item * left_exp, chooser_compare_func_creator fc, st_select_lex *select_lex, bool all_arg) - :Item_in_subselect(), all(all_arg), func_creator(fc) + :Item_in_subselect(), func_creator(fc), all(all_arg) { DBUG_ENTER("Item_in_subselect::Item_in_subselect"); left_expr= left_exp; diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 619755fc6ff..3298b4e6c8e 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -523,6 +523,8 @@ class sys_var; class Comp_creator; typedef Comp_creator* (*chooser_compare_func_creator)(bool invert); #include "item.h" +extern my_decimal decimal_zero; + /* sql_parse.cc */ void free_items(Item *item); void cleanup_items(Item *item); From 43df9fd34c2d2b05a29b17e39920ab270f82d483 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 22 Jul 2006 12:44:54 -0700 Subject: [PATCH 11/21] Fixed bug #18925: wrong results for queries with subqueries on information schema that use MIN/MAX aggregation. Execution of some correlated subqueries may set the value of null_row to 1 for tables used in the subquery. If the the subquery is on information schema it causes rejection of any row for the following executions of the subquery in the case when an optimization filtering by some condition is applied. The fix restores the value of the null_row flag for each execution of a subquery on information schema. mysql-test/r/information_schema.result: Added a test case for bug #18925. mysql-test/t/information_schema.test: Added a test case for bug #18925. sql/sql_show.cc: Fixed bug #18925. Execution of some correlated subqueries may set the value of null_row to 1 for tables used in the subquery. If the the subquery is on information schema it causes rejection of any row for the following execitions of the subquery in the case when an optimization filtering by some condition is applied. The fix restores the value of the null_row flag for each execution of a subquery on information schema. --- mysql-test/r/information_schema.result | 62 ++++++++++++++++++++++++++ mysql-test/t/information_schema.test | 33 ++++++++++++++ sql/sql_show.cc | 1 + 3 files changed, 96 insertions(+) diff --git a/mysql-test/r/information_schema.result b/mysql-test/r/information_schema.result index a2feba7ad5d..3b3669119d5 100644 --- a/mysql-test/r/information_schema.result +++ b/mysql-test/r/information_schema.result @@ -1170,3 +1170,65 @@ f1() DROP FUNCTION f1; DROP PROCEDURE p1; DROP USER mysql_bug20230@localhost; +SELECT t.table_name, c1.column_name +FROM information_schema.tables t +INNER JOIN +information_schema.columns c1 +ON t.table_schema = c1.table_schema AND +t.table_name = c1.table_name +WHERE t.table_schema = 'information_schema' AND +c1.ordinal_position = +( SELECT COALESCE(MIN(c2.ordinal_position),1) +FROM information_schema.columns c2 +WHERE c2.table_schema = t.table_schema AND +c2.table_name = t.table_name AND +c2.column_name LIKE '%SCHEMA%' + ); +table_name column_name +CHARACTER_SETS CHARACTER_SET_NAME +COLLATIONS COLLATION_NAME +COLLATION_CHARACTER_SET_APPLICABILITY COLLATION_NAME +COLUMNS TABLE_SCHEMA +COLUMN_PRIVILEGES TABLE_SCHEMA +KEY_COLUMN_USAGE CONSTRAINT_SCHEMA +ROUTINES ROUTINE_SCHEMA +SCHEMATA SCHEMA_NAME +SCHEMA_PRIVILEGES TABLE_SCHEMA +STATISTICS TABLE_SCHEMA +TABLES TABLE_SCHEMA +TABLE_CONSTRAINTS CONSTRAINT_SCHEMA +TABLE_PRIVILEGES TABLE_SCHEMA +TRIGGERS TRIGGER_SCHEMA +USER_PRIVILEGES GRANTEE +VIEWS TABLE_SCHEMA +SELECT t.table_name, c1.column_name +FROM information_schema.tables t +INNER JOIN +information_schema.columns c1 +ON t.table_schema = c1.table_schema AND +t.table_name = c1.table_name +WHERE t.table_schema = 'information_schema' AND +c1.ordinal_position = +( SELECT COALESCE(MIN(c2.ordinal_position),1) +FROM information_schema.columns c2 +WHERE c2.table_schema = 'information_schema' AND +c2.table_name = t.table_name AND +c2.column_name LIKE '%SCHEMA%' + ); +table_name column_name +CHARACTER_SETS CHARACTER_SET_NAME +COLLATIONS COLLATION_NAME +COLLATION_CHARACTER_SET_APPLICABILITY COLLATION_NAME +COLUMNS TABLE_SCHEMA +COLUMN_PRIVILEGES TABLE_SCHEMA +KEY_COLUMN_USAGE CONSTRAINT_SCHEMA +ROUTINES ROUTINE_SCHEMA +SCHEMATA SCHEMA_NAME +SCHEMA_PRIVILEGES TABLE_SCHEMA +STATISTICS TABLE_SCHEMA +TABLES TABLE_SCHEMA +TABLE_CONSTRAINTS CONSTRAINT_SCHEMA +TABLE_PRIVILEGES TABLE_SCHEMA +TRIGGERS TRIGGER_SCHEMA +USER_PRIVILEGES GRANTEE +VIEWS TABLE_SCHEMA diff --git a/mysql-test/t/information_schema.test b/mysql-test/t/information_schema.test index a2e19112cf9..b49ec9e2f31 100644 --- a/mysql-test/t/information_schema.test +++ b/mysql-test/t/information_schema.test @@ -887,4 +887,37 @@ DROP FUNCTION f1; DROP PROCEDURE p1; DROP USER mysql_bug20230@localhost; +# +# Bug#18925: subqueries with MIN/MAX functions on INFORMARTION_SCHEMA +# + +SELECT t.table_name, c1.column_name + FROM information_schema.tables t + INNER JOIN + information_schema.columns c1 + ON t.table_schema = c1.table_schema AND + t.table_name = c1.table_name + WHERE t.table_schema = 'information_schema' AND + c1.ordinal_position = + ( SELECT COALESCE(MIN(c2.ordinal_position),1) + FROM information_schema.columns c2 + WHERE c2.table_schema = t.table_schema AND + c2.table_name = t.table_name AND + c2.column_name LIKE '%SCHEMA%' + ); +SELECT t.table_name, c1.column_name + FROM information_schema.tables t + INNER JOIN + information_schema.columns c1 + ON t.table_schema = c1.table_schema AND + t.table_name = c1.table_name + WHERE t.table_schema = 'information_schema' AND + c1.ordinal_position = + ( SELECT COALESCE(MIN(c2.ordinal_position),1) + FROM information_schema.columns c2 + WHERE c2.table_schema = 'information_schema' AND + c2.table_name = t.table_name AND + c2.column_name LIKE '%SCHEMA%' + ); + # End of 5.0 tests. diff --git a/sql/sql_show.cc b/sql/sql_show.cc index cabb04c5f16..e2adefb0ca9 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -3963,6 +3963,7 @@ bool get_schema_tables_result(JOIN *join) table_list->table->file->delete_all_rows(); free_io_cache(table_list->table); filesort_free_buffers(table_list->table); + table_list->table->null_row= 0; } else table_list->table->file->records= 0; From d64f605e48d42bc9a8fa33e206e427eab69b1a24 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 24 Jul 2006 19:05:46 -0700 Subject: [PATCH 12/21] Fixed bug #21231: wrong results for a simple query with a a non-correlated single-row subquery over information schema. The function get_all_tables filling all information schema tables reset lex->sql_command to SQLCOM_SHOW_FIELDS. After this the function could evaluate partial conditions related to some columns. If these conditions contained a subquery over information schema it led to a wrong evaluation and a wrong result set. This bug was already fixed in 5.1. This patch follows the way how it was done in 5.1 where the value of lex->sql_command is set to SQLCOM_SHOW_FIELDS in get_all_tables only for the calls of the function open_normal_and_derived_tables and is restored after these calls. mysql-test/r/information_schema.result: Added a test case for bug #21231. mysql-test/t/information_schema.test: Added a test case for bug #21231. --- mysql-test/r/information_schema.result | 8 ++++++++ mysql-test/t/information_schema.test | 10 ++++++++++ sql/sql_show.cc | 16 ++++++++++------ 3 files changed, 28 insertions(+), 6 deletions(-) diff --git a/mysql-test/r/information_schema.result b/mysql-test/r/information_schema.result index 3b3669119d5..652af1c8387 100644 --- a/mysql-test/r/information_schema.result +++ b/mysql-test/r/information_schema.result @@ -1232,3 +1232,11 @@ TABLE_PRIVILEGES TABLE_SCHEMA TRIGGERS TRIGGER_SCHEMA USER_PRIVILEGES GRANTEE VIEWS TABLE_SCHEMA +SELECT MAX(table_name) FROM information_schema.tables; +MAX(table_name) +VIEWS +SELECT table_name from information_schema.tables +WHERE table_name=(SELECT MAX(table_name) +FROM information_schema.tables); +table_name +VIEWS diff --git a/mysql-test/t/information_schema.test b/mysql-test/t/information_schema.test index b49ec9e2f31..9e5dac8b853 100644 --- a/mysql-test/t/information_schema.test +++ b/mysql-test/t/information_schema.test @@ -920,4 +920,14 @@ SELECT t.table_name, c1.column_name c2.column_name LIKE '%SCHEMA%' ); +# +# Bug#21231: query with a simple non-correlated subquery over +# INFORMARTION_SCHEMA.TABLES +# + +SELECT MAX(table_name) FROM information_schema.tables; +SELECT table_name from information_schema.tables + WHERE table_name=(SELECT MAX(table_name) + FROM information_schema.tables); + # End of 5.0 tests. diff --git a/sql/sql_show.cc b/sql/sql_show.cc index e2adefb0ca9..e22873dad9a 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -2116,12 +2116,6 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) LINT_INIT(end); LINT_INIT(len); - /* - Let us set fake sql_command so views won't try to merge - themselves into main statement. - */ - lex->sql_command= SQLCOM_SHOW_FIELDS; - lex->reset_n_backup_query_tables_list(&query_tables_list_backup); /* @@ -2144,8 +2138,16 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) I_S tables will be done. */ thd->temporary_tables= open_tables_state_backup.temporary_tables; + /* + Let us set fake sql_command so views won't try to merge + themselves into main statement. If we don't do this, + SELECT * from information_schema.xxxx will cause problems. + SQLCOM_SHOW_FIELDS is used because it satisfies 'only_view_structure()' + */ + lex->sql_command= SQLCOM_SHOW_FIELDS; res= open_normal_and_derived_tables(thd, show_table_list, MYSQL_LOCK_IGNORE_FLUSH); + lex->sql_command= save_sql_command; /* get_all_tables() returns 1 on failure and 0 on success thus return only these and not the result code of ::process_table() @@ -2267,8 +2269,10 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) TABLE_LIST *show_table_list= (TABLE_LIST*) sel.table_list.first; lex->all_selects_list= &sel; lex->derived_tables= 0; + lex->sql_command= SQLCOM_SHOW_FIELDS; res= open_normal_and_derived_tables(thd, show_table_list, MYSQL_LOCK_IGNORE_FLUSH); + lex->sql_command= save_sql_command; /* We should use show_table_list->alias instead of show_table_list->table_name because table_name From 4e7121c07b0cfb5ed39e25edd9022ba1811d65fa Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 25 Jul 2006 11:45:10 +0300 Subject: [PATCH 13/21] Bug#16712: group_concat returns odd srting insead of intended result when calculating GROUP_CONCAT all blob fields are transformed to varchar when making the temp table. However a varchar has at max 2 bytes for length. This fix makes the conversion only for blobs whose max length is below that limit. Otherwise blob field is created by make_string_field() call. mysql-test/r/func_gconcat.result: Bug#16712: group_concat returns odd srting insead of intended result * testsuite for the bug mysql-test/t/func_gconcat.test: Bug#16712: group_concat returns odd srting insead of intended result * testsuite for the bug sql/item_sum.cc: Bug#16712: group_concat returns odd srting insead of intended result * force blob->varchar conversion for small enough blobs only sql/sql_select.cc: Bug#16712: group_concat returns odd srting insead of intended result * force blob->varchar conversion for small enough blobs only --- mysql-test/r/func_gconcat.result | 13 +++++++++++++ mysql-test/t/func_gconcat.test | 14 ++++++++++++++ sql/item_sum.cc | 8 +++++++- sql/sql_select.cc | 14 ++++++++++++-- 4 files changed, 46 insertions(+), 3 deletions(-) diff --git a/mysql-test/r/func_gconcat.result b/mysql-test/r/func_gconcat.result index d8a539da3fe..dc09a68682c 100644 --- a/mysql-test/r/func_gconcat.result +++ b/mysql-test/r/func_gconcat.result @@ -641,3 +641,16 @@ select charset(group_concat(c1 order by c2)) from t1; charset(group_concat(c1 order by c2)) latin1 drop table t1; +CREATE TABLE t1 (a INT(10), b LONGTEXT, PRIMARY KEY (a)); +SET GROUP_CONCAT_MAX_LEN = 20000000; +INSERT INTO t1 VALUES (1,REPEAT(CONCAT('A',CAST(CHAR(0) AS BINARY),'B'), 40000)); +INSERT INTO t1 SELECT a + 1, b FROM t1; +SELECT a, CHAR_LENGTH(b) FROM t1; +a CHAR_LENGTH(b) +1 120000 +2 120000 +SELECT CHAR_LENGTH( GROUP_CONCAT(b) ) FROM t1; +CHAR_LENGTH( GROUP_CONCAT(b) ) +240001 +SET GROUP_CONCAT_MAX_LEN = 1024; +DROP TABLE t1; diff --git a/mysql-test/t/func_gconcat.test b/mysql-test/t/func_gconcat.test index fbfdfa3b5d0..98c21986aa9 100644 --- a/mysql-test/t/func_gconcat.test +++ b/mysql-test/t/func_gconcat.test @@ -433,3 +433,17 @@ create table t1 (c1 varchar(10), c2 int); select charset(group_concat(c1 order by c2)) from t1; drop table t1; +# +# Bug #16712: group_concat returns odd string instead of intended result +# +CREATE TABLE t1 (a INT(10), b LONGTEXT, PRIMARY KEY (a)); + +SET GROUP_CONCAT_MAX_LEN = 20000000; + +INSERT INTO t1 VALUES (1,REPEAT(CONCAT('A',CAST(CHAR(0) AS BINARY),'B'), 40000)); +INSERT INTO t1 SELECT a + 1, b FROM t1; + +SELECT a, CHAR_LENGTH(b) FROM t1; +SELECT CHAR_LENGTH( GROUP_CONCAT(b) ) FROM t1; +SET GROUP_CONCAT_MAX_LEN = 1024; +DROP TABLE t1; diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 877eb908d27..69b93909b3c 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -377,7 +377,13 @@ Field *Item_sum::create_tmp_field(bool group, TABLE *table, case INT_RESULT: return new Field_longlong(max_length,maybe_null,name,table,unsigned_flag); case STRING_RESULT: - if (max_length/collation.collation->mbmaxlen > 255 && convert_blob_length) + /* + Make sure that the blob fits into a Field_varstring which has + 2-byte lenght. + */ + if (max_length/collation.collation->mbmaxlen > 255 && + max_length/collation.collation->mbmaxlen < UINT_MAX16 && + convert_blob_length) return new Field_varstring(convert_blob_length, maybe_null, name, table, collation.collation); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 41ff9185cfb..6f3e6d8868d 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -8011,7 +8011,12 @@ Field* create_tmp_field_from_field(THD *thd, Field* org_field, { Field *new_field; - if (convert_blob_length && (org_field->flags & BLOB_FLAG)) + /* + Make sure that the blob fits into a Field_varstring which has + 2-byte lenght. + */ + if (convert_blob_length && convert_blob_length < UINT_MAX16 && + (org_field->flags & BLOB_FLAG)) new_field= new Field_varstring(convert_blob_length, org_field->maybe_null(), org_field->field_name, table, @@ -8087,8 +8092,13 @@ static Field *create_tmp_field_from_item(THD *thd, Item *item, TABLE *table, if ((type= item->field_type()) == MYSQL_TYPE_DATETIME || type == MYSQL_TYPE_TIME || type == MYSQL_TYPE_DATE) new_field= item->tmp_table_field_from_field_type(table); + /* + Make sure that the blob fits into a Field_varstring which has + 2-byte lenght. + */ else if (item->max_length/item->collation.collation->mbmaxlen > 255 && - convert_blob_length) + item->max_length/item->collation.collation->mbmaxlen < UINT_MAX16 + && convert_blob_length) new_field= new Field_varstring(convert_blob_length, maybe_null, item->name, table, item->collation.collation); From 1b3cdb6085c944e1c371779d4d4b6473ebcd116d Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 25 Jul 2006 18:42:49 +0300 Subject: [PATCH 14/21] Bug #21086: server crashes when VIEW defined with a SELECT with COLLATE clause is called When executing INSERT over a view with calculated columns it was assuming all elements of the fields collection are actually Item_field instances. This may not be true when inserting into a view and that view has columns that are such expressions that allow updating (like setting a collation for example). Corrected to access field information through the filed_for_view_update() function and retrieve correctly the field info even for "update-friendly" non-Item_field items. mysql-test/r/view.result: Bug #21086: server crashes when VIEW defined with a SELECT with COLLATE clause is called - test suite mysql-test/t/view.test: Bug #21086: server crashes when VIEW defined with a SELECT with COLLATE clause is called - test suite sql/item_strfunc.h: Bug #21086: server crashes when VIEW defined with a SELECT with COLLATE clause is called - obvious typo fixed sql/sql_base.cc: Bug #21086: server crashes when VIEW defined with a SELECT with COLLATE clause is called - must access field information through the filed_for_view_update() function to retrieve correctly the field info even for "update-friendly" non-Item_field items. --- mysql-test/r/view.result | 13 +++++++++++++ mysql-test/t/view.test | 19 +++++++++++++++++++ sql/item_strfunc.h | 2 +- sql/sql_base.cc | 9 +++++++-- 4 files changed, 40 insertions(+), 3 deletions(-) diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index c8a673e2209..b2c65423b59 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -2807,3 +2807,16 @@ yadda yad DROP VIEW v1; DROP TABLE t1; +CREATE TABLE t1 (s1 char); +INSERT INTO t1 VALUES ('Z'); +CREATE VIEW v1 AS SELECT s1 collate latin1_german1_ci AS col FROM t1; +CREATE VIEW v2 (col) AS SELECT s1 collate latin1_german1_ci FROM t1; +INSERT INTO v1 (col) VALUES ('b'); +INSERT INTO v2 (col) VALUES ('c'); +SELECT s1 FROM t1; +s1 +Z +b +c +DROP VIEW v1, v2; +DROP TABLE t1; diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index 6399cef9086..1b930353ca4 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -2667,3 +2667,22 @@ SELECT * FROM v1; DROP VIEW v1; DROP TABLE t1; + +# +# Bug #21086: server crashes when VIEW defined with a SELECT with COLLATE +# clause is called +# +CREATE TABLE t1 (s1 char); +INSERT INTO t1 VALUES ('Z'); + +CREATE VIEW v1 AS SELECT s1 collate latin1_german1_ci AS col FROM t1; + +CREATE VIEW v2 (col) AS SELECT s1 collate latin1_german1_ci FROM t1; + +# either of these statements will cause crash +INSERT INTO v1 (col) VALUES ('b'); +INSERT INTO v2 (col) VALUES ('c'); + +SELECT s1 FROM t1; +DROP VIEW v1, v2; +DROP TABLE t1; diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index a72182abcf7..488dc20b063 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -728,7 +728,7 @@ public: void fix_length_and_dec(); bool eq(const Item *item, bool binary_cmp) const; const char *func_name() const { return "collate"; } - enum Functype func_type() const { return COLLATE_FUNC; } + enum Functype functype() const { return COLLATE_FUNC; } void print(String *str); Item_field *filed_for_view_update() { diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 7f9076bb46e..28edee5c729 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -4959,12 +4959,17 @@ fill_record(THD * thd, List &fields, List &values, bool ignore_errors) { List_iterator_fast f(fields),v(values); - Item *value; + Item *value, *fld; Item_field *field; DBUG_ENTER("fill_record"); - while ((field=(Item_field*) f++)) + while ((fld= f++)) { + if (!(field= fld->filed_for_view_update())) + { + my_error(ER_NONUPDATEABLE_COLUMN, MYF(0), fld->name); + DBUG_RETURN(TRUE); + } value=v++; Field *rfield= field->field; TABLE *table= rfield->table; From 9a63adc8fd18489aa3a75c7715abaea0dcd16349 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 26 Jul 2006 00:31:29 +0400 Subject: [PATCH 15/21] Fixed bug#19862: Sort with filesort by function evaluates function twice When there is no index defined filesort is used to sort the result of a query. If there is a function in the select list and the result set should be ordered by it's value then this function will be evaluated twice. First time to get the value of the sort key and second time to send its value to a user. This happens because filesort when sorts a table remembers only values of its fields but not values of functions. All functions are affected. But taking into account that SP and UDF functions can be both expensive and non-deterministic a temporary table should be used to store their results and then sort it to avoid twice SP evaluation and to get a correct result. If an expression referenced in an ORDER clause contains a SP or UDF function, force the use of a temporary table. A new Item_processor function called func_type_checker_processor is added to check whether the expression contains a function of a particular type. mysql-test/t/udf.test: Added test case for bug#19862: Sort with filesort by function evaluates function twice mysql-test/t/sp.test: Added test case for bug#19862: Sort with filesort by function evaluates function twice mysql-test/r/sp.result: Added test case for bug#19862: Sort with filesort by function evaluates function twice mysql-test/r/udf.result: Added test case for bug#19862: Sort with filesort by function evaluates function twice sql/sql_select.cc: Fixed bug#19862: Sort with filesort by function evaluates function twice If an expression referenced in an ORDER clause contains a SP or UDF function, force the use of a temporary table. sql/item_func.h: Fixed bug#19862: Sort with filesort by function evaluates function twice A new Item_processor function called func_type_checker_processor is added to check whether the expression contains a function of a particular type. sql/item.h: Fixed bug#19862: Sort with filesort by function evaluates function twice A new Item_processor function called func_type_checker_processor is added to check whether the expression contains a function of a particular type. sql/item_func.cc: Fixed bug#19862: Sort with filesort by function evaluates function twice A new Item_processor function called func_type_checker_processor is added to check whether the expression contains a function of a particular type. --- mysql-test/r/sp.result | 19 +++++++++++++++++++ mysql-test/r/udf.result | 6 ++++++ mysql-test/t/sp.test | 18 ++++++++++++++++++ mysql-test/t/udf.test | 7 +++++++ sql/item.h | 1 + sql/item_func.cc | 7 +++++++ sql/item_func.h | 4 +++- sql/sql_select.cc | 20 ++++++++++++++++++++ 8 files changed, 81 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index 50913fb1b90..f04b5b2c635 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -5057,4 +5057,23 @@ concat('data was: /', var1, '/') data was: /1/ drop table t3| drop procedure bug15217| +drop procedure if exists bug19862| +CREATE TABLE t11 (a INT)| +CREATE TABLE t12 (a INT)| +CREATE FUNCTION bug19862(x INT) RETURNS INT +BEGIN +INSERT INTO t11 VALUES (x); +RETURN x+1; +END| +INSERT INTO t12 VALUES (1), (2)| +SELECT bug19862(a) FROM t12 ORDER BY 1| +bug19862(a) +2 +3 +SELECT * FROM t11| +a +1 +2 +DROP TABLE t11, t12| +DROP FUNCTION bug19862| drop table t1,t2; diff --git a/mysql-test/r/udf.result b/mysql-test/r/udf.result index 484c42c41bf..b44dce14230 100644 --- a/mysql-test/r/udf.result +++ b/mysql-test/r/udf.result @@ -93,6 +93,12 @@ NULL 0R FR DROP TABLE bug19904; +create table t1(f1 int); +insert into t1 values(1),(2); +explain select myfunc_int(f1) from t1 order by 1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 2 Using temporary; Using filesort +drop table t1; End of 5.0 tests. DROP FUNCTION metaphon; DROP FUNCTION myfunc_double; diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index 25c96042e6f..cb9972fb800 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -5962,6 +5962,24 @@ call bug15217()| drop table t3| drop procedure bug15217| +# +# BUG#19862: Sort with filesort by function evaluates function twice +# +--disable_warnings +drop procedure if exists bug19862| +--enable_warnings +CREATE TABLE t11 (a INT)| +CREATE TABLE t12 (a INT)| +CREATE FUNCTION bug19862(x INT) RETURNS INT + BEGIN + INSERT INTO t11 VALUES (x); + RETURN x+1; + END| +INSERT INTO t12 VALUES (1), (2)| +SELECT bug19862(a) FROM t12 ORDER BY 1| +SELECT * FROM t11| +DROP TABLE t11, t12| +DROP FUNCTION bug19862| # # BUG#NNNN: New bug synopsis # diff --git a/mysql-test/t/udf.test b/mysql-test/t/udf.test index f3be08c8537..560ec88eb10 100644 --- a/mysql-test/t/udf.test +++ b/mysql-test/t/udf.test @@ -109,6 +109,13 @@ SELECT myfunc_double(n) AS f FROM bug19904; SELECT metaphon(v) AS f FROM bug19904; DROP TABLE bug19904; +# +# Bug#19862: Sort with filesort by function evaluates function twice +# +create table t1(f1 int); +insert into t1 values(1),(2); +explain select myfunc_int(f1) from t1 order by 1; +drop table t1; --echo End of 5.0 tests. # diff --git a/sql/item.h b/sql/item.h index 0f49145082f..c59d84aaeaa 100644 --- a/sql/item.h +++ b/sql/item.h @@ -752,6 +752,7 @@ public: virtual bool find_item_in_field_list_processor(byte *arg) { return 0; } virtual bool change_context_processor(byte *context) { return 0; } virtual bool reset_query_id_processor(byte *query_id) { return 0; } + virtual bool func_type_checker_processor(byte *arg) { return 0; } virtual Item *equal_fields_propagator(byte * arg) { return this; } virtual Item *set_no_const_sub(byte *arg) { return this; } diff --git a/sql/item_func.cc b/sql/item_func.cc index 1d906b300b6..c31ac2bf047 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -398,6 +398,13 @@ Field *Item_func::tmp_table_field(TABLE *t_arg) return res; } + +bool Item_func::func_type_checker_processor(byte *arg) +{ + return *((Functype*)arg) == functype(); +} + + my_decimal *Item_func::val_decimal(my_decimal *decimal_value) { DBUG_ASSERT(fixed); diff --git a/sql/item_func.h b/sql/item_func.h index 2ca4be9f3f2..88a52d7f46e 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -55,7 +55,7 @@ public: NOT_FUNC, NOT_ALL_FUNC, NOW_FUNC, TRIG_COND_FUNC, GUSERVAR_FUNC, COLLATE_FUNC, - EXTRACT_FUNC, CHAR_TYPECAST_FUNC, FUNC_SP }; + EXTRACT_FUNC, CHAR_TYPECAST_FUNC, FUNC_SP, UDF_FUNC }; enum optimize_type { OPTIMIZE_NONE,OPTIMIZE_KEY,OPTIMIZE_OP, OPTIMIZE_NULL, OPTIMIZE_EQUAL }; enum Type type() const { return FUNC_ITEM; } @@ -186,6 +186,7 @@ public: Item *transform(Item_transformer transformer, byte *arg); void traverse_cond(Cond_traverser traverser, void * arg, traverse_order order); + bool func_type_checker_processor(byte *arg); }; @@ -930,6 +931,7 @@ public: Item_udf_func(udf_func *udf_arg, List &list) :Item_func(list), udf(udf_arg) {} const char *func_name() const { return udf.name(); } + enum Functype functype() const { return UDF_FUNC; } bool fix_fields(THD *thd, Item **ref) { DBUG_ASSERT(fixed == 0); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index a7158960ed0..14389a57465 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1064,6 +1064,26 @@ JOIN::optimize() { need_tmp=1; simple_order=simple_group=0; // Force tmp table without sort } + if (order) + { + /* + Force using of tmp table if sorting by a SP or UDF function due to + their expensive and probably non-deterministic nature. + */ + for (ORDER *tmp_order= order; tmp_order ; tmp_order=tmp_order->next) + { + Item *item= *tmp_order->item; + Item_func::Functype type=Item_func::FUNC_SP; + Item_func::Functype type1=Item_func::UDF_FUNC; + if (item->walk(&Item::func_type_checker_processor,(byte*)&type) || + item->walk(&Item::func_type_checker_processor,(byte*)&type1)) + { + /* Force tmp table without sort */ + need_tmp=1; simple_order=simple_group=0; + break; + } + } + } } tmp_having= having; From 585b5bbc922f9b8a972f7b8d54c93c5eb3683b22 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 26 Jul 2006 01:11:19 +0300 Subject: [PATCH 16/21] Fix for BUG#20954: avg(keyval) retuns 0.38 but max(keyval) returns an empty set The problem was in that opt_sum_query() replaced MIN/MAX functions with the corresponding constant found in a key, but due to imprecise representation of float numbers, when evaluating the where clause, this comparison failed. When MIN/MAX optimization detects that all tables can be removed, also remove all conjuncts in a where clause that refer to these tables. As a result of this fix, these conditions are not evaluated twice, and in the case of float number comparisons we do not discard result rows due to imprecise float representation. As a side-effect this fix also corrects an unnoticed problem in bug 12882. mysql-test/r/func_group.result: BUG#20954 - test result adjustment. Adjusted the test result of bug 12882 which was not preperly fixed. The current patch corrects the problem that was fully corrected by the patch for 12882. The problem was that opt_sum_query() indicated that the optimizer may remove all tables because all MIN/MAX/COUNT functions are constants, but this lead to an empty result instead of NULL because the WHERE clause was still evaluated. The current fix removes all conjuncts in the where clause that reference the removed tables, and thus corrects the problem. mysql-test/r/select.result: BUG#20954 - added test mysql-test/r/subselect.result: BUG#20954 - test result adjustment. The fix removes those conditions in a where clause that refer to tables optimized away by MIN/MAX optimization (opt_sum_query()). mysql-test/t/select.test: BUG#20954 - added test sql/sql_select.cc: Fix for BUG#20954: avg(keyval) retuns 0.38 but max(keyval) returns an empty set When MIN/MAX optimization detects that all tables can be removed, also remove all conjuncts in a where clause that refer to these tables. As a result of this fix, these conditions are not evaluated twice, and in the case of float number comparisons we do not discard result rows due to imprecise float representation. As a side-effect this fix also corrects an unnoticed problem in bug 12882. --- mysql-test/r/func_group.result | 2 ++ mysql-test/r/select.result | 49 ++++++++++++++++++++++++++++++++++ mysql-test/r/subselect.result | 2 +- mysql-test/t/select.test | 30 +++++++++++++++++++++ sql/sql_select.cc | 18 +++++++++++++ 5 files changed, 100 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/func_group.result b/mysql-test/r/func_group.result index ffa68f279f3..932ef133087 100644 --- a/mysql-test/r/func_group.result +++ b/mysql-test/r/func_group.result @@ -824,6 +824,7 @@ select 1, min(a) from t1m where 1=99; 1 NULL select 1, min(1) from t1m where a=99; 1 min(1) +1 NULL select 1, min(1) from t1m where 1=99; 1 min(1) 1 NULL @@ -835,6 +836,7 @@ select 1, max(a) from t1m where 1=99; 1 NULL select 1, max(1) from t1m where a=99; 1 max(1) +1 NULL select 1, max(1) from t1m where 1=99; 1 max(1) 1 NULL diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result index c7df11ab018..d7c01fa5a57 100644 --- a/mysql-test/r/select.result +++ b/mysql-test/r/select.result @@ -2744,3 +2744,52 @@ SELECT i='1e+01',i=1e+01, i in (1e+01), i in ('1e+01') FROM t1; i='1e+01' i=1e+01 i in (1e+01) i in ('1e+01') 0 1 1 1 DROP TABLE t1; +CREATE TABLE t1 (key1 float default NULL, UNIQUE KEY key1 (key1)); +CREATE TABLE t2 (key2 float default NULL, UNIQUE KEY key2 (key2)); +INSERT INTO t1 VALUES (0.3762),(0.3845),(0.6158),(0.7941); +INSERT INTO t2 VALUES (1.3762),(1.3845),(1.6158),(1.7941); +explain select max(key1) from t1 where key1 <= 0.6158; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +explain select max(key2) from t2 where key2 <= 1.6158; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +explain select min(key1) from t1 where key1 >= 0.3762; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +explain select min(key2) from t2 where key2 >= 1.3762; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +explain select max(key1), min(key2) from t1, t2 +where key1 <= 0.6158 and key2 >= 1.3762; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +explain select max(key1) from t1 where key1 <= 0.6158 and rand() + 0.5 >= 0.5; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +explain select min(key1) from t1 where key1 >= 0.3762 and rand() + 0.5 >= 0.5; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +select max(key1) from t1 where key1 <= 0.6158; +max(key1) +0.61580002307892 +select max(key2) from t2 where key2 <= 1.6158; +max(key2) +1.6158000230789 +select min(key1) from t1 where key1 >= 0.3762; +min(key1) +0.37619999051094 +select min(key2) from t2 where key2 >= 1.3762; +min(key2) +1.3761999607086 +select max(key1), min(key2) from t1, t2 +where key1 <= 0.6158 and key2 >= 1.3762; +max(key1) min(key2) +0.61580002307892 1.3761999607086 +select max(key1) from t1 where key1 <= 0.6158 and rand() + 0.5 >= 0.5; +max(key1) +0.61580002307892 +select min(key1) from t1 where key1 >= 0.3762 and rand() + 0.5 >= 0.5; +min(key1) +0.37619999051094 +DROP TABLE t1,t2; diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index 595d80f1218..dc921f747ee 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -539,7 +539,7 @@ EXPLAIN EXTENDED SELECT MAX(numreponse) FROM t1 WHERE numeropost='1'; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away Warnings: -Note 1003 select max(test.t1.numreponse) AS `MAX(numreponse)` from test.t1 where (test.t1.numeropost = _latin1'1') +Note 1003 select max(test.t1.numreponse) AS `MAX(numreponse)` from test.t1 EXPLAIN EXTENDED SELECT numreponse FROM t1 WHERE numeropost='1' AND numreponse=(SELECT MAX(numreponse) FROM t1 WHERE numeropost='1'); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 const PRIMARY,numreponse PRIMARY 7 const,const 1 Using index diff --git a/mysql-test/t/select.test b/mysql-test/t/select.test index 4cdfc220350..acf9fd77c1b 100644 --- a/mysql-test/t/select.test +++ b/mysql-test/t/select.test @@ -2297,4 +2297,34 @@ INSERT INTO t1 VALUES (10); SELECT i='1e+01',i=1e+01, i in (1e+01), i in ('1e+01') FROM t1; DROP TABLE t1; +# +# Bug #20954 "avg(keyval) retuns 0.38 but max(keyval) returns an empty set" +# +--disable_ps_protocol +CREATE TABLE t1 (key1 float default NULL, UNIQUE KEY key1 (key1)); +CREATE TABLE t2 (key2 float default NULL, UNIQUE KEY key2 (key2)); +INSERT INTO t1 VALUES (0.3762),(0.3845),(0.6158),(0.7941); +INSERT INTO t2 VALUES (1.3762),(1.3845),(1.6158),(1.7941); + +explain select max(key1) from t1 where key1 <= 0.6158; +explain select max(key2) from t2 where key2 <= 1.6158; +explain select min(key1) from t1 where key1 >= 0.3762; +explain select min(key2) from t2 where key2 >= 1.3762; +explain select max(key1), min(key2) from t1, t2 +where key1 <= 0.6158 and key2 >= 1.3762; +explain select max(key1) from t1 where key1 <= 0.6158 and rand() + 0.5 >= 0.5; +explain select min(key1) from t1 where key1 >= 0.3762 and rand() + 0.5 >= 0.5; + +select max(key1) from t1 where key1 <= 0.6158; +select max(key2) from t2 where key2 <= 1.6158; +select min(key1) from t1 where key1 >= 0.3762; +select min(key2) from t2 where key2 >= 1.3762; +select max(key1), min(key2) from t1, t2 +where key1 <= 0.6158 and key2 >= 1.3762; +select max(key1) from t1 where key1 <= 0.6158 and rand() + 0.5 >= 0.5; +select min(key1) from t1 where key1 >= 0.3762 and rand() + 0.5 >= 0.5; + +DROP TABLE t1,t2; +--enable_ps_protocol + # End of 4.1 tests diff --git a/sql/sql_select.cc b/sql/sql_select.cc index fd8a5149edd..96ac98cfb88 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -547,6 +547,24 @@ JOIN::optimize() } zero_result_cause= "Select tables optimized away"; tables_list= 0; // All tables resolved + /* + Extract all table-independent conditions and replace the WHERE + clause with them. All other conditions were computed by opt_sum_query + and the MIN/MAX/COUNT function(s) have been replaced by constants, + so there is no need to compute the whole WHERE clause again. + Notice that make_cond_for_table() will always succeed to remove all + computed conditions, because opt_sum_query() is applicable only to + conjunctions. + */ + if (conds) + { + COND *table_independent_conds= + make_cond_for_table(conds, PSEUDO_TABLE_BITS, 0); + DBUG_EXECUTE("where", + print_where(table_independent_conds, + "where after opt_sum_query()");); + conds= table_independent_conds; + } } } if (!tables_list) From 5ca1ee5eea4d08491772388f39a664e21df32b9b Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 26 Jul 2006 13:32:28 +0300 Subject: [PATCH 17/21] Bug #21019: First result of SELECT COUNT(*) different than consecutive runs When optimizing conditions like 'a = OR a IS NULL' so that they're united into a single condition on the key and checked together the server must check which value is the NULL value in a correct way : not only using ->is_null but also check if the expression doesn't depend on any tables referenced in the current statement. This additional check must be performed because that optimization takes place before the actual execution of the statement, so if the field was initialized to NULL from a previous statement the optimization would be applied incorrectly. mysql-test/r/select.result: Bug #21019: First result of SELECT COUNT(*) different than consecutive runs - test case mysql-test/t/select.test: Bug #21019: First result of SELECT COUNT(*) different than consecutive runs - test case. Note that ALTER TABLE is important here : it happens to leave the Field instance for t1.b set to NULL, witch is vital for demonstrating the problem fixed by this changeset. sql/sql_select.cc: Bug #21019: First result of SELECT COUNT(*) different than consecutive runs - check whether a value is null taking into account its table dependency. --- mysql-test/r/select.result | 26 ++++++++++++++++++++++++++ mysql-test/t/select.test | 15 +++++++++++++++ sql/sql_select.cc | 7 +++++-- 3 files changed, 46 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result index c7df11ab018..d415c336715 100644 --- a/mysql-test/r/select.result +++ b/mysql-test/r/select.result @@ -2744,3 +2744,29 @@ SELECT i='1e+01',i=1e+01, i in (1e+01), i in ('1e+01') FROM t1; i='1e+01' i=1e+01 i in (1e+01) i in ('1e+01') 0 1 1 1 DROP TABLE t1; +CREATE TABLE t1 (a int, b int); +INSERT INTO t1 VALUES (1,1), (2,1), (4,10); +CREATE TABLE t2 (a int PRIMARY KEY, b int, KEY b (b)); +INSERT INTO t2 VALUES (1,NULL), (2,10); +ALTER TABLE t1 ENABLE KEYS; +EXPLAIN SELECT STRAIGHT_JOIN SQL_NO_CACHE COUNT(*) FROM t2, t1 WHERE t1.b = t2.b OR t2.b IS NULL; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 index b b 5 NULL 2 Using index +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 Using where +SELECT STRAIGHT_JOIN SQL_NO_CACHE * FROM t2, t1 WHERE t1.b = t2.b OR t2.b IS NULL; +a b a b +1 NULL 1 1 +1 NULL 2 1 +1 NULL 4 10 +2 10 4 10 +EXPLAIN SELECT STRAIGHT_JOIN SQL_NO_CACHE COUNT(*) FROM t2, t1 WHERE t1.b = t2.b OR t2.b IS NULL; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 index b b 5 NULL 2 Using index +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 Using where +SELECT STRAIGHT_JOIN SQL_NO_CACHE * FROM t2, t1 WHERE t1.b = t2.b OR t2.b IS NULL; +a b a b +1 NULL 1 1 +1 NULL 2 1 +1 NULL 4 10 +2 10 4 10 +DROP TABLE IF EXISTS t1,t2; diff --git a/mysql-test/t/select.test b/mysql-test/t/select.test index 4cdfc220350..23fc09b5e39 100644 --- a/mysql-test/t/select.test +++ b/mysql-test/t/select.test @@ -2297,4 +2297,19 @@ INSERT INTO t1 VALUES (10); SELECT i='1e+01',i=1e+01, i in (1e+01), i in ('1e+01') FROM t1; DROP TABLE t1; +# +# Bug #21019: First result of SELECT COUNT(*) different than consecutive runs +# +CREATE TABLE t1 (a int, b int); +INSERT INTO t1 VALUES (1,1), (2,1), (4,10); + +CREATE TABLE t2 (a int PRIMARY KEY, b int, KEY b (b)); +INSERT INTO t2 VALUES (1,NULL), (2,10); +ALTER TABLE t1 ENABLE KEYS; + +EXPLAIN SELECT STRAIGHT_JOIN SQL_NO_CACHE COUNT(*) FROM t2, t1 WHERE t1.b = t2.b OR t2.b IS NULL; +SELECT STRAIGHT_JOIN SQL_NO_CACHE * FROM t2, t1 WHERE t1.b = t2.b OR t2.b IS NULL; +EXPLAIN SELECT STRAIGHT_JOIN SQL_NO_CACHE COUNT(*) FROM t2, t1 WHERE t1.b = t2.b OR t2.b IS NULL; +SELECT STRAIGHT_JOIN SQL_NO_CACHE * FROM t2, t1 WHERE t1.b = t2.b OR t2.b IS NULL; +DROP TABLE IF EXISTS t1,t2; # End of 4.1 tests diff --git a/sql/sql_select.cc b/sql/sql_select.cc index fd8a5149edd..77ad0b8b163 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -2143,8 +2143,11 @@ merge_key_fields(KEY_FIELD *start,KEY_FIELD *new_fields,KEY_FIELD *end, /* field = expression OR field IS NULL */ old->level= and_level; old->optimize= KEY_OPTIMIZE_REF_OR_NULL; - /* Remember the NOT NULL value */ - if (old->val->is_null()) + /* + Remember the NOT NULL value unless the value does not depend + on other tables. + */ + if (!old->val->used_tables() && old->val->is_null()) old->val= new_fields->val; /* The referred expression can be NULL: */ old->null_rejecting= 0; From 8c92143b4bf715abd307b69a7f3637feec7df2ba Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 26 Jul 2006 18:18:34 +0300 Subject: [PATCH 18/21] Bug #21019: First result of SELECT COUNT(*) different than consecutive runs Correct merge --- mysql-test/r/select.result | 52 +++++++++++++++++++------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result index 69228d2ff44..32c9fabb19e 100644 --- a/mysql-test/r/select.result +++ b/mysql-test/r/select.result @@ -2736,6 +2736,32 @@ SELECT i='1e+01',i=1e+01, i in (1e+01,1e+01), i in ('1e+01','1e+01') FROM t1; i='1e+01' i=1e+01 i in (1e+01,1e+01) i in ('1e+01','1e+01') 0 1 1 1 DROP TABLE t1; +CREATE TABLE t1 (a int, b int); +INSERT INTO t1 VALUES (1,1), (2,1), (4,10); +CREATE TABLE t2 (a int PRIMARY KEY, b int, KEY b (b)); +INSERT INTO t2 VALUES (1,NULL), (2,10); +ALTER TABLE t1 ENABLE KEYS; +EXPLAIN SELECT STRAIGHT_JOIN SQL_NO_CACHE COUNT(*) FROM t2, t1 WHERE t1.b = t2.b OR t2.b IS NULL; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 index b b 5 NULL 2 Using index +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 Using where +SELECT STRAIGHT_JOIN SQL_NO_CACHE * FROM t2, t1 WHERE t1.b = t2.b OR t2.b IS NULL; +a b a b +1 NULL 1 1 +1 NULL 2 1 +1 NULL 4 10 +2 10 4 10 +EXPLAIN SELECT STRAIGHT_JOIN SQL_NO_CACHE COUNT(*) FROM t2, t1 WHERE t1.b = t2.b OR t2.b IS NULL; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 index b b 5 NULL 2 Using index +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 Using where +SELECT STRAIGHT_JOIN SQL_NO_CACHE * FROM t2, t1 WHERE t1.b = t2.b OR t2.b IS NULL; +a b a b +1 NULL 1 1 +1 NULL 2 1 +1 NULL 4 10 +2 10 4 10 +DROP TABLE IF EXISTS t1,t2; CREATE TABLE t1 ( K2C4 varchar(4) character set latin1 collate latin1_bin NOT NULL default '', K4N4 varchar(4) character set latin1 collate latin1_bin NOT NULL default '0000', @@ -3125,32 +3151,6 @@ select count(*) from t1 inner join (t2 right join t3 on t2.id = t3.b_id) on t1.id = t3.a_id; count(*) 6 -CREATE TABLE t1 (a int, b int); -INSERT INTO t1 VALUES (1,1), (2,1), (4,10); -CREATE TABLE t2 (a int PRIMARY KEY, b int, KEY b (b)); -INSERT INTO t2 VALUES (1,NULL), (2,10); -ALTER TABLE t1 ENABLE KEYS; -EXPLAIN SELECT STRAIGHT_JOIN SQL_NO_CACHE COUNT(*) FROM t2, t1 WHERE t1.b = t2.b OR t2.b IS NULL; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t2 index b b 5 NULL 2 Using index -1 SIMPLE t1 ALL NULL NULL NULL NULL 3 Using where -SELECT STRAIGHT_JOIN SQL_NO_CACHE * FROM t2, t1 WHERE t1.b = t2.b OR t2.b IS NULL; -a b a b -1 NULL 1 1 -1 NULL 2 1 -1 NULL 4 10 -2 10 4 10 -EXPLAIN SELECT STRAIGHT_JOIN SQL_NO_CACHE COUNT(*) FROM t2, t1 WHERE t1.b = t2.b OR t2.b IS NULL; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t2 index b b 5 NULL 2 Using index -1 SIMPLE t1 ALL NULL NULL NULL NULL 3 Using where -SELECT STRAIGHT_JOIN SQL_NO_CACHE * FROM t2, t1 WHERE t1.b = t2.b OR t2.b IS NULL; -a b a b -1 NULL 1 1 -1 NULL 2 1 -1 NULL 4 10 -2 10 4 10 -DROP TABLE IF EXISTS t1,t2; drop table t1,t2,t3; create table t1 (a int); create table t2 (b int); From 6b75e24b73828316dd1715ab32811a614ce74314 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 26 Jul 2006 19:19:30 +0300 Subject: [PATCH 19/21] * Bug #20792: Incorrect results from aggregate subquery When processing aggregate functions all tables values are reset to NULLs at the end of each group. When doing that if there are no rows found for a group the const tables must not be reset as they are not recalculated by do_select()/sub_select() for each group. mysql-test/r/subselect2.result: * Bug #20792: Incorrect results from aggregate subquery - test suite for the bug. This is dependent on InnoDB despite the fact that the bug and the fix are not InnoDB specific. This is because of the table flag HA_NOT_EXACT_COUNT. When this flag is off (as in MyISAM) both t2 and t3 become of join type 'system' as they are estimated to have 1 record and and this statistics can be trusted (according to the absence of HA_NOT_EXACT_COUNT). mysql-test/t/subselect2.test: * Bug #20792: Incorrect results from aggregate subquery - test suite for the bug sql/sql_select.cc: * Bug #20792: Incorrect results from aggregate subquery - when clearing results if there are not rows found for group the const tables must not be reset as they are not recalculated for each group. --- mysql-test/r/subselect2.result | 12 ++++++++++++ mysql-test/t/subselect2.test | 18 ++++++++++++++++++ sql/sql_select.cc | 10 ++++++++-- 3 files changed, 38 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/subselect2.result b/mysql-test/r/subselect2.result index 8fcfa06a8ae..db1848105f8 100644 --- a/mysql-test/r/subselect2.result +++ b/mysql-test/r/subselect2.result @@ -130,3 +130,15 @@ id select_type table type possible_keys key key_len ref rows Extra 5 DEPENDENT SUBQUERY t3 unique_subquery PRIMARY,FFOLDERID_IDX PRIMARY 32 func 1 Using index; Using where 6 DEPENDENT SUBQUERY t3 unique_subquery PRIMARY,FFOLDERID_IDX,CMFLDRPARNT_IDX PRIMARY 32 func 1 Using index; Using where drop table t1, t2, t3, t4; +CREATE TABLE t1 (a int(10) , PRIMARY KEY (a)) Engine=InnoDB; +INSERT INTO t1 VALUES (1),(2); +CREATE TABLE t2 (a int(10), PRIMARY KEY (a)) Engine=InnoDB; +INSERT INTO t2 VALUES (1); +CREATE TABLE t3 (a int(10), b int(10), c int(10), +PRIMARY KEY (a)) Engine=InnoDB; +INSERT INTO t3 VALUES (1,2,1); +SELECT t1.* FROM t1 WHERE (SELECT COUNT(*) FROM t3,t2 WHERE t3.c=t2.a +and t2.a='1' AND t1.a=t3.b) > 0; +a +2 +DROP TABLE t1,t2,t3; diff --git a/mysql-test/t/subselect2.test b/mysql-test/t/subselect2.test index b21eda176b6..162bdd0d90a 100644 --- a/mysql-test/t/subselect2.test +++ b/mysql-test/t/subselect2.test @@ -150,3 +150,21 @@ EXPLAIN SELECT t2.*, t4.DOCTYPENAME, t1.CONTENTSIZE,t1.MIMETYPE FROM t2 INNER JO drop table t1, t2, t3, t4; # End of 4.1 tests + +# +# Bug #20792: Incorrect results from aggregate subquery +# +CREATE TABLE t1 (a int(10) , PRIMARY KEY (a)) Engine=InnoDB; +INSERT INTO t1 VALUES (1),(2); + +CREATE TABLE t2 (a int(10), PRIMARY KEY (a)) Engine=InnoDB; +INSERT INTO t2 VALUES (1); + +CREATE TABLE t3 (a int(10), b int(10), c int(10), + PRIMARY KEY (a)) Engine=InnoDB; +INSERT INTO t3 VALUES (1,2,1); + +SELECT t1.* FROM t1 WHERE (SELECT COUNT(*) FROM t3,t2 WHERE t3.c=t2.a + and t2.a='1' AND t1.a=t3.b) > 0; + +DROP TABLE t1,t2,t3; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index fd8a5149edd..ce573136faf 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -4452,10 +4452,16 @@ return_zero_rows(JOIN *join, select_result *result,TABLE_LIST *tables, DBUG_RETURN(0); } - +/* + used only in JOIN::clear +*/ static void clear_tables(JOIN *join) { - for (uint i=0 ; i < join->tables ; i++) + /* + must clear only the non-const tables, as const tables + are not re-calculated. + */ + for (uint i=join->const_tables ; i < join->tables ; i++) mark_as_null_row(join->table[i]); // All fields are NULL } From 1150869c4a6418b9dbcbe6b9b2f6036e1c5379f1 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 26 Jul 2006 21:36:03 +0400 Subject: [PATCH 20/21] item_func.h, item_func.cc, sql_select.cc, item.h: Post review changes for bug#19862. sql/sql_select.cc: Post review changes for bug#19862. sql/item_func.h: Post review changes for bug#19862. sql/item_func.cc: Post review changes for bug#19862. sql/item.h: Post review changes for bug#19862. --- sql/item.h | 2 +- sql/item_func.cc | 4 ++-- sql/item_func.h | 5 ++++- sql/sql_select.cc | 5 +---- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/sql/item.h b/sql/item.h index c59d84aaeaa..514c31c2d74 100644 --- a/sql/item.h +++ b/sql/item.h @@ -752,7 +752,7 @@ public: virtual bool find_item_in_field_list_processor(byte *arg) { return 0; } virtual bool change_context_processor(byte *context) { return 0; } virtual bool reset_query_id_processor(byte *query_id) { return 0; } - virtual bool func_type_checker_processor(byte *arg) { return 0; } + virtual bool is_expensive_processor(byte *arg) { return 0; } virtual Item *equal_fields_propagator(byte * arg) { return this; } virtual Item *set_no_const_sub(byte *arg) { return this; } diff --git a/sql/item_func.cc b/sql/item_func.cc index c31ac2bf047..cbab9a4de1b 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -399,9 +399,9 @@ Field *Item_func::tmp_table_field(TABLE *t_arg) } -bool Item_func::func_type_checker_processor(byte *arg) +bool Item_func::is_expensive_processor(byte *arg) { - return *((Functype*)arg) == functype(); + return is_expensive(); } diff --git a/sql/item_func.h b/sql/item_func.h index bac4a186867..b33dae092ac 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -189,7 +189,8 @@ public: Item *transform(Item_transformer transformer, byte *arg); void traverse_cond(Cond_traverser traverser, void * arg, traverse_order order); - bool func_type_checker_processor(byte *arg); + bool is_expensive_processor(byte *arg); + virtual bool is_expensive() { return 0; } }; @@ -947,6 +948,7 @@ public: void cleanup(); Item_result result_type () const { return udf.result_type(); } table_map not_null_tables() const { return 0; } + bool is_expensive() { return 1; } }; @@ -1475,6 +1477,7 @@ public: virtual enum Functype functype() const { return FUNC_SP; } bool fix_fields(THD *thd, Item **ref); + bool is_expensive() { return 1; } }; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 36962a233b8..20945117da1 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1073,10 +1073,7 @@ JOIN::optimize() for (ORDER *tmp_order= order; tmp_order ; tmp_order=tmp_order->next) { Item *item= *tmp_order->item; - Item_func::Functype type=Item_func::FUNC_SP; - Item_func::Functype type1=Item_func::UDF_FUNC; - if (item->walk(&Item::func_type_checker_processor,(byte*)&type) || - item->walk(&Item::func_type_checker_processor,(byte*)&type1)) + if (item->walk(&Item::is_expensive_processor,(byte*)0)) { /* Force tmp table without sort */ need_tmp=1; simple_order=simple_group=0; From 45871dbfd907cd0f0e68d4c73bbb1e96b4d0eb22 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 31 Jul 2006 23:05:54 +0400 Subject: [PATCH 21/21] select.result, func_group.result, sql_select.cc: After merge fix mysql-test/r/select.result: After merge fix mysql-test/r/func_group.result: After merge fix sql/sql_select.cc: After merge fix --- mysql-test/r/func_group.result | 138 --------------------------------- mysql-test/r/select.result | 98 +++++++++++------------ sql/sql_select.cc | 3 +- 3 files changed, 51 insertions(+), 188 deletions(-) diff --git a/mysql-test/r/func_group.result b/mysql-test/r/func_group.result index f0fd489867d..896b79297f8 100644 --- a/mysql-test/r/func_group.result +++ b/mysql-test/r/func_group.result @@ -821,144 +821,6 @@ SELECT MAX(id) FROM t1 WHERE id < 3 AND a=2 AND b=6; MAX(id) NULL DROP TABLE t1; -create table t1m (a int) engine=myisam; -create table t1i (a int) engine=innodb; -create table t2m (a int) engine=myisam; -create table t2i (a int) engine=innodb; -insert into t2m values (5); -insert into t2i values (5); -select min(a) from t1m; -min(a) -NULL -select min(7) from t1m; -min(7) -NULL -select min(7) from DUAL; -min(7) -NULL -explain select min(7) from t2m join t1m; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away -select min(7) from t2m join t1m; -min(7) -NULL -select max(a) from t1m; -max(a) -NULL -select max(7) from t1m; -max(7) -NULL -select max(7) from DUAL; -max(7) -NULL -explain select max(7) from t2m join t1m; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away -select max(7) from t2m join t1m; -max(7) -NULL -select 1, min(a) from t1m where a=99; -1 min(a) -1 NULL -select 1, min(a) from t1m where 1=99; -1 min(a) -1 NULL -select 1, min(1) from t1m where a=99; -1 min(1) -1 NULL -select 1, min(1) from t1m where 1=99; -1 min(1) -1 NULL -select 1, max(a) from t1m where a=99; -1 max(a) -1 NULL -select 1, max(a) from t1m where 1=99; -1 max(a) -1 NULL -select 1, max(1) from t1m where a=99; -1 max(1) -1 NULL -select 1, max(1) from t1m where 1=99; -1 max(1) -1 NULL -select min(a) from t1i; -min(a) -NULL -select min(7) from t1i; -min(7) -NULL -select min(7) from DUAL; -min(7) -NULL -explain select min(7) from t2i join t1i; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t2i ALL NULL NULL NULL NULL 1 -1 SIMPLE t1i ALL NULL NULL NULL NULL 1 -select min(7) from t2i join t1i; -min(7) -NULL -select max(a) from t1i; -max(a) -NULL -select max(7) from t1i; -max(7) -NULL -select max(7) from DUAL; -max(7) -NULL -explain select max(7) from t2i join t1i; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t2i ALL NULL NULL NULL NULL 1 -1 SIMPLE t1i ALL NULL NULL NULL NULL 1 -select max(7) from t2i join t1i; -max(7) -NULL -select 1, min(a) from t1i where a=99; -1 min(a) -1 NULL -select 1, min(a) from t1i where 1=99; -1 min(a) -1 NULL -select 1, min(1) from t1i where a=99; -1 min(1) -1 NULL -select 1, min(1) from t1i where 1=99; -1 min(1) -1 NULL -select 1, max(a) from t1i where a=99; -1 max(a) -1 NULL -select 1, max(a) from t1i where 1=99; -1 max(a) -1 NULL -select 1, max(1) from t1i where a=99; -1 max(1) -1 NULL -select 1, max(1) from t1i where 1=99; -1 max(1) -1 NULL -explain select count(*), min(7), max(7) from t1m, t1i; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1m system NULL NULL NULL NULL 0 const row not found -1 SIMPLE t1i ALL NULL NULL NULL NULL 1 -select count(*), min(7), max(7) from t1m, t1i; -count(*) min(7) max(7) -0 NULL NULL -explain select count(*), min(7), max(7) from t1m, t2i; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1m system NULL NULL NULL NULL 0 const row not found -1 SIMPLE t2i ALL NULL NULL NULL NULL 1 -select count(*), min(7), max(7) from t1m, t2i; -count(*) min(7) max(7) -0 NULL NULL -explain select count(*), min(7), max(7) from t2m, t1i; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t2m system NULL NULL NULL NULL 1 -1 SIMPLE t1i ALL NULL NULL NULL NULL 1 -select count(*), min(7), max(7) from t2m, t1i; -count(*) min(7) max(7) -0 NULL NULL -drop table t1m, t1i, t2m, t2i; CREATE TABLE t1 (id int PRIMARY KEY, b char(3), INDEX(b)); INSERT INTO t1 VALUES (1,'xx'), (2,'aa'); SELECT * FROM t1; diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result index 3df4f3f78ec..b5d059be4c5 100644 --- a/mysql-test/r/select.result +++ b/mysql-test/r/select.result @@ -2762,6 +2762,55 @@ a b a b 1 NULL 4 10 2 10 4 10 DROP TABLE IF EXISTS t1,t2; +CREATE TABLE t1 (key1 float default NULL, UNIQUE KEY key1 (key1)); +CREATE TABLE t2 (key2 float default NULL, UNIQUE KEY key2 (key2)); +INSERT INTO t1 VALUES (0.3762),(0.3845),(0.6158),(0.7941); +INSERT INTO t2 VALUES (1.3762),(1.3845),(1.6158),(1.7941); +explain select max(key1) from t1 where key1 <= 0.6158; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +explain select max(key2) from t2 where key2 <= 1.6158; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +explain select min(key1) from t1 where key1 >= 0.3762; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +explain select min(key2) from t2 where key2 >= 1.3762; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +explain select max(key1), min(key2) from t1, t2 +where key1 <= 0.6158 and key2 >= 1.3762; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +explain select max(key1) from t1 where key1 <= 0.6158 and rand() + 0.5 >= 0.5; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +explain select min(key1) from t1 where key1 >= 0.3762 and rand() + 0.5 >= 0.5; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +select max(key1) from t1 where key1 <= 0.6158; +max(key1) +0.61580002307892 +select max(key2) from t2 where key2 <= 1.6158; +max(key2) +1.6158000230789 +select min(key1) from t1 where key1 >= 0.3762; +min(key1) +0.37619999051094 +select min(key2) from t2 where key2 >= 1.3762; +min(key2) +1.3761999607086 +select max(key1), min(key2) from t1, t2 +where key1 <= 0.6158 and key2 >= 1.3762; +max(key1) min(key2) +0.61580002307892 1.3761999607086 +select max(key1) from t1 where key1 <= 0.6158 and rand() + 0.5 >= 0.5; +max(key1) +0.61580002307892 +select min(key1) from t1 where key1 >= 0.3762 and rand() + 0.5 >= 0.5; +min(key1) +0.37619999051094 +DROP TABLE t1,t2; CREATE TABLE t1 ( K2C4 varchar(4) character set latin1 collate latin1_bin NOT NULL default '', K4N4 varchar(4) character set latin1 collate latin1_bin NOT NULL default '0000', @@ -3151,55 +3200,6 @@ select count(*) from t1 inner join (t2 right join t3 on t2.id = t3.b_id) on t1.id = t3.a_id; count(*) 6 -CREATE TABLE t1 (key1 float default NULL, UNIQUE KEY key1 (key1)); -CREATE TABLE t2 (key2 float default NULL, UNIQUE KEY key2 (key2)); -INSERT INTO t1 VALUES (0.3762),(0.3845),(0.6158),(0.7941); -INSERT INTO t2 VALUES (1.3762),(1.3845),(1.6158),(1.7941); -explain select max(key1) from t1 where key1 <= 0.6158; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away -explain select max(key2) from t2 where key2 <= 1.6158; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away -explain select min(key1) from t1 where key1 >= 0.3762; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away -explain select min(key2) from t2 where key2 >= 1.3762; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away -explain select max(key1), min(key2) from t1, t2 -where key1 <= 0.6158 and key2 >= 1.3762; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away -explain select max(key1) from t1 where key1 <= 0.6158 and rand() + 0.5 >= 0.5; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away -explain select min(key1) from t1 where key1 >= 0.3762 and rand() + 0.5 >= 0.5; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away -select max(key1) from t1 where key1 <= 0.6158; -max(key1) -0.61580002307892 -select max(key2) from t2 where key2 <= 1.6158; -max(key2) -1.6158000230789 -select min(key1) from t1 where key1 >= 0.3762; -min(key1) -0.37619999051094 -select min(key2) from t2 where key2 >= 1.3762; -min(key2) -1.3761999607086 -select max(key1), min(key2) from t1, t2 -where key1 <= 0.6158 and key2 >= 1.3762; -max(key1) min(key2) -0.61580002307892 1.3761999607086 -select max(key1) from t1 where key1 <= 0.6158 and rand() + 0.5 >= 0.5; -max(key1) -0.61580002307892 -select min(key1) from t1 where key1 >= 0.3762 and rand() + 0.5 >= 0.5; -min(key1) -0.37619999051094 -DROP TABLE t1,t2; drop table t1,t2,t3; create table t1 (a int); create table t2 (b int); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index f6f45aea41e..412dbb529b6 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -687,8 +687,9 @@ JOIN::optimize() Notice that make_cond_for_table() will always succeed to remove all computed conditions, because opt_sum_query() is applicable only to conjunctions. + Preserve conditions for EXPLAIN. */ - if (conds) + if (conds && !(thd->lex->describe & DESCRIBE_EXTENDED)) { COND *table_independent_conds= make_cond_for_table(conds, PSEUDO_TABLE_BITS, 0);