mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +03:00
MDEV-12001 Split Item_func_round::fix_length_and_dec to virtual methods in Type_handler
This patch makes the following changes (according to the task description): - Adds Type_handler::Item_func_round_fix_length_and_dec(). - Splits the code from Item_func_round::fix_length_and_dec() into new Item_func_round methods fix_arg_int(), fix_arg_decimal(), fix_arg_double(). - Calls the new Item_func_round methods from the relevant implementations of Type_handler_xxx::Item_func_round_fix_length_and_dec(). - Adds a new error message ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION - Makes ROUND() return the new error for GEOMETRY Additionally: - Inherits Item_func_round directly from Item_func_numhybrid as it uses nothing from Item_func_num1. - Fixes "MDEV-12000 ROUND(expr,const_expr_returning_NULL) creates DOUBLE(0,0)". Now if args[1] returns NULL, the data type is set to DOUBLE with NOT_FIXED_DEC decimals instead of 0 decimals.
This commit is contained in:
@ -817,3 +817,21 @@ select 0=0, 0=-0, 0.0= -0.0, 0.0 = -(0.0), 0.0E1=-0.0E1, 0.0E1=-(0.0E1);
|
||||
select CRC32(NULL), CRC32(''), CRC32('MySQL'), CRC32('mysql'), CRC32('01234567'), CRC32('012345678');
|
||||
CRC32(NULL) CRC32('') CRC32('MySQL') CRC32('mysql') CRC32('01234567') CRC32('012345678')
|
||||
NULL 0 3259397556 2501908538 763378421 939184570
|
||||
#
|
||||
# Start of 10.3 tests
|
||||
#
|
||||
#
|
||||
# MDEV-12000 ROUND(expr,const_expr_returning_NULL) creates DOUBLE(0,0)
|
||||
#
|
||||
CREATE OR REPLACE TABLE t1 AS SELECT
|
||||
ROUND(10,NULL) AS c1,
|
||||
ROUND(10.1,NULL) AS c2,
|
||||
ROUND(10e0,NULL) AS c3;
|
||||
SHOW CREATE TABLE t1;
|
||||
Table Create Table
|
||||
t1 CREATE TABLE `t1` (
|
||||
`c1` double DEFAULT NULL,
|
||||
`c2` double DEFAULT NULL,
|
||||
`c3` double DEFAULT NULL
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=latin1
|
||||
DROP TABLE t1;
|
||||
|
@ -3711,5 +3711,14 @@ CASE a WHEN POINT(1,1) THEN "a" WHEN POINT(1,2) THEN "b" END
|
||||
DROP PROCEDURE p1;
|
||||
DROP PROCEDURE p2;
|
||||
#
|
||||
# MDEV-12001 Split Item_func_round::fix_length_and_dec to virtual methods in Type_handler
|
||||
#
|
||||
CREATE TABLE t1 (a GEOMETRY);
|
||||
SELECT ROUND(a) FROM t1;
|
||||
ERROR HY000: Illegal parameter data type geometry for operation 'round'
|
||||
DROP TABLE t1;
|
||||
SELECT ROUND(POINT(1,1));
|
||||
ERROR HY000: Illegal parameter data type geometry for operation 'round'
|
||||
#
|
||||
# End of 10.3 tests
|
||||
#
|
||||
|
@ -608,3 +608,19 @@ select 0=0, 0=-0, 0.0= -0.0, 0.0 = -(0.0), 0.0E1=-0.0E1, 0.0E1=-(0.0E1);
|
||||
--echo #
|
||||
|
||||
select CRC32(NULL), CRC32(''), CRC32('MySQL'), CRC32('mysql'), CRC32('01234567'), CRC32('012345678');
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # Start of 10.3 tests
|
||||
--echo #
|
||||
|
||||
--echo #
|
||||
--echo # MDEV-12000 ROUND(expr,const_expr_returning_NULL) creates DOUBLE(0,0)
|
||||
--echo #
|
||||
|
||||
CREATE OR REPLACE TABLE t1 AS SELECT
|
||||
ROUND(10,NULL) AS c1,
|
||||
ROUND(10.1,NULL) AS c2,
|
||||
ROUND(10e0,NULL) AS c3;
|
||||
SHOW CREATE TABLE t1;
|
||||
DROP TABLE t1;
|
||||
|
@ -1868,6 +1868,18 @@ CALL p1('CREATE TABLE t1 (a Point, b Point, c Point)');
|
||||
DROP PROCEDURE p1;
|
||||
DROP PROCEDURE p2;
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # MDEV-12001 Split Item_func_round::fix_length_and_dec to virtual methods in Type_handler
|
||||
--echo #
|
||||
|
||||
CREATE TABLE t1 (a GEOMETRY);
|
||||
--error ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION
|
||||
SELECT ROUND(a) FROM t1;
|
||||
DROP TABLE t1;
|
||||
--error ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION
|
||||
SELECT ROUND(POINT(1,1));
|
||||
|
||||
--echo #
|
||||
--echo # End of 10.3 tests
|
||||
--echo #
|
||||
|
15
sql/item.h
15
sql/item.h
@ -841,6 +841,21 @@ public:
|
||||
unsigned_flag to check the sign of the item.
|
||||
*/
|
||||
inline ulonglong val_uint() { return (ulonglong) val_int(); }
|
||||
/*
|
||||
Adjust the result of val_int() to an unsigned number:
|
||||
- NULL value is converted to 0. The caller can check "null_value"
|
||||
to distinguish between 0 and NULL when necessary.
|
||||
- Negative numbers are converted to 0.
|
||||
- Positive numbers bigger than upper_bound are converted to upper_bound.
|
||||
- Other numbers are returned as is.
|
||||
*/
|
||||
ulonglong val_uint_from_val_int(ulonglong upper_bound)
|
||||
{
|
||||
longlong nr= val_int();
|
||||
return (null_value || (nr < 0 && !unsigned_flag)) ? 0 :
|
||||
(ulonglong) nr > upper_bound ? upper_bound : (ulonglong) nr;
|
||||
}
|
||||
|
||||
/*
|
||||
Return string representation of this item object.
|
||||
|
||||
|
147
sql/item_func.cc
147
sql/item_func.cc
@ -2347,85 +2347,92 @@ my_decimal *Item_func_floor::decimal_op(my_decimal *decimal_value)
|
||||
}
|
||||
|
||||
|
||||
void Item_func_round::fix_length_and_dec()
|
||||
void Item_func_round::fix_length_and_dec_decimal(uint decimals_to_set)
|
||||
{
|
||||
int decimals_to_set;
|
||||
longlong val1;
|
||||
bool val1_unsigned;
|
||||
|
||||
unsigned_flag= args[0]->unsigned_flag;
|
||||
if (!args[1]->const_item())
|
||||
{
|
||||
decimals= args[0]->decimals;
|
||||
max_length= float_length(decimals);
|
||||
if (args[0]->result_type() == DECIMAL_RESULT)
|
||||
{
|
||||
max_length++;
|
||||
set_handler_by_result_type(DECIMAL_RESULT);
|
||||
}
|
||||
else
|
||||
set_handler_by_result_type(REAL_RESULT);
|
||||
return;
|
||||
}
|
||||
|
||||
val1= args[1]->val_int();
|
||||
if ((null_value= args[1]->null_value))
|
||||
return;
|
||||
|
||||
val1_unsigned= args[1]->unsigned_flag;
|
||||
if (val1 < 0)
|
||||
decimals_to_set= val1_unsigned ? INT_MAX : 0;
|
||||
else
|
||||
decimals_to_set= (val1 > INT_MAX) ? INT_MAX : (int) val1;
|
||||
|
||||
if (args[0]->decimals == NOT_FIXED_DEC)
|
||||
{
|
||||
decimals= MY_MIN(decimals_to_set, NOT_FIXED_DEC);
|
||||
max_length= float_length(decimals);
|
||||
set_handler_by_result_type(REAL_RESULT);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (args[0]->result_type()) {
|
||||
case REAL_RESULT:
|
||||
case STRING_RESULT:
|
||||
set_handler_by_result_type(REAL_RESULT);
|
||||
decimals= MY_MIN(decimals_to_set, NOT_FIXED_DEC);
|
||||
max_length= float_length(decimals);
|
||||
break;
|
||||
case INT_RESULT:
|
||||
if ((!decimals_to_set && truncate) || (args[0]->decimal_precision() < DECIMAL_LONGLONG_DIGITS))
|
||||
{
|
||||
int length_can_increase= MY_TEST(!truncate && (val1 < 0) &&
|
||||
!val1_unsigned);
|
||||
max_length= args[0]->max_length + length_can_increase;
|
||||
/* Here we can keep INT_RESULT */
|
||||
set_handler_by_result_type(INT_RESULT);
|
||||
decimals= 0;
|
||||
break;
|
||||
}
|
||||
/* fall through */
|
||||
case DECIMAL_RESULT:
|
||||
{
|
||||
set_handler_by_result_type(DECIMAL_RESULT);
|
||||
decimals_to_set= MY_MIN(DECIMAL_MAX_SCALE, decimals_to_set);
|
||||
int decimals_delta= args[0]->decimals - decimals_to_set;
|
||||
int precision= args[0]->decimal_precision();
|
||||
int length_increase= ((decimals_delta <= 0) || truncate) ? 0:1;
|
||||
|
||||
precision-= decimals_delta - length_increase;
|
||||
decimals= MY_MIN(decimals_to_set, DECIMAL_MAX_SCALE);
|
||||
int length_increase= (decimals_delta <= 0 || truncate) ? 0 : 1;
|
||||
int precision= args[0]->decimal_precision() + length_increase -
|
||||
decimals_delta;
|
||||
DBUG_ASSERT(decimals_to_set <= DECIMAL_MAX_SCALE);
|
||||
set_handler(&type_handler_newdecimal);
|
||||
unsigned_flag= args[0]->unsigned_flag;
|
||||
decimals= decimals_to_set;
|
||||
max_length= my_decimal_precision_to_length_no_truncation(precision,
|
||||
decimals,
|
||||
unsigned_flag);
|
||||
break;
|
||||
}
|
||||
|
||||
void Item_func_round::fix_length_and_dec_double(uint decimals_to_set)
|
||||
{
|
||||
set_handler(&type_handler_double);
|
||||
unsigned_flag= args[0]->unsigned_flag;
|
||||
decimals= decimals_to_set;
|
||||
max_length= float_length(decimals_to_set);
|
||||
}
|
||||
|
||||
|
||||
void Item_func_round::fix_arg_decimal()
|
||||
{
|
||||
if (args[1]->const_item())
|
||||
{
|
||||
uint dec= (uint) args[1]->val_uint_from_val_int(DECIMAL_MAX_SCALE);
|
||||
if (args[1]->null_value)
|
||||
fix_length_and_dec_double(NOT_FIXED_DEC);
|
||||
else
|
||||
fix_length_and_dec_decimal(dec);
|
||||
}
|
||||
case ROW_RESULT:
|
||||
case TIME_RESULT:
|
||||
DBUG_ASSERT(0); /* This result type isn't handled */
|
||||
else
|
||||
{
|
||||
set_handler(&type_handler_newdecimal);
|
||||
unsigned_flag= args[0]->unsigned_flag;
|
||||
decimals= args[0]->decimals;
|
||||
max_length= float_length(args[0]->decimals) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Item_func_round::fix_arg_double()
|
||||
{
|
||||
if (args[1]->const_item())
|
||||
{
|
||||
uint dec= (uint) args[1]->val_uint_from_val_int(NOT_FIXED_DEC);
|
||||
fix_length_and_dec_double(args[1]->null_value ? NOT_FIXED_DEC : dec);
|
||||
}
|
||||
else
|
||||
fix_length_and_dec_double(args[0]->decimals);
|
||||
}
|
||||
|
||||
|
||||
void Item_func_round::fix_arg_int()
|
||||
{
|
||||
if (args[1]->const_item())
|
||||
{
|
||||
longlong val1= args[1]->val_int();
|
||||
bool val1_is_negative= val1 < 0 && !args[1]->unsigned_flag;
|
||||
uint decimals_to_set= val1_is_negative ?
|
||||
0 : (uint) MY_MIN(val1, DECIMAL_MAX_SCALE);
|
||||
if (args[1]->null_value)
|
||||
fix_length_and_dec_double(NOT_FIXED_DEC);
|
||||
else if ((!decimals_to_set && truncate) ||
|
||||
args[0]->decimal_precision() < DECIMAL_LONGLONG_DIGITS)
|
||||
{
|
||||
// Length can increase in some cases: ROUND(9,-1) -> 10
|
||||
int length_can_increase= MY_TEST(!truncate && val1_is_negative);
|
||||
max_length= args[0]->max_length + length_can_increase;
|
||||
// Here we can keep INT_RESULT
|
||||
set_handler(&type_handler_longlong);
|
||||
unsigned_flag= args[0]->unsigned_flag;
|
||||
decimals= 0;
|
||||
}
|
||||
else
|
||||
fix_length_and_dec_decimal(decimals_to_set);
|
||||
}
|
||||
else
|
||||
fix_length_and_dec_double(args[0]->decimals);
|
||||
|
||||
}
|
||||
|
||||
|
||||
double my_double_round(double value, longlong dec, bool dec_unsigned,
|
||||
bool truncate)
|
||||
{
|
||||
|
@ -1202,17 +1202,25 @@ public:
|
||||
|
||||
/* This handles round and truncate */
|
||||
|
||||
class Item_func_round :public Item_func_num1
|
||||
class Item_func_round :public Item_func_numhybrid
|
||||
{
|
||||
bool truncate;
|
||||
void fix_length_and_dec_decimal(uint decimals_to_set);
|
||||
void fix_length_and_dec_double(uint decimals_to_set);
|
||||
public:
|
||||
Item_func_round(THD *thd, Item *a, Item *b, bool trunc_arg)
|
||||
:Item_func_num1(thd, a, b), truncate(trunc_arg) {}
|
||||
:Item_func_numhybrid(thd, a, b), truncate(trunc_arg) {}
|
||||
const char *func_name() const { return truncate ? "truncate" : "round"; }
|
||||
double real_op();
|
||||
longlong int_op();
|
||||
my_decimal *decimal_op(my_decimal *);
|
||||
void fix_length_and_dec();
|
||||
void fix_arg_decimal();
|
||||
void fix_arg_int();
|
||||
void fix_arg_double();
|
||||
void fix_length_and_dec()
|
||||
{
|
||||
args[0]->type_handler()->Item_func_round_fix_length_and_dec(this);
|
||||
}
|
||||
Item *get_copy(THD *thd, MEM_ROOT *mem_root)
|
||||
{ return get_item_copy<Item_func_round>(thd, mem_root, this); }
|
||||
};
|
||||
|
@ -7450,3 +7450,5 @@ ER_JSON_PATH_EMPTY
|
||||
eng "Path expression '$' is not allowed in argument %d to function '%s'."
|
||||
ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
|
||||
eng "Illegal parameter data types %s and %s for operation '%s'"
|
||||
ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION
|
||||
eng "Illegal parameter data type %s for operation '%s'"
|
||||
|
@ -26,7 +26,6 @@ static Type_handler_long type_handler_long;
|
||||
static Type_handler_int24 type_handler_int24;
|
||||
static Type_handler_year type_handler_year;
|
||||
static Type_handler_float type_handler_float;
|
||||
static Type_handler_double type_handler_double;
|
||||
static Type_handler_time type_handler_time;
|
||||
static Type_handler_time2 type_handler_time2;
|
||||
static Type_handler_date type_handler_date;
|
||||
@ -51,6 +50,7 @@ Type_handler_null type_handler_null;
|
||||
Type_handler_row type_handler_row;
|
||||
Type_handler_varchar type_handler_varchar;
|
||||
Type_handler_longlong type_handler_longlong;
|
||||
Type_handler_double type_handler_double;
|
||||
Type_handler_newdecimal type_handler_newdecimal;
|
||||
Type_handler_datetime type_handler_datetime;
|
||||
Type_handler_bit type_handler_bit;
|
||||
@ -2154,4 +2154,64 @@ String *Type_handler_timestamp_common::
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
bool Type_handler_row::
|
||||
Item_func_round_fix_length_and_dec(Item_func_round *item) const
|
||||
{
|
||||
DBUG_ASSERT(0);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool Type_handler_int_result::
|
||||
Item_func_round_fix_length_and_dec(Item_func_round *item) const
|
||||
{
|
||||
item->fix_arg_int();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool Type_handler_real_result::
|
||||
Item_func_round_fix_length_and_dec(Item_func_round *item) const
|
||||
{
|
||||
item->fix_arg_double();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool Type_handler_decimal_result::
|
||||
Item_func_round_fix_length_and_dec(Item_func_round *item) const
|
||||
{
|
||||
item->fix_arg_decimal();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool Type_handler_temporal_result::
|
||||
Item_func_round_fix_length_and_dec(Item_func_round *item) const
|
||||
{
|
||||
item->fix_arg_double();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool Type_handler_string_result::
|
||||
Item_func_round_fix_length_and_dec(Item_func_round *item) const
|
||||
{
|
||||
item->fix_arg_double();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
#ifdef HAVE_SPATIAL
|
||||
bool Type_handler_geometry::
|
||||
Item_func_round_fix_length_and_dec(Item_func_round *item) const
|
||||
{
|
||||
my_error(ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION, MYF(0),
|
||||
type_handler_geometry.name().ptr(), item->func_name());
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
/***************************************************************************/
|
||||
|
@ -35,6 +35,7 @@ class Item_func_hybrid_field_type;
|
||||
class Item_bool_func2;
|
||||
class Item_func_between;
|
||||
class Item_func_in;
|
||||
class Item_func_round;
|
||||
class cmp_item;
|
||||
class in_vector;
|
||||
class Type_std_attributes;
|
||||
@ -443,6 +444,9 @@ public:
|
||||
virtual bool
|
||||
Item_func_in_fix_comparator_compatible_types(THD *thd, Item_func_in *)
|
||||
const= 0;
|
||||
|
||||
virtual bool
|
||||
Item_func_round_fix_length_and_dec(Item_func_round *round) const= 0;
|
||||
};
|
||||
|
||||
|
||||
@ -594,6 +598,7 @@ public:
|
||||
in_vector *make_in_vector(THD *thd, const Item_func_in *f, uint nargs) const;
|
||||
bool Item_func_in_fix_comparator_compatible_types(THD *thd,
|
||||
Item_func_in *) const;
|
||||
bool Item_func_round_fix_length_and_dec(Item_func_round *) const;
|
||||
};
|
||||
|
||||
|
||||
@ -662,6 +667,7 @@ public:
|
||||
bool Item_func_in_fix_comparator_compatible_types(THD *thd,
|
||||
Item_func_in *) const;
|
||||
|
||||
bool Item_func_round_fix_length_and_dec(Item_func_round *) const;
|
||||
};
|
||||
|
||||
|
||||
@ -704,6 +710,7 @@ public:
|
||||
in_vector *make_in_vector(THD *, const Item_func_in *, uint nargs) const;
|
||||
bool Item_func_in_fix_comparator_compatible_types(THD *thd,
|
||||
Item_func_in *) const;
|
||||
bool Item_func_round_fix_length_and_dec(Item_func_round *) const;
|
||||
};
|
||||
|
||||
|
||||
@ -745,6 +752,7 @@ public:
|
||||
in_vector *make_in_vector(THD *, const Item_func_in *, uint nargs) const;
|
||||
bool Item_func_in_fix_comparator_compatible_types(THD *thd,
|
||||
Item_func_in *) const;
|
||||
bool Item_func_round_fix_length_and_dec(Item_func_round *) const;
|
||||
};
|
||||
|
||||
|
||||
@ -790,6 +798,7 @@ public:
|
||||
longlong Item_func_between_val_int(Item_func_between *func) const;
|
||||
bool Item_func_in_fix_comparator_compatible_types(THD *thd,
|
||||
Item_func_in *) const;
|
||||
bool Item_func_round_fix_length_and_dec(Item_func_round *) const;
|
||||
};
|
||||
|
||||
|
||||
@ -849,6 +858,7 @@ public:
|
||||
in_vector *make_in_vector(THD *, const Item_func_in *, uint nargs) const;
|
||||
bool Item_func_in_fix_comparator_compatible_types(THD *thd,
|
||||
Item_func_in *) const;
|
||||
bool Item_func_round_fix_length_and_dec(Item_func_round *) const;
|
||||
};
|
||||
|
||||
|
||||
@ -1263,6 +1273,7 @@ public:
|
||||
{
|
||||
return false;
|
||||
}
|
||||
bool Item_func_round_fix_length_and_dec(Item_func_round *) const;
|
||||
};
|
||||
#endif
|
||||
|
||||
@ -1381,6 +1392,7 @@ extern Type_handler_row type_handler_row;
|
||||
extern Type_handler_null type_handler_null;
|
||||
extern Type_handler_varchar type_handler_varchar;
|
||||
extern Type_handler_longlong type_handler_longlong;
|
||||
extern Type_handler_double type_handler_double;
|
||||
extern Type_handler_newdecimal type_handler_newdecimal;
|
||||
extern Type_handler_datetime type_handler_datetime;
|
||||
extern Type_handler_longlong type_handler_longlong;
|
||||
|
Reference in New Issue
Block a user