summaryrefslogtreecommitdiff
path: root/sql/item_cmpfunc.cc
diff options
context:
space:
mode:
authorAlexander Barkov <bar@mariadb.com>2020-06-05 12:57:42 +0400
committerAlexander Barkov <bar@mariadb.com>2020-06-06 11:33:11 +0400
commit79cdd7e76bbebf62629066166f43279095a0fcc9 (patch)
treef18fc41438f97b84427815e6b82727706c86b4c0 /sql/item_cmpfunc.cc
parenta793ae5bc1270b18ab9359363dedab951f9a912f (diff)
downloadmariadb-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.cc78
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)