From 4b603e488125e0bae275936bb35208bb3ddde90a Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Tue, 15 Dec 2009 10:37:10 +0200 Subject: [PATCH 1/4] Bug #49480: WHERE using YEAR columns returns unexpected results Merge the fix from 5.1-bugteam to 5.1-main --- mysql-test/r/type_year.result | 264 ++++++++++++++++++++++++++++++++++ mysql-test/t/type_year.test | 106 ++++++++++++++ sql/item_cmpfunc.cc | 144 +++++++------------ sql/item_cmpfunc.h | 9 +- 4 files changed, 421 insertions(+), 102 deletions(-) diff --git a/mysql-test/r/type_year.result b/mysql-test/r/type_year.result index e52947455c8..56b326327c6 100644 --- a/mysql-test/r/type_year.result +++ b/mysql-test/r/type_year.result @@ -46,3 +46,267 @@ a 2001 drop table t1; End of 5.0 tests +# +# Bug #49480: WHERE using YEAR columns returns unexpected results +# +CREATE TABLE t2(yy YEAR(2), c2 CHAR(4)); +CREATE TABLE t4(yyyy YEAR(4), c4 CHAR(4)); +INSERT INTO t2 (c2) VALUES (NULL),(1970),(1999),(2000),(2001),(2069); +INSERT INTO t4 (c4) SELECT c2 FROM t2; +UPDATE t2 SET yy = c2; +UPDATE t4 SET yyyy = c4; +SELECT * FROM t2; +yy c2 +NULL NULL +70 1970 +99 1999 +00 2000 +01 2001 +69 2069 +SELECT * FROM t4; +yyyy c4 +NULL NULL +1970 1970 +1999 1999 +2000 2000 +2001 2001 +2069 2069 +# Comparison of YEAR(2) with YEAR(4) +SELECT * FROM t2, t4 WHERE yy = yyyy; +yy c2 yyyy c4 +70 1970 1970 1970 +99 1999 1999 1999 +00 2000 2000 2000 +01 2001 2001 2001 +69 2069 2069 2069 +SELECT * FROM t2, t4 WHERE yy <=> yyyy; +yy c2 yyyy c4 +NULL NULL NULL NULL +70 1970 1970 1970 +99 1999 1999 1999 +00 2000 2000 2000 +01 2001 2001 2001 +69 2069 2069 2069 +SELECT * FROM t2, t4 WHERE yy < yyyy; +yy c2 yyyy c4 +70 1970 1999 1999 +70 1970 2000 2000 +99 1999 2000 2000 +70 1970 2001 2001 +99 1999 2001 2001 +00 2000 2001 2001 +70 1970 2069 2069 +99 1999 2069 2069 +00 2000 2069 2069 +01 2001 2069 2069 +SELECT * FROM t2, t4 WHERE yy > yyyy; +yy c2 yyyy c4 +99 1999 1970 1970 +00 2000 1970 1970 +01 2001 1970 1970 +69 2069 1970 1970 +00 2000 1999 1999 +01 2001 1999 1999 +69 2069 1999 1999 +01 2001 2000 2000 +69 2069 2000 2000 +69 2069 2001 2001 +# Comparison of YEAR(2) with YEAR(2) +SELECT * FROM t2 a, t2 b WHERE a.yy = b.yy; +yy c2 yy c2 +70 1970 70 1970 +99 1999 99 1999 +00 2000 00 2000 +01 2001 01 2001 +69 2069 69 2069 +SELECT * FROM t2 a, t2 b WHERE a.yy <=> b.yy; +yy c2 yy c2 +NULL NULL NULL NULL +70 1970 70 1970 +99 1999 99 1999 +00 2000 00 2000 +01 2001 01 2001 +69 2069 69 2069 +SELECT * FROM t2 a, t2 b WHERE a.yy < b.yy; +yy c2 yy c2 +70 1970 99 1999 +70 1970 00 2000 +99 1999 00 2000 +70 1970 01 2001 +99 1999 01 2001 +00 2000 01 2001 +70 1970 69 2069 +99 1999 69 2069 +00 2000 69 2069 +01 2001 69 2069 +# Comparison of YEAR(4) with YEAR(4) +SELECT * FROM t4 a, t4 b WHERE a.yyyy = b.yyyy; +yyyy c4 yyyy c4 +1970 1970 1970 1970 +1999 1999 1999 1999 +2000 2000 2000 2000 +2001 2001 2001 2001 +2069 2069 2069 2069 +SELECT * FROM t4 a, t4 b WHERE a.yyyy <=> b.yyyy; +yyyy c4 yyyy c4 +NULL NULL NULL NULL +1970 1970 1970 1970 +1999 1999 1999 1999 +2000 2000 2000 2000 +2001 2001 2001 2001 +2069 2069 2069 2069 +SELECT * FROM t4 a, t4 b WHERE a.yyyy < b.yyyy; +yyyy c4 yyyy c4 +1970 1970 1999 1999 +1970 1970 2000 2000 +1999 1999 2000 2000 +1970 1970 2001 2001 +1999 1999 2001 2001 +2000 2000 2001 2001 +1970 1970 2069 2069 +1999 1999 2069 2069 +2000 2000 2069 2069 +2001 2001 2069 2069 +# Comparison with constants: +SELECT * FROM t2 WHERE yy = NULL; +yy c2 +SELECT * FROM t4 WHERE yyyy = NULL; +yyyy c4 +SELECT * FROM t2 WHERE yy <=> NULL; +yy c2 +NULL NULL +SELECT * FROM t4 WHERE yyyy <=> NULL; +yyyy c4 +NULL NULL +SELECT * FROM t2 WHERE yy < NULL; +yy c2 +SELECT * FROM t2 WHERE yy > NULL; +yy c2 +SELECT * FROM t2 WHERE yy = NOW(); +yy c2 +SELECT * FROM t4 WHERE yyyy = NOW(); +yyyy c4 +SELECT * FROM t2 WHERE yy = 99; +yy c2 +99 1999 +SELECT * FROM t2 WHERE 99 = yy; +yy c2 +99 1999 +SELECT * FROM t4 WHERE yyyy = 99; +yyyy c4 +1999 1999 +SELECT * FROM t2 WHERE yy = 'test'; +yy c2 +00 2000 +Warnings: +Warning 1292 Truncated incorrect DOUBLE value: 'test' +SELECT * FROM t4 WHERE yyyy = 'test'; +yyyy c4 +Warnings: +Warning 1292 Truncated incorrect DOUBLE value: 'test' +SELECT * FROM t2 WHERE yy = '1999'; +yy c2 +99 1999 +SELECT * FROM t4 WHERE yyyy = '1999'; +yyyy c4 +1999 1999 +SELECT * FROM t2 WHERE yy = 1999; +yy c2 +99 1999 +SELECT * FROM t4 WHERE yyyy = 1999; +yyyy c4 +1999 1999 +SELECT * FROM t2 WHERE yy = 1999.1; +yy c2 +99 1999 +SELECT * FROM t4 WHERE yyyy = 1999.1; +yyyy c4 +1999 1999 +SELECT * FROM t2 WHERE yy = 1998.9; +yy c2 +99 1999 +SELECT * FROM t4 WHERE yyyy = 1998.9; +yyyy c4 +1999 1999 +# Coverage tests for YEAR with zero/2000 constants: +SELECT * FROM t2 WHERE yy = 0; +yy c2 +00 2000 +SELECT * FROM t2 WHERE yy = '0'; +yy c2 +00 2000 +SELECT * FROM t2 WHERE yy = '0000'; +yy c2 +00 2000 +SELECT * FROM t2 WHERE yy = '2000'; +yy c2 +00 2000 +SELECT * FROM t2 WHERE yy = 2000; +yy c2 +00 2000 +SELECT * FROM t4 WHERE yyyy = 0; +yyyy c4 +SELECT * FROM t4 WHERE yyyy = '0'; +yyyy c4 +2000 2000 +SELECT * FROM t4 WHERE yyyy = '0000'; +yyyy c4 +SELECT * FROM t4 WHERE yyyy = '2000'; +yyyy c4 +2000 2000 +SELECT * FROM t4 WHERE yyyy = 2000; +yyyy c4 +2000 2000 +# Comparison with constants those are out of YEAR range +# (coverage test for backward compatibility) +SELECT COUNT(yy) FROM t2; +COUNT(yy) +5 +SELECT COUNT(yyyy) FROM t4; +COUNT(yyyy) +5 +SELECT COUNT(*) FROM t2 WHERE yy = -1; +COUNT(*) +0 +SELECT COUNT(*) FROM t4 WHERE yyyy > -1; +COUNT(*) +5 +SELECT COUNT(*) FROM t2 WHERE yy > -1000000000000000000; +COUNT(*) +5 +SELECT COUNT(*) FROM t4 WHERE yyyy > -1000000000000000000; +COUNT(*) +5 +SELECT COUNT(*) FROM t2 WHERE yy < 2156; +COUNT(*) +5 +SELECT COUNT(*) FROM t4 WHERE yyyy < 2156; +COUNT(*) +5 +SELECT COUNT(*) FROM t2 WHERE yy < 1000000000000000000; +COUNT(*) +5 +SELECT COUNT(*) FROM t4 WHERE yyyy < 1000000000000000000; +COUNT(*) +5 +SELECT * FROM t2 WHERE yy < 123; +yy c2 +70 1970 +99 1999 +00 2000 +01 2001 +69 2069 +SELECT * FROM t2 WHERE yy > 123; +yy c2 +SELECT * FROM t4 WHERE yyyy < 123; +yyyy c4 +SELECT * FROM t4 WHERE yyyy > 123; +yyyy c4 +1970 1970 +1999 1999 +2000 2000 +2001 2001 +2069 2069 +DROP TABLE t2, t4; +# +End of 5.1 tests diff --git a/mysql-test/t/type_year.test b/mysql-test/t/type_year.test index 0e174a556d6..16fd39a59d8 100644 --- a/mysql-test/t/type_year.test +++ b/mysql-test/t/type_year.test @@ -30,3 +30,109 @@ select * from t1; drop table t1; --echo End of 5.0 tests + +--echo # +--echo # Bug #49480: WHERE using YEAR columns returns unexpected results +--echo # + +CREATE TABLE t2(yy YEAR(2), c2 CHAR(4)); +CREATE TABLE t4(yyyy YEAR(4), c4 CHAR(4)); + +INSERT INTO t2 (c2) VALUES (NULL),(1970),(1999),(2000),(2001),(2069); +INSERT INTO t4 (c4) SELECT c2 FROM t2; +UPDATE t2 SET yy = c2; +UPDATE t4 SET yyyy = c4; + +SELECT * FROM t2; +SELECT * FROM t4; + +--echo # Comparison of YEAR(2) with YEAR(4) + +SELECT * FROM t2, t4 WHERE yy = yyyy; +SELECT * FROM t2, t4 WHERE yy <=> yyyy; +SELECT * FROM t2, t4 WHERE yy < yyyy; +SELECT * FROM t2, t4 WHERE yy > yyyy; + +--echo # Comparison of YEAR(2) with YEAR(2) + +SELECT * FROM t2 a, t2 b WHERE a.yy = b.yy; +SELECT * FROM t2 a, t2 b WHERE a.yy <=> b.yy; +SELECT * FROM t2 a, t2 b WHERE a.yy < b.yy; + +--echo # Comparison of YEAR(4) with YEAR(4) + +SELECT * FROM t4 a, t4 b WHERE a.yyyy = b.yyyy; +SELECT * FROM t4 a, t4 b WHERE a.yyyy <=> b.yyyy; +SELECT * FROM t4 a, t4 b WHERE a.yyyy < b.yyyy; + +--echo # Comparison with constants: + +SELECT * FROM t2 WHERE yy = NULL; +SELECT * FROM t4 WHERE yyyy = NULL; +SELECT * FROM t2 WHERE yy <=> NULL; +SELECT * FROM t4 WHERE yyyy <=> NULL; +SELECT * FROM t2 WHERE yy < NULL; +SELECT * FROM t2 WHERE yy > NULL; + +SELECT * FROM t2 WHERE yy = NOW(); +SELECT * FROM t4 WHERE yyyy = NOW(); + +SELECT * FROM t2 WHERE yy = 99; +SELECT * FROM t2 WHERE 99 = yy; +SELECT * FROM t4 WHERE yyyy = 99; + +SELECT * FROM t2 WHERE yy = 'test'; +SELECT * FROM t4 WHERE yyyy = 'test'; + +SELECT * FROM t2 WHERE yy = '1999'; +SELECT * FROM t4 WHERE yyyy = '1999'; + +SELECT * FROM t2 WHERE yy = 1999; +SELECT * FROM t4 WHERE yyyy = 1999; + +SELECT * FROM t2 WHERE yy = 1999.1; +SELECT * FROM t4 WHERE yyyy = 1999.1; + +SELECT * FROM t2 WHERE yy = 1998.9; +SELECT * FROM t4 WHERE yyyy = 1998.9; + +--echo # Coverage tests for YEAR with zero/2000 constants: + +SELECT * FROM t2 WHERE yy = 0; +SELECT * FROM t2 WHERE yy = '0'; +SELECT * FROM t2 WHERE yy = '0000'; +SELECT * FROM t2 WHERE yy = '2000'; +SELECT * FROM t2 WHERE yy = 2000; + +SELECT * FROM t4 WHERE yyyy = 0; +SELECT * FROM t4 WHERE yyyy = '0'; +SELECT * FROM t4 WHERE yyyy = '0000'; +SELECT * FROM t4 WHERE yyyy = '2000'; +SELECT * FROM t4 WHERE yyyy = 2000; + +--echo # Comparison with constants those are out of YEAR range +--echo # (coverage test for backward compatibility) + +SELECT COUNT(yy) FROM t2; +SELECT COUNT(yyyy) FROM t4; + +SELECT COUNT(*) FROM t2 WHERE yy = -1; +SELECT COUNT(*) FROM t4 WHERE yyyy > -1; +SELECT COUNT(*) FROM t2 WHERE yy > -1000000000000000000; +SELECT COUNT(*) FROM t4 WHERE yyyy > -1000000000000000000; + +SELECT COUNT(*) FROM t2 WHERE yy < 2156; +SELECT COUNT(*) FROM t4 WHERE yyyy < 2156; +SELECT COUNT(*) FROM t2 WHERE yy < 1000000000000000000; +SELECT COUNT(*) FROM t4 WHERE yyyy < 1000000000000000000; + +SELECT * FROM t2 WHERE yy < 123; +SELECT * FROM t2 WHERE yy > 123; +SELECT * FROM t4 WHERE yyyy < 123; +SELECT * FROM t4 WHERE yyyy > 123; + +DROP TABLE t2, t4; + +--echo # + +--echo End of 5.1 tests diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index fd5eca8911a..d99748b87a0 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -956,40 +956,9 @@ int Arg_comparator::set_cmp_func(Item_result_field *owner_arg, if (agg_item_set_converter(coll, owner->func_name(), b, 1, MY_COLL_CMP_CONV, 1)) return 1; - } else if (type != ROW_RESULT && ((*a)->field_type() == MYSQL_TYPE_YEAR || - (*b)->field_type() == MYSQL_TYPE_YEAR)) - { - is_nulls_eq= is_owner_equal_func(); - year_as_datetime= FALSE; - - if ((*a)->is_datetime()) - { - year_as_datetime= TRUE; - get_value_a_func= &get_datetime_value; - } else if ((*a)->field_type() == MYSQL_TYPE_YEAR) - get_value_a_func= &get_year_value; - else - { - /* - Because convert_constant_item is called only for EXECUTE in PS mode - the value of get_value_x_func set in PREPARE might be not - valid for EXECUTE. - */ - get_value_a_func= NULL; - } - - if ((*b)->is_datetime()) - { - year_as_datetime= TRUE; - get_value_b_func= &get_datetime_value; - } else if ((*b)->field_type() == MYSQL_TYPE_YEAR) - get_value_b_func= &get_year_value; - else - get_value_b_func= NULL; - - func= &Arg_comparator::compare_year; - return 0; } + else if (try_year_cmp_func(type)) + return 0; a= cache_converted_constant(thd, a, &a_cache, type); b= cache_converted_constant(thd, b, &b_cache, type); @@ -997,6 +966,45 @@ int Arg_comparator::set_cmp_func(Item_result_field *owner_arg, } +/* + Helper function to call from Arg_comparator::set_cmp_func() +*/ + +bool Arg_comparator::try_year_cmp_func(Item_result type) +{ + if (type == ROW_RESULT) + return FALSE; + + bool a_is_year= (*a)->field_type() == MYSQL_TYPE_YEAR; + bool b_is_year= (*b)->field_type() == MYSQL_TYPE_YEAR; + + if (!a_is_year && !b_is_year) + return FALSE; + + if (a_is_year && b_is_year) + { + get_value_a_func= &get_year_value; + get_value_b_func= &get_year_value; + } + else if (a_is_year && (*b)->is_datetime()) + { + get_value_a_func= &get_year_value; + get_value_b_func= &get_datetime_value; + } + else if (b_is_year && (*a)->is_datetime()) + { + get_value_b_func= &get_year_value; + get_value_a_func= &get_datetime_value; + } + else + return FALSE; + + is_nulls_eq= is_owner_equal_func(); + func= &Arg_comparator::compare_datetime; + + return TRUE; +} + /** Convert and cache a constant. @@ -1147,7 +1155,7 @@ get_datetime_value(THD *thd, Item ***item_arg, Item **cache_arg, /* - Retrieves YEAR value of 19XX form from given item. + Retrieves YEAR value of 19XX-00-00 00:00:00 form from given item. SYNOPSIS get_year_value() @@ -1159,7 +1167,9 @@ get_datetime_value(THD *thd, Item ***item_arg, Item **cache_arg, DESCRIPTION Retrieves the YEAR value of 19XX form from given item for comparison by the - compare_year() function. + compare_datetime() function. + Converts year to DATETIME of form YYYY-00-00 00:00:00 for the compatibility + with the get_datetime_value function result. RETURN obtained value @@ -1186,6 +1196,9 @@ get_year_value(THD *thd, Item ***item_arg, Item **cache_arg, if (value <= 1900) value+= 1900; + /* Convert year to DATETIME of form YYYY-00-00 00:00:00 (YYYY0000000000). */ + value*= 10000000000LL; + return value; } @@ -1615,67 +1628,6 @@ int Arg_comparator::compare_e_row() } -/** - Compare values as YEAR. - - @details - Compare items as YEAR for EQUAL_FUNC and for other comparison functions. - The YEAR values of form 19XX are obtained with help of the get_year_value() - function. - If one of arguments is of DATE/DATETIME type its value is obtained - with help of the get_datetime_value function. In this case YEAR values - prior to comparison are converted to the ulonglong YYYY-00-00 00:00:00 - DATETIME form. - If an argument type neither YEAR nor DATE/DATEIME then val_int function - is used to obtain value for comparison. - - RETURN - If is_nulls_eq is TRUE: - 1 if items are equal or both are null - 0 otherwise - If is_nulls_eq is FALSE: - -1 a < b - 0 a == b or at least one of items is null - 1 a > b - See the table: - is_nulls_eq | 1 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | - a_is_null | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | - b_is_null | 1 | 1 | 0 | 0 | 1 | 1 | 0 | 0 | - result | 1 | 0 | 0 |0/1| 0 | 0 | 0 |-1/0/1| -*/ - -int Arg_comparator::compare_year() -{ - bool a_is_null, b_is_null; - ulonglong val1= get_value_a_func ? - (*get_value_a_func)(thd, &a, &a_cache, *b, &a_is_null) : - (*a)->val_int(); - ulonglong val2= get_value_b_func ? - (*get_value_b_func)(thd, &b, &b_cache, *a, &b_is_null) : - (*b)->val_int(); - if (!(*a)->null_value) - { - if (!(*b)->null_value) - { - if (set_null) - owner->null_value= 0; - /* Convert year to DATETIME of form YYYY-00-00 00:00:00 when necessary. */ - if((*a)->field_type() == MYSQL_TYPE_YEAR && year_as_datetime) - val1*= 10000000000LL; - if((*b)->field_type() == MYSQL_TYPE_YEAR && year_as_datetime) - val2*= 10000000000LL; - - if (val1 < val2) return is_nulls_eq ? 0 : -1; - if (val1 == val2) return is_nulls_eq ? 1 : 0; - return is_nulls_eq ? 0 : 1; - } - } - if (set_null) - owner->null_value= is_nulls_eq ? 0 : 1; - return (is_nulls_eq && (*a)->null_value == (*b)->null_value) ? 1 : 0; -} - - void Item_func_truth::fix_length_and_dec() { maybe_null= 0; diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 52af6a31c0c..d4542dac820 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -42,24 +42,22 @@ class Arg_comparator: public Sql_alloc bool is_nulls_eq; // TRUE <=> compare for the EQUAL_FUNC bool set_null; // TRUE <=> set owner->null_value // when one of arguments is NULL. - bool year_as_datetime; // TRUE <=> convert YEAR value to - // the YYYY-00-00 00:00:00 DATETIME - // format. See compare_year. enum enum_date_cmp_type { CMP_DATE_DFLT= 0, CMP_DATE_WITH_DATE, CMP_DATE_WITH_STR, CMP_STR_WITH_DATE }; longlong (*get_value_a_func)(THD *thd, Item ***item_arg, Item **cache_arg, Item *warn_item, bool *is_null); longlong (*get_value_b_func)(THD *thd, Item ***item_arg, Item **cache_arg, Item *warn_item, bool *is_null); + bool try_year_cmp_func(Item_result type); public: DTCollation cmp_collation; /* Allow owner function to use string buffers. */ String value1, value2; Arg_comparator(): thd(0), a_cache(0), b_cache(0), set_null(0), - year_as_datetime(0), get_value_a_func(0), get_value_b_func(0) {}; + get_value_a_func(0), get_value_b_func(0) {}; Arg_comparator(Item **a1, Item **a2): a(a1), b(a2), thd(0), - a_cache(0), b_cache(0), set_null(0), year_as_datetime(0), + a_cache(0), b_cache(0), set_null(0), get_value_a_func(0), get_value_b_func(0) {}; int set_compare_func(Item_result_field *owner, Item_result type); @@ -101,7 +99,6 @@ public: int compare_real_fixed(); int compare_e_real_fixed(); int compare_datetime(); // compare args[0] & args[1] as DATETIMEs - int compare_year(); static enum enum_date_cmp_type can_compare_as_dates(Item *a, Item *b, ulonglong *const_val_arg); From 7b7a5c6e7abb98e86f579332b35e35f78fd6f440 Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Tue, 15 Dec 2009 10:54:53 +0200 Subject: [PATCH 2/4] Bug#49489: Uninitialized cache led to a wrong result. Merge the fix from 5.1-bugteam to 5.1-main --- mysql-test/r/select.result | 10 ++++++++++ mysql-test/t/select.test | 9 +++++++++ sql/item_cmpfunc.cc | 2 +- 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result index d0b2a575a32..1750051289a 100644 --- a/mysql-test/r/select.result +++ b/mysql-test/r/select.result @@ -4609,4 +4609,14 @@ HAVING v <= 't' ORDER BY pk; v DROP TABLE t1; +# +# Bug#49489 Uninitialized cache led to a wrong result. +# +CREATE TABLE t1(c1 DOUBLE(5,4)); +INSERT INTO t1 VALUES (9.1234); +SELECT * FROM t1 WHERE c1 < 9.12345; +c1 +9.1234 +DROP TABLE t1; +# End of test for bug#49489. End of 5.1 tests diff --git a/mysql-test/t/select.test b/mysql-test/t/select.test index ac65e5cbaf5..982aec726f7 100644 --- a/mysql-test/t/select.test +++ b/mysql-test/t/select.test @@ -3964,4 +3964,13 @@ ORDER BY pk; DROP TABLE t1; +--echo # +--echo # Bug#49489 Uninitialized cache led to a wrong result. +--echo # +CREATE TABLE t1(c1 DOUBLE(5,4)); +INSERT INTO t1 VALUES (9.1234); +SELECT * FROM t1 WHERE c1 < 9.12345; +DROP TABLE t1; +--echo # End of test for bug#49489. + --echo End of 5.1 tests diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index d99748b87a0..419b79377d7 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -1031,7 +1031,7 @@ Item** Arg_comparator::cache_converted_constant(THD *thd, Item **value, (*value)->const_item() && type != (*value)->result_type()) { Item_cache *cache= Item_cache::get_cache(*value, type); - cache->store(*value); + cache->setup(*value); *cache_item= cache; return cache_item; } From b4def7bea14b2102166365c44e359a26ae92d39b Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Tue, 15 Dec 2009 11:03:24 +0200 Subject: [PATCH 3/4] Bug #48985: show create table crashes if previous access to the table was killed Merge the fix from 5.1-bugteam to 5.1-main --- mysql-test/r/show_check.result | 6 ++++++ mysql-test/t/show_check.test | 22 ++++++++++++++++++++++ sql/sql_show.cc | 2 +- 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/show_check.result b/mysql-test/r/show_check.result index e6550bee954..ec0a70ff581 100644 --- a/mysql-test/r/show_check.result +++ b/mysql-test/r/show_check.result @@ -1454,4 +1454,10 @@ GRANT PROCESS ON *.* TO test_u@localhost; SHOW ENGINE MYISAM MUTEX; SHOW ENGINE MYISAM STATUS; DROP USER test_u@localhost; +# +# Bug #48985: show create table crashes if previous access to the table +# was killed +# +SHOW CREATE TABLE non_existent; +ERROR 70100: Query execution was interrupted End of 5.1 tests diff --git a/mysql-test/t/show_check.test b/mysql-test/t/show_check.test index 0ce807ae73e..d46261f38d2 100644 --- a/mysql-test/t/show_check.test +++ b/mysql-test/t/show_check.test @@ -1207,6 +1207,28 @@ connection default; DROP USER test_u@localhost; +--echo # +--echo # Bug #48985: show create table crashes if previous access to the table +--echo # was killed +--echo # + +connect(con1,localhost,root,,); +CONNECTION con1; +LET $ID= `SELECT connection_id()`; + +CONNECTION default; +--disable_query_log +eval KILL QUERY $ID; +--enable_query_log + +CONNECTION con1; +--error ER_QUERY_INTERRUPTED +SHOW CREATE TABLE non_existent; + +CONNECTION default; +DISCONNECT con1; + + --echo End of 5.1 tests # Wait till all disconnects are completed diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 2c1f360104b..e55000c0f65 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -719,7 +719,7 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list) thd->push_internal_handler(&view_error_suppressor); bool error= open_normal_and_derived_tables(thd, table_list, 0); thd->pop_internal_handler(); - if (error && thd->main_da.is_error()) + if (error && (thd->killed || thd->main_da.is_error())) DBUG_RETURN(TRUE); } From 4422b0f665fa3cba9f86b1c5e8e242f7839f6335 Mon Sep 17 00:00:00 2001 From: Ramil Kalimullin Date: Tue, 15 Dec 2009 21:08:21 +0400 Subject: [PATCH 4/4] Fix for bug#49517: Inconsistent behavior while using NULLable BIGINT and INT columns in comparison Problem: a consequence of the fix for 43668. Some Arg_comparator inner initialization missed, that may lead to unpredictable (wrong) comparison results. Fix: always properly initialize Arg_comparator before its usage. --- mysql-test/r/select.result | 15 +++++++++++++++ mysql-test/t/select.test | 14 ++++++++++++++ sql/item_cmpfunc.cc | 2 +- sql/item_cmpfunc.h | 4 ++-- 4 files changed, 32 insertions(+), 3 deletions(-) diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result index 1750051289a..f38af4ceb32 100644 --- a/mysql-test/r/select.result +++ b/mysql-test/r/select.result @@ -4619,4 +4619,19 @@ c1 9.1234 DROP TABLE t1; # End of test for bug#49489. +# +# Bug #49517: Inconsistent behavior while using +# NULLable BIGINT and INT columns in comparison +# +CREATE TABLE t1(a BIGINT UNSIGNED NOT NULL, b BIGINT NULL, c INT NULL); +INSERT INTO t1 VALUES(105, NULL, NULL); +SELECT * FROM t1 WHERE b < 102; +a b c +SELECT * FROM t1 WHERE c < 102; +a b c +SELECT * FROM t1 WHERE 102 < b; +a b c +SELECT * FROM t1 WHERE 102 < c; +a b c +DROP TABLE t1; End of 5.1 tests diff --git a/mysql-test/t/select.test b/mysql-test/t/select.test index 982aec726f7..e81c298166d 100644 --- a/mysql-test/t/select.test +++ b/mysql-test/t/select.test @@ -3973,4 +3973,18 @@ SELECT * FROM t1 WHERE c1 < 9.12345; DROP TABLE t1; --echo # End of test for bug#49489. + +--echo # +--echo # Bug #49517: Inconsistent behavior while using +--echo # NULLable BIGINT and INT columns in comparison +--echo # +CREATE TABLE t1(a BIGINT UNSIGNED NOT NULL, b BIGINT NULL, c INT NULL); +INSERT INTO t1 VALUES(105, NULL, NULL); +SELECT * FROM t1 WHERE b < 102; +SELECT * FROM t1 WHERE c < 102; +SELECT * FROM t1 WHERE 102 < b; +SELECT * FROM t1 WHERE 102 < c; +DROP TABLE t1; + + --echo End of 5.1 tests diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 419b79377d7..e4f26978431 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -895,9 +895,9 @@ int Arg_comparator::set_cmp_func(Item_result_field *owner_arg, ulonglong const_value= (ulonglong)-1; thd= current_thd; owner= owner_arg; + set_null= set_null && owner_arg; a= a1; b= a2; - owner= owner_arg; thd= current_thd; if ((cmp_type= can_compare_as_dates(*a, *b, &const_value))) diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index d4542dac820..05c9fc96ff5 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -54,10 +54,10 @@ public: /* Allow owner function to use string buffers. */ String value1, value2; - Arg_comparator(): thd(0), a_cache(0), b_cache(0), set_null(0), + Arg_comparator(): thd(0), a_cache(0), b_cache(0), set_null(TRUE), get_value_a_func(0), get_value_b_func(0) {}; Arg_comparator(Item **a1, Item **a2): a(a1), b(a2), thd(0), - a_cache(0), b_cache(0), set_null(0), + a_cache(0), b_cache(0), set_null(TRUE), get_value_a_func(0), get_value_b_func(0) {}; int set_compare_func(Item_result_field *owner, Item_result type);