diff options
author | Jorgen Loland <jorgen.loland@oracle.com> | 2011-03-04 15:46:17 +0100 |
---|---|---|
committer | Jorgen Loland <jorgen.loland@oracle.com> | 2011-03-04 15:46:17 +0100 |
commit | 4015719c01c679544d47f4a788756128d9c34b93 (patch) | |
tree | d344171eb27cd61a824d74c757654e16caf999bb | |
parent | a4711099716c53490a69c3c17a8b61a4a3282b19 (diff) | |
download | mariadb-git-4015719c01c679544d47f4a788756128d9c34b93.tar.gz |
BUG#11766317: FIND_IN_SET won't work normaly after upgrade
from 5.1 to 5.5
(Former 59405)
In this bug, args[0] in an Item_func_find_in_set stored an
Item_func_weekday that was constant. In
Item_func_find_in_set::fix_length_and_dec(), args[0]->val_str()
was called. Later, when Item_func_find_in_set::val_int() was
called, args[0]->null_value was checked. However, the
Item_func_weekday in args[0] had now been replaced with an
Item_cache. No val_*() calls had been made to this Item_cache,
thus null_value was incorrectly 'true', resulting in missing
rows in the result set.
enum_value gets a value in fix_length_and_dec() iff args[0]
is both constant and non-null. It is therefore unnecessary
to check the null_value of args[0] in val_int().
An alternative fix would be to call args[0]->val_int() inside
Item_func_find_in_set::val_int(). This would ensure
args[0]->null_value was set correctly (always false in this case),
but that would have to be done for every record this const value
is checked against.
mysql-test/r/func_set.result:
Add test for BUG#59405
mysql-test/t/func_set.test:
Add test for BUG#59405
-rw-r--r-- | mysql-test/r/func_set.result | 42 | ||||
-rw-r--r-- | mysql-test/t/func_set.test | 22 | ||||
-rw-r--r-- | sql/item_func.cc | 19 |
3 files changed, 80 insertions, 3 deletions
diff --git a/mysql-test/r/func_set.result b/mysql-test/r/func_set.result index 14ebc8203ec..ba9500bff46 100644 --- a/mysql-test/r/func_set.result +++ b/mysql-test/r/func_set.result @@ -159,3 +159,45 @@ SELECT CONVERT( a USING latin1 ) FROM t2; CONVERT( a USING latin1 ) DROP TABLE t1, t2; +# +# BUG#59405: FIND_IN_SET won't work normaly after upgrade from 5.1 to 5.5 +# +CREATE TABLE t1(days set('1','2','3','4','5','6','7')); +INSERT INTO t1 VALUES('1,2,3,4,5,6,7'), (NULL), ('1,2,3,4,5,6,7'); + +SELECT * FROM t1 WHERE FIND_IN_SET(DAYOFWEEK(CURRENT_DATE()), days); +days +1,2,3,4,5,6,7 +1,2,3,4,5,6,7 +SELECT * FROM t1 WHERE FIND_IN_SET(DAYOFWEEK(CURRENT_DATE()), days) IS UNKNOWN; +days +NULL +SELECT * FROM t1 WHERE FIND_IN_SET(DAYOFWEEK(CURRENT_DATE()), NULL); +days +SELECT * FROM t1 WHERE FIND_IN_SET(DAYOFWEEK(CURRENT_DATE()), NULL) IS UNKNOWN; +days +1,2,3,4,5,6,7 +NULL +1,2,3,4,5,6,7 +SELECT * FROM t1 WHERE FIND_IN_SET(7, days); +days +1,2,3,4,5,6,7 +1,2,3,4,5,6,7 +SELECT * FROM t1 WHERE FIND_IN_SET(8, days); +days +SELECT * FROM t1 WHERE FIND_IN_SET(NULL, days); +days +SELECT * FROM t1 WHERE FIND_IN_SET(NULL, days) IS UNKNOWN; +days +1,2,3,4,5,6,7 +NULL +1,2,3,4,5,6,7 +SELECT * FROM t1 WHERE FIND_IN_SET(NULL, NULL); +days +SELECT * FROM t1 WHERE FIND_IN_SET(NULL, NULL) IS UNKNOWN; +days +1,2,3,4,5,6,7 +NULL +1,2,3,4,5,6,7 + +DROP TABLE t1; diff --git a/mysql-test/t/func_set.test b/mysql-test/t/func_set.test index 294efa8caf1..3531864c860 100644 --- a/mysql-test/t/func_set.test +++ b/mysql-test/t/func_set.test @@ -97,3 +97,25 @@ SELECT CONVERT( a USING latin1 ) FROM t1; SELECT CONVERT( a USING latin1 ) FROM t2; DROP TABLE t1, t2; + +--echo # +--echo # BUG#59405: FIND_IN_SET won't work normaly after upgrade from 5.1 to 5.5 +--echo # + +CREATE TABLE t1(days set('1','2','3','4','5','6','7')); +INSERT INTO t1 VALUES('1,2,3,4,5,6,7'), (NULL), ('1,2,3,4,5,6,7'); + +--echo +SELECT * FROM t1 WHERE FIND_IN_SET(DAYOFWEEK(CURRENT_DATE()), days); +SELECT * FROM t1 WHERE FIND_IN_SET(DAYOFWEEK(CURRENT_DATE()), days) IS UNKNOWN; +SELECT * FROM t1 WHERE FIND_IN_SET(DAYOFWEEK(CURRENT_DATE()), NULL); +SELECT * FROM t1 WHERE FIND_IN_SET(DAYOFWEEK(CURRENT_DATE()), NULL) IS UNKNOWN; +SELECT * FROM t1 WHERE FIND_IN_SET(7, days); +SELECT * FROM t1 WHERE FIND_IN_SET(8, days); +SELECT * FROM t1 WHERE FIND_IN_SET(NULL, days); +SELECT * FROM t1 WHERE FIND_IN_SET(NULL, days) IS UNKNOWN; +SELECT * FROM t1 WHERE FIND_IN_SET(NULL, NULL); +SELECT * FROM t1 WHERE FIND_IN_SET(NULL, NULL) IS UNKNOWN; + +--echo +DROP TABLE t1; diff --git a/sql/item_func.cc b/sql/item_func.cc index 9b8ba6968b3..1908eda7d99 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -3003,6 +3003,8 @@ void Item_func_find_in_set::fix_length_and_dec() String *find=args[0]->val_str(&value); if (find) { + // find is not NULL pointer so args[0] is not a null-value + DBUG_ASSERT(!args[0]->null_value); enum_value= find_type(((Field_enum*) field)->typelib,find->ptr(), find->length(), 0); enum_bit=0; @@ -3021,11 +3023,22 @@ longlong Item_func_find_in_set::val_int() DBUG_ASSERT(fixed == 1); if (enum_value) { - ulonglong tmp=(ulonglong) args[1]->val_int(); - if (!(null_value=args[1]->null_value || args[0]->null_value)) + // enum_value is set iff args[0]->const_item() in fix_length_and_dec(). + DBUG_ASSERT(args[0]->const_item()); + + ulonglong tmp= (ulonglong) args[1]->val_int(); + null_value= args[1]->null_value; + /* + No need to check args[0]->null_value since enum_value is set iff + args[0] is a non-null const item. Note: no DBUG_ASSERT on + args[0]->null_value here because args[0] may have been replaced + by an Item_cache on which val_int() has not been called. See + BUG#11766317 + */ + if (!null_value) { if (tmp & enum_bit) - return enum_value; + return enum_value; } return 0L; } |