Commit 45730fb1 authored by Alexander Barkov's avatar Alexander Barkov

MDEV-12238 Add Type_handler::Item_func_{plus|minus|mul|div|mod}_fix_length_and_dec()

parent 949faa2e
...@@ -352,3 +352,56 @@ Note 1105 DBUG: types_compatible=yes bisect=yes ...@@ -352,3 +352,56 @@ Note 1105 DBUG: types_compatible=yes bisect=yes
DROP TABLE t1; DROP TABLE t1;
SET SESSION debug_dbug="-d,Predicant_to_list_comparator"; SET SESSION debug_dbug="-d,Predicant_to_list_comparator";
SET SESSION debug_dbug="-d,Item_func_in"; SET SESSION debug_dbug="-d,Item_func_in";
#
# MDEV-12238 Add Type_handler::Item_func_{plus|minus|mul|div|mod}_fix_length_and_dec()
#
SET debug_dbug='+d,num_op';
CREATE TABLE t1 AS SELECT
POINT(0,0)+POINT(0,0),
POINT(0,0)-POINT(0,0),
POINT(0,0)*POINT(0,0),
POINT(0,0)/POINT(0,0),
POINT(0,0) MOD POINT(0,0) LIMIT 0;
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`POINT(0,0)+POINT(0,0)` geometry DEFAULT NULL,
`POINT(0,0)-POINT(0,0)` geometry DEFAULT NULL,
`POINT(0,0)*POINT(0,0)` geometry DEFAULT NULL,
`POINT(0,0)/POINT(0,0)` geometry DEFAULT NULL,
`POINT(0,0) MOD POINT(0,0)` geometry DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
DROP TABLE t1;
CREATE TABLE t1 AS SELECT
POINT(0,0)+'0',
POINT(0,0)-'0',
POINT(0,0)*'0',
POINT(0,0)/'0',
POINT(0,0) MOD '0' LIMIT 0;
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`POINT(0,0)+'0'` longtext DEFAULT NULL,
`POINT(0,0)-'0'` longtext DEFAULT NULL,
`POINT(0,0)*'0'` longtext DEFAULT NULL,
`POINT(0,0)/'0'` longtext DEFAULT NULL,
`POINT(0,0) MOD '0'` longtext DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
DROP TABLE t1;
CREATE TABLE t1 AS SELECT
'0'+POINT(0,0),
'0'*POINT(0,0) LIMIT 0;
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`'0'+POINT(0,0)` longtext DEFAULT NULL,
`'0'*POINT(0,0)` longtext DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
DROP TABLE t1;
CREATE TABLE t1 AS SELECT '0'-POINT(0,0) LIMIT 0;
ERROR HY000: Illegal parameter data types varchar and geometry for operation '-'
CREATE TABLE t1 AS SELECT '0'/POINT(0,0) LIMIT 0;
ERROR HY000: Illegal parameter data types varchar and geometry for operation '/'
CREATE TABLE t1 AS SELECT '0' MOD POINT(0,0) LIMIT 0;
ERROR HY000: Illegal parameter data types varchar and geometry for operation '%'
SET debug_dbug='-d,num_op';
...@@ -3837,5 +3837,70 @@ SELECT LENGTH(CAST(COALESCE(a) AS BINARY)) FROM t1; ...@@ -3837,5 +3837,70 @@ SELECT LENGTH(CAST(COALESCE(a) AS BINARY)) FROM t1;
LENGTH(CAST(COALESCE(a) AS BINARY)) LENGTH(CAST(COALESCE(a) AS BINARY))
DROP TABLE t1; DROP TABLE t1;
# #
# MDEV-12238 Add Type_handler::Item_func_{plus|minus|mul|div|mod}_fix_length_and_dec()
#
CREATE TABLE t1 (a GEOMETRY);
SELECT POINT(1,1) + 1;
ERROR HY000: Illegal parameter data types geometry and bigint for operation '+'
SELECT POINT(1,1) - 1;
ERROR HY000: Illegal parameter data types geometry and bigint for operation '-'
SELECT POINT(1,1) * 1;
ERROR HY000: Illegal parameter data types geometry and bigint for operation '*'
SELECT POINT(1,1) / 1;
ERROR HY000: Illegal parameter data types geometry and bigint for operation '/'
SELECT POINT(1,1) MOD 1;
ERROR HY000: Illegal parameter data types geometry and bigint for operation '%'
SELECT 1 + POINT(1,1);
ERROR HY000: Illegal parameter data types bigint and geometry for operation '+'
SELECT 1 - POINT(1,1);
ERROR HY000: Illegal parameter data types bigint and geometry for operation '-'
SELECT 1 * POINT(1,1);
ERROR HY000: Illegal parameter data types bigint and geometry for operation '*'
SELECT 1 / POINT(1,1);
ERROR HY000: Illegal parameter data types bigint and geometry for operation '/'
SELECT 1 MOD POINT(1,1);
ERROR HY000: Illegal parameter data types bigint and geometry for operation '%'
SELECT a + 1 FROM t1;
ERROR HY000: Illegal parameter data types geometry and bigint for operation '+'
SELECT a - 1 FROM t1;
ERROR HY000: Illegal parameter data types geometry and bigint for operation '-'
SELECT a * 1 FROM t1;
ERROR HY000: Illegal parameter data types geometry and bigint for operation '*'
SELECT a / 1 FROM t1;
ERROR HY000: Illegal parameter data types geometry and bigint for operation '/'
SELECT a MOD 1 FROM t1;
ERROR HY000: Illegal parameter data types geometry and bigint for operation '%'
SELECT 1 + a FROM t1;
ERROR HY000: Illegal parameter data types bigint and geometry for operation '+'
SELECT 1 - a FROM t1;
ERROR HY000: Illegal parameter data types bigint and geometry for operation '-'
SELECT 1 * a FROM t1;
ERROR HY000: Illegal parameter data types bigint and geometry for operation '*'
SELECT 1 / a FROM t1;
ERROR HY000: Illegal parameter data types bigint and geometry for operation '/'
SELECT 1 MOD a FROM t1;
ERROR HY000: Illegal parameter data types bigint and geometry for operation '%'
SELECT COALESCE(a) + 1 FROM t1;
ERROR HY000: Illegal parameter data types geometry and bigint for operation '+'
SELECT COALESCE(a) - 1 FROM t1;
ERROR HY000: Illegal parameter data types geometry and bigint for operation '-'
SELECT COALESCE(a) * 1 FROM t1;
ERROR HY000: Illegal parameter data types geometry and bigint for operation '*'
SELECT COALESCE(a) / 1 FROM t1;
ERROR HY000: Illegal parameter data types geometry and bigint for operation '/'
SELECT COALESCE(a) MOD 1 FROM t1;
ERROR HY000: Illegal parameter data types geometry and bigint for operation '%'
SELECT 1 + COALESCE(a) FROM t1;
ERROR HY000: Illegal parameter data types bigint and geometry for operation '+'
SELECT 1 - COALESCE(a) FROM t1;
ERROR HY000: Illegal parameter data types bigint and geometry for operation '-'
SELECT 1 * COALESCE(a) FROM t1;
ERROR HY000: Illegal parameter data types bigint and geometry for operation '*'
SELECT 1 / COALESCE(a) FROM t1;
ERROR HY000: Illegal parameter data types bigint and geometry for operation '/'
SELECT 1 MOD COALESCE(a) FROM t1;
ERROR HY000: Illegal parameter data types bigint and geometry for operation '%'
DROP TABLE t1;
#
# End of 10.3 tests # End of 10.3 tests
# #
...@@ -46,3 +46,68 @@ DROP TABLE t1; ...@@ -46,3 +46,68 @@ DROP TABLE t1;
SET SESSION debug_dbug="-d,Predicant_to_list_comparator"; SET SESSION debug_dbug="-d,Predicant_to_list_comparator";
SET SESSION debug_dbug="-d,Item_func_in"; SET SESSION debug_dbug="-d,Item_func_in";
--echo #
--echo # MDEV-12238 Add Type_handler::Item_func_{plus|minus|mul|div|mod}_fix_length_and_dec()
--echo #
# This tests is to check that operators '+' and '*' are commutative,
# while operators '/', '-' and 'MOD' are not commutative.
#
# It forces substitution of type_aggregator_for_{plus|minus|mul|div|mod} to
# type_aggregator_for_result / type_aggregator_non_commutative_test,
# which have pairs:
# (GEOMETRY,GEOMETRY)->GEOMETRY
# (GEOMETRY,VARCHAR)->GEOMETRY
# Note, they don't not have a pair:
# (VARCHAR,GEOMETRY)->GEOMETRY
#
# Commutative operators should work for all these argument type combinations:
# (GEOMETRY,GEOMETRY), (GEOMETRY,VARCHAR), (VARCHAR,GEOMETRY).
# Non-commutative operators should work for:
# (GEOMETRY,GEOMETRY), (GEOMETRY,VARCHAR),
# but should fail for (VARCHAR,GEOMETRY).
#
# Note, LIMIT 0 is needed to avoid calling str_op(), which does DBUG_ASSERT(0).
SET debug_dbug='+d,num_op';
# (GEOMETRY,GEOMETRY) gives GEOMETRY for all operators
CREATE TABLE t1 AS SELECT
POINT(0,0)+POINT(0,0),
POINT(0,0)-POINT(0,0),
POINT(0,0)*POINT(0,0),
POINT(0,0)/POINT(0,0),
POINT(0,0) MOD POINT(0,0) LIMIT 0;
SHOW CREATE TABLE t1;
DROP TABLE t1;
# (GEOMETRY,VARCHAR) gives GEOMETRY for all operators
CREATE TABLE t1 AS SELECT
POINT(0,0)+'0',
POINT(0,0)-'0',
POINT(0,0)*'0',
POINT(0,0)/'0',
POINT(0,0) MOD '0' LIMIT 0;
SHOW CREATE TABLE t1;
DROP TABLE t1;
# (VARCHAR,GEOMETRY) gives GEOMETRY for commutative operators
CREATE TABLE t1 AS SELECT
'0'+POINT(0,0),
'0'*POINT(0,0) LIMIT 0;
SHOW CREATE TABLE t1;
DROP TABLE t1;
# (VARCHAR,GEOMETRY) gives an error for non-commutative operators
--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
CREATE TABLE t1 AS SELECT '0'-POINT(0,0) LIMIT 0;
--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
CREATE TABLE t1 AS SELECT '0'/POINT(0,0) LIMIT 0;
--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
CREATE TABLE t1 AS SELECT '0' MOD POINT(0,0) LIMIT 0;
SET debug_dbug='-d,num_op';
...@@ -2016,6 +2016,81 @@ SELECT LENGTH(CAST(COALESCE(a) AS BINARY)) FROM t1; ...@@ -2016,6 +2016,81 @@ SELECT LENGTH(CAST(COALESCE(a) AS BINARY)) FROM t1;
DROP TABLE t1; DROP TABLE t1;
--echo #
--echo # MDEV-12238 Add Type_handler::Item_func_{plus|minus|mul|div|mod}_fix_length_and_dec()
--echo #
CREATE TABLE t1 (a GEOMETRY);
--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
SELECT POINT(1,1) + 1;
--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
SELECT POINT(1,1) - 1;
--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
SELECT POINT(1,1) * 1;
--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
SELECT POINT(1,1) / 1;
--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
SELECT POINT(1,1) MOD 1;
--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
SELECT 1 + POINT(1,1);
--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
SELECT 1 - POINT(1,1);
--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
SELECT 1 * POINT(1,1);
--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
SELECT 1 / POINT(1,1);
--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
SELECT 1 MOD POINT(1,1);
--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
SELECT a + 1 FROM t1;
--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
SELECT a - 1 FROM t1;
--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
SELECT a * 1 FROM t1;
--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
SELECT a / 1 FROM t1;
--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
SELECT a MOD 1 FROM t1;
--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
SELECT 1 + a FROM t1;
--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
SELECT 1 - a FROM t1;
--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
SELECT 1 * a FROM t1;
--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
SELECT 1 / a FROM t1;
--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
SELECT 1 MOD a FROM t1;
--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
SELECT COALESCE(a) + 1 FROM t1;
--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
SELECT COALESCE(a) - 1 FROM t1;
--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
SELECT COALESCE(a) * 1 FROM t1;
--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
SELECT COALESCE(a) / 1 FROM t1;
--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
SELECT COALESCE(a) MOD 1 FROM t1;
--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
SELECT 1 + COALESCE(a) FROM t1;
--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
SELECT 1 - COALESCE(a) FROM t1;
--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
SELECT 1 * COALESCE(a) FROM t1;
--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
SELECT 1 / COALESCE(a) FROM t1;
--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
SELECT 1 MOD COALESCE(a) FROM t1;
DROP TABLE t1;
--echo # --echo #
--echo # End of 10.3 tests --echo # End of 10.3 tests
--echo # --echo #
...@@ -729,47 +729,31 @@ bool Item_func_connection_id::fix_fields(THD *thd, Item **ref) ...@@ -729,47 +729,31 @@ bool Item_func_connection_id::fix_fields(THD *thd, Item **ref)
} }
/** bool Item_num_op::fix_type_handler(const Type_aggregator *aggregator)
Check arguments here to determine result's type for a numeric
function of two arguments.
*/
void Item_num_op::fix_length_and_dec(void)
{ {
DBUG_ENTER("Item_num_op::fix_length_and_dec");
DBUG_PRINT("info", ("name %s", func_name()));
DBUG_ASSERT(arg_count == 2); DBUG_ASSERT(arg_count == 2);
Item_result r0= args[0]->cast_to_int_type_handler()->cmp_type(); const Type_handler *h0= args[0]->cast_to_int_type_handler();
Item_result r1= args[1]->cast_to_int_type_handler()->cmp_type(); const Type_handler *h1= args[1]->cast_to_int_type_handler();
if (!aggregate_for_num_op(aggregator, h0, h1))
return false;
my_error(ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION, MYF(0),
h0->name().ptr(), h1->name().ptr(), func_name());
return true;
}
if (r0 == REAL_RESULT || r1 == REAL_RESULT ||
r0 == STRING_RESULT || r1 ==STRING_RESULT) void Item_func_plus::fix_length_and_dec(void)
{ {
count_real_length(args, arg_count); DBUG_ENTER("Item_func_plus::fix_length_and_dec");
max_length= float_length(decimals); DBUG_PRINT("info", ("name %s", func_name()));
set_handler_by_result_type(REAL_RESULT); const Type_aggregator *aggregator= &type_handler_data->m_type_aggregator_for_plus;
} DBUG_EXECUTE_IF("num_op", aggregator= &type_handler_data->m_type_aggregator_for_result;);
else if (r0 == DECIMAL_RESULT || r1 == DECIMAL_RESULT || DBUG_ASSERT(aggregator->is_commutative());
r0 == TIME_RESULT || r1 == TIME_RESULT) if (!fix_type_handler(aggregator))
{
set_handler_by_result_type(DECIMAL_RESULT);
result_precision();
fix_decimals();
if ((r0 == TIME_RESULT || r1 == TIME_RESULT) && decimals == 0)
set_handler_by_result_type(INT_RESULT);
}
else
{ {
DBUG_ASSERT(r0 == INT_RESULT && r1 == INT_RESULT); Item_func_plus::type_handler()->Item_func_plus_fix_length_and_dec(this);
set_handler_by_result_type(INT_RESULT); DBUG_PRINT("info", ("Type: %s", type_handler()->name().ptr()));
result_precision();
decimals= 0;
} }
DBUG_PRINT("info", ("Type: %s",
(result_type() == REAL_RESULT ? "REAL_RESULT" :
result_type() == DECIMAL_RESULT ? "DECIMAL_RESULT" :
result_type() == INT_RESULT ? "INT_RESULT" :
"--ILLEGAL!!!--")));
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
...@@ -1299,11 +1283,6 @@ void Item_func_additive_op::result_precision() ...@@ -1299,11 +1283,6 @@ void Item_func_additive_op::result_precision()
DBUG_ASSERT(arg1_int >= 0); DBUG_ASSERT(arg1_int >= 0);
DBUG_ASSERT(arg2_int >= 0); DBUG_ASSERT(arg2_int >= 0);
/* Integer operations keep unsigned_flag if one of arguments is unsigned */
if (result_type() == INT_RESULT)
unsigned_flag= args[0]->unsigned_flag | args[1]->unsigned_flag;
else
unsigned_flag= args[0]->unsigned_flag & args[1]->unsigned_flag;
max_length= my_decimal_precision_to_length_no_truncation(precision, decimals, max_length= my_decimal_precision_to_length_no_truncation(precision, decimals,
unsigned_flag); unsigned_flag);
} }
...@@ -1313,16 +1292,30 @@ void Item_func_additive_op::result_precision() ...@@ -1313,16 +1292,30 @@ void Item_func_additive_op::result_precision()
The following function is here to allow the user to force The following function is here to allow the user to force
subtraction of UNSIGNED BIGINT to return negative values. subtraction of UNSIGNED BIGINT to return negative values.
*/ */
void Item_func_minus::fix_unsigned_flag()
void Item_func_minus::fix_length_and_dec()
{ {
Item_num_op::fix_length_and_dec();
if (unsigned_flag && if (unsigned_flag &&
(current_thd->variables.sql_mode & MODE_NO_UNSIGNED_SUBTRACTION)) (current_thd->variables.sql_mode & MODE_NO_UNSIGNED_SUBTRACTION))
unsigned_flag=0; unsigned_flag=0;
} }
void Item_func_minus::fix_length_and_dec()
{
DBUG_ENTER("Item_func_minus::fix_length_and_dec");
DBUG_PRINT("info", ("name %s", func_name()));
const Type_aggregator *aggregator= &type_handler_data->m_type_aggregator_for_minus;
DBUG_EXECUTE_IF("num_op", aggregator= &type_handler_data->m_type_aggregator_non_commutative_test;);
DBUG_ASSERT(!aggregator->is_commutative());
if (!fix_type_handler(aggregator))
{
Item_func_minus::type_handler()->Item_func_minus_fix_length_and_dec(this);
DBUG_PRINT("info", ("Type: %s", type_handler()->name().ptr()));
}
DBUG_VOID_RETURN;
}
double Item_func_minus::real_op() double Item_func_minus::real_op()
{ {
double value= args[0]->val_real() - args[1]->val_real(); double value= args[0]->val_real() - args[1]->val_real();
...@@ -1530,13 +1523,8 @@ my_decimal *Item_func_mul::decimal_op(my_decimal *decimal_value) ...@@ -1530,13 +1523,8 @@ my_decimal *Item_func_mul::decimal_op(my_decimal *decimal_value)
void Item_func_mul::result_precision() void Item_func_mul::result_precision()
{ {
/* Integer operations keep unsigned_flag if one of arguments is unsigned */
if (result_type() == INT_RESULT)
unsigned_flag= args[0]->unsigned_flag | args[1]->unsigned_flag;
else
unsigned_flag= args[0]->unsigned_flag & args[1]->unsigned_flag;
decimals= MY_MIN(args[0]->decimal_scale() + args[1]->decimal_scale(), decimals= MY_MIN(args[0]->decimal_scale() + args[1]->decimal_scale(),
DECIMAL_MAX_SCALE); DECIMAL_MAX_SCALE);
uint est_prec = args[0]->decimal_precision() + args[1]->decimal_precision(); uint est_prec = args[0]->decimal_precision() + args[1]->decimal_precision();
uint precision= MY_MIN(est_prec, DECIMAL_MAX_PRECISION); uint precision= MY_MIN(est_prec, DECIMAL_MAX_PRECISION);
max_length= my_decimal_precision_to_length_no_truncation(precision, decimals, max_length= my_decimal_precision_to_length_no_truncation(precision, decimals,
...@@ -1544,6 +1532,22 @@ void Item_func_mul::result_precision() ...@@ -1544,6 +1532,22 @@ void Item_func_mul::result_precision()
} }
void Item_func_mul::fix_length_and_dec(void)
{
DBUG_ENTER("Item_func_mul::fix_length_and_dec");
DBUG_PRINT("info", ("name %s", func_name()));
const Type_aggregator *aggregator= &type_handler_data->m_type_aggregator_for_mul;
DBUG_EXECUTE_IF("num_op", aggregator= &type_handler_data->m_type_aggregator_for_result;);
DBUG_ASSERT(aggregator->is_commutative());
if (!fix_type_handler(aggregator))
{
Item_func_mul::type_handler()->Item_func_mul_fix_length_and_dec(this);
DBUG_PRINT("info", ("Type: %s", type_handler()->name().ptr()));
}
DBUG_VOID_RETURN;
}
double Item_func_div::real_op() double Item_func_div::real_op()
{ {
DBUG_ASSERT(fixed == 1); DBUG_ASSERT(fixed == 1);
...@@ -1605,53 +1609,51 @@ void Item_func_div::result_precision() ...@@ -1605,53 +1609,51 @@ void Item_func_div::result_precision()
uint precision=MY_MIN(args[0]->decimal_precision() + uint precision=MY_MIN(args[0]->decimal_precision() +
args[1]->divisor_precision_increment() + prec_increment, args[1]->divisor_precision_increment() + prec_increment,
DECIMAL_MAX_PRECISION); DECIMAL_MAX_PRECISION);
/* Integer operations keep unsigned_flag if one of arguments is unsigned */
if (result_type() == INT_RESULT)
unsigned_flag= args[0]->unsigned_flag | args[1]->unsigned_flag;
else
unsigned_flag= args[0]->unsigned_flag & args[1]->unsigned_flag;
decimals= MY_MIN(args[0]->decimal_scale() + prec_increment, DECIMAL_MAX_SCALE); decimals= MY_MIN(args[0]->decimal_scale() + prec_increment, DECIMAL_MAX_SCALE);
max_length= my_decimal_precision_to_length_no_truncation(precision, decimals, max_length= my_decimal_precision_to_length_no_truncation(precision, decimals,
unsigned_flag); unsigned_flag);
} }
void Item_func_div::fix_length_and_dec() void Item_func_div::fix_length_and_dec_double(void)
{
Item_num_op::fix_length_and_dec_double();
decimals= MY_MAX(args[0]->decimals, args[1]->decimals) + prec_increment;
set_if_smaller(decimals, NOT_FIXED_DEC);
uint tmp= float_length(decimals);
if (decimals == NOT_FIXED_DEC)
max_length= tmp;
else
{
max_length=args[0]->max_length - args[0]->decimals + decimals;
set_if_smaller(max_length, tmp);
}
}
void Item_func_div::fix_length_and_dec_int(void)
{
set_handler(&type_handler_newdecimal);
DBUG_PRINT("info", ("Type changed: %s", type_handler()->name().ptr()));
Item_num_op::fix_length_and_dec_decimal();
}
void Item_func_div::fix_length_and_dec(void)
{ {
DBUG_ENTER("Item_func_div::fix_length_and_dec"); DBUG_ENTER("Item_func_div::fix_length_and_dec");
DBUG_PRINT("info", ("name %s", func_name()));
prec_increment= current_thd->variables.div_precincrement; prec_increment= current_thd->variables.div_precincrement;
Item_num_op::fix_length_and_dec(); maybe_null= 1; // devision by zero
switch (Item_func_div::result_type()) {
case REAL_RESULT: const Type_aggregator *aggregator= &type_handler_data->m_type_aggregator_for_div;
DBUG_EXECUTE_IF("num_op", aggregator= &type_handler_data->m_type_aggregator_non_commutative_test;);
DBUG_ASSERT(!aggregator->is_commutative());
if (!fix_type_handler(aggregator))
{ {
decimals=MY_MAX(args[0]->decimals,args[1]->decimals)+prec_increment; Item_func_div::type_handler()->Item_func_div_fix_length_and_dec(this);
set_if_smaller(decimals, NOT_FIXED_DEC); DBUG_PRINT("info", ("Type: %s", type_handler()->name().ptr()));
uint tmp=float_length(decimals);
if (decimals == NOT_FIXED_DEC)
max_length= tmp;
else
{
max_length=args[0]->max_length - args[0]->decimals + decimals;
set_if_smaller(max_length,tmp);
}
break;
}
case INT_RESULT:
set_handler_by_result_type(DECIMAL_RESULT);
DBUG_PRINT("info", ("Type changed: DECIMAL_RESULT"));
result_precision();
break;
case DECIMAL_RESULT:
result_precision();
fix_decimals();
break;
case STRING_RESULT:
case ROW_RESULT:
case TIME_RESULT:
DBUG_ASSERT(0);
} }
maybe_null= 1; // devision by zero
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
...@@ -1823,9 +1825,18 @@ void Item_func_mod::result_precision() ...@@ -1823,9 +1825,18 @@ void Item_func_mod::result_precision()
void Item_func_mod::fix_length_and_dec() void Item_func_mod::fix_length_and_dec()
{ {
Item_num_op::fix_length_and_dec(); DBUG_ENTER("Item_func_mod::fix_length_and_dec");
maybe_null= 1; DBUG_PRINT("info", ("name %s", func_name()));
unsigned_flag= args[0]->unsigned_flag; maybe_null= true; // division by zero
const Type_aggregator *aggregator= &type_handler_data->m_type_aggregator_for_mod;
DBUG_EXECUTE_IF("num_op", aggregator= &type_handler_data->m_type_aggregator_non_commutative_test;);
DBUG_ASSERT(!aggregator->is_commutative());
if (!fix_type_handler(aggregator))
{
Item_func_mod::type_handler()->Item_func_mod_fix_length_and_dec(this);
DBUG_PRINT("info", ("Type: %s", type_handler()->name().ptr()));
}
DBUG_VOID_RETURN;
} }
......
...@@ -695,7 +695,31 @@ class Item_num_op :public Item_func_numhybrid ...@@ -695,7 +695,31 @@ class Item_num_op :public Item_func_numhybrid
{ {
print_op(str, query_type); print_op(str, query_type);
} }
void fix_length_and_dec(); bool fix_type_handler(const Type_aggregator *aggregator);
void fix_length_and_dec_double()
{
count_real_length(args, arg_count);
max_length= float_length(decimals);
}
void fix_length_and_dec_decimal()
{
unsigned_flag= args[0]->unsigned_flag & args[1]->unsigned_flag;
result_precision();
fix_decimals();
}
void fix_length_and_dec_int()
{
unsigned_flag= args[0]->unsigned_flag | args[1]->unsigned_flag;
result_precision();
decimals= 0;
}
void fix_length_and_dec_temporal()
{
set_handler(&type_handler_newdecimal);
fix_length_and_dec_decimal();
if (decimals == 0)
set_handler(&type_handler_longlong);
}
bool need_parentheses_in_default() { return true; } bool need_parentheses_in_default() { return true; }
}; };
...@@ -949,6 +973,7 @@ class Item_func_plus :public Item_func_additive_op ...@@ -949,6 +973,7 @@ class Item_func_plus :public Item_func_additive_op
Item_func_additive_op(thd, a, b) {} Item_func_additive_op(thd, a, b) {}
const char *func_name() const { return "+"; } const char *func_name() const { return "+"; }
enum precedence precedence() const { return ADD_PRECEDENCE; } enum precedence precedence() const { return ADD_PRECEDENCE; }
void fix_length_and_dec();
longlong int_op(); longlong int_op();
double real_op(); double real_op();
my_decimal *decimal_op(my_decimal *); my_decimal *decimal_op(my_decimal *);
...@@ -967,6 +992,22 @@ class Item_func_minus :public Item_func_additive_op ...@@ -967,6 +992,22 @@ class Item_func_minus :public Item_func_additive_op
double real_op(); double real_op();
my_decimal *decimal_op(my_decimal *); my_decimal *decimal_op(my_decimal *);
void fix_length_and_dec(); void fix_length_and_dec();
void fix_unsigned_flag();
void fix_length_and_dec_double()
{
Item_func_additive_op::fix_length_and_dec_double();
fix_unsigned_flag();
}
void fix_length_and_dec_decimal()
{
Item_func_additive_op::fix_length_and_dec_decimal();
fix_unsigned_flag();
}
void fix_length_and_dec_int()
{
Item_func_additive_op::fix_length_and_dec_int();
fix_unsigned_flag();
}
Item *get_copy(THD *thd, MEM_ROOT *mem_root) Item *get_copy(THD *thd, MEM_ROOT *mem_root)
{ return get_item_copy<Item_func_minus>(thd, mem_root, this); } { return get_item_copy<Item_func_minus>(thd, mem_root, this); }
}; };
...@@ -983,6 +1024,7 @@ class Item_func_mul :public Item_num_op ...@@ -983,6 +1024,7 @@ class Item_func_mul :public Item_num_op
double real_op(); double real_op();
my_decimal *decimal_op(my_decimal *); my_decimal *decimal_op(my_decimal *);
void result_precision(); void result_precision();
void fix_length_and_dec();
bool check_partition_func_processor(void *int_arg) {return FALSE;} bool check_partition_func_processor(void *int_arg) {return FALSE;}
bool check_vcol_func_processor(void *arg) { return FALSE;} bool check_vcol_func_processor(void *arg) { return FALSE;}
Item *get_copy(THD *thd, MEM_ROOT *mem_root) Item *get_copy(THD *thd, MEM_ROOT *mem_root)
...@@ -1001,6 +1043,8 @@ class Item_func_div :public Item_num_op ...@@ -1001,6 +1043,8 @@ class Item_func_div :public Item_num_op
const char *func_name() const { return "/"; } const char *func_name() const { return "/"; }
enum precedence precedence() const { return MUL_PRECEDENCE; } enum precedence precedence() const { return MUL_PRECEDENCE; }
void fix_length_and_dec(); void fix_length_and_dec();
void fix_length_and_dec_double();
void fix_length_and_dec_int();
void result_precision(); void result_precision();
Item *get_copy(THD *thd, MEM_ROOT *mem_root) Item *get_copy(THD *thd, MEM_ROOT *mem_root)
{ return get_item_copy<Item_func_div>(thd, mem_root, this); } { return get_item_copy<Item_func_div>(thd, mem_root, this); }
...@@ -1040,6 +1084,22 @@ class Item_func_mod :public Item_num_op ...@@ -1040,6 +1084,22 @@ class Item_func_mod :public Item_num_op
enum precedence precedence() const { return MUL_PRECEDENCE; } enum precedence precedence() const { return MUL_PRECEDENCE; }
void result_precision(); void result_precision();
void fix_length_and_dec(); void fix_length_and_dec();
void fix_length_and_dec_double()
{
Item_num_op::fix_length_and_dec_double();
unsigned_flag= args[0]->unsigned_flag;
}
void fix_length_and_dec_decimal()
{
Item_num_op::fix_length_and_dec_decimal();
unsigned_flag= args[0]->unsigned_flag;
}
void fix_length_and_dec_int()
{
max_length= MY_MAX(args[0]->max_length, args[1]->max_length);
decimals= 0;
unsigned_flag= args[0]->unsigned_flag;
}
bool check_partition_func_processor(void *int_arg) {return FALSE;} bool check_partition_func_processor(void *int_arg) {return FALSE;}
bool check_vcol_func_processor(void *arg) { return FALSE;} bool check_vcol_func_processor(void *arg) { return FALSE;}
Item *get_copy(THD *thd, MEM_ROOT *mem_root) Item *get_copy(THD *thd, MEM_ROOT *mem_root)
......
...@@ -60,6 +60,17 @@ Type_handler_geometry type_handler_geometry; ...@@ -60,6 +60,17 @@ Type_handler_geometry type_handler_geometry;
bool Type_handler_data::init() bool Type_handler_data::init()
{ {
#ifdef HAVE_SPATIAL #ifdef HAVE_SPATIAL
#ifndef DBUG_OFF
if (m_type_aggregator_non_commutative_test.add(&type_handler_geometry,
&type_handler_geometry,
&type_handler_geometry) ||
m_type_aggregator_non_commutative_test.add(&type_handler_geometry,
&type_handler_varchar,
&type_handler_long_blob))
return true;
#endif
return return
m_type_aggregator_for_result.add(&type_handler_geometry, m_type_aggregator_for_result.add(&type_handler_geometry,
&type_handler_null, &type_handler_null,
...@@ -466,6 +477,63 @@ Type_handler_hybrid_field_type::aggregate_for_comparison(const Type_handler *h) ...@@ -466,6 +477,63 @@ Type_handler_hybrid_field_type::aggregate_for_comparison(const Type_handler *h)
} }
const Type_handler *
Type_handler::aggregate_for_num_op_traditional(const Type_handler *h0,
const Type_handler *h1)
{
Item_result r0= h0->cmp_type();
Item_result r1= h1->cmp_type();
if (r0 == REAL_RESULT || r1 == REAL_RESULT ||
r0 == STRING_RESULT || r1 ==STRING_RESULT)
return &type_handler_double;
if (r0 == TIME_RESULT || r1 == TIME_RESULT)
return &type_handler_datetime;
if (r0 == DECIMAL_RESULT || r1 == DECIMAL_RESULT)
return &type_handler_newdecimal;
DBUG_ASSERT(r0 == INT_RESULT && r1 == INT_RESULT);
return &type_handler_longlong;
}
const Type_aggregator::Pair*
Type_aggregator::find_pair(const Type_handler *handler1,
const Type_handler *handler2) const
{
for (uint i= 0; i < m_array.elements(); i++)
{
const Pair& el= m_array.at(i);
if (el.eq(handler1, handler2) ||
(m_is_commutative && el.eq(handler2, handler1)))
return &el;
}
return NULL;
}
bool
Type_handler_hybrid_field_type::aggregate_for_num_op(const Type_aggregator *agg,
const Type_handler *h0,
const Type_handler *h1)
{
const Type_handler *hres;
if (h0->is_traditional_type() && h1->is_traditional_type())
{
set_handler(Type_handler::aggregate_for_num_op_traditional(h0, h1));
return false;
}
if ((hres= agg->find_handler(h0, h1)))
{
set_handler(hres);
return false;
}
return true;
}
/***************************************************************************/ /***************************************************************************/
const Type_handler * const Type_handler *
...@@ -2709,3 +2777,248 @@ bool Type_handler_geometry:: ...@@ -2709,3 +2777,248 @@ bool Type_handler_geometry::
#endif /* HAVE_SPATIAL */ #endif /* HAVE_SPATIAL */
/***************************************************************************/ /***************************************************************************/
bool Type_handler_row::
Item_func_plus_fix_length_and_dec(Item_func_plus *item) const
{
DBUG_ASSERT(0);
return true;
}
bool Type_handler_int_result::
Item_func_plus_fix_length_and_dec(Item_func_plus *item) const
{
item->fix_length_and_dec_int();
return false;
}
bool Type_handler_real_result::
Item_func_plus_fix_length_and_dec(Item_func_plus *item) const
{
item->fix_length_and_dec_double();
return false;
}
bool Type_handler_decimal_result::
Item_func_plus_fix_length_and_dec(Item_func_plus *item) const
{
item->fix_length_and_dec_decimal();
return false;
}
bool Type_handler_temporal_result::
Item_func_plus_fix_length_and_dec(Item_func_plus *item) const
{
item->fix_length_and_dec_temporal();
return false;
}
bool Type_handler_string_result::
Item_func_plus_fix_length_and_dec(Item_func_plus *item) const
{
item->fix_length_and_dec_double();
return false;
}
/***************************************************************************/
bool Type_handler_row::
Item_func_minus_fix_length_and_dec(Item_func_minus *item) const
{
DBUG_ASSERT(0);
return true;
}
bool Type_handler_int_result::
Item_func_minus_fix_length_and_dec(Item_func_minus *item) const
{
item->fix_length_and_dec_int();
return false;
}
bool Type_handler_real_result::
Item_func_minus_fix_length_and_dec(Item_func_minus *item) const
{
item->fix_length_and_dec_double();
return false;
}
bool Type_handler_decimal_result::
Item_func_minus_fix_length_and_dec(Item_func_minus *item) const
{
item->fix_length_and_dec_decimal();
return false;
}
bool Type_handler_temporal_result::
Item_func_minus_fix_length_and_dec(Item_func_minus *item) const
{
item->fix_length_and_dec_temporal();
return false;
}
bool Type_handler_string_result::
Item_func_minus_fix_length_and_dec(Item_func_minus *item) const
{
item->fix_length_and_dec_double();
return false;
}
/***************************************************************************/
bool Type_handler_row::
Item_func_mul_fix_length_and_dec(Item_func_mul *item) const
{
DBUG_ASSERT(0);
return true;
}
bool Type_handler_int_result::
Item_func_mul_fix_length_and_dec(Item_func_mul *item) const
{
item->fix_length_and_dec_int();
return false;
}
bool Type_handler_real_result::
Item_func_mul_fix_length_and_dec(Item_func_mul *item) const
{
item->fix_length_and_dec_double();
return false;
}
bool Type_handler_decimal_result::
Item_func_mul_fix_length_and_dec(Item_func_mul *item) const
{
item->fix_length_and_dec_decimal();
return false;
}
bool Type_handler_temporal_result::
Item_func_mul_fix_length_and_dec(Item_func_mul *item) const
{
item->fix_length_and_dec_temporal();
return false;
}
bool Type_handler_string_result::
Item_func_mul_fix_length_and_dec(Item_func_mul *item) const
{
item->fix_length_and_dec_double();
return false;
}
/***************************************************************************/
bool Type_handler_row::
Item_func_div_fix_length_and_dec(Item_func_div *item) const
{
DBUG_ASSERT(0);
return true;
}
bool Type_handler_int_result::
Item_func_div_fix_length_and_dec(Item_func_div *item) const
{
item->fix_length_and_dec_int();
return false;
}
bool Type_handler_real_result::
Item_func_div_fix_length_and_dec(Item_func_div *item) const
{
item->fix_length_and_dec_double();
return false;
}
bool Type_handler_decimal_result::
Item_func_div_fix_length_and_dec(Item_func_div *item) const
{
item->fix_length_and_dec_decimal();
return false;
}
bool Type_handler_temporal_result::
Item_func_div_fix_length_and_dec(Item_func_div *item) const
{
item->fix_length_and_dec_temporal();
return false;
}
bool Type_handler_string_result::
Item_func_div_fix_length_and_dec(Item_func_div *item) const
{
item->fix_length_and_dec_double();
return false;
}
/***************************************************************************/
bool Type_handler_row::
Item_func_mod_fix_length_and_dec(Item_func_mod *item) const
{
DBUG_ASSERT(0);
return true;
}
bool Type_handler_int_result::
Item_func_mod_fix_length_and_dec(Item_func_mod *item) const
{
item->fix_length_and_dec_int();
return false;
}
bool Type_handler_real_result::
Item_func_mod_fix_length_and_dec(Item_func_mod *item) const
{
item->fix_length_and_dec_double();
return false;
}
bool Type_handler_decimal_result::
Item_func_mod_fix_length_and_dec(Item_func_mod *item) const
{
item->fix_length_and_dec_decimal();
return false;
}
bool Type_handler_temporal_result::
Item_func_mod_fix_length_and_dec(Item_func_mod *item) const
{
item->fix_length_and_dec_temporal();
return false;
}
bool Type_handler_string_result::
Item_func_mod_fix_length_and_dec(Item_func_mod *item) const
{
item->fix_length_and_dec_double();
return false;
}
/***************************************************************************/
...@@ -51,6 +51,11 @@ class Item_char_typecast; ...@@ -51,6 +51,11 @@ class Item_char_typecast;
class Item_time_typecast; class Item_time_typecast;
class Item_date_typecast; class Item_date_typecast;
class Item_datetime_typecast; class Item_datetime_typecast;
class Item_func_plus;
class Item_func_minus;
class Item_func_mul;
class Item_func_div;
class Item_func_mod;
class cmp_item; class cmp_item;
class in_vector; class in_vector;
class Type_std_attributes; class Type_std_attributes;
...@@ -303,6 +308,9 @@ class Type_handler ...@@ -303,6 +308,9 @@ class Type_handler
static const static const
Type_handler *aggregate_for_result_traditional(const Type_handler *h1, Type_handler *aggregate_for_result_traditional(const Type_handler *h1,
const Type_handler *h2); const Type_handler *h2);
static const
Type_handler *aggregate_for_num_op_traditional(const Type_handler *h1,
const Type_handler *h2);
virtual const Name name() const= 0; virtual const Name name() const= 0;
virtual enum_field_types field_type() const= 0; virtual enum_field_types field_type() const= 0;
...@@ -497,6 +505,17 @@ class Type_handler ...@@ -497,6 +505,17 @@ class Type_handler
Item_date_typecast_fix_length_and_dec(Item_date_typecast *item) const; Item_date_typecast_fix_length_and_dec(Item_date_typecast *item) const;
virtual bool virtual bool
Item_datetime_typecast_fix_length_and_dec(Item_datetime_typecast *item) const; Item_datetime_typecast_fix_length_and_dec(Item_datetime_typecast *item) const;
virtual bool
Item_func_plus_fix_length_and_dec(Item_func_plus *func) const= 0;
virtual bool
Item_func_minus_fix_length_and_dec(Item_func_minus *func) const= 0;
virtual bool
Item_func_mul_fix_length_and_dec(Item_func_mul *func) const= 0;
virtual bool
Item_func_div_fix_length_and_dec(Item_func_div *func) const= 0;
virtual bool
Item_func_mod_fix_length_and_dec(Item_func_mod *func) const= 0;
}; };
...@@ -708,6 +727,12 @@ class Type_handler_row: public Type_handler ...@@ -708,6 +727,12 @@ class Type_handler_row: public Type_handler
DBUG_ASSERT(0); DBUG_ASSERT(0);
return true; return true;
} }
bool Item_func_plus_fix_length_and_dec(Item_func_plus *) const;
bool Item_func_minus_fix_length_and_dec(Item_func_minus *) const;
bool Item_func_mul_fix_length_and_dec(Item_func_mul *) const;
bool Item_func_div_fix_length_and_dec(Item_func_div *) const;
bool Item_func_mod_fix_length_and_dec(Item_func_mod *) const;
}; };
...@@ -784,6 +809,11 @@ class Type_handler_real_result: public Type_handler_numeric ...@@ -784,6 +809,11 @@ class Type_handler_real_result: public Type_handler_numeric
bool Item_func_int_val_fix_length_and_dec(Item_func_int_val *) const; bool Item_func_int_val_fix_length_and_dec(Item_func_int_val *) const;
bool Item_func_abs_fix_length_and_dec(Item_func_abs *) const; bool Item_func_abs_fix_length_and_dec(Item_func_abs *) const;
bool Item_func_neg_fix_length_and_dec(Item_func_neg *) const; bool Item_func_neg_fix_length_and_dec(Item_func_neg *) const;
bool Item_func_plus_fix_length_and_dec(Item_func_plus *) const;
bool Item_func_minus_fix_length_and_dec(Item_func_minus *) const;
bool Item_func_mul_fix_length_and_dec(Item_func_mul *) const;
bool Item_func_div_fix_length_and_dec(Item_func_div *) const;
bool Item_func_mod_fix_length_and_dec(Item_func_mod *) const;
}; };
...@@ -833,6 +863,11 @@ class Type_handler_decimal_result: public Type_handler_numeric ...@@ -833,6 +863,11 @@ class Type_handler_decimal_result: public Type_handler_numeric
bool Item_func_int_val_fix_length_and_dec(Item_func_int_val *) const; bool Item_func_int_val_fix_length_and_dec(Item_func_int_val *) const;
bool Item_func_abs_fix_length_and_dec(Item_func_abs *) const; bool Item_func_abs_fix_length_and_dec(Item_func_abs *) const;
bool Item_func_neg_fix_length_and_dec(Item_func_neg *) const; bool Item_func_neg_fix_length_and_dec(Item_func_neg *) const;
bool Item_func_plus_fix_length_and_dec(Item_func_plus *) const;
bool Item_func_minus_fix_length_and_dec(Item_func_minus *) const;
bool Item_func_mul_fix_length_and_dec(Item_func_mul *) const;
bool Item_func_div_fix_length_and_dec(Item_func_div *) const;
bool Item_func_mod_fix_length_and_dec(Item_func_mod *) const;
}; };
...@@ -881,6 +916,11 @@ class Type_handler_int_result: public Type_handler_numeric ...@@ -881,6 +916,11 @@ class Type_handler_int_result: public Type_handler_numeric
bool Item_func_int_val_fix_length_and_dec(Item_func_int_val *) const; bool Item_func_int_val_fix_length_and_dec(Item_func_int_val *) const;
bool Item_func_abs_fix_length_and_dec(Item_func_abs *) const; bool Item_func_abs_fix_length_and_dec(Item_func_abs *) const;
bool Item_func_neg_fix_length_and_dec(Item_func_neg *) const; bool Item_func_neg_fix_length_and_dec(Item_func_neg *) const;
bool Item_func_plus_fix_length_and_dec(Item_func_plus *) const;
bool Item_func_minus_fix_length_and_dec(Item_func_minus *) const;
bool Item_func_mul_fix_length_and_dec(Item_func_mul *) const;
bool Item_func_div_fix_length_and_dec(Item_func_div *) const;
bool Item_func_mod_fix_length_and_dec(Item_func_mod *) const;
}; };
...@@ -933,6 +973,11 @@ class Type_handler_temporal_result: public Type_handler ...@@ -933,6 +973,11 @@ class Type_handler_temporal_result: public Type_handler
bool Item_func_int_val_fix_length_and_dec(Item_func_int_val *) const; bool Item_func_int_val_fix_length_and_dec(Item_func_int_val *) const;
bool Item_func_abs_fix_length_and_dec(Item_func_abs *) const; bool Item_func_abs_fix_length_and_dec(Item_func_abs *) const;
bool Item_func_neg_fix_length_and_dec(Item_func_neg *) const; bool Item_func_neg_fix_length_and_dec(Item_func_neg *) const;
bool Item_func_plus_fix_length_and_dec(Item_func_plus *) const;
bool Item_func_minus_fix_length_and_dec(Item_func_minus *) const;
bool Item_func_mul_fix_length_and_dec(Item_func_mul *) const;
bool Item_func_div_fix_length_and_dec(Item_func_div *) const;
bool Item_func_mod_fix_length_and_dec(Item_func_mod *) const;
}; };
...@@ -999,6 +1044,11 @@ class Type_handler_string_result: public Type_handler ...@@ -999,6 +1044,11 @@ class Type_handler_string_result: public Type_handler
bool Item_func_int_val_fix_length_and_dec(Item_func_int_val *) const; bool Item_func_int_val_fix_length_and_dec(Item_func_int_val *) const;
bool Item_func_abs_fix_length_and_dec(Item_func_abs *) const; bool Item_func_abs_fix_length_and_dec(Item_func_abs *) const;
bool Item_func_neg_fix_length_and_dec(Item_func_neg *) const; bool Item_func_neg_fix_length_and_dec(Item_func_neg *) const;
bool Item_func_plus_fix_length_and_dec(Item_func_plus *) const;
bool Item_func_minus_fix_length_and_dec(Item_func_minus *) const;
bool Item_func_mul_fix_length_and_dec(Item_func_mul *) const;
bool Item_func_div_fix_length_and_dec(Item_func_div *) const;
bool Item_func_mod_fix_length_and_dec(Item_func_mod *) const;
}; };
...@@ -1528,6 +1578,8 @@ class Type_handler_hybrid_field_type ...@@ -1528,6 +1578,8 @@ class Type_handler_hybrid_field_type
bool aggregate_for_result(const Type_handler *other); bool aggregate_for_result(const Type_handler *other);
bool aggregate_for_result(const char *funcname, bool aggregate_for_result(const char *funcname,
Item **item, uint nitems, bool treat_bit_as_number); Item **item, uint nitems, bool treat_bit_as_number);
bool aggregate_for_num_op(const class Type_aggregator *aggregator,
const Type_handler *h0, const Type_handler *h1);
}; };
...@@ -1547,6 +1599,7 @@ extern Type_handler_set type_handler_set; ...@@ -1547,6 +1599,7 @@ extern Type_handler_set type_handler_set;
class Type_aggregator class Type_aggregator
{ {
bool m_is_commutative;
class Pair class Pair
{ {
public: public:
...@@ -1566,18 +1619,10 @@ class Type_aggregator ...@@ -1566,18 +1619,10 @@ class Type_aggregator
}; };
Dynamic_array<Pair> m_array; Dynamic_array<Pair> m_array;
const Pair* find_pair(const Type_handler *handler1, const Pair* find_pair(const Type_handler *handler1,
const Type_handler *handler2) const const Type_handler *handler2) const;
{
for (uint i= 0; i < m_array.elements(); i++)
{
const Pair& el= m_array.at(i);
if (el.eq(handler1, handler2) || el.eq(handler2, handler1))
return &el;
}
return NULL;
}
public: public:
Type_aggregator() Type_aggregator(bool is_commutative= false)
:m_is_commutative(is_commutative)
{ } { }
bool add(const Type_handler *handler1, bool add(const Type_handler *handler1,
const Type_handler *handler2, const Type_handler *handler2,
...@@ -1591,14 +1636,35 @@ class Type_aggregator ...@@ -1591,14 +1636,35 @@ class Type_aggregator
const Pair* el= find_pair(handler1, handler2); const Pair* el= find_pair(handler1, handler2);
return el ? el->m_result : NULL; return el ? el->m_result : NULL;
} }
bool is_commutative() const { return m_is_commutative; }
};
class Type_aggregator_commutative: public Type_aggregator
{
public:
Type_aggregator_commutative()
:Type_aggregator(true)
{ }
}; };
class Type_handler_data class Type_handler_data
{ {
public: public:
Type_aggregator m_type_aggregator_for_result; Type_aggregator_commutative m_type_aggregator_for_result;
Type_aggregator m_type_aggregator_for_comparison; Type_aggregator_commutative m_type_aggregator_for_comparison;
Type_aggregator_commutative m_type_aggregator_for_plus;
Type_aggregator_commutative m_type_aggregator_for_mul;
Type_aggregator m_type_aggregator_for_minus;
Type_aggregator m_type_aggregator_for_div;
Type_aggregator m_type_aggregator_for_mod;
#ifndef DBUG_OFF
// This is used for mtr purposes in debug builds
Type_aggregator m_type_aggregator_non_commutative_test;
#endif
bool init(); bool init();
}; };
......
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