diff options
Diffstat (limited to 'sql/item_func.cc')
-rw-r--r-- | sql/item_func.cc | 165 |
1 files changed, 134 insertions, 31 deletions
diff --git a/sql/item_func.cc b/sql/item_func.cc index fa835542eb1..7aa455b1b4a 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -451,11 +451,45 @@ Field *Item_func::tmp_table_field(TABLE *table) case STRING_RESULT: return make_string_field(table); case DECIMAL_RESULT: - field= new Field_new_decimal(my_decimal_precision_to_length(decimal_precision(), - decimals, - unsigned_flag), - maybe_null, name, decimals, unsigned_flag); + { + uint8 dec= decimals; + uint8 intg= decimal_precision() - dec; + uint32 len= max_length; + + /* + Trying to put too many digits overall in a DECIMAL(prec,dec) + will always throw a warning. We must limit dec to + DECIMAL_MAX_SCALE however to prevent an assert() later. + */ + + if (dec > 0) + { + int overflow; + + dec= min(dec, DECIMAL_MAX_SCALE); + + /* + If the value still overflows the field with the corrected dec, + we'll throw out decimals rather than integers. This is still + bad and of course throws a truncation warning. + */ + + const int required_length= + my_decimal_precision_to_length(intg + dec, dec, + unsigned_flag); + + overflow= required_length - len; + + if (overflow > 0) + dec= max(0, dec - overflow); // too long, discard fract + else + /* Corrected value fits. */ + len= required_length; + } + + field= new Field_new_decimal(len, maybe_null, name, dec, unsigned_flag); break; + } case ROW_RESULT: default: // This case should never be chosen @@ -544,8 +578,8 @@ void Item_func::count_decimal_length() set_if_smaller(unsigned_flag, args[i]->unsigned_flag); } int precision= min(max_int_part + decimals, DECIMAL_MAX_PRECISION); - max_length= my_decimal_precision_to_length(precision, decimals, - unsigned_flag); + max_length= my_decimal_precision_to_length_no_truncation(precision, decimals, + unsigned_flag); } @@ -1140,16 +1174,15 @@ void Item_func_additive_op::result_precision() decimals= max(args[0]->decimals, args[1]->decimals); int arg1_int= args[0]->decimal_precision() - args[0]->decimals; int arg2_int= args[1]->decimal_precision() - args[1]->decimals; - int est_prec= max(arg1_int, arg2_int) + 1 + decimals; - int precision= min(est_prec, DECIMAL_MAX_PRECISION); + int precision= max(arg1_int, arg2_int) + 1 + decimals; /* 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(precision, decimals, - unsigned_flag); + max_length= my_decimal_precision_to_length_no_truncation(precision, decimals, + unsigned_flag); } @@ -1254,7 +1287,8 @@ void Item_func_mul::result_precision() decimals= min(args[0]->decimals + args[1]->decimals, DECIMAL_MAX_SCALE); uint est_prec = args[0]->decimal_precision() + args[1]->decimal_precision(); uint precision= min(est_prec, DECIMAL_MAX_PRECISION); - max_length= my_decimal_precision_to_length(precision, decimals,unsigned_flag); + max_length= my_decimal_precision_to_length_no_truncation(precision, decimals, + unsigned_flag); } @@ -1310,8 +1344,8 @@ void Item_func_div::result_precision() else unsigned_flag= args[0]->unsigned_flag & args[1]->unsigned_flag; decimals= min(args[0]->decimals + prec_increment, DECIMAL_MAX_SCALE); - max_length= my_decimal_precision_to_length(precision, decimals, - unsigned_flag); + max_length= my_decimal_precision_to_length_no_truncation(precision, decimals, + unsigned_flag); } @@ -1943,8 +1977,8 @@ void Item_func_round::fix_length_and_dec() unsigned_flag= args[0]->unsigned_flag; if (!args[1]->const_item()) { - max_length= args[0]->max_length; decimals= args[0]->decimals; + max_length= float_length(decimals); if (args[0]->result_type() == DECIMAL_RESULT) { max_length++; @@ -1964,8 +1998,8 @@ void Item_func_round::fix_length_and_dec() if (args[0]->decimals == NOT_FIXED_DEC) { - max_length= args[0]->max_length; decimals= min(decimals_to_set, NOT_FIXED_DEC); + max_length= float_length(decimals); hybrid_type= REAL_RESULT; return; } @@ -1998,8 +2032,9 @@ void Item_func_round::fix_length_and_dec() precision-= decimals_delta - length_increase; decimals= min(decimals_to_set, DECIMAL_MAX_SCALE); - max_length= my_decimal_precision_to_length(precision, decimals, - unsigned_flag); + max_length= my_decimal_precision_to_length_no_truncation(precision, + decimals, + unsigned_flag); break; } default: @@ -2142,9 +2177,6 @@ bool Item_func_rand::fix_fields(THD *thd,Item **ref) if (!rand && !(rand= (struct my_rnd_struct*) thd->stmt_arena->alloc(sizeof(*rand)))) return TRUE; - - if (args[0]->const_item()) - seed_random (args[0]); } else { @@ -2174,8 +2206,21 @@ void Item_func_rand::update_used_tables() double Item_func_rand::val_real() { DBUG_ASSERT(fixed == 1); - if (arg_count && !args[0]->const_item()) - seed_random (args[0]); + if (arg_count) + { + if (!args[0]->const_item()) + seed_random(args[0]); + else if (first_eval) + { + /* + Constantness of args[0] may be set during JOIN::optimize(), if arg[0] + is a field item of "constant" table. Thus, we have to evaluate + seed_random() for constant arg there but not at the fix_fields method. + */ + first_eval= FALSE; + seed_random(args[0]); + } + } return my_rnd(rand); } @@ -2232,8 +2277,9 @@ void Item_func_min_max::fix_length_and_dec() } } else if ((cmp_type == DECIMAL_RESULT) || (cmp_type == INT_RESULT)) - max_length= my_decimal_precision_to_length(max_int_part+decimals, decimals, - unsigned_flag); + max_length= my_decimal_precision_to_length_no_truncation(max_int_part + + decimals, decimals, + unsigned_flag); cached_field_type= agg_field_type(args, arg_count); } @@ -2714,7 +2760,7 @@ longlong Item_func_find_in_set::val_int() if ((int) (buffer->length() - find->length()) >= 0) { - my_wc_t wc; + my_wc_t wc= 0; CHARSET_INFO *cs= cmp_collation.collation; const char *str_begin= buffer->ptr(); const char *str_end= buffer->ptr(); @@ -4181,6 +4227,41 @@ Item_func_set_user_var::check(bool use_result_field) /** + @brief Evaluate and store item's result. + This function is invoked on "SELECT ... INTO @var ...". + + @param item An item to get value from. +*/ + +void Item_func_set_user_var::save_item_result(Item *item) +{ + DBUG_ENTER("Item_func_set_user_var::save_item_result"); + + switch (cached_result_type) { + case REAL_RESULT: + save_result.vreal= item->val_result(); + break; + case INT_RESULT: + save_result.vint= item->val_int_result(); + unsigned_flag= item->unsigned_flag; + break; + case STRING_RESULT: + save_result.vstr= item->str_result(&value); + break; + case DECIMAL_RESULT: + save_result.vdec= item->val_decimal_result(&decimal_buff); + break; + case ROW_RESULT: + default: + // Should never happen + DBUG_ASSERT(0); + break; + } + DBUG_VOID_RETURN; +} + + +/** This functions is invoked on SET \@variable or \@variable:= expression. @@ -4838,10 +4919,20 @@ bool Item_func_get_system_var::is_written_to_binlog() } +void Item_func_get_system_var::update_null_value() +{ + THD *thd= current_thd; + int save_no_errors= thd->no_errors; + thd->no_errors= TRUE; + Item::update_null_value(); + thd->no_errors= save_no_errors; +} + + void Item_func_get_system_var::fix_length_and_dec() { char *cptr; - maybe_null=0; + maybe_null= TRUE; max_length= 0; if (var->check_type(var_type)) @@ -5750,6 +5841,14 @@ Item_func_sp::func_name() const } +int my_missing_function_error(const LEX_STRING &token, const char *func_name) +{ + if (token.length && is_lex_native_function (&token)) + return my_error(ER_FUNC_INEXISTENT_NAME_COLLISION, MYF(0), func_name); + else + return my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "FUNCTION", func_name); +} + /** @brief Initialize the result field by creating a temporary dummy table @@ -5782,7 +5881,7 @@ Item_func_sp::init_result_field(THD *thd) if (!(m_sp= sp_find_routine(thd, TYPE_ENUM_FUNCTION, m_name, &thd->sp_func_cache, TRUE))) { - my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "FUNCTION", m_name->m_qname.str); + my_missing_function_error (m_name->m_name, m_name->m_qname.str); context->process_error(thd); DBUG_RETURN(TRUE); } @@ -5894,6 +5993,9 @@ Item_func_sp::execute_impl(THD *thd) #ifndef NO_EMBEDDED_ACCESS_CHECKS Security_context *save_security_ctx= thd->security_ctx; #endif + enum enum_sp_data_access access= + (m_sp->m_chistics->daccess == SP_DEFAULT_ACCESS) ? + SP_DEFAULT_ACCESS_MAPPING : m_sp->m_chistics->daccess; DBUG_ENTER("Item_func_sp::execute_impl"); @@ -5911,11 +6013,13 @@ Item_func_sp::execute_impl(THD *thd) Throw an error if a non-deterministic function is called while statement-based replication (SBR) is active. */ + if (!m_sp->m_chistics->detistic && !trust_function_creators && + (access == SP_CONTAINS_SQL || access == SP_MODIFIES_SQL_DATA) && (mysql_bin_log.is_open() && thd->variables.binlog_format == BINLOG_FORMAT_STMT)) { - my_error(ER_BINLOG_ROW_RBR_TO_SBR, MYF(0)); + my_error(ER_BINLOG_UNSAFE_ROUTINE, MYF(0)); goto error; } @@ -6107,13 +6211,12 @@ void uuid_short_init() (((ulonglong) server_start_time) << 24)); } -pthread_mutex_t LOCK_uuid_short; longlong Item_func_uuid_short::val_int() { ulonglong val; - pthread_mutex_lock(&LOCK_uuid_short); + pthread_mutex_lock(&LOCK_uuid_generator); val= uuid_value++; - pthread_mutex_unlock(&LOCK_uuid_short); + pthread_mutex_unlock(&LOCK_uuid_generator); return (longlong) val; } |