Commit 79cdd7e7 authored by Alexander Barkov's avatar Alexander Barkov

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.
parent a793ae5b
This diff is collapsed.
--echo #
--echo # Start of 10.5 tests
--echo #
--echo #
--echo # MDEV-20305 Data loss on DOUBLE and DECIMAL conversion to INT
--echo #
DELIMITER $$;
CREATE PROCEDURE p1(type VARCHAR(64), val VARCHAR(64))
BEGIN
EXECUTE IMMEDIATE CONCAT('CREATE TABLE t1 (a ', type, ')');
SHOW CREATE TABLE t1;
EXECUTE IMMEDIATE CONCAT('INSERT INTO t1 VALUES (', val, ')');
SELECT
a,
~a,
a & 18446744073709551615,
18446744073709551615 & a,
0 | a,
a | 0,
a << 0,
a >> 0,
a ^ 1,
1 ^ a,
BIT_COUNT(a)
FROM t1;
SHOW WARNINGS;
DROP TABLE t1;
END;
$$
DELIMITER ;$$
--vertical_results
CALL p1('BIGINT UNSIGNED', 18446744073709551615);
CALL p1('DOUBLE', 18446744073709551615);
CALL p1('DECIMAL(30,0)', 18446744073709551615);
CALL p1('BIGINT', -1);
CALL p1('DOUBLE', -1);
CALL p1('DECIMAL(30,0)', -1);
CALL p1('BIGINT', -9223372036854775808);
CALL p1('DOUBLE', -9223372036854775808);
CALL p1('DECIMAL(30,0)', -9223372036854775808);
--horizontal_results
DROP PROCEDURE p1;
SELECT CAST(CAST(18446744073709551615 AS UNSIGNED) AS DECIMAL(32))<<0 AS c1;
SELECT CAST(CAST(18446744073709551615 AS UNSIGNED) AS DOUBLE)<<0 AS c1;
SELECT COALESCE(CAST(CAST(0xFFFFFFFFFFFFFFFF AS UNSIGNED) AS DECIMAL(32))) << 0 AS c1;
SELECT COALESCE(CAST(CAST(0xFFFFFFFFFFFFFFFF AS UNSIGNED) AS DOUBLE)) << 0 AS c1;
SELECT 18446744073709551615 ^ 1 AS c1;
SELECT 18446744073709551615.0 ^ 1 AS c1;
SELECT 18446744073709551615e0 ^ 1 AS c1;
SELECT LAST_VALUE(18446744073709551615) ^ 1 AS c1;
SELECT LAST_VALUE(18446744073709551615.0) ^ 1 AS c1;
SELECT LAST_VALUE(18446744073709551615e0) ^ 1 AS c1;
SELECT 18446744073709551615 & 18446744073709551615 AS c1;
SELECT 18446744073709551615 & 18446744073709551615.0 AS c1;
SELECT 18446744073709551615 & 18446744073709551615e0 AS c1;
SELECT 18446744073709551615.0 & 18446744073709551615 AS c1;
SELECT 18446744073709551615.0 & 18446744073709551615.0 AS c1;
SELECT 18446744073709551615.0 & 18446744073709551615e0 AS c1;
SELECT 18446744073709551615e0 & 18446744073709551615 AS c1;
SELECT 18446744073709551615e0 & 18446744073709551615.0 AS c1;
SELECT 18446744073709551615e0 & 18446744073709551615e0 AS c1;
SELECT 0 | 18446744073709551615 AS c1;
SELECT 0 | 18446744073709551615.0 AS c1;
SELECT 0 | 18446744073709551615e0 AS c1;
SELECT 18446744073709551615 | 0 AS c1;
SELECT 18446744073709551615.0 | 0 AS c1;
SELECT 18446744073709551615e0 | 0 AS c1;
SELECT ~18446744073709551615 AS c1;
SELECT ~18446744073709551615.0 AS c1;
SELECT ~18446744073709551615e0 AS c1;
SELECT BIT_COUNT(18446744073709551615) AS c1;
SELECT BIT_COUNT(18446744073709551615.0) AS c1;
SELECT BIT_COUNT(18446744073709551615e0) AS c1;
SELECT BIT_COUNT(-9223372036854775808) AS c1;
SELECT BIT_COUNT(-9223372036854775808.0) AS c1;
SELECT BIT_COUNT(-9223372036854775808e0) AS c1;
--echo #
--echo # End of 10.5 tests
--echo #
......@@ -2326,7 +2326,7 @@ SELECT MAX('x') << 1, CAST(MAX('x') AS DOUBLE), CAST(MAX('x') AS DECIMAL);
MAX('x') << 1 CAST(MAX('x') AS DOUBLE) CAST(MAX('x') AS DECIMAL)
0 0 0
Warnings:
Warning 1292 Truncated incorrect INTEGER value: 'x'
Warning 1292 Truncated incorrect DECIMAL value: 'x'
Warning 1292 Truncated incorrect DOUBLE value: 'x'
Warning 1292 Truncated incorrect DECIMAL value: 'x'
#
......
......@@ -3071,7 +3071,7 @@ SELECT ((rpad(1.0,2048,1)) = ('4(') ^ (0.1));
((rpad(1.0,2048,1)) = ('4(') ^ (0.1))
0
Warnings:
Warning 1292 Truncated incorrect INTEGER value: '4('
Warning 1292 Truncated incorrect DECIMAL value: '4('
SELECT
pow((rpad(10.0,2048,1)),(b'1111111111111111111111111111111111111111111'));
ERROR 22003: DOUBLE value is out of range in 'pow(rpad(10.0,2048,1),0x07ffffffffff)'
......@@ -3079,7 +3079,7 @@ SELECT ((rpad(1.0,2048,1)) + (0) ^ ('../'));
((rpad(1.0,2048,1)) + (0) ^ ('../'))
1.011111111111111
Warnings:
Warning 1292 Truncated incorrect INTEGER value: '../'
Warning 1292 Truncated incorrect DECIMAL value: '../'
SELECT stddev_samp(rpad(1.0,2048,1));
stddev_samp(rpad(1.0,2048,1))
NULL
......
......@@ -2795,7 +2795,7 @@ SET sql_mode=DEFAULT;
DO TO_DAYS(SEC_TO_TIME(TIME(CEILING(UUID()))));
DO TO_DAYS(SEC_TO_TIME(MAKEDATE('',RAND(~('')))));
Warnings:
Warning 1292 Truncated incorrect INTEGER value: ''
Warning 1292 Truncated incorrect DECIMAL value: ''
Warning 1292 Truncated incorrect INTEGER value: ''
Warning 1292 Truncated incorrect seconds value: '20000101'
SELECT SEC_TO_TIME(MAKEDATE(0,RAND(~0)));
......
......@@ -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)
......
......@@ -2139,44 +2139,103 @@ double Item_func_cot::val_real()
// Shift-functions, same as << and >> in C/C++
longlong Item_func_shift_left::val_int()
class Func_handler_shift_left_int_to_ulonglong:
public Item_handled_func::Handler_ulonglong
{
DBUG_ASSERT(fixed == 1);
uint shift;
ulonglong res= ((ulonglong) args[0]->val_int() <<
(shift=(uint) args[1]->val_int()));
if (args[0]->null_value || args[1]->null_value)
public:
Longlong_null to_longlong_null(Item_handled_func *item) const
{
null_value=1;
return 0;
DBUG_ASSERT(item->is_fixed());
return item->arguments()[0]->to_longlong_null() <<
item->arguments()[1]->to_longlong_null();
}
null_value=0;
return (shift < sizeof(longlong)*8 ? (longlong) res : 0);
};
class Func_handler_shift_left_decimal_to_ulonglong:
public Item_handled_func::Handler_ulonglong
{
public:
Longlong_null to_longlong_null(Item_handled_func *item) const
{
DBUG_ASSERT(item->is_fixed());
return VDec(item->arguments()[0]).to_xlonglong_null() <<
item->arguments()[1]->to_longlong_null();
}
};
bool Item_func_shift_left::fix_length_and_dec()
{
static Func_handler_shift_left_int_to_ulonglong ha_int_to_ull;
static Func_handler_shift_left_decimal_to_ulonglong ha_dec_to_ull;
return fix_length_and_dec_op1_std(&ha_int_to_ull, &ha_dec_to_ull);
}
longlong Item_func_shift_right::val_int()
class Func_handler_shift_right_int_to_ulonglong:
public Item_handled_func::Handler_ulonglong
{
DBUG_ASSERT(fixed == 1);
uint shift;
ulonglong res= (ulonglong) args[0]->val_int() >>
(shift=(uint) args[1]->val_int());
if (args[0]->null_value || args[1]->null_value)
public:
Longlong_null to_longlong_null(Item_handled_func *item) const
{
null_value=1;
return 0;
DBUG_ASSERT(item->fixed == 1);
return item->arguments()[0]->to_longlong_null() >>
item->arguments()[1]->to_longlong_null();
}
null_value=0;
return (shift < sizeof(longlong)*8 ? (longlong) res : 0);
};
class Func_handler_shift_right_decimal_to_ulonglong:
public Item_handled_func::Handler_ulonglong
{
public:
Longlong_null to_longlong_null(Item_handled_func *item) const
{
DBUG_ASSERT(item->is_fixed());
return VDec(item->arguments()[0]).to_xlonglong_null() >>
item->arguments()[1]->to_longlong_null();
}
};
bool Item_func_shift_right::fix_length_and_dec()
{
static Func_handler_shift_right_int_to_ulonglong ha_int_to_ull;
static Func_handler_shift_right_decimal_to_ulonglong ha_dec_to_ull;
return fix_length_and_dec_op1_std(&ha_int_to_ull, &ha_dec_to_ull);
}
longlong Item_func_bit_neg::val_int()
class Func_handler_bit_neg_int_to_ulonglong:
public Item_handled_func::Handler_ulonglong
{
DBUG_ASSERT(fixed == 1);
ulonglong res= (ulonglong) args[0]->val_int();
if ((null_value=args[0]->null_value))
return 0;
return ~res;
public:
Longlong_null to_longlong_null(Item_handled_func *item) const
{
DBUG_ASSERT(item->is_fixed());
return ~ item->arguments()[0]->to_longlong_null();
}
};
class Func_handler_bit_neg_decimal_to_ulonglong:
public Item_handled_func::Handler_ulonglong
{
public:
Longlong_null to_longlong_null(Item_handled_func *item) const
{
DBUG_ASSERT(item->is_fixed());
return ~ VDec(item->arguments()[0]).to_xlonglong_null();
}
};
bool Item_func_bit_neg::fix_length_and_dec()
{
static Func_handler_bit_neg_int_to_ulonglong ha_int_to_ull;
static Func_handler_bit_neg_decimal_to_ulonglong ha_dec_to_ull;
return fix_length_and_dec_op1_std(&ha_int_to_ull, &ha_dec_to_ull);
}
......@@ -3199,13 +3258,39 @@ longlong Item_func_find_in_set::val_int()
return 0;
}
longlong Item_func_bit_count::val_int()
class Func_handler_bit_count_int_to_slong:
public Item_handled_func::Handler_slong2
{
DBUG_ASSERT(fixed == 1);
ulonglong value= (ulonglong) args[0]->val_int();
if ((null_value= args[0]->null_value))
return 0; /* purecov: inspected */
return (longlong) my_count_bits(value);
public:
Longlong_null to_longlong_null(Item_handled_func *item) const
{
DBUG_ASSERT(item->is_fixed());
return item->arguments()[0]->to_longlong_null().bit_count();
}
};
class Func_handler_bit_count_decimal_to_slong:
public Item_handled_func::Handler_slong2
{
public:
Longlong_null to_longlong_null(Item_handled_func *item) const
{
DBUG_ASSERT(item->is_fixed());
return VDec(item->arguments()[0]).to_xlonglong_null().bit_count();
}
};
bool Item_func_bit_count::fix_length_and_dec()
{
static Func_handler_bit_count_int_to_slong ha_int_to_slong;
static Func_handler_bit_count_decimal_to_slong ha_dec_to_slong;
set_func_handler(args[0]->cmp_type() == INT_RESULT ?
(const Handler *) &ha_int_to_slong :
(const Handler *) &ha_dec_to_slong);
return m_func_handler->fix_length_and_dec(this);
}
......@@ -6221,14 +6306,38 @@ void Item_func_match::print(String *str, enum_query_type query_type)
str->append(STRING_WITH_LEN("))"));
}
longlong Item_func_bit_xor::val_int()
class Func_handler_bit_xor_int_to_ulonglong:
public Item_handled_func::Handler_ulonglong
{
DBUG_ASSERT(fixed == 1);
ulonglong arg1= (ulonglong) args[0]->val_int();
ulonglong arg2= (ulonglong) args[1]->val_int();
if ((null_value= (args[0]->null_value || args[1]->null_value)))
return 0;
return (longlong) (arg1 ^ arg2);
public:
Longlong_null to_longlong_null(Item_handled_func *item) const
{
DBUG_ASSERT(item->is_fixed());
return item->arguments()[0]->to_longlong_null() ^
item->arguments()[1]->to_longlong_null();
}
};
class Func_handler_bit_xor_dec_to_ulonglong:
public Item_handled_func::Handler_ulonglong
{
public:
Longlong_null to_longlong_null(Item_handled_func *item) const
{
DBUG_ASSERT(item->is_fixed());
return VDec(item->arguments()[0]).to_xlonglong_null() ^
VDec(item->arguments()[1]).to_xlonglong_null();
}
};
bool Item_func_bit_xor::fix_length_and_dec()
{
static const Func_handler_bit_xor_int_to_ulonglong ha_int_to_ull;
static const Func_handler_bit_xor_dec_to_ulonglong ha_dec_to_ull;
return fix_length_and_dec_op2_std(&ha_int_to_ull, &ha_dec_to_ull);
}
......
......@@ -641,6 +641,87 @@ class Item_handled_func: public Item_func
};
class Handler_int: public Handler
{
public:
String *val_str(Item_handled_func *item, String *to) const
{
longlong nr= val_int(item);
if (item->null_value)
return 0;
to->set_int(nr, item->unsigned_flag, item->collation.collation);
return to;
}
String *val_str_ascii(Item_handled_func *item, String *to) const
{
return item->Item::val_str_ascii(to);
}
double val_real(Item_handled_func *item) const
{
return item->unsigned_flag ? (double) ((ulonglong) val_int(item)) :
(double) val_int(item);
}
my_decimal *val_decimal(Item_handled_func *item, my_decimal *to) const
{
return item->val_decimal_from_int(to);
}
bool get_date(THD *thd, Item_handled_func *item,
MYSQL_TIME *to, date_mode_t fuzzydate) const
{
return item->get_date_from_int(thd, to, fuzzydate);
}
longlong val_int(Item_handled_func *item) const
{
Longlong_null tmp= to_longlong_null(item);
item->null_value= tmp.is_null();
return tmp.value();
}
virtual Longlong_null to_longlong_null(Item_handled_func *item) const= 0;
};
class Handler_slong: public Handler_int
{
public:
const Type_handler *return_type_handler(const Item_handled_func *item) const
{
return &type_handler_slong;
}
bool fix_length_and_dec(Item_handled_func *item) const
{
item->unsigned_flag= false;
item->collation= DTCollation_numeric();
item->fix_char_length(11);
return false;
}
};
class Handler_slong2: public Handler_slong
{
public:
bool fix_length_and_dec(Item_handled_func *func) const
{
bool rc= Handler_slong::fix_length_and_dec(func);
func->max_length= 2;
return rc;
}
};
class Handler_ulonglong: public Handler_int
{
public:
const Type_handler *return_type_handler(const Item_handled_func *item) const
{
return &type_handler_ulonglong;
}
bool fix_length_and_dec(Item_handled_func *item) const
{
item->unsigned_flag= true;
item->collation= DTCollation_numeric();
item->fix_char_length(21);
return false;
}
};
protected:
const Handler *m_func_handler;
public:
......@@ -2188,84 +2269,99 @@ class Item_func_find_in_set :public Item_long_func
/* Base class for all bit functions: '~', '|', '^', '&', '>>', '<<' */
class Item_func_bit: public Item_longlong_func
class Item_func_bit_operator: public Item_handled_func
{
bool check_arguments() const
{ return check_argument_types_can_return_int(0, arg_count); }
protected:
bool fix_length_and_dec_op1_std(const Handler *ha_int, const Handler *ha_dec)
{
set_func_handler(args[0]->cmp_type() == INT_RESULT ? ha_int : ha_dec);
return m_func_handler->fix_length_and_dec(this);
}
bool fix_length_and_dec_op2_std(const Handler *ha_int, const Handler *ha_dec)
{
set_func_handler(args[0]->cmp_type() == INT_RESULT &&
args[1]->cmp_type() == INT_RESULT ? ha_int : ha_dec);
return m_func_handler->fix_length_and_dec(this);
}
public:
Item_func_bit(THD *thd, Item *a, Item *b): Item_longlong_func(thd, a, b) {}
Item_func_bit(THD *thd, Item *a): Item_longlong_func(thd, a) {}
bool fix_length_and_dec() { unsigned_flag= 1; return FALSE; }
virtual inline void print(String *str, enum_query_type query_type)
Item_func_bit_operator(THD *thd, Item *a)
:Item_handled_func(thd, a) {}
Item_func_bit_operator(THD *thd, Item *a, Item *b)
:Item_handled_func(thd, a, b) {}
void print(String *str, enum_query_type query_type)
{
print_op(str, query_type);
}
bool need_parentheses_in_default() { return true; }
};
class Item_func_bit_or :public Item_func_bit
class Item_func_bit_or :public Item_func_bit_operator
{
public:
Item_func_bit_or(THD *thd, Item *a, Item *b): Item_func_bit(thd, a, b) {}
longlong val_int();
Item_func_bit_or(THD *thd, Item *a, Item *b)
:Item_func_bit_operator(thd, a, b) {}
bool fix_length_and_dec();
const char *func_name() const { return "|"; }
enum precedence precedence() const { return BITOR_PRECEDENCE; }
Item *get_copy(THD *thd)
{ return get_item_copy<Item_func_bit_or>(thd, this); }
};
class Item_func_bit_and :public Item_func_bit
class Item_func_bit_and :public Item_func_bit_operator
{
public:
Item_func_bit_and(THD *thd, Item *a, Item *b): Item_func_bit(thd, a, b) {}
longlong val_int();
Item_func_bit_and(THD *thd, Item *a, Item *b)
:Item_func_bit_operator(thd, a, b) {}
bool fix_length_and_dec();
const char *func_name() const { return "&"; }
enum precedence precedence() const { return BITAND_PRECEDENCE; }
Item *get_copy(THD *thd)
{ return get_item_copy<Item_func_bit_and>(thd, this); }
};
class Item_func_bit_count :public Item_long_func
class Item_func_bit_count :public Item_handled_func
{
bool check_arguments() const
{ return args[0]->check_type_can_return_int(func_name()); }
public:
Item_func_bit_count(THD *thd, Item *a): Item_long_func(thd, a) {}
longlong val_int();
Item_func_bit_count(THD *thd, Item *a): Item_handled_func(thd, a) {}
const char *func_name() const { return "bit_count"; }
bool fix_length_and_dec() { max_length=2; return FALSE; }
bool fix_length_and_dec();
Item *get_copy(THD *thd)
{ return get_item_copy<Item_func_bit_count>(thd, this); }
};
class Item_func_shift_left :public Item_func_bit
class Item_func_shift_left :public Item_func_bit_operator
{
public:
Item_func_shift_left(THD *thd, Item *a, Item *b): Item_func_bit(thd, a, b) {}
longlong val_int();
Item_func_shift_left(THD *thd, Item *a, Item *b)
:Item_func_bit_operator(thd, a, b) {}
bool fix_length_and_dec();
const char *func_name() const { return "<<"; }
enum precedence precedence() const { return SHIFT_PRECEDENCE; }
Item *get_copy(THD *thd)
{ return get_item_copy<Item_func_shift_left>(thd, this); }
};
class Item_func_shift_right :public Item_func_bit
class Item_func_shift_right :public Item_func_bit_operator
{
public:
Item_func_shift_right(THD *thd, Item *a, Item *b): Item_func_bit(thd, a, b) {}
longlong val_int();
Item_func_shift_right(THD *thd, Item *a, Item *b)
:Item_func_bit_operator(thd, a, b) {}
bool fix_length_and_dec();
const char *func_name() const { return ">>"; }
enum precedence precedence() const { return SHIFT_PRECEDENCE; }
Item *get_copy(THD *thd)
{ return get_item_copy<Item_func_shift_right>(thd, this); }
};
class Item_func_bit_neg :public Item_func_bit
class Item_func_bit_neg :public Item_func_bit_operator
{
public:
Item_func_bit_neg(THD *thd, Item *a): Item_func_bit(thd, a) {}
longlong val_int();
Item_func_bit_neg(THD *thd, Item *a): Item_func_bit_operator(thd, a) {}
bool fix_length_and_dec();
const char *func_name() const { return "~"; }
enum precedence precedence() const { return NEG_PRECEDENCE; }
void print(String *str, enum_query_type query_type)
......@@ -3156,11 +3252,12 @@ class Item_func_match :public Item_real_func
};
class Item_func_bit_xor : public Item_func_bit
class Item_func_bit_xor : public Item_func_bit_operator
{
public:
Item_func_bit_xor(THD *thd, Item *a, Item *b): Item_func_bit(thd, a, b) {}
longlong val_int();
Item_func_bit_xor(THD *thd, Item *a, Item *b)
:Item_func_bit_operator(thd, a, b) {}
bool fix_length_and_dec();
const char *func_name() const { return "^"; }
enum precedence precedence() const { return BITXOR_PRECEDENCE; }
Item *get_copy(THD *thd)
......
......@@ -195,6 +195,16 @@ class my_decimal :public decimal_t
return res;
}
longlong to_longlong(bool unsigned_flag) const;
/*
Return the value as a signed or unsigned longlong, depending on the sign.
- Positive values are returned as unsigned.
- Negative values are returned as signed.
This is used by bit SQL operators: | & ^ ~
as well as by the SQL function BIT_COUNT().
*/
longlong to_xlonglong() const
{ return to_longlong(!sign()); }
// Convert to string returning decimal2string() error code
int to_string_native(String *to, uint prec, uint dec, char filler,
uint mask= E_DEC_FATAL_ERROR) const;
......
......@@ -338,6 +338,10 @@ class Dec_ptr
double to_double() const { return m_ptr ? m_ptr->to_double() : 0.0; }
longlong to_longlong(bool unsigned_flag)
{ return m_ptr ? m_ptr->to_longlong(unsigned_flag) : 0; }
Longlong_null to_xlonglong_null()
{
return m_ptr ? Longlong_null(m_ptr->to_xlonglong()) : Longlong_null();
}
bool to_bool() const { return m_ptr ? m_ptr->to_bool() : false; }
String *to_string(String *to) const
{
......
......@@ -16,6 +16,8 @@
#ifndef SQL_TYPE_INT_INCLUDED
#define SQL_TYPE_INT_INCLUDED
#include "my_bit.h" // my_count_bits()
class Null_flag
{
......@@ -43,6 +45,58 @@ class Longlong_null: public Longlong, public Null_flag
Longlong_null(longlong nr, bool is_null)
:Longlong(nr), Null_flag(is_null)
{ }
explicit Longlong_null()
:Longlong(0), Null_flag(true)
{ }
explicit Longlong_null(longlong nr)
:Longlong(nr), Null_flag(false)
{ }
Longlong_null operator|(const Longlong_null &other) const
{
if (is_null() || other.is_null())
return Longlong_null();
return Longlong_null(value() | other.value());
}
Longlong_null operator&(const Longlong_null &other) const
{
if (is_null() || other.is_null())
return Longlong_null();
return Longlong_null(value() & other.value());
}
Longlong_null operator^(const Longlong_null &other) const
{
if (is_null() || other.is_null())
return Longlong_null();
return Longlong_null((longlong) (value() ^ other.value()));
}
Longlong_null operator~() const
{
if (is_null())
return *this;
return Longlong_null((longlong) ~ (ulonglong) value());
}
Longlong_null operator<<(const Longlong_null &llshift) const
{
if (is_null() || llshift.is_null())
return Longlong_null();
uint shift= (uint) llshift.value();
ulonglong res= ((ulonglong) value()) << shift;
return Longlong_null(shift < sizeof(longlong) * 8 ? (longlong) res : 0);
}
Longlong_null operator>>(const Longlong_null &llshift) const
{
if (is_null() || llshift.is_null())
return Longlong_null();
uint shift= (uint) llshift.value();
ulonglong res= ((ulonglong) value()) >> shift;
return Longlong_null(shift < sizeof(longlong) * 8 ? (longlong) res : 0);
}
Longlong_null bit_count() const
{
if (is_null())
return *this;
return Longlong_null((longlong) my_count_bits((ulonglong) value()));
}
};
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment