From 36f8bfb22eda01d6d09c29007fe98d4a29610076 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 14 Jun 2007 18:55:07 -0700 Subject: [PATCH 1/5] Fixed bug #27932: the function LOCATE returned NULL if any of its arguments was evaluated to NULL, while the predicate LOCATE(str,NULL) IS NULL erroneously was evaluated to FALSE. This happened because the Item_func_locate::fix_length_and_dec method by mistake set the value of the maybe_null flag for the function item to 0. In consequence of this the function was considered as the one that could not ever return NULL. mysql-test/r/func_str.result: Added a test case for bug #27932. mysql-test/t/func_str.test: Added a test case for bug #27932. --- mysql-test/r/func_str.result | 76 ++++++++++++++++++++++++++++++++++++ mysql-test/t/func_str.test | 33 ++++++++++++++++ sql/item_func.cc | 1 - 3 files changed, 109 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/func_str.result b/mysql-test/r/func_str.result index d8afbe13c76..e79670b3f76 100644 --- a/mysql-test/r/func_str.result +++ b/mysql-test/r/func_str.result @@ -2061,4 +2061,80 @@ C 2707236321 DROP TABLE t1, t2; DROP VIEW v1; +SELECT LOCATE('foo', NULL) FROM DUAL; +LOCATE('foo', NULL) +NULL +SELECT LOCATE(NULL, 'o') FROM DUAL; +LOCATE(NULL, 'o') +NULL +SELECT LOCATE(NULL, NULL) FROM DUAL; +LOCATE(NULL, NULL) +NULL +SELECT LOCATE('foo', NULL) IS NULL FROM DUAL; +LOCATE('foo', NULL) IS NULL +1 +SELECT LOCATE(NULL, 'o') IS NULL FROM DUAL; +LOCATE(NULL, 'o') IS NULL +1 +SELECT LOCATE(NULL, NULL) IS NULL FROM DUAL; +LOCATE(NULL, NULL) IS NULL +1 +SELECT ISNULL(LOCATE('foo', NULL)) FROM DUAL; +ISNULL(LOCATE('foo', NULL)) +1 +SELECT ISNULL(LOCATE(NULL, 'o')) FROM DUAL; +ISNULL(LOCATE(NULL, 'o')) +1 +SELECT ISNULL(LOCATE(NULL, NULL)) FROM DUAL; +ISNULL(LOCATE(NULL, NULL)) +1 +SELECT LOCATE('foo', NULL) <=> NULL FROM DUAL; +LOCATE('foo', NULL) <=> NULL +1 +SELECT LOCATE(NULL, 'o') <=> NULL FROM DUAL; +LOCATE(NULL, 'o') <=> NULL +1 +SELECT LOCATE(NULL, NULL) <=> NULL FROM DUAL; +LOCATE(NULL, NULL) <=> NULL +1 +CREATE TABLE t1 (id int NOT NULL PRIMARY KEY, a varchar(10), p varchar(10)); +INSERT INTO t1 VALUES (1, 'foo', 'o'); +INSERT INTO t1 VALUES (2, 'foo', NULL); +INSERT INTO t1 VALUES (3, NULL, 'o'); +INSERT INTO t1 VALUES (4, NULL, NULL); +SELECT id, LOCATE(a,p) FROM t1; +id LOCATE(a,p) +1 0 +2 NULL +3 NULL +4 NULL +SELECT id, LOCATE(a,p) IS NULL FROM t1; +id LOCATE(a,p) IS NULL +1 0 +2 1 +3 1 +4 1 +SELECT id, ISNULL(LOCATE(a,p)) FROM t1; +id ISNULL(LOCATE(a,p)) +1 0 +2 1 +3 1 +4 1 +SELECT id, LOCATE(a,p) <=> NULL FROM t1; +id LOCATE(a,p) <=> NULL +1 0 +2 1 +3 1 +4 1 +SELECT id FROM t1 WHERE LOCATE(a,p) IS NULL; +id +2 +3 +4 +SELECT id FROM t1 WHERE LOCATE(a,p) <=> NULL; +id +2 +3 +4 +DROP TABLE t1; End of 5.0 tests diff --git a/mysql-test/t/func_str.test b/mysql-test/t/func_str.test index bca977e6df3..c8fd06cd1cd 100644 --- a/mysql-test/t/func_str.test +++ b/mysql-test/t/func_str.test @@ -1076,4 +1076,37 @@ SELECT * FROM (SELECT * FROM v1) x; DROP TABLE t1, t2; DROP VIEW v1; +# +# Bug #27932: LOCATE with argument evaluated to NULL +# + +SELECT LOCATE('foo', NULL) FROM DUAL; +SELECT LOCATE(NULL, 'o') FROM DUAL; +SELECT LOCATE(NULL, NULL) FROM DUAL; +SELECT LOCATE('foo', NULL) IS NULL FROM DUAL; +SELECT LOCATE(NULL, 'o') IS NULL FROM DUAL; +SELECT LOCATE(NULL, NULL) IS NULL FROM DUAL; +SELECT ISNULL(LOCATE('foo', NULL)) FROM DUAL; +SELECT ISNULL(LOCATE(NULL, 'o')) FROM DUAL; +SELECT ISNULL(LOCATE(NULL, NULL)) FROM DUAL; +SELECT LOCATE('foo', NULL) <=> NULL FROM DUAL; +SELECT LOCATE(NULL, 'o') <=> NULL FROM DUAL; +SELECT LOCATE(NULL, NULL) <=> NULL FROM DUAL; + +CREATE TABLE t1 (id int NOT NULL PRIMARY KEY, a varchar(10), p varchar(10)); + +INSERT INTO t1 VALUES (1, 'foo', 'o'); +INSERT INTO t1 VALUES (2, 'foo', NULL); +INSERT INTO t1 VALUES (3, NULL, 'o'); +INSERT INTO t1 VALUES (4, NULL, NULL); + +SELECT id, LOCATE(a,p) FROM t1; +SELECT id, LOCATE(a,p) IS NULL FROM t1; +SELECT id, ISNULL(LOCATE(a,p)) FROM t1; +SELECT id, LOCATE(a,p) <=> NULL FROM t1; +SELECT id FROM t1 WHERE LOCATE(a,p) IS NULL; +SELECT id FROM t1 WHERE LOCATE(a,p) <=> NULL; + +DROP TABLE t1; + --echo End of 5.0 tests diff --git a/sql/item_func.cc b/sql/item_func.cc index ab4a9c50332..17a2c584e9d 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -2507,7 +2507,6 @@ longlong Item_func_coercibility::val_int() void Item_func_locate::fix_length_and_dec() { - maybe_null= 0; max_length= MY_INT32_NUM_DECIMAL_DIGITS; agg_arg_charsets(cmp_collation, args, 2, MY_COLL_CMP_CONV, 1); } From 1b9f594f4af29311fa3f079dc0fd8365a86187df Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 16 Jun 2007 13:05:07 +0500 Subject: [PATCH 2/5] Fixed bug #28625: DECIMAL column was used instead of BIGINT for the minimal possible BIGINT (-9223372036854775808). The Item_func_neg::fix_length_and_dec has been adjusted to to inherit the type of the argument in the case when it's an Item_int object whose value is equal to LONGLONG_MIN. sql/item_func.cc: Fixed bug #28625. The Item_func_neg::fix_length_and_dec has been adjusted to to inherit the type of the argument in the case when it's an Item_int object whose value is equal to LONGLONG_MIN. mysql-test/t/bigint.test: Added test result for bug #28625. mysql-test/r/bigint.result: Added test case for bug #28625. --- mysql-test/r/bigint.result | 26 ++++++++++++++++++++++++++ mysql-test/t/bigint.test | 13 +++++++++++++ sql/item_func.cc | 22 +++++++++++++--------- 3 files changed, 52 insertions(+), 9 deletions(-) diff --git a/mysql-test/r/bigint.result b/mysql-test/r/bigint.result index f18d1c9b583..064304b27aa 100644 --- a/mysql-test/r/bigint.result +++ b/mysql-test/r/bigint.result @@ -362,3 +362,29 @@ cast(-19999999999999999999 as signed) -9223372036854775808 Warnings: Error 1292 Truncated incorrect DECIMAL value: '' +select -9223372036854775808; +Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr +def -9223372036854775808 8 20 20 N 32897 0 63 +-9223372036854775808 +-9223372036854775808 +select -(9223372036854775808); +Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr +def -(9223372036854775808) 8 20 20 N 32897 0 63 +-(9223372036854775808) +-9223372036854775808 +select -((9223372036854775808)); +Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr +def -((9223372036854775808)) 8 20 20 N 32897 0 63 +-((9223372036854775808)) +-9223372036854775808 +select -(-(9223372036854775808)); +Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr +def -(-(9223372036854775808)) 246 21 19 N 129 0 63 +-(-(9223372036854775808)) +9223372036854775808 +select --9223372036854775808, ---9223372036854775808, ----9223372036854775808; +--9223372036854775808 ---9223372036854775808 ----9223372036854775808 +9223372036854775808 -9223372036854775808 9223372036854775808 +select -(-9223372036854775808), -(-(-9223372036854775808)); +-(-9223372036854775808) -(-(-9223372036854775808)) +9223372036854775808 -9223372036854775808 diff --git a/mysql-test/t/bigint.test b/mysql-test/t/bigint.test index 9a5fb11229d..1f0f7763e87 100644 --- a/mysql-test/t/bigint.test +++ b/mysql-test/t/bigint.test @@ -294,3 +294,16 @@ drop table t1; select cast(19999999999999999999 as signed); select cast(-19999999999999999999 as signed); + +# +# Bug #28625: -9223372036854775808 doesn't fit in BIGINT. +# + +--enable_metadata +select -9223372036854775808; +select -(9223372036854775808); +select -((9223372036854775808)); +select -(-(9223372036854775808)); +--disable_metadata +select --9223372036854775808, ---9223372036854775808, ----9223372036854775808; +select -(-9223372036854775808), -(-(-9223372036854775808)); diff --git a/sql/item_func.cc b/sql/item_func.cc index 95ff432ca5a..487e91e4917 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -1523,16 +1523,20 @@ void Item_func_neg::fix_length_and_dec() Use val() to get value as arg_type doesn't mean that item is Item_int or Item_real due to existence of Item_param. */ - if (hybrid_type == INT_RESULT && - args[0]->type() == INT_ITEM && - ((ulonglong) args[0]->val_int() >= (ulonglong) LONGLONG_MIN)) + if (hybrid_type == INT_RESULT && args[0]->const_item()) { - /* - Ensure that result is converted to DECIMAL, as longlong can't hold - the negated number - */ - hybrid_type= DECIMAL_RESULT; - DBUG_PRINT("info", ("Type changed: DECIMAL_RESULT")); + longlong val= args[0]->val_int(); + if ((ulonglong) val >= (ulonglong) LONGLONG_MIN && + ((ulonglong) val != (ulonglong) LONGLONG_MIN || + args[0]->type() != INT_ITEM)) + { + /* + Ensure that result is converted to DECIMAL, as longlong can't hold + the negated number + */ + hybrid_type= DECIMAL_RESULT; + DBUG_PRINT("info", ("Type changed: DECIMAL_RESULT")); + } } unsigned_flag= 0; DBUG_VOID_RETURN; From 67988a75fc3030462d43c9625caa924bfc8c443d Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 16 Jun 2007 17:00:29 +0500 Subject: [PATCH 3/5] bigint.test: Updated test case for bug #28625. mysql-test/t/bigint.test: Updated test case for bug #28625. --- mysql-test/t/bigint.test | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mysql-test/t/bigint.test b/mysql-test/t/bigint.test index 1f0f7763e87..4aef7395184 100644 --- a/mysql-test/t/bigint.test +++ b/mysql-test/t/bigint.test @@ -299,11 +299,14 @@ select cast(-19999999999999999999 as signed); # Bug #28625: -9223372036854775808 doesn't fit in BIGINT. # +# PS protocol gives different metadata for `Max length' column +--disable_ps_protocol --enable_metadata select -9223372036854775808; select -(9223372036854775808); select -((9223372036854775808)); select -(-(9223372036854775808)); --disable_metadata +--endble_ps_protocol select --9223372036854775808, ---9223372036854775808, ----9223372036854775808; select -(-9223372036854775808), -(-(-9223372036854775808)); From a07b055b9ab75b54e9df33bb7634bde22543e8f1 Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 17 Jun 2007 11:23:19 -0700 Subject: [PATCH 4/5] Fixed bug #27130. If the third argument of the function SUBSTR was represented by an expression of the type UNSIGNED INT and this expression was evaluated to 0 then the function erroneously returned the value of the first argument instead of an empty string. This problem was introduced by the patch for bug 10963. The problem has been resolved by a proper modification of the code of Item_func_substr::val_str. mysql-test/r/func_str.result: Added a test case for bug #27130. mysql-test/t/func_str.test: Added a test case for bug #27130. --- mysql-test/r/func_str.result | 16 ++++++++++++++++ mysql-test/t/func_str.test | 15 +++++++++++++++ sql/item_strfunc.cc | 5 +++-- 3 files changed, 34 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/func_str.result b/mysql-test/r/func_str.result index d8afbe13c76..0dd7bd8f309 100644 --- a/mysql-test/r/func_str.result +++ b/mysql-test/r/func_str.result @@ -2061,4 +2061,20 @@ C 2707236321 DROP TABLE t1, t2; DROP VIEW v1; +SELECT SUBSTR('foo',1,0) FROM DUAL; +SUBSTR('foo',1,0) + +SELECT SUBSTR('foo',1,CAST(0 AS SIGNED)) FROM DUAL; +SUBSTR('foo',1,CAST(0 AS SIGNED)) + +SELECT SUBSTR('foo',1,CAST(0 AS UNSIGNED)) FROM DUAL; +SUBSTR('foo',1,CAST(0 AS UNSIGNED)) + +CREATE TABLE t1 (a varchar(10), len int unsigned); +INSERT INTO t1 VALUES ('bar', 2), ('foo', 0); +SELECT SUBSTR(a,1,len) FROM t1; +SUBSTR(a,1,len) +ba + +DROP TABLE t1; End of 5.0 tests diff --git a/mysql-test/t/func_str.test b/mysql-test/t/func_str.test index bca977e6df3..012e6be2868 100644 --- a/mysql-test/t/func_str.test +++ b/mysql-test/t/func_str.test @@ -1076,4 +1076,19 @@ SELECT * FROM (SELECT * FROM v1) x; DROP TABLE t1, t2; DROP VIEW v1; +# +# Bug #27130: SUBSTR with UNSIGNED 0 as the last argument +# + +SELECT SUBSTR('foo',1,0) FROM DUAL; +SELECT SUBSTR('foo',1,CAST(0 AS SIGNED)) FROM DUAL; +SELECT SUBSTR('foo',1,CAST(0 AS UNSIGNED)) FROM DUAL; + +CREATE TABLE t1 (a varchar(10), len int unsigned); +INSERT INTO t1 VALUES ('bar', 2), ('foo', 0); + +SELECT SUBSTR(a,1,len) FROM t1; + +DROP TABLE t1; + --echo End of 5.0 tests diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 33e9b8de823..0c24f14c8fe 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -1145,8 +1145,9 @@ String *Item_func_substr::val_str(String *str) (arg_count == 3 && args[2]->null_value)))) return 0; /* purecov: inspected */ - /* Negative length, will return empty string. */ - if ((arg_count == 3) && (length <= 0) && !args[2]->unsigned_flag) + /* Negative or zero length, will return empty string. */ + if ((arg_count == 3) && (length <= 0) && + (length == 0 || !args[2]->unsigned_flag)) return &my_empty_string; /* Assumes that the maximum length of a String is < INT_MAX32. */ From 6e315bfae2fdd147c901647bb28ed09359aa0add Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 17 Jun 2007 11:43:49 -0700 Subject: [PATCH 5/5] Post-merge fix mysql-test/r/func_str.result: Post-merge fix. --- mysql-test/r/func_str.result | 1 + 1 file changed, 1 insertion(+) diff --git a/mysql-test/r/func_str.result b/mysql-test/r/func_str.result index d22b184b9ec..ce9633006af 100644 --- a/mysql-test/r/func_str.result +++ b/mysql-test/r/func_str.result @@ -2151,5 +2151,6 @@ INSERT INTO t1 VALUES ('bar', 2), ('foo', 0); SELECT SUBSTR(a,1,len) FROM t1; SUBSTR(a,1,len) ba + DROP TABLE t1; End of 5.0 tests