diff --git a/sql/item.cc b/sql/item.cc index eed9af1f86d..a7245313097 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -2977,13 +2977,12 @@ default_set_param_func(Item_param *param, Item_param::Item_param(THD *thd, uint pos_in_query_arg): + Type_handler_hybrid_field_type(MYSQL_TYPE_VARCHAR), Item_basic_value(thd), Rewritable_query_parameter(pos_in_query_arg, 1), state(NO_VALUE), - item_result_type(STRING_RESULT), /* Don't pretend to be a literal unless value for this item is set. */ item_type(PARAM_ITEM), - param_type(MYSQL_TYPE_VARCHAR), set_param_func(default_set_param_func), m_out_param_info(NULL) { @@ -3183,25 +3182,25 @@ bool Item_param::set_from_user_var(THD *thd, const user_var_entry *entry) DBUG_ENTER("Item_param::set_from_user_var"); if (entry && entry->value) { - item_result_type= entry->type; unsigned_flag= entry->unsigned_flag; if (limit_clause_param) { bool unused; set_int(entry->val_int(&unused), MY_INT64_NUM_DECIMAL_DIGITS); item_type= Item::INT_ITEM; + set_handler_by_result_type(entry->type); DBUG_RETURN(!unsigned_flag && value.integer < 0 ? 1 : 0); } - switch (item_result_type) { + switch (entry->type) { case REAL_RESULT: set_double(*(double*)entry->value); item_type= Item::REAL_ITEM; - param_type= MYSQL_TYPE_DOUBLE; + set_handler_by_field_type(MYSQL_TYPE_DOUBLE); break; case INT_RESULT: set_int(*(longlong*)entry->value, MY_INT64_NUM_DECIMAL_DIGITS); item_type= Item::INT_ITEM; - param_type= MYSQL_TYPE_LONGLONG; + set_handler_by_field_type(MYSQL_TYPE_LONGLONG); break; case STRING_RESULT: { @@ -3224,7 +3223,7 @@ bool Item_param::set_from_user_var(THD *thd, const user_var_entry *entry) charset of connection, so we have to set it later. */ item_type= Item::STRING_ITEM; - param_type= MYSQL_TYPE_VARCHAR; + set_handler_by_field_type(MYSQL_TYPE_VARCHAR); if (set_str((const char *)entry->value, entry->length)) DBUG_RETURN(1); @@ -3240,7 +3239,7 @@ bool Item_param::set_from_user_var(THD *thd, const user_var_entry *entry) my_decimal_precision_to_length_no_truncation(ent_value->precision(), decimals, unsigned_flag); item_type= Item::DECIMAL_ITEM; - param_type= MYSQL_TYPE_NEWDECIMAL; + set_handler_by_field_type(MYSQL_TYPE_NEWDECIMAL); break; } case ROW_RESULT: @@ -3665,10 +3664,9 @@ void Item_param::set_param_type_and_swap_value(Item_param *src) { Type_std_attributes::set(src); - param_type= src->param_type; + set_handler(src->type_handler()); set_param_func= src->set_param_func; item_type= src->item_type; - item_result_type= src->item_result_type; maybe_null= src->maybe_null; null_value= src->null_value; @@ -3756,7 +3754,7 @@ Item_param::set_value(THD *thd, sp_rcontext *ctx, Item **it) return FALSE; } - item_result_type= arg->result_type(); + set_handler_by_result_type(arg->result_type()); item_type= arg->type(); return FALSE; } @@ -3775,7 +3773,7 @@ void Item_param::set_out_param_info(Send_field *info) { m_out_param_info= info; - param_type= m_out_param_info->type; + set_handler_by_field_type(m_out_param_info->type); } diff --git a/sql/item.h b/sql/item.h index d132817a56a..9432310290d 100644 --- a/sql/item.h +++ b/sql/item.h @@ -2594,11 +2594,22 @@ public: } }; -/* Item represents one placeholder ('?') of prepared statement */ +/* + Item represents one placeholder ('?') of prepared statement + + Notes: + Item_param::field_type() is used when this item is in a temporary table. + This is NOT placeholder metadata sent to client, as this value + is assigned after sending metadata (in setup_one_conversion_function). + For example in case of 'SELECT ?' you'll get MYSQL_TYPE_STRING both + in result set and placeholders metadata, no matter what type you will + supply for this placeholder in mysql_stmt_execute. +*/ class Item_param :public Item_basic_value, private Settable_routine_parameter, - public Rewritable_query_parameter + public Rewritable_query_parameter, + public Type_handler_hybrid_field_type { public: enum enum_item_param_state @@ -2645,25 +2656,18 @@ public: MYSQL_TIME time; } value; - /* Cached values for virtual methods to save us one switch. */ - enum Item_result item_result_type; enum Type item_type; - /* - Used when this item is used in a temporary table. - This is NOT placeholder metadata sent to client, as this value - is assigned after sending metadata (in setup_one_conversion_function). - For example in case of 'SELECT ?' you'll get MYSQL_TYPE_STRING both - in result set and placeholders metadata, no matter what type you will - supply for this placeholder in mysql_stmt_execute. - */ - enum enum_field_types param_type; + enum_field_types field_type() const + { return Type_handler_hybrid_field_type::field_type(); } + enum Item_result result_type () const + { return Type_handler_hybrid_field_type::result_type(); } + enum Item_result cmp_type () const + { return Type_handler_hybrid_field_type::cmp_type(); } Item_param(THD *thd, uint pos_in_query_arg); - enum Item_result result_type () const { return item_result_type; } enum Type type() const { return item_type; } - enum_field_types field_type() const { return param_type; } double val_real(); longlong val_int(); diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index dfe6d1c2117..1cb4b56d244 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -718,54 +718,44 @@ static void setup_one_conversion_function(THD *thd, Item_param *param, case MYSQL_TYPE_TINY: param->set_param_func= set_param_tiny; param->item_type= Item::INT_ITEM; - param->item_result_type= INT_RESULT; break; case MYSQL_TYPE_SHORT: param->set_param_func= set_param_short; param->item_type= Item::INT_ITEM; - param->item_result_type= INT_RESULT; break; case MYSQL_TYPE_LONG: param->set_param_func= set_param_int32; param->item_type= Item::INT_ITEM; - param->item_result_type= INT_RESULT; break; case MYSQL_TYPE_LONGLONG: param->set_param_func= set_param_int64; param->item_type= Item::INT_ITEM; - param->item_result_type= INT_RESULT; break; case MYSQL_TYPE_FLOAT: param->set_param_func= set_param_float; param->item_type= Item::REAL_ITEM; - param->item_result_type= REAL_RESULT; break; case MYSQL_TYPE_DOUBLE: param->set_param_func= set_param_double; param->item_type= Item::REAL_ITEM; - param->item_result_type= REAL_RESULT; break; case MYSQL_TYPE_DECIMAL: case MYSQL_TYPE_NEWDECIMAL: param->set_param_func= set_param_decimal; param->item_type= Item::DECIMAL_ITEM; - param->item_result_type= DECIMAL_RESULT; break; case MYSQL_TYPE_TIME: param->set_param_func= set_param_time; param->item_type= Item::STRING_ITEM; - param->item_result_type= STRING_RESULT; break; case MYSQL_TYPE_DATE: param->set_param_func= set_param_date; param->item_type= Item::STRING_ITEM; - param->item_result_type= STRING_RESULT; break; case MYSQL_TYPE_DATETIME: case MYSQL_TYPE_TIMESTAMP: param->set_param_func= set_param_datetime; param->item_type= Item::STRING_ITEM; - param->item_result_type= STRING_RESULT; break; case MYSQL_TYPE_TINY_BLOB: case MYSQL_TYPE_MEDIUM_BLOB: @@ -778,7 +768,6 @@ static void setup_one_conversion_function(THD *thd, Item_param *param, DBUG_ASSERT(thd->variables.character_set_client); param->value.cs_info.final_character_set_of_str_value= &my_charset_bin; param->item_type= Item::STRING_ITEM; - param->item_result_type= STRING_RESULT; break; default: /* @@ -808,10 +797,9 @@ static void setup_one_conversion_function(THD *thd, Item_param *param, charset of connection, so we have to set it later. */ param->item_type= Item::STRING_ITEM; - param->item_result_type= STRING_RESULT; } } - param->param_type= (enum enum_field_types) param_type; + param->set_handler_by_field_type((enum enum_field_types) param_type); } #ifndef EMBEDDED_LIBRARY @@ -823,8 +811,8 @@ static void setup_one_conversion_function(THD *thd, Item_param *param, */ inline bool is_param_long_data_type(Item_param *param) { - return ((param->param_type >= MYSQL_TYPE_TINY_BLOB) && - (param->param_type <= MYSQL_TYPE_STRING)); + return ((param->field_type() >= MYSQL_TYPE_TINY_BLOB) && + (param->field_type() <= MYSQL_TYPE_STRING)); } @@ -1213,7 +1201,7 @@ static bool insert_params_from_vars_with_log(Prepared_statement *stmt, the parameter's members that might be needed further (e.g. value.cs_info.character_set_client is used in the query_val_str()). */ - setup_one_conversion_function(thd, param, param->param_type); + setup_one_conversion_function(thd, param, param->field_type()); if (param->set_from_user_var(thd, entry)) DBUG_RETURN(1); diff --git a/sql/sql_type.h b/sql/sql_type.h index a68cce527e1..f78a9a2abce 100644 --- a/sql/sql_type.h +++ b/sql/sql_type.h @@ -318,6 +318,10 @@ public: enum_field_types field_type() const { return m_type_handler->field_type(); } Item_result result_type() const { return m_type_handler->result_type(); } Item_result cmp_type() const { return m_type_handler->cmp_type(); } + void set_handler(const Type_handler *other) + { + m_type_handler= other; + } const Type_handler *set_handler_by_result_type(Item_result type) { return (m_type_handler= get_handler_by_result_type(type));