diff options
author | Alexander Barkov <bar@mariadb.com> | 2020-06-05 12:57:42 +0400 |
---|---|---|
committer | Alexander Barkov <bar@mariadb.com> | 2020-06-06 11:33:11 +0400 |
commit | 79cdd7e76bbebf62629066166f43279095a0fcc9 (patch) | |
tree | f18fc41438f97b84427815e6b82727706c86b4c0 /sql/item_cmpfunc.cc | |
parent | a793ae5bc1270b18ab9359363dedab951f9a912f (diff) | |
download | mariadb-git-79cdd7e76bbebf62629066166f43279095a0fcc9.tar.gz |
MDEV-20305 Data loss on DOUBLE and DECIMAL conversion to INT
Bit operators (~ ^ | & << >>) and the function BIT_COUNT()
always called val_int() for their arguments.
It worked correctly only for INT type arguments.
In case of DECIMAL and DOUBLE arguments it did not work well:
the argument values were truncated to the maximum SIGNED BIGINT value
of 9223372036854775807.
Fixing the code as follows:
- If the argument if of an integer data type,
it works using val_int() as before.
- If the argument if of some other data type, it gets the argument value
using val_decimal(), to avoid truncation, and then converts the result
to ulonglong.
Using Item_handled_func to switch between the two approaches easier.
As an additional advantage, with Item_handled_func it will be easier
to implement overloading in the future, so data type plugings will be able
to define their own behavioir of bit operators and BIT_COUNT().
Moving the code from the former val_int() implementations
as methods to Longlong_null, to avoid code duplication in the
INT and DECIMAL branches.
Diffstat (limited to 'sql/item_cmpfunc.cc')
-rw-r--r-- | sql/item_cmpfunc.cc | 78 |
1 files changed, 54 insertions, 24 deletions
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 7fe16848082..24914accc6f 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -4733,43 +4733,73 @@ void Item_func_in::mark_as_condition_AND_part(TABLE_LIST *embedding) } -longlong Item_func_bit_or::val_int() +class Func_handler_bit_or_int_to_ulonglong: + public Item_handled_func::Handler_ulonglong { - DBUG_ASSERT(fixed == 1); - ulonglong arg1= (ulonglong) args[0]->val_int(); - if (args[0]->null_value) +public: + Longlong_null to_longlong_null(Item_handled_func *item) const { - null_value=1; /* purecov: inspected */ - return 0; /* purecov: inspected */ + DBUG_ASSERT(item->is_fixed()); + Longlong_null a= item->arguments()[0]->to_longlong_null(); + return a.is_null() ? a : a | item->arguments()[1]->to_longlong_null(); } - ulonglong arg2= (ulonglong) args[1]->val_int(); - if (args[1]->null_value) +}; + + +class Func_handler_bit_or_dec_to_ulonglong: + public Item_handled_func::Handler_ulonglong +{ +public: + Longlong_null to_longlong_null(Item_handled_func *item) const { - null_value=1; - return 0; + DBUG_ASSERT(item->is_fixed()); + VDec a(item->arguments()[0]); + return a.is_null() ? Longlong_null() : + a.to_xlonglong_null() | VDec(item->arguments()[1]).to_xlonglong_null(); } - null_value=0; - return (longlong) (arg1 | arg2); +}; + + +bool Item_func_bit_or::fix_length_and_dec() +{ + static Func_handler_bit_or_int_to_ulonglong ha_int_to_ull; + static Func_handler_bit_or_dec_to_ulonglong ha_dec_to_ull; + return fix_length_and_dec_op2_std(&ha_int_to_ull, &ha_dec_to_ull); } -longlong Item_func_bit_and::val_int() +class Func_handler_bit_and_int_to_ulonglong: + public Item_handled_func::Handler_ulonglong { - DBUG_ASSERT(fixed == 1); - ulonglong arg1= (ulonglong) args[0]->val_int(); - if (args[0]->null_value) +public: + Longlong_null to_longlong_null(Item_handled_func *item) const { - null_value=1; /* purecov: inspected */ - return 0; /* purecov: inspected */ + DBUG_ASSERT(item->is_fixed()); + Longlong_null a= item->arguments()[0]->to_longlong_null(); + return a.is_null() ? a : a & item->arguments()[1]->to_longlong_null(); } - ulonglong arg2= (ulonglong) args[1]->val_int(); - if (args[1]->null_value) +}; + + +class Func_handler_bit_and_dec_to_ulonglong: + public Item_handled_func::Handler_ulonglong +{ +public: + Longlong_null to_longlong_null(Item_handled_func *item) const { - null_value=1; /* purecov: inspected */ - return 0; /* purecov: inspected */ + DBUG_ASSERT(item->is_fixed()); + VDec a(item->arguments()[0]); + return a.is_null() ? Longlong_null() : + a.to_xlonglong_null() & VDec(item->arguments()[1]).to_xlonglong_null(); } - null_value=0; - return (longlong) (arg1 & arg2); +}; + + +bool Item_func_bit_and::fix_length_and_dec() +{ + static Func_handler_bit_and_int_to_ulonglong ha_int_to_ull; + static Func_handler_bit_and_dec_to_ulonglong ha_dec_to_ull; + return fix_length_and_dec_op2_std(&ha_int_to_ull, &ha_dec_to_ull); } Item_cond::Item_cond(THD *thd, Item_cond *item) |