diff options
author | Alexander Barkov <bar@mariadb.org> | 2017-04-13 06:50:00 +0400 |
---|---|---|
committer | Alexander Barkov <bar@mariadb.org> | 2017-04-13 06:50:00 +0400 |
commit | 45730fb11e08571bbe4023cd7a7e8d1168ceb008 (patch) | |
tree | 09c11aeb42732b74cf08c85b6afa5d68b2411e17 /sql/item_func.cc | |
parent | 949faa2ec24999ce35c558433d5932805542e278 (diff) | |
download | mariadb-git-45730fb11e08571bbe4023cd7a7e8d1168ceb008.tar.gz |
MDEV-12238 Add Type_handler::Item_func_{plus|minus|mul|div|mod}_fix_length_and_dec()
Diffstat (limited to 'sql/item_func.cc')
-rw-r--r-- | sql/item_func.cc | 189 |
1 files changed, 100 insertions, 89 deletions
diff --git a/sql/item_func.cc b/sql/item_func.cc index 8b52ed3c613..03d0b1068a2 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -729,47 +729,31 @@ bool Item_func_connection_id::fix_fields(THD *thd, Item **ref) } -/** - Check arguments here to determine result's type for a numeric - function of two arguments. -*/ - -void Item_num_op::fix_length_and_dec(void) +bool Item_num_op::fix_type_handler(const Type_aggregator *aggregator) { - DBUG_ENTER("Item_num_op::fix_length_and_dec"); - DBUG_PRINT("info", ("name %s", func_name())); DBUG_ASSERT(arg_count == 2); - Item_result r0= args[0]->cast_to_int_type_handler()->cmp_type(); - Item_result r1= args[1]->cast_to_int_type_handler()->cmp_type(); + const Type_handler *h0= args[0]->cast_to_int_type_handler(); + 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) - { - count_real_length(args, arg_count); - max_length= float_length(decimals); - set_handler_by_result_type(REAL_RESULT); - } - else if (r0 == DECIMAL_RESULT || r1 == DECIMAL_RESULT || - r0 == TIME_RESULT || r1 == TIME_RESULT) - { - 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 + +void Item_func_plus::fix_length_and_dec(void) +{ + DBUG_ENTER("Item_func_plus::fix_length_and_dec"); + DBUG_PRINT("info", ("name %s", func_name())); + 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;); + DBUG_ASSERT(aggregator->is_commutative()); + if (!fix_type_handler(aggregator)) { - DBUG_ASSERT(r0 == INT_RESULT && r1 == INT_RESULT); - set_handler_by_result_type(INT_RESULT); - result_precision(); - decimals= 0; + Item_func_plus::type_handler()->Item_func_plus_fix_length_and_dec(this); + DBUG_PRINT("info", ("Type: %s", type_handler()->name().ptr())); } - 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; } @@ -1299,11 +1283,6 @@ void Item_func_additive_op::result_precision() DBUG_ASSERT(arg1_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, unsigned_flag); } @@ -1313,16 +1292,30 @@ void Item_func_additive_op::result_precision() The following function is here to allow the user to force subtraction of UNSIGNED BIGINT to return negative values. */ - -void Item_func_minus::fix_length_and_dec() +void Item_func_minus::fix_unsigned_flag() { - Item_num_op::fix_length_and_dec(); if (unsigned_flag && (current_thd->variables.sql_mode & MODE_NO_UNSIGNED_SUBTRACTION)) 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 value= args[0]->val_real() - args[1]->val_real(); @@ -1530,13 +1523,8 @@ my_decimal *Item_func_mul::decimal_op(my_decimal *decimal_value) 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(), - DECIMAL_MAX_SCALE); + DECIMAL_MAX_SCALE); uint est_prec = args[0]->decimal_precision() + args[1]->decimal_precision(); uint precision= MY_MIN(est_prec, DECIMAL_MAX_PRECISION); max_length= my_decimal_precision_to_length_no_truncation(precision, decimals, @@ -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() { DBUG_ASSERT(fixed == 1); @@ -1605,53 +1609,51 @@ void Item_func_div::result_precision() uint precision=MY_MIN(args[0]->decimal_precision() + args[1]->divisor_precision_increment() + prec_increment, 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); max_length= my_decimal_precision_to_length_no_truncation(precision, decimals, 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_PRINT("info", ("name %s", func_name())); prec_increment= current_thd->variables.div_precincrement; - Item_num_op::fix_length_and_dec(); - switch (Item_func_div::result_type()) { - case REAL_RESULT: + maybe_null= 1; // devision by zero + + 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; - 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); - } - 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); + Item_func_div::type_handler()->Item_func_div_fix_length_and_dec(this); + DBUG_PRINT("info", ("Type: %s", type_handler()->name().ptr())); } - maybe_null= 1; // devision by zero DBUG_VOID_RETURN; } @@ -1823,9 +1825,18 @@ void Item_func_mod::result_precision() void Item_func_mod::fix_length_and_dec() { - Item_num_op::fix_length_and_dec(); - maybe_null= 1; - unsigned_flag= args[0]->unsigned_flag; + DBUG_ENTER("Item_func_mod::fix_length_and_dec"); + DBUG_PRINT("info", ("name %s", func_name())); + 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; } |