summaryrefslogtreecommitdiff
path: root/sql/item.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/item.cc')
-rw-r--r--sql/item.cc3400
1 files changed, 1638 insertions, 1762 deletions
diff --git a/sql/item.cc b/sql/item.cc
index 6c605dba776..7f4e69a3523 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -19,7 +19,7 @@
#ifdef USE_PRAGMA_IMPLEMENTATION
#pragma implementation // gcc: Class implementation
#endif
-#include <my_global.h> /* NO_EMBEDDED_ACCESS_CHECKS */
+#include "mariadb.h" /* NO_EMBEDDED_ACCESS_CHECKS */
#include "sql_priv.h"
#include <mysql.h>
#include <m_ctype.h>
@@ -45,6 +45,15 @@
const String my_null_string("NULL", 4, default_charset_info);
const String my_default_string("DEFAULT", 7, default_charset_info);
+/*
+ item_empty_name is used when calling Item::set_name with NULL
+ pointer, to make it easier to use the name in printf.
+ item_used_name is used when calling Item::set_name with a 0 length
+ string.
+*/
+const char *item_empty_name="";
+const char *item_used_name= "\0";
+
static int save_field_in_field(Field *, bool *, Field *, bool);
@@ -69,6 +78,12 @@ inline void set_max_sum_func_level(THD *thd, SELECT_LEX *select)
select->nest_level - 1);
}
+
+MEM_ROOT *get_thd_memroot(THD *thd)
+{
+ return thd->mem_root;
+}
+
/*****************************************************************************
** Item functions
*****************************************************************************/
@@ -100,61 +115,16 @@ void Item::push_note_converted_to_positive_complement(THD *thd)
}
-/**
- @todo
- Make this functions class dependent
-*/
-
-bool Item::val_bool()
+longlong Item::val_datetime_packed_result()
{
- switch(result_type()) {
- case INT_RESULT:
- return val_int() != 0;
- case DECIMAL_RESULT:
- {
- my_decimal decimal_value;
- my_decimal *val= val_decimal(&decimal_value);
- if (val)
- return !my_decimal_is_zero(val);
+ MYSQL_TIME ltime, tmp;
+ if (get_date_result(&ltime, TIME_FUZZY_DATES | TIME_INVALID_DATES))
return 0;
- }
- case REAL_RESULT:
- case STRING_RESULT:
- return val_real() != 0.0;
- case ROW_RESULT:
- case TIME_RESULT:
- DBUG_ASSERT(0);
- return 0; // Wrong (but safe)
- }
- return 0; // Wrong (but safe)
-}
-
-
-/**
- Get date/time/datetime.
- Optionally extend TIME result to DATETIME.
-*/
-bool Item::get_date_with_conversion(MYSQL_TIME *ltime, ulonglong fuzzydate)
-{
- THD *thd= current_thd;
-
- /*
- Some TIME type items return error when trying to do get_date()
- without TIME_TIME_ONLY set (e.g. Item_field for Field_time).
- In the SQL standard time->datetime conversion mode we add TIME_TIME_ONLY.
- In the legacy time->datetime conversion mode we do not add TIME_TIME_ONLY
- and leave it to get_date() to check date.
- */
- ulonglong time_flag= (field_type() == MYSQL_TYPE_TIME &&
- !(thd->variables.old_behavior & OLD_MODE_ZERO_DATE_TIME_CAST)) ?
- TIME_TIME_ONLY : 0;
- if (get_date(ltime, fuzzydate | time_flag))
- return true;
- if (ltime->time_type == MYSQL_TIMESTAMP_TIME &&
- !(fuzzydate & TIME_TIME_ONLY) &&
- convert_time_to_datetime(thd, ltime, fuzzydate))
- return true;
- return false;
+ if (ltime.time_type != MYSQL_TIMESTAMP_TIME)
+ return pack_time(&ltime);
+ if ((null_value= time_to_datetime_with_warn(current_thd, &ltime, &tmp, 0)))
+ return 0;
+ return pack_time(&tmp);
}
@@ -232,6 +202,19 @@ String *Item::val_str_ascii(String *str)
}
+String *Item::val_str_ascii_revert_empty_string_is_null(THD *thd, String *str)
+{
+ String *res= val_str_ascii(str);
+ if (!res && (thd->variables.sql_mode & MODE_EMPTY_STRING_IS_NULL))
+ {
+ null_value= false;
+ str->set("", 0, &my_charset_latin1);
+ return str;
+ }
+ return res;
+}
+
+
String *Item::val_str(String *str, String *converter, CHARSET_INFO *cs)
{
String *res= val_str(str);
@@ -300,6 +283,56 @@ bool Item::is_null_from_temporal()
}
+longlong Item::val_int_from_str(int *error)
+{
+ char buff[MAX_FIELD_WIDTH];
+ String tmp(buff,sizeof(buff), &my_charset_bin), *res;
+
+ /*
+ For a string result, we must first get the string and then convert it
+ to a longlong
+ */
+ if (!(res= val_str(&tmp)))
+ {
+ *error= 0;
+ return 0;
+ }
+ Converter_strtoll10_with_warn cnv(NULL, Warn_filter_all(),
+ res->charset(), res->ptr(), res->length());
+ *error= cnv.error();
+ return cnv.result();
+}
+
+
+longlong Item::val_int_signed_typecast_from_str()
+{
+ int error;
+ longlong value= val_int_from_str(&error);
+ if (unlikely(!null_value && value < 0 && error == 0))
+ push_note_converted_to_negative_complement(current_thd);
+ return value;
+}
+
+
+longlong Item::val_int_unsigned_typecast_from_str()
+{
+ int error;
+ longlong value= val_int_from_str(&error);
+ if (unlikely(!null_value && error < 0))
+ push_note_converted_to_positive_complement(current_thd);
+ return value;
+}
+
+
+longlong Item::val_int_unsigned_typecast_from_int()
+{
+ longlong value= val_int();
+ if (!null_value && unsigned_flag == 0 && value < 0)
+ push_note_converted_to_positive_complement(current_thd);
+ return value;
+}
+
+
String *Item::val_string_from_date(String *str)
{
MYSQL_TIME ltime;
@@ -417,21 +450,33 @@ longlong Item::val_int_from_decimal()
return result;
}
-int Item::save_time_in_field(Field *field)
+
+longlong Item::val_int_unsigned_typecast_from_decimal()
+{
+ longlong result;
+ my_decimal tmp, *dec= val_decimal(&tmp);
+ if (null_value)
+ return 0;
+ my_decimal2int(E_DEC_FATAL_ERROR, dec, 1, &result);
+ return result;
+}
+
+
+int Item::save_time_in_field(Field *field, bool no_conversions)
{
MYSQL_TIME ltime;
if (get_time(&ltime))
- return set_field_to_null_with_conversions(field, 0);
+ return set_field_to_null_with_conversions(field, no_conversions);
field->set_notnull();
return field->store_time_dec(&ltime, decimals);
}
-int Item::save_date_in_field(Field *field)
+int Item::save_date_in_field(Field *field, bool no_conversions)
{
MYSQL_TIME ltime;
if (get_date(&ltime, sql_mode_for_dates(field->table->in_use)))
- return set_field_to_null_with_conversions(field, 0);
+ return set_field_to_null_with_conversions(field, no_conversions);
field->set_notnull();
return field->store_time_dec(&ltime, decimals);
}
@@ -469,17 +514,16 @@ int Item::save_str_value_in_field(Field *field, String *result)
Item::Item(THD *thd):
- is_expensive_cache(-1), rsize(0), name(0), orig_name(0), name_length(0),
+ is_expensive_cache(-1), rsize(0), name(null_clex_str), orig_name(0),
fixed(0), is_autogenerated_name(TRUE)
{
DBUG_ASSERT(thd);
marker= 0;
maybe_null=null_value=with_sum_func=with_window_func=with_field=0;
in_rollup= 0;
- with_subselect= 0;
with_param= 0;
- /* Initially this item is not attached to any JOIN_TAB. */
+ /* Initially this item is not attached to any JOIN_TAB. */
join_tab_idx= MAX_TABLES;
/* Put item in free list so that we can free all items at end */
@@ -517,14 +561,13 @@ const TABLE_SHARE *Item::field_table_or_null()
tables.
*/
Item::Item(THD *thd, Item *item):
- Type_std_attributes(item),
+ Type_all_attributes(item),
join_tab_idx(item->join_tab_idx),
is_expensive_cache(-1),
rsize(0),
str_value(item->str_value),
name(item->name),
orig_name(item->orig_name),
- name_length(item->name_length),
marker(item->marker),
maybe_null(item->maybe_null),
in_rollup(item->in_rollup),
@@ -534,57 +577,13 @@ Item::Item(THD *thd, Item *item):
with_window_func(item->with_window_func),
with_field(item->with_field),
fixed(item->fixed),
- is_autogenerated_name(item->is_autogenerated_name),
- with_subselect(item->has_subquery())
+ is_autogenerated_name(item->is_autogenerated_name)
{
next= thd->free_list; // Put in free list
thd->free_list= this;
}
-uint Item::decimal_precision() const
-{
- Item_result restype= result_type();
-
- if ((restype == DECIMAL_RESULT) || (restype == INT_RESULT))
- {
- uint prec=
- my_decimal_length_to_precision(max_char_length(), decimals,
- unsigned_flag);
- return MY_MIN(prec, DECIMAL_MAX_PRECISION);
- }
- uint res= max_char_length();
- /*
- Return at least one decimal digit, even if Item::max_char_length()
- returned 0. This is important to avoid attempts to create fields of types
- INT(0) or DECIMAL(0,0) when converting NULL or empty strings to INT/DECIMAL:
- CREATE TABLE t1 AS SELECT CONVERT(NULL,SIGNED) AS a;
- */
- return res ? MY_MIN(res, DECIMAL_MAX_PRECISION) : 1;
-}
-
-
-uint Item::temporal_precision(enum_field_types type_arg)
-{
- if (const_item() && result_type() == STRING_RESULT &&
- !is_temporal_type(field_type()))
- {
- MYSQL_TIME ltime;
- String buf, *tmp;
- MYSQL_TIME_STATUS status;
- DBUG_ASSERT(fixed);
- if ((tmp= val_str(&buf)) &&
- !(type_arg == MYSQL_TYPE_TIME ?
- str_to_time(tmp->charset(), tmp->ptr(), tmp->length(),
- &ltime, TIME_TIME_ONLY, &status) :
- str_to_datetime(tmp->charset(), tmp->ptr(), tmp->length(),
- &ltime, TIME_FUZZY_DATES, &status)))
- return MY_MIN(status.precision, TIME_SECOND_PART_DIGITS);
- }
- return MY_MIN(decimals, TIME_SECOND_PART_DIGITS);
-}
-
-
void Item::print_parenthesised(String *str, enum_query_type query_type,
enum precedence parent_prec)
{
@@ -607,11 +606,12 @@ void Item::print_item_w_name(String *str, enum_query_type query_type)
{
print(str, query_type);
- if (name)
+ if (name.str)
{
+ DBUG_ASSERT(name.length == strlen(name.str));
THD *thd= current_thd;
str->append(STRING_WITH_LEN(" AS "));
- append_identifier(thd, str, name, (uint) strlen(name));
+ append_identifier(thd, str, &name);
}
}
@@ -650,7 +650,10 @@ void Item::cleanup()
marker= 0;
join_tab_idx= MAX_TABLES;
if (orig_name)
- name= orig_name;
+ {
+ name.str= orig_name;
+ name.length= strlen(orig_name);
+ }
DBUG_VOID_RETURN;
}
@@ -670,24 +673,6 @@ bool Item::cleanup_processor(void *arg)
/**
- rename item (used for views, cleanup() return original name).
-
- @param new_name new name of item;
-*/
-
-void Item::rename(char *new_name)
-{
- /*
- we can compare pointers to names here, because if name was not changed,
- pointer will be same
- */
- if (!orig_name && new_name != name)
- orig_name= name;
- name= new_name;
-}
-
-
-/**
Traverse item tree possibly transforming it (replacing items).
This function is designed to ease transformation of Item trees.
@@ -743,12 +728,11 @@ Item* Item::set_expr_cache(THD *thd)
{
DBUG_ENTER("Item::set_expr_cache");
Item_cache_wrapper *wrapper;
- if ((wrapper= new (thd->mem_root) Item_cache_wrapper(thd, this)) &&
- !wrapper->fix_fields(thd, (Item**)&wrapper))
+ if (likely((wrapper= new (thd->mem_root) Item_cache_wrapper(thd, this))) &&
+ likely(!wrapper->fix_fields(thd, (Item**)&wrapper)))
{
- if (wrapper->set_cache(thd))
- DBUG_RETURN(NULL);
- DBUG_RETURN(wrapper);
+ if (likely(!wrapper->set_cache(thd)))
+ DBUG_RETURN(wrapper);
}
DBUG_RETURN(NULL);
}
@@ -756,31 +740,31 @@ Item* Item::set_expr_cache(THD *thd)
Item_ident::Item_ident(THD *thd, Name_resolution_context *context_arg,
const char *db_name_arg,const char *table_name_arg,
- const char *field_name_arg)
+ const LEX_CSTRING *field_name_arg)
:Item_result_field(thd), orig_db_name(db_name_arg),
orig_table_name(table_name_arg),
- orig_field_name(field_name_arg), context(context_arg),
+ orig_field_name(*field_name_arg), context(context_arg),
db_name(db_name_arg), table_name(table_name_arg),
- field_name(field_name_arg),
+ field_name(*field_name_arg),
alias_name_used(FALSE), cached_field_index(NO_CACHED_FIELD_INDEX),
cached_table(0), depended_from(0), can_be_depended(TRUE)
{
- name = (char*) field_name_arg;
- name_length= name ? strlen(name) : 0;
+ name= *field_name_arg;
}
-Item_ident::Item_ident(THD *thd, TABLE_LIST *view_arg, const char *field_name_arg)
+Item_ident::Item_ident(THD *thd, TABLE_LIST *view_arg,
+ const LEX_CSTRING *field_name_arg)
:Item_result_field(thd), orig_db_name(NullS),
- orig_table_name(view_arg->table_name),
- orig_field_name(field_name_arg), context(&view_arg->view->select_lex.context),
- db_name(NullS), table_name(view_arg->alias),
- field_name(field_name_arg),
+ orig_table_name(view_arg->table_name.str),
+ orig_field_name(*field_name_arg),
+ context(&view_arg->view->select_lex.context),
+ db_name(NullS), table_name(view_arg->alias.str),
+ field_name(*field_name_arg),
alias_name_used(FALSE), cached_field_index(NO_CACHED_FIELD_INDEX),
cached_table(NULL), depended_from(NULL), can_be_depended(TRUE)
{
- name = (char*) field_name_arg;
- name_length= name ? strlen(name) : 0;
+ name= *field_name_arg;
}
@@ -871,7 +855,8 @@ bool Item_ident::collect_outer_ref_processor(void *param)
bool Item_field::collect_item_field_processor(void *arg)
{
DBUG_ENTER("Item_field::collect_item_field_processor");
- DBUG_PRINT("info", ("%s", field->field_name ? field->field_name : "noname"));
+ DBUG_PRINT("info", ("%s", field->field_name.str ?
+ field->field_name.str : "noname"));
List<Item_field> *item_list= (List<Item_field>*) arg;
List_iterator<Item_field> item_list_it(*item_list);
Item_field *curr_item;
@@ -888,7 +873,8 @@ bool Item_field::collect_item_field_processor(void *arg)
bool Item_field::add_field_to_set_processor(void *arg)
{
DBUG_ENTER("Item_field::add_field_to_set_processor");
- DBUG_PRINT("info", ("%s", field->field_name ? field->field_name : "noname"));
+ DBUG_PRINT("info", ("%s", field->field_name.str ? field->field_name.str :
+ "noname"));
TABLE *table= (TABLE *) arg;
if (field->table == table)
bitmap_set_bit(&table->tmp_set, field->field_index);
@@ -908,12 +894,12 @@ bool Item_field::rename_fields_processor(void *arg)
while ((def=def_it++))
{
- if (def->change &&
+ if (def->change.str &&
(!db_name || !db_name[0] ||
!my_strcasecmp(table_alias_charset, db_name, rename->db_name.str)) &&
(!table_name || !table_name[0] ||
!my_strcasecmp(table_alias_charset, table_name, rename->table_name.str)) &&
- !my_strcasecmp(system_charset_info, field_name, def->change))
+ !my_strcasecmp(system_charset_info, field_name.str, def->change.str))
{
field_name= def->field_name;
break;
@@ -1044,7 +1030,7 @@ bool Item_field::check_field_expression_processor(void *arg)
{
my_error(ER_EXPRESSION_REFERS_TO_UNINIT_FIELD,
MYF(0),
- org_field->field_name, field->field_name);
+ org_field->field_name.str, field->field_name.str);
return 1;
}
}
@@ -1075,13 +1061,151 @@ bool Item::check_cols(uint c)
}
-void Item::set_name(THD *thd, const char *str, uint length, CHARSET_INFO *cs)
+bool Item::check_type_or_binary(const char *opname,
+ const Type_handler *expect) const
+{
+ const Type_handler *handler= type_handler();
+ if (handler == expect ||
+ (handler->is_general_purpose_string_type() &&
+ collation.collation == &my_charset_bin))
+ return false;
+ my_error(ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION, MYF(0),
+ handler->name().ptr(), opname);
+ return true;
+}
+
+
+bool Item::check_type_general_purpose_string(const char *opname) const
+{
+ const Type_handler *handler= type_handler();
+ if (handler->is_general_purpose_string_type())
+ return false;
+ my_error(ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION, MYF(0),
+ handler->name().ptr(), opname);
+ return true;
+}
+
+
+bool Item::check_type_traditional_scalar(const char *opname) const
+{
+ const Type_handler *handler= type_handler();
+ if (handler->is_traditional_type() && handler->is_scalar_type())
+ return false;
+ my_error(ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION, MYF(0),
+ handler->name().ptr(), opname);
+ return true;
+}
+
+
+bool Item::check_type_can_return_int(const char *opname) const
+{
+ const Type_handler *handler= type_handler();
+ if (handler->can_return_int())
+ return false;
+ my_error(ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION, MYF(0),
+ handler->name().ptr(), opname);
+ return true;
+}
+
+
+bool Item::check_type_can_return_decimal(const char *opname) const
+{
+ const Type_handler *handler= type_handler();
+ if (handler->can_return_decimal())
+ return false;
+ my_error(ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION, MYF(0),
+ handler->name().ptr(), opname);
+ return true;
+}
+
+
+bool Item::check_type_can_return_real(const char *opname) const
+{
+ const Type_handler *handler= type_handler();
+ if (handler->can_return_real())
+ return false;
+ my_error(ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION, MYF(0),
+ handler->name().ptr(), opname);
+ return true;
+}
+
+
+bool Item::check_type_can_return_date(const char *opname) const
+{
+ const Type_handler *handler= type_handler();
+ if (handler->can_return_date())
+ return false;
+ my_error(ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION, MYF(0),
+ handler->name().ptr(), opname);
+ return true;
+}
+
+
+bool Item::check_type_can_return_time(const char *opname) const
+{
+ const Type_handler *handler= type_handler();
+ if (handler->can_return_time())
+ return false;
+ my_error(ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION, MYF(0),
+ handler->name().ptr(), opname);
+ return true;
+}
+
+
+bool Item::check_type_can_return_str(const char *opname) const
+{
+ const Type_handler *handler= type_handler();
+ if (handler->can_return_str())
+ return false;
+ my_error(ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION, MYF(0),
+ handler->name().ptr(), opname);
+ return true;
+}
+
+
+bool Item::check_type_can_return_text(const char *opname) const
+{
+ const Type_handler *handler= type_handler();
+ if (handler->can_return_text())
+ return false;
+ my_error(ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION, MYF(0),
+ handler->name().ptr(), opname);
+ return true;
+}
+
+
+bool Item::check_type_scalar(const char *opname) const
+{
+ /*
+ fixed==true usually means than the Item has an initialized
+ and reliable data type handler and attributes.
+ Item_outer_ref is an exception. It copies the data type and the attributes
+ from the referenced Item in the constructor, but then sets "fixed" to false,
+ and re-fixes itself again in fix_inner_refs().
+ This hack in Item_outer_ref should probably be refactored eventually.
+ Discuss with Sanja.
+ */
+ DBUG_ASSERT(fixed || type() == REF_ITEM);
+ const Type_handler *handler= type_handler();
+ if (handler->is_scalar_type())
+ return false;
+ my_error(ER_OPERAND_COLUMNS, MYF(0), 1);
+ return true;
+}
+
+
+void Item::set_name(THD *thd, const char *str, size_t length, CHARSET_INFO *cs)
{
if (!length)
{
- /* Empty string, used by AS or internal function like last_insert_id() */
- name= (char*) str;
- name_length= 0;
+ /*
+ Null string are replaced by item_empty_name. This is used by AS or
+ internal function like last_insert_id() to detect if we need to
+ change the name later.
+ Used by sql_yacc.yy in select_alias handling
+ */
+ name.str= str ? item_used_name : item_empty_name;
+ name.length= 0;
return;
}
@@ -1123,13 +1247,13 @@ void Item::set_name(THD *thd, const char *str, uint length, CHARSET_INFO *cs)
if (!my_charset_same(cs, system_charset_info))
{
size_t res_length;
- name= sql_strmake_with_convert(thd, str, length, cs,
- MAX_ALIAS_NAME, system_charset_info,
- &res_length);
- name_length= res_length;
+ name.str= sql_strmake_with_convert(thd, str, length, cs,
+ MAX_ALIAS_NAME, system_charset_info,
+ &res_length);
+ name.length= res_length;
}
else
- name= thd->strmake(str, (name_length= MY_MIN(length,MAX_ALIAS_NAME)));
+ name.str= thd->strmake(str, (name.length= MY_MIN(length,MAX_ALIAS_NAME)));
}
@@ -1139,28 +1263,13 @@ void Item::set_name_no_truncate(THD *thd, const char *str, uint length,
if (!my_charset_same(cs, system_charset_info))
{
size_t res_length;
- name= sql_strmake_with_convert(thd, str, length, cs,
- UINT_MAX, system_charset_info,
- &res_length);
- name_length= res_length;
+ name.str= sql_strmake_with_convert(thd, str, length, cs,
+ UINT_MAX, system_charset_info,
+ &res_length);
+ name.length= res_length;
}
else
- name= thd->strmake(str, (name_length= length));
-}
-
-
-void Item::set_name_for_rollback(THD *thd, const char *str, uint length,
- CHARSET_INFO *cs)
-{
- char *old_name, *new_name;
- old_name= name;
- set_name(thd, str, length, cs);
- new_name= name;
- if (old_name != new_name)
- {
- name= old_name;
- thd->change_item_tree((Item **) &name, (Item *) new_name);
- }
+ name.str= thd->strmake(str, (name.length= length));
}
@@ -1178,8 +1287,8 @@ bool Item::eq(const Item *item, bool binary_cmp) const
for all basic constants we have special checks, and Item_param's
type() can be only among basic constant types.
*/
- return type() == item->type() && name && item->name &&
- !my_strcasecmp(system_charset_info,name,item->name);
+ return type() == item->type() && name.str && item->name.str &&
+ !lex_string_cmp(system_charset_info, &name, &item->name);
}
@@ -1188,7 +1297,7 @@ Item *Item::safe_charset_converter(THD *thd, CHARSET_INFO *tocs)
if (!needs_charset_converter(tocs))
return this;
Item_func_conv_charset *conv= new (thd->mem_root) Item_func_conv_charset(thd, this, tocs, 1);
- return conv->safe ? conv : NULL;
+ return conv && conv->safe ? conv : NULL;
}
@@ -1222,7 +1331,7 @@ Item *Item_cache::safe_charset_converter(THD *thd, CHARSET_INFO *tocs)
return this;
Item_cache *cache;
if (!conv || conv->fix_fields(thd, (Item **) NULL) ||
- !(cache= new (thd->mem_root) Item_cache_str(thd, conv)))
+ unlikely(!(cache= new (thd->mem_root) Item_cache_str(thd, conv))))
return NULL; // Safe conversion is not possible, or OEM
cache->setup(thd, conv);
cache->fixed= false; // Make Item::fix_fields() happy
@@ -1304,7 +1413,7 @@ Item *Item::const_charset_converter(THD *thd, CHARSET_INFO *tocs,
collation.derivation,
collation.repertoire));
- if (!conv || (conv_errors && lossless))
+ if (unlikely(!conv || (conv_errors && lossless)))
{
/*
Safe conversion is not possible (or EOM).
@@ -1344,70 +1453,72 @@ Item *Item_param::safe_charset_converter(THD *thd, CHARSET_INFO *tocs)
As a extra convenience the time structure is reset on error or NULL values!
*/
-bool Item::get_date(MYSQL_TIME *ltime,ulonglong fuzzydate)
+bool Item::get_date_from_int(MYSQL_TIME *ltime, ulonglong fuzzydate)
{
- if (field_type() == MYSQL_TYPE_TIME)
- fuzzydate|= TIME_TIME_ONLY;
+ longlong value= val_int();
+ bool neg= !unsigned_flag && value < 0;
+ if (null_value || int_to_datetime_with_warn(neg, neg ? -value : value,
+ ltime, fuzzydate,
+ field_table_or_null(),
+ field_name_or_null()))
+ return null_value|= make_zero_date(ltime, fuzzydate);
+ return null_value= false;
+}
- switch (result_type()) {
- case INT_RESULT:
- {
- longlong value= val_int();
- bool neg= !unsigned_flag && value < 0;
- if (field_type() == MYSQL_TYPE_YEAR)
- {
- if (max_length == 2)
- {
- if (value < 70)
- value+= 2000;
- else if (value <= 1900)
- value+= 1900;
- }
- value*= 10000; /* make it YYYYMMHH */
- }
- if (null_value || int_to_datetime_with_warn(neg, neg ? -value : value,
- ltime, fuzzydate,
- field_table_or_null(),
- field_name_or_null()))
- goto err;
- return null_value= false;
- }
- case REAL_RESULT:
- {
- double value= val_real();
- if (null_value || double_to_datetime_with_warn(value, ltime, fuzzydate,
- field_table_or_null(),
- field_name_or_null()))
- goto err;
- return null_value= false;
- }
- case DECIMAL_RESULT:
- {
- my_decimal value, *res;
- if (!(res= val_decimal(&value)) ||
- decimal_to_datetime_with_warn(res, ltime, fuzzydate,
- field_table_or_null(),
- field_name_or_null()))
- goto err;
- return null_value= false;
- }
- case STRING_RESULT:
+
+bool Item::get_date_from_year(MYSQL_TIME *ltime, ulonglong fuzzydate)
+{
+ longlong value= val_int();
+ DBUG_ASSERT(unsigned_flag || value >= 0);
+ if (max_length == 2)
{
- char buff[40];
- String tmp(buff,sizeof(buff), &my_charset_bin),*res;
- if (!(res=val_str(&tmp)) ||
- str_to_datetime_with_warn(res->charset(), res->ptr(), res->length(),
- ltime, fuzzydate))
- goto err;
- return null_value= false;
- }
- default:
- null_value= true;
- DBUG_ASSERT(0);
+ if (value < 70)
+ value+= 2000;
+ else if (value <= 1900)
+ value+= 1900;
}
+ value*= 10000; /* make it YYYYMMHH */
+ if (null_value || int_to_datetime_with_warn(false, value,
+ ltime, fuzzydate,
+ field_table_or_null(),
+ field_name_or_null()))
+ return null_value|= make_zero_date(ltime, fuzzydate);
+ return null_value= false;
+}
-err:
- return null_value|= make_zero_date(ltime, fuzzydate);
+
+bool Item::get_date_from_real(MYSQL_TIME *ltime, ulonglong fuzzydate)
+{
+ double value= val_real();
+ if (null_value || double_to_datetime_with_warn(value, ltime, fuzzydate,
+ field_table_or_null(),
+ field_name_or_null()))
+ return null_value|= make_zero_date(ltime, fuzzydate);
+ return null_value= false;
+}
+
+
+bool Item::get_date_from_decimal(MYSQL_TIME *ltime, ulonglong fuzzydate)
+{
+ my_decimal value, *res;
+ if (!(res= val_decimal(&value)) ||
+ decimal_to_datetime_with_warn(res, ltime, fuzzydate,
+ field_table_or_null(),
+ field_name_or_null()))
+ return null_value|= make_zero_date(ltime, fuzzydate);
+ return null_value= false;
+}
+
+
+bool Item::get_date_from_string(MYSQL_TIME *ltime, ulonglong fuzzydate)
+{
+ char buff[40];
+ String tmp(buff,sizeof(buff), &my_charset_bin),*res;
+ if (!(res=val_str(&tmp)) ||
+ str_to_datetime_with_warn(res->charset(), res->ptr(), res->length(),
+ ltime, fuzzydate))
+ return null_value|= make_zero_date(ltime, fuzzydate);
+ return null_value= false;
}
@@ -1453,6 +1564,25 @@ bool Item::get_seconds(ulonglong *sec, ulong *sec_part)
return my_decimal2seconds(dec, sec, sec_part);
}
+const MY_LOCALE *Item::locale_from_val_str()
+{
+ StringBuffer<MAX_FIELD_WIDTH> tmp;
+ String *locale_name= val_str_ascii(&tmp);
+ const MY_LOCALE *lc;
+ if (!locale_name ||
+ !(lc= my_locale_by_name(locale_name->c_ptr_safe())))
+ {
+ THD *thd= current_thd;
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
+ ER_UNKNOWN_LOCALE,
+ ER_THD(thd, ER_UNKNOWN_LOCALE),
+ locale_name ? locale_name->c_ptr_safe() : "NULL");
+ lc= &my_locale_en_US;
+ }
+ return lc;
+}
+
+
CHARSET_INFO *Item::default_charset()
{
return current_thd->variables.collation_connection;
@@ -1525,28 +1655,68 @@ bool mark_unsupported_function(const char *w1, const char *w2,
return mark_unsupported_function(ptr, store, result);
}
+
+Query_fragment::Query_fragment(THD *thd, sp_head *sphead,
+ const char *start, const char *end)
+{
+ DBUG_ASSERT(start <= end);
+ if (thd->lex->clone_spec_offset)
+ {
+ Lex_input_stream *lip= (& thd->m_parser_state->m_lip);
+ DBUG_ASSERT(lip->get_buf() <= start);
+ DBUG_ASSERT(end <= lip->get_end_of_query());
+ set(start - lip->get_buf(), end - start);
+ }
+ else if (sphead)
+ {
+ if (sphead->m_tmp_query)
+ {
+ // Normal SP statement
+ DBUG_ASSERT(sphead->m_tmp_query <= start);
+ set(start - sphead->m_tmp_query, end - start);
+ }
+ else
+ {
+ /*
+ We're in the "if" expression of a compound query:
+ if (expr)
+ do_something;
+ end if;
+ sphead->m_tmp_query is not set yet at this point, because
+ the "if" part of such statements is never put into the binary log.
+ Values of Rewritable_query_parameter::pos_in_query and
+ Rewritable_query_parameter:len_in_query will not be important,
+ so setting both to 0 should be fine.
+ */
+ set(0, 0);
+ }
+ }
+ else
+ {
+ // Non-SP statement
+ DBUG_ASSERT(thd->query() <= start);
+ DBUG_ASSERT(end <= thd->query_end());
+ set(start - thd->query(), end - start);
+ }
+}
+
+
/*****************************************************************************
Item_sp_variable methods
*****************************************************************************/
-Item_sp_variable::Item_sp_variable(THD *thd, char *sp_var_name_str,
- uint sp_var_name_length):
- Item(thd), m_thd(0)
+Item_sp_variable::Item_sp_variable(THD *thd, const LEX_CSTRING *sp_var_name)
+ :Item(thd), m_thd(0), m_name(*sp_var_name)
#ifndef DBUG_OFF
, m_sp(0)
#endif
{
- m_name.str= sp_var_name_str;
- m_name.length= sp_var_name_length;
}
-bool Item_sp_variable::fix_fields(THD *thd, Item **)
+bool Item_sp_variable::fix_fields_from_item(THD *thd, Item **, const Item *it)
{
- Item *it;
-
m_thd= thd; /* NOTE: this must be set before any this_xxx() */
- it= this_item();
DBUG_ASSERT(it->fixed);
@@ -1629,62 +1799,106 @@ my_decimal *Item_sp_variable::val_decimal(my_decimal *decimal_value)
}
+bool Item_sp_variable::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+{
+ DBUG_ASSERT(fixed);
+ Item *it= this_item();
+ bool val= it->get_date(ltime, fuzzydate);
+ null_value= it->null_value;
+ return val;
+}
+
+
bool Item_sp_variable::is_null()
{
return this_item()->is_null();
}
+void Item_sp_variable::make_send_field(THD *thd, Send_field *field)
+{
+ Item *it= this_item();
+
+ it->make_send_field(thd, field);
+ if (name.str)
+ field->col_name= name;
+ else
+ field->col_name= m_name;
+}
/*****************************************************************************
Item_splocal methods
*****************************************************************************/
-Item_splocal::Item_splocal(THD *thd, const LEX_STRING &sp_var_name,
+Item_splocal::Item_splocal(THD *thd,
+ const Sp_rcontext_handler *rh,
+ const LEX_CSTRING *sp_var_name,
uint sp_var_idx,
- enum_field_types sp_var_type,
+ const Type_handler *handler,
uint pos_in_q, uint len_in_q):
- Item_sp_variable(thd, sp_var_name.str, sp_var_name.length),
+ Item_sp_variable(thd, sp_var_name),
Rewritable_query_parameter(pos_in_q, len_in_q),
+ Type_handler_hybrid_field_type(handler),
+ m_rcontext_handler(rh),
m_var_idx(sp_var_idx)
{
maybe_null= TRUE;
+ m_type= sp_map_item_type(handler);
+}
+
- sp_var_type= real_type_to_type(sp_var_type);
- m_type= sp_map_item_type(sp_var_type);
- set_handler_by_field_type(sp_var_type);
+sp_rcontext *Item_splocal::get_rcontext(sp_rcontext *local_ctx) const
+{
+ return m_rcontext_handler->get_rcontext(local_ctx);
+}
+
+
+Item_field *Item_splocal::get_variable(sp_rcontext *ctx) const
+{
+ return get_rcontext(ctx)->get_variable(m_var_idx);
+}
+
+
+bool Item_splocal::fix_fields(THD *thd, Item **ref)
+{
+ DBUG_ASSERT(!fixed);
+ Item *item= get_variable(thd->spcont);
+ set_handler(item->type_handler());
+ return fix_fields_from_item(thd, ref, item);
}
Item *
Item_splocal::this_item()
{
- DBUG_ASSERT(m_sp == m_thd->spcont->sp);
-
- return m_thd->spcont->get_item(m_var_idx);
+ DBUG_ASSERT(m_sp == m_thd->spcont->m_sp);
+ DBUG_ASSERT(fixed);
+ return get_variable(m_thd->spcont);
}
const Item *
Item_splocal::this_item() const
{
- DBUG_ASSERT(m_sp == m_thd->spcont->sp);
-
- return m_thd->spcont->get_item(m_var_idx);
+ DBUG_ASSERT(m_sp == m_thd->spcont->m_sp);
+ DBUG_ASSERT(fixed);
+ return get_variable(m_thd->spcont);
}
Item **
Item_splocal::this_item_addr(THD *thd, Item **)
{
- DBUG_ASSERT(m_sp == thd->spcont->sp);
-
- return thd->spcont->get_item_addr(m_var_idx);
+ DBUG_ASSERT(m_sp == thd->spcont->m_sp);
+ DBUG_ASSERT(fixed);
+ return get_rcontext(thd->spcont)->get_variable_addr(m_var_idx);
}
void Item_splocal::print(String *str, enum_query_type)
{
- str->reserve(m_name.length+8);
- str->append(m_name.str, m_name.length);
+ const LEX_CSTRING *prefix= m_rcontext_handler->get_name_prefix();
+ str->reserve(m_name.length + 8 + prefix->length);
+ str->append(prefix);
+ str->append(&m_name);
str->append('@');
str->qs_append(m_var_idx);
}
@@ -1692,7 +1906,181 @@ void Item_splocal::print(String *str, enum_query_type)
bool Item_splocal::set_value(THD *thd, sp_rcontext *ctx, Item **it)
{
- return ctx->set_variable(thd, get_var_idx(), it);
+ return get_rcontext(ctx)->set_variable(thd, get_var_idx(), it);
+}
+
+
+/**
+ These two declarations are different:
+ x INT;
+ ROW(x INT);
+ A ROW with one elements should not be comparable to scalar value.
+
+ TODO: Currently we don't support one argument with the function ROW(), so
+ this query returns a syntax error, meaning that more arguments are expected:
+ SELECT ROW(1);
+
+ Therefore, all around the code we assume that cols()==1 means a scalar value
+ and cols()>1 means a ROW value. With adding ROW SP variables this
+ assumption is not true any more. ROW variables with one element are
+ now possible.
+
+ To implement Item::check_cols() correctly, we now should extend it to
+ know if a ROW or a scalar value is being tested. For example,
+ these new prototypes should work:
+ virtual bool check_cols(Item_result result, uint c);
+ or
+ virtual bool check_cols(const Type_handler *type, uint c);
+
+ The current implementation of Item_splocal::check_cols() is a compromise
+ that should be more or less fine until we extend check_cols().
+ It disallows ROW variables to appear in a scalar context.
+ The "|| n == 1" part of the conditon is responsible for this.
+ For example, it disallows ROW variables to appear in SELECT list:
+
+DELIMITER $$;
+CREATE PROCEDURE p1()
+AS
+ a ROW (a INT);
+BEGIN
+ SELECT a;
+END;
+$$
+DELIMITER ;$$
+--error ER_OPERAND_COLUMNS
+CALL p1();
+
+ But is produces false negatives with ROW variables consisting of one element.
+ For example, this script fails:
+
+SET sql_mode=ORACLE;
+DROP PROCEDURE IF EXISTS p1;
+DELIMITER $$
+CREATE PROCEDURE p1
+AS
+ a ROW(a INT);
+ b ROW(a INT);
+BEGIN
+ SELECT a=b;
+END;
+$$
+DELIMITER ;
+CALL p1();
+
+ and returns "ERROR 1241 (21000): Operand should contain 1 column(s)".
+ This will be fixed that we change check_cols().
+*/
+
+bool Item_splocal::check_cols(uint n)
+{
+ DBUG_ASSERT(m_thd->spcont);
+ if (Type_handler_hybrid_field_type::cmp_type() != ROW_RESULT)
+ return Item::check_cols(n);
+
+ if (n != this_item()->cols() || n == 1)
+ {
+ my_error(ER_OPERAND_COLUMNS, MYF(0), n);
+ return true;
+ }
+ return false;
+}
+
+
+bool Item_splocal_row_field::fix_fields(THD *thd, Item **ref)
+{
+ DBUG_ASSERT(!fixed);
+ Item *item= get_variable(thd->spcont)->element_index(m_field_idx);
+ return fix_fields_from_item(thd, ref, item);
+}
+
+
+Item *
+Item_splocal_row_field::this_item()
+{
+ DBUG_ASSERT(m_sp == m_thd->spcont->m_sp);
+ DBUG_ASSERT(fixed);
+ return get_variable(m_thd->spcont)->element_index(m_field_idx);
+}
+
+
+const Item *
+Item_splocal_row_field::this_item() const
+{
+ DBUG_ASSERT(m_sp == m_thd->spcont->m_sp);
+ DBUG_ASSERT(fixed);
+ return get_variable(m_thd->spcont)->element_index(m_field_idx);
+}
+
+
+Item **
+Item_splocal_row_field::this_item_addr(THD *thd, Item **)
+{
+ DBUG_ASSERT(m_sp == thd->spcont->m_sp);
+ DBUG_ASSERT(fixed);
+ return get_variable(thd->spcont)->addr(m_field_idx);
+}
+
+
+void Item_splocal_row_field::print(String *str, enum_query_type)
+{
+ const LEX_CSTRING *prefix= m_rcontext_handler->get_name_prefix();
+ str->reserve(m_name.length + m_field_name.length + 8 + prefix->length);
+ str->append(prefix);
+ str->append(&m_name);
+ str->append('.');
+ str->append(&m_field_name);
+ str->append('@');
+ str->qs_append(m_var_idx);
+ str->append('[');
+ str->qs_append(m_field_idx);
+ str->append(']');
+}
+
+
+bool Item_splocal_row_field::set_value(THD *thd, sp_rcontext *ctx, Item **it)
+{
+ return get_rcontext(ctx)->set_variable_row_field(thd, m_var_idx, m_field_idx,
+ it);
+}
+
+
+bool Item_splocal_row_field_by_name::fix_fields(THD *thd, Item **it)
+{
+ DBUG_ASSERT(!fixed);
+ m_thd= thd;
+ if (get_rcontext(thd->spcont)->find_row_field_by_name_or_error(&m_field_idx,
+ m_var_idx,
+ m_field_name))
+ return true;
+ Item *item= get_variable(thd->spcont)->element_index(m_field_idx);
+ set_handler(item->type_handler());
+ return fix_fields_from_item(thd, it, item);
+}
+
+
+void Item_splocal_row_field_by_name::print(String *str, enum_query_type)
+{
+ const LEX_CSTRING *prefix= m_rcontext_handler->get_name_prefix();
+ // +16 should be enough for .NNN@[""]
+ if (str->reserve(m_name.length + 2 * m_field_name.length +
+ prefix->length + 16))
+ return;
+ str->qs_append(prefix);
+ str->qs_append(&m_name);
+ str->qs_append('.');
+ str->qs_append(&m_field_name);
+ str->qs_append('@');
+ str->qs_append(m_var_idx);
+ str->qs_append("[\"", 2);
+ str->qs_append(&m_field_name);
+ str->qs_append("\"]", 2);
+}
+
+
+bool Item_splocal_row_field_by_name::set_value(THD *thd, sp_rcontext *ctx, Item **it)
+{
+ DBUG_ASSERT(fixed); // Make sure m_field_idx is already set
+ return Item_splocal_row_field::set_value(thd, ctx, it);
}
@@ -1700,17 +2088,26 @@ bool Item_splocal::set_value(THD *thd, sp_rcontext *ctx, Item **it)
Item_case_expr methods
*****************************************************************************/
+LEX_CSTRING str_case_expr= { STRING_WITH_LEN("case_expr") };
+
Item_case_expr::Item_case_expr(THD *thd, uint case_expr_id):
- Item_sp_variable(thd, C_STRING_WITH_LEN("case_expr")),
+ Item_sp_variable(thd, &str_case_expr),
m_case_expr_id(case_expr_id)
{
}
+bool Item_case_expr::fix_fields(THD *thd, Item **ref)
+{
+ Item *item= thd->spcont->get_case_expr(m_case_expr_id);
+ return fix_fields_from_item(thd, ref, item);
+}
+
+
Item *
Item_case_expr::this_item()
{
- DBUG_ASSERT(m_sp == m_thd->spcont->sp);
+ DBUG_ASSERT(m_sp == m_thd->spcont->m_sp);
return m_thd->spcont->get_case_expr(m_case_expr_id);
}
@@ -1720,7 +2117,7 @@ Item_case_expr::this_item()
const Item *
Item_case_expr::this_item() const
{
- DBUG_ASSERT(m_sp == m_thd->spcont->sp);
+ DBUG_ASSERT(m_sp == m_thd->spcont->m_sp);
return m_thd->spcont->get_case_expr(m_case_expr_id);
}
@@ -1729,7 +2126,7 @@ Item_case_expr::this_item() const
Item **
Item_case_expr::this_item_addr(THD *thd, Item **)
{
- DBUG_ASSERT(m_sp == thd->spcont->sp);
+ DBUG_ASSERT(m_sp == thd->spcont->m_sp);
return thd->spcont->get_case_expr_addr(m_case_expr_id);
}
@@ -1783,6 +2180,13 @@ my_decimal *Item_name_const::val_decimal(my_decimal *decimal_value)
return val;
}
+bool Item_name_const::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+{
+ DBUG_ASSERT(fixed);
+ bool rc= value_item->get_date(ltime, fuzzydate);
+ null_value= value_item->null_value;
+ return rc;
+}
bool Item_name_const::is_null()
{
@@ -1878,6 +2282,7 @@ bool Item_name_const::fix_fields(THD *thd, Item **ref)
collation.set(value_item->collation.collation, DERIVATION_IMPLICIT);
max_length= value_item->max_length;
decimals= value_item->decimals;
+ unsigned_flag= value_item->unsigned_flag;
fixed= 1;
return FALSE;
}
@@ -1903,7 +2308,7 @@ class Item_aggregate_ref : public Item_ref
public:
Item_aggregate_ref(THD *thd, Name_resolution_context *context_arg,
Item **item, const char *table_name_arg,
- const char *field_name_arg):
+ const LEX_CSTRING *field_name_arg):
Item_ref(thd, context_arg, item, table_name_arg, field_name_arg) {}
virtual inline void print (String *str, enum_query_type query_type)
@@ -2019,14 +2424,14 @@ void Item::split_sum_func2(THD *thd, Ref_ptr_array ref_pointer_array,
already a reference.
*/
Item *real_itm= real_item();
-
ref_pointer_array[el]= real_itm;
if (type() == WINDOW_FUNC_ITEM)
{
if (!(item_ref= (new (thd->mem_root)
Item_direct_ref(thd,
- &thd->lex->current_select->context,
- &ref_pointer_array[el], 0, name))))
+ &thd->lex->current_select->context,
+ &ref_pointer_array[el], 0,
+ &name))))
return; // fatal_error is set
}
else
@@ -2034,7 +2439,8 @@ void Item::split_sum_func2(THD *thd, Ref_ptr_array ref_pointer_array,
if (!(item_ref= (new (thd->mem_root)
Item_aggregate_ref(thd,
&thd->lex->current_select->context,
- &ref_pointer_array[el], 0, name))))
+ &ref_pointer_array[el], 0,
+ &name))))
return; // fatal_error is set
}
if (type() == SUM_FUNC_ITEM)
@@ -2239,9 +2645,9 @@ void my_coll_agg_error(Item** args, uint count, const char *fname,
}
-bool Item_func_or_sum::agg_item_collations(DTCollation &c, const char *fname,
- Item **av, uint count,
- uint flags, int item_sep)
+bool Type_std_attributes::agg_item_collations(DTCollation &c, const char *fname,
+ Item **av, uint count,
+ uint flags, int item_sep)
{
uint i;
Item **arg;
@@ -2286,10 +2692,10 @@ bool Item_func_or_sum::agg_item_collations(DTCollation &c, const char *fname,
}
-bool Item_func_or_sum::agg_item_set_converter(const DTCollation &coll,
- const char *fname,
- Item **args, uint nargs,
- uint flags, int item_sep)
+bool Type_std_attributes::agg_item_set_converter(const DTCollation &coll,
+ const char *fname,
+ Item **args, uint nargs,
+ uint flags, int item_sep)
{
THD *thd= current_thd;
if (thd->lex->is_ps_or_view_context_analysis())
@@ -2385,16 +2791,16 @@ bool Item_func_or_sum::agg_item_set_converter(const DTCollation &coll,
0 if an error occured
*/
-Item* Item_func_or_sum::build_clone(THD *thd, MEM_ROOT *mem_root)
+Item* Item_func_or_sum::build_clone(THD *thd)
{
- Item_func_or_sum *copy= (Item_func_or_sum *) get_copy(thd, mem_root);
- if (!copy)
+ Item_func_or_sum *copy= (Item_func_or_sum *) get_copy(thd);
+ if (unlikely(!copy))
return 0;
if (arg_count > 2)
{
copy->args=
- (Item**) alloc_root(mem_root, sizeof(Item*) * arg_count);
- if (!copy->args)
+ (Item**) alloc_root(thd->mem_root, sizeof(Item*) * arg_count);
+ if (unlikely(!copy->args))
return 0;
}
else if (arg_count > 0)
@@ -2403,7 +2809,7 @@ Item* Item_func_or_sum::build_clone(THD *thd, MEM_ROOT *mem_root)
for (uint i= 0; i < arg_count; i++)
{
- Item *arg_clone= args[i]->build_clone(thd, mem_root);
+ Item *arg_clone= args[i]->build_clone(thd);
if (!arg_clone)
return 0;
copy->args[i]= arg_clone;
@@ -2411,6 +2817,263 @@ Item* Item_func_or_sum::build_clone(THD *thd, MEM_ROOT *mem_root)
return copy;
}
+Item_sp::Item_sp(THD *thd, Name_resolution_context *context_arg,
+ sp_name *name_arg) :
+ context(context_arg), m_name(name_arg), m_sp(NULL), func_ctx(NULL),
+ sp_result_field(NULL)
+{
+ dummy_table= (TABLE*) thd->calloc(sizeof(TABLE) + sizeof(TABLE_SHARE) +
+ sizeof(Query_arena));
+ dummy_table->s= (TABLE_SHARE*) (dummy_table + 1);
+ /* TODO(cvicentiu) Move this sp_query_arena in the class as a direct member.
+ Currently it can not be done due to header include dependencies. */
+ sp_query_arena= (Query_arena *) (dummy_table->s + 1);
+ memset(&sp_mem_root, 0, sizeof(sp_mem_root));
+}
+
+Item_sp::Item_sp(THD *thd, Item_sp *item):
+ context(item->context), m_name(item->m_name),
+ m_sp(item->m_sp), func_ctx(NULL), sp_result_field(NULL)
+{
+ dummy_table= (TABLE*) thd->calloc(sizeof(TABLE)+ sizeof(TABLE_SHARE) +
+ sizeof(Query_arena));
+ dummy_table->s= (TABLE_SHARE*) (dummy_table+1);
+ sp_query_arena= (Query_arena *) (dummy_table->s + 1);
+ memset(&sp_mem_root, 0, sizeof(sp_mem_root));
+}
+
+const char *
+Item_sp::func_name(THD *thd) const
+{
+ /* Calculate length to avoid reallocation of string for sure */
+ size_t len= (((m_name->m_explicit_name ? m_name->m_db.length : 0) +
+ m_name->m_name.length)*2 + //characters*quoting
+ 2 + // ` and `
+ (m_name->m_explicit_name ?
+ 3 : 0) + // '`', '`' and '.' for the db
+ 1 + // end of string
+ ALIGN_SIZE(1)); // to avoid String reallocation
+ String qname((char *)alloc_root(thd->mem_root, len), len,
+ system_charset_info);
+
+ qname.length(0);
+ if (m_name->m_explicit_name)
+ {
+ append_identifier(thd, &qname, &m_name->m_db);
+ qname.append('.');
+ }
+ append_identifier(thd, &qname, &m_name->m_name);
+ return qname.c_ptr_safe();
+}
+
+void
+Item_sp::cleanup()
+{
+ delete sp_result_field;
+ sp_result_field= NULL;
+ m_sp= NULL;
+ delete func_ctx;
+ func_ctx= NULL;
+ free_root(&sp_mem_root, MYF(0));
+ dummy_table->alias.free();
+}
+
+/**
+ @brief Checks if requested access to function can be granted to user.
+ If function isn't found yet, it searches function first.
+ If function can't be found or user don't have requested access
+ error is raised.
+
+ @param thd thread handler
+
+ @return Indication if the access was granted or not.
+ @retval FALSE Access is granted.
+ @retval TRUE Requested access can't be granted or function doesn't exists.
+
+*/
+bool
+Item_sp::sp_check_access(THD *thd)
+{
+ DBUG_ENTER("Item_sp::sp_check_access");
+ DBUG_ASSERT(m_sp);
+ DBUG_RETURN(m_sp->check_execute_access(thd));
+}
+
+/**
+ @brief Execute function & store value in field.
+
+ @return Function returns error status.
+ @retval FALSE on success.
+ @retval TRUE if an error occurred.
+*/
+bool Item_sp::execute(THD *thd, bool *null_value, Item **args, uint arg_count)
+{
+ if (unlikely(execute_impl(thd, args, arg_count)))
+ {
+ *null_value= 1;
+ context->process_error(thd);
+ if (thd->killed)
+ thd->send_kill_message();
+ return true;
+ }
+
+ /* Check that the field (the value) is not NULL. */
+
+ *null_value= sp_result_field->is_null();
+ return (*null_value);
+}
+
+/**
+ @brief Execute function and store the return value in the field.
+
+ @note This function was intended to be the concrete implementation of
+ the interface function execute. This was never realized.
+
+ @return The error state.
+ @retval FALSE on success
+ @retval TRUE if an error occurred.
+*/
+bool
+Item_sp::execute_impl(THD *thd, Item **args, uint arg_count)
+{
+ Sub_statement_state statement_state;
+ Security_context *save_security_ctx= thd->security_ctx;
+ enum enum_sp_data_access access=
+ (m_sp->daccess() == SP_DEFAULT_ACCESS) ?
+ SP_DEFAULT_ACCESS_MAPPING : m_sp->daccess();
+
+ DBUG_ENTER("Item_sp::execute_impl");
+
+ if (context->security_ctx)
+ {
+ /* Set view definer security context */
+ thd->security_ctx= context->security_ctx;
+ }
+
+ if (unlikely(sp_check_access(thd)))
+ {
+ thd->security_ctx= save_security_ctx;
+ DBUG_RETURN(TRUE);
+ }
+
+ /*
+ Throw an error if a non-deterministic function is called while
+ statement-based replication (SBR) is active.
+ */
+
+ if (unlikely(!m_sp->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_UNSAFE_ROUTINE, MYF(0));
+ thd->security_ctx= save_security_ctx;
+ DBUG_RETURN(TRUE);
+ }
+
+ /*
+ Disable the binlogging if this is not a SELECT statement. If this is a
+ SELECT, leave binlogging on, so execute_function() code writes the
+ function call into binlog.
+ */
+ thd->reset_sub_statement_state(&statement_state, SUB_STMT_FUNCTION);
+
+ /*
+ If this function is an aggregate function, we want to initialise the
+ mem_root only once per group. For a regular stored function, we will
+ initialise once for each call to execute_function.
+ */
+ m_sp->agg_type();
+ DBUG_ASSERT(m_sp->agg_type() == GROUP_AGGREGATE ||
+ (m_sp->agg_type() == NOT_AGGREGATE && !func_ctx));
+ if (!func_ctx)
+ {
+ init_sql_alloc(&sp_mem_root, "Item_sp", MEM_ROOT_BLOCK_SIZE, 0, MYF(0));
+ *sp_query_arena= Query_arena(&sp_mem_root,
+ Query_arena::STMT_INITIALIZED_FOR_SP);
+ }
+
+ bool err_status= m_sp->execute_function(thd, args, arg_count,
+ sp_result_field, &func_ctx,
+ sp_query_arena);
+ /*
+ We free the function context when the function finished executing normally
+ (quit_func == TRUE) or the function has exited with an error.
+ */
+ if (err_status || func_ctx->quit_func)
+ {
+ /* Free Items allocated during function execution. */
+ delete func_ctx;
+ func_ctx= NULL;
+ sp_query_arena->free_items();
+ free_root(&sp_mem_root, MYF(0));
+ memset(&sp_mem_root, 0, sizeof(sp_mem_root));
+ }
+ thd->restore_sub_statement_state(&statement_state);
+
+ thd->security_ctx= save_security_ctx;
+ DBUG_RETURN(err_status);
+}
+
+
+/**
+ @brief Initialize the result field by creating a temporary dummy table
+ and assign it to a newly created field object. Meta data used to
+ create the field is fetched from the sp_head belonging to the stored
+ proceedure found in the stored procedure functon cache.
+
+ @note This function should be called from fix_fields to init the result
+ field. It is some what related to Item_field.
+
+ @see Item_field
+
+ @param thd A pointer to the session and thread context.
+
+ @return Function return error status.
+ @retval TRUE is returned on an error
+ @retval FALSE is returned on success.
+*/
+
+bool
+Item_sp::init_result_field(THD *thd, uint max_length, uint maybe_null,
+ bool *null_value, LEX_CSTRING *name)
+{
+ DBUG_ENTER("Item_sp::init_result_field");
+
+ DBUG_ASSERT(m_sp != NULL);
+ DBUG_ASSERT(sp_result_field == NULL);
+
+ /*
+ A Field needs to be attached to a Table.
+ Below we "create" a dummy table by initializing
+ the needed pointers.
+ */
+ dummy_table->alias.set("", 0, table_alias_charset);
+ dummy_table->in_use= thd;
+ dummy_table->copy_blobs= TRUE;
+ dummy_table->s->table_cache_key= empty_clex_str;
+ dummy_table->s->table_name= empty_clex_str;
+ dummy_table->maybe_null= maybe_null;
+
+ if (!(sp_result_field= m_sp->create_result_field(max_length, name,
+ dummy_table)))
+ DBUG_RETURN(TRUE);
+
+ if (sp_result_field->pack_length() > sizeof(result_buf))
+ {
+ void *tmp;
+ if (!(tmp= thd->alloc(sp_result_field->pack_length())))
+ DBUG_RETURN(TRUE);
+ sp_result_field->move_field((uchar*) tmp);
+ }
+ else
+ sp_result_field->move_field(result_buf);
+
+ sp_result_field->null_ptr= (uchar *) null_value;
+ sp_result_field->null_bit= 1;
+
+ DBUG_RETURN(FALSE);
+}
/**
@brief
@@ -2428,29 +3091,23 @@ Item* Item_func_or_sum::build_clone(THD *thd, MEM_ROOT *mem_root)
0 if an error occured
*/
-Item* Item_ref::build_clone(THD *thd, MEM_ROOT *mem_root)
+Item* Item_ref::build_clone(THD *thd)
{
- Item_ref *copy= (Item_ref *) get_copy(thd, mem_root);
- if (!copy)
- return 0;
- copy->ref=
- (Item**) alloc_root(mem_root, sizeof(Item*));
- if (!copy->ref)
- return 0;
- Item *item_clone= (* ref)->build_clone(thd, mem_root);
- if (!item_clone)
+ Item_ref *copy= (Item_ref *) get_copy(thd);
+ if (unlikely(!copy) ||
+ unlikely(!(copy->ref= (Item**) alloc_root(thd->mem_root,
+ sizeof(Item*)))) ||
+ unlikely(!(*copy->ref= (* ref)->build_clone(thd))))
return 0;
- *copy->ref= item_clone;
return copy;
}
-void Item_ident_for_show::make_field(THD *thd, Send_field *tmp_field)
+void Item_ident_for_show::make_send_field(THD *thd, Send_field *tmp_field)
{
tmp_field->table_name= tmp_field->org_table_name= table_name;
tmp_field->db_name= db_name;
tmp_field->col_name= tmp_field->org_col_name= field->field_name;
- tmp_field->charsetnr= field->charset()->number;
tmp_field->length=field->field_length;
tmp_field->type=field->type();
tmp_field->flags= field->table->maybe_null ?
@@ -2461,16 +3118,14 @@ void Item_ident_for_show::make_field(THD *thd, Send_field *tmp_field)
/**********************************************/
Item_field::Item_field(THD *thd, Field *f)
- :Item_ident(thd, 0, NullS, *f->table_name, f->field_name),
+ :Item_ident(thd, 0, NullS, *f->table_name, &f->field_name),
item_equal(0),
have_privileges(0), any_privileges(0)
{
set_field(f);
- /*
- field_name and table_name should not point to garbage
- if this item is to be reused
- */
- orig_table_name= orig_field_name= "";
+
+ orig_table_name= table_name;
+ orig_field_name= field_name;
with_field= 1;
}
@@ -2484,7 +3139,8 @@ Item_field::Item_field(THD *thd, Field *f)
Item_field::Item_field(THD *thd, Name_resolution_context *context_arg,
Field *f)
- :Item_ident(thd, context_arg, f->table->s->db.str, *f->table_name, f->field_name),
+ :Item_ident(thd, context_arg, f->table->s->db.str, *f->table_name,
+ &f->field_name),
item_equal(0),
have_privileges(0), any_privileges(0)
{
@@ -2510,14 +3166,15 @@ Item_field::Item_field(THD *thd, Name_resolution_context *context_arg,
orig_db_name= thd->strdup(db_name);
if (table_name)
orig_table_name= thd->strdup(table_name);
- if (field_name)
- orig_field_name= thd->strdup(field_name);
+ if (field_name.str)
+ thd->make_lex_string(&orig_field_name, field_name.str,
+ field_name.length);
/*
We don't restore 'name' in cleanup because it's not changed
during execution. Still we need it to point to persistent
memory if this item is to be reused.
*/
- name= (char*) orig_field_name;
+ name= orig_field_name;
}
set_field(f);
with_field= 1;
@@ -2526,7 +3183,7 @@ Item_field::Item_field(THD *thd, Name_resolution_context *context_arg,
Item_field::Item_field(THD *thd, Name_resolution_context *context_arg,
const char *db_arg,const char *table_name_arg,
- const char *field_name_arg)
+ const LEX_CSTRING *field_name_arg)
:Item_ident(thd, context_arg, db_arg, table_name_arg, field_name_arg),
field(0), item_equal(0),
have_privileges(0), any_privileges(0)
@@ -2554,75 +3211,15 @@ Item_field::Item_field(THD *thd, Item_field *item)
}
-/**
- Calculate the max column length not taking into account the
- limitations over integer types.
-
- When storing data into fields the server currently just ignores the
- limits specified on integer types, e.g. 1234 can safely be stored in
- an int(2) and will not cause an error.
- Thus when creating temporary tables and doing transformations
- we must adjust the maximum field length to reflect this fact.
- We take the un-restricted maximum length and adjust it similarly to
- how the declared length is adjusted wrt unsignedness etc.
- TODO: this all needs to go when we disable storing 1234 in int(2).
-
- @param field_par Original field the use to calculate the lengths
- @param max_length Item's calculated explicit max length
- @return The adjusted max length
-*/
-
-inline static uint32
-adjust_max_effective_column_length(Field *field_par, uint32 max_length)
-{
- uint32 new_max_length= field_par->max_display_length();
- uint32 sign_length= (field_par->flags & UNSIGNED_FLAG) ? 0 : 1;
-
- switch (field_par->type())
- {
- case MYSQL_TYPE_INT24:
- /*
- Compensate for MAX_MEDIUMINT_WIDTH being 1 too long (8)
- compared to the actual number of digits that can fit into
- the column.
- */
- new_max_length+= 1;
- /* fall through */
- case MYSQL_TYPE_LONG:
- case MYSQL_TYPE_TINY:
- case MYSQL_TYPE_SHORT:
-
- /* Take out the sign and add a conditional sign */
- new_max_length= new_max_length - 1 + sign_length;
- break;
-
- /* BINGINT is always 20 no matter the sign */
- case MYSQL_TYPE_LONGLONG:
- /* make gcc happy */
- default:
- break;
- }
-
- /* Adjust only if the actual precision based one is bigger than specified */
- return new_max_length > max_length ? new_max_length : max_length;
-}
-
-
void Item_field::set_field(Field *field_par)
{
field=result_field=field_par; // for easy coding with fields
maybe_null=field->maybe_null();
- decimals= field->decimals();
+ Type_std_attributes::set(field_par->type_std_attributes());
table_name= *field_par->table_name;
field_name= field_par->field_name;
db_name= field_par->table->s->db.str;
alias_name_used= field_par->table->alias_name_used;
- unsigned_flag= MY_TEST(field_par->flags & UNSIGNED_FLAG);
- collation.set(field_par->charset(), field_par->derivation(),
- field_par->repertoire());
- fix_char_length(field_par->char_length());
-
- max_length= adjust_max_effective_column_length(field_par, max_length);
fixed= 1;
if (field->table->s->tmp_table == SYSTEM_TMP_TABLE)
@@ -2640,13 +3237,13 @@ void Item_field::reset_field(Field *f)
{
set_field(f);
/* 'name' is pointing at field->field_name of old field */
- name= (char*) f->field_name;
+ name= f->field_name;
}
void Item_field::load_data_print_for_log_event(THD *thd, String *to) const
{
- append_identifier(thd, to, name, (uint) strlen(name));
+ append_identifier(thd, to, name.str, name.length);
}
@@ -2704,15 +3301,15 @@ bool Item_field::switch_to_nullable_fields_processor(void *arg)
const char *Item_ident::full_name() const
{
char *tmp;
- if (!table_name || !field_name)
- return field_name ? field_name : name ? name : "tmp_field";
+ if (!table_name || !field_name.str)
+ return field_name.str ? field_name.str : name.str ? name.str : "tmp_field";
if (db_name && db_name[0])
{
THD *thd= current_thd;
tmp=(char*) thd->alloc((uint) strlen(db_name)+(uint) strlen(table_name)+
- (uint) strlen(field_name)+3);
- strxmov(tmp,db_name,".",table_name,".",field_name,NullS);
+ (uint) field_name.length+3);
+ strxmov(tmp,db_name,".",table_name,".",field_name.str,NullS);
}
else
{
@@ -2720,11 +3317,11 @@ const char *Item_ident::full_name() const
{
THD *thd= current_thd;
tmp= (char*) thd->alloc((uint) strlen(table_name) +
- (uint) strlen(field_name) + 2);
- strxmov(tmp, table_name, ".", field_name, NullS);
+ field_name.length + 2);
+ strxmov(tmp, table_name, ".", field_name.str, NullS);
}
else
- tmp= (char*) field_name;
+ return field_name.str;
}
return tmp;
}
@@ -2738,7 +3335,7 @@ void Item_ident::print(String *str, enum_query_type query_type)
bool use_db_name= use_table_name && db_name && db_name[0] && !alias_name_used;
if (use_db_name && (query_type & QT_ITEM_IDENT_SKIP_DB_NAMES))
- use_db_name= !thd->db || strcmp(thd->db, db_name);
+ use_db_name= !thd->db.str || strcmp(thd->db.str, db_name);
if (use_db_name)
use_db_name= !(cached_table && cached_table->belong_to_view &&
@@ -2761,7 +3358,7 @@ void Item_ident::print(String *str, enum_query_type query_type)
use_db_name= use_table_name= false;
}
- if (!field_name || !field_name[0])
+ if (!field_name.str || !field_name.str[0])
{
append_identifier(thd, str, STRING_WITH_LEN("tmp_field"));
return;
@@ -2795,7 +3392,7 @@ void Item_ident::print(String *str, enum_query_type query_type)
append_identifier(thd, str, t_name, (uint) strlen(t_name));
str->append('.');
}
- append_identifier(thd, str, field_name, (uint) strlen(field_name));
+ append_identifier(thd, str, &field_name);
}
/* ARGSUSED */
@@ -2926,8 +3523,8 @@ bool Item_field::eq(const Item *item, bool binary_cmp) const
(In cases where we would choose wrong we would have to generate a
ER_NON_UNIQ_ERROR).
*/
- return (!my_strcasecmp(system_charset_info, item_field->name,
- field_name) &&
+ return (!lex_string_cmp(system_charset_info, &item_field->name,
+ &field_name) &&
(!item_field->table_name || !table_name ||
(!my_strcasecmp(table_alias_charset, item_field->table_name,
table_name) &&
@@ -2949,6 +3546,11 @@ table_map Item_field::all_used_tables() const
return (get_depended_from() ? OUTER_REF_TABLE_BIT : field->table->map);
}
+
+/*
+ @Note thd->fatal_error can be set in case of OOM
+*/
+
void Item_field::fix_after_pullout(st_select_lex *new_parent, Item **ref,
bool merge)
{
@@ -3008,6 +3610,8 @@ void Item_field::fix_after_pullout(st_select_lex *new_parent, Item **ref,
}
Name_resolution_context *ctx= new Name_resolution_context();
+ if (!ctx)
+ return; // Fatal error set
if (context->select_lex == new_parent)
{
/*
@@ -3061,14 +3665,19 @@ longlong Item_field::val_int_endpoint(bool left_endp, bool *incl_endp)
This is always 'signed'. Unsigned values are created with Item_uint()
*/
-Item_int::Item_int(THD *thd, const char *str_arg, uint length):
+Item_int::Item_int(THD *thd, const char *str_arg, size_t length):
Item_num(thd)
{
char *end_ptr= (char*) str_arg + length;
int error;
value= my_strtoll10(str_arg, &end_ptr, &error);
max_length= (uint) (end_ptr - str_arg);
- name= (char*) str_arg;
+ name.str= str_arg;
+ /*
+ We can't trust max_length as in show_routine_code we are using "Pos" as
+ the field name.
+ */
+ name.length= !str_arg[max_length] ? max_length : strlen(str_arg);
fixed= 1;
}
@@ -3098,12 +3707,12 @@ void Item_int::print(String *str, enum_query_type query_type)
Item *Item_bool::neg_transformer(THD *thd)
{
value= !value;
- name= 0;
+ name= null_clex_str;
return this;
}
-Item_uint::Item_uint(THD *thd, const char *str_arg, uint length):
+Item_uint::Item_uint(THD *thd, const char *str_arg, size_t length):
Item_int(thd, str_arg, length)
{
unsigned_flag= 1;
@@ -3134,12 +3743,13 @@ void Item_uint::print(String *str, enum_query_type query_type)
}
-Item_decimal::Item_decimal(THD *thd, const char *str_arg, uint length,
+Item_decimal::Item_decimal(THD *thd, const char *str_arg, size_t length,
CHARSET_INFO *charset):
Item_num(thd)
{
str2my_decimal(E_DEC_FATAL_ERROR, str_arg, length, charset, &decimal_value);
- name= (char*) str_arg;
+ name.str= str_arg;
+ name.length= safe_strlen(str_arg);
decimals= (uint8) decimal_value.frac;
fixed= 1;
max_length= my_decimal_precision_to_length_no_truncation(decimal_value.intg +
@@ -3179,7 +3789,8 @@ Item_decimal::Item_decimal(THD *thd, const char *str, const my_decimal *val_arg,
Item_num(thd)
{
my_decimal2decimal(val_arg, &decimal_value);
- name= (char*) str;
+ name.str= str;
+ name.length= safe_strlen(str);
decimals= (uint8) decimal_par;
max_length= length;
fixed= 1;
@@ -3271,7 +3882,7 @@ void Item_decimal::set_decimal_value(my_decimal *value_par)
Item *Item_decimal::clone_item(THD *thd)
{
- return new (thd->mem_root) Item_decimal(thd, name, &decimal_value, decimals,
+ return new (thd->mem_root) Item_decimal(thd, name.str, &decimal_value, decimals,
max_length);
}
@@ -3296,7 +3907,7 @@ my_decimal *Item_float::val_decimal(my_decimal *decimal_value)
Item *Item_float::clone_item(THD *thd)
{
- return new (thd->mem_root) Item_float(thd, name, value, decimals,
+ return new (thd->mem_root) Item_float(thd, name.str, value, decimals,
max_length);
}
@@ -3416,34 +4027,47 @@ Item *Item_null::safe_charset_converter(THD *thd, CHARSET_INFO *tocs)
Item *Item_null::clone_item(THD *thd)
{
- return new (thd->mem_root) Item_null(thd, name);
+ return new (thd->mem_root) Item_null(thd, name.str);
}
-/*********************** Item_param related ******************************/
-
-/**
- Default function of Item_param::set_param_func, so in case
- of malformed packet the server won't SIGSEGV.
-*/
-static void
-default_set_param_func(Item_param *param,
- uchar **pos __attribute__((unused)),
- ulong len __attribute__((unused)))
+Item_basic_constant *
+Item_null::make_string_literal_concat(THD *thd, const LEX_CSTRING *str)
{
- param->set_null();
+ DBUG_ASSERT(thd->variables.sql_mode & MODE_EMPTY_STRING_IS_NULL);
+ if (str->length)
+ {
+ CHARSET_INFO *cs= thd->variables.collation_connection;
+ uint repertoire= my_string_repertoire(cs, str->str, str->length);
+ return new (thd->mem_root) Item_string(thd,
+ str->str, (uint) str->length, cs,
+ DERIVATION_COERCIBLE, repertoire);
+ }
+ return this;
}
-Item_param::Item_param(THD *thd, uint pos_in_query_arg):
+/*********************** Item_param related ******************************/
+
+Item_param::Item_param(THD *thd, const LEX_CSTRING *name_arg,
+ uint pos_in_query_arg, uint len_in_query_arg):
Item_basic_value(thd),
- Rewritable_query_parameter(pos_in_query_arg, 1),
- Type_handler_hybrid_field_type(MYSQL_TYPE_VARCHAR),
+ Rewritable_query_parameter(pos_in_query_arg, len_in_query_arg),
+ /*
+ Set handler to type_handler_null. Its data type test methods such as:
+ - is_scalar_type()
+ - can_return_int()
+ - can_return_real(),
+ - is_general_purpose_string_type()
+ all return "true". This is needed to avoid any "illegal parameter type"
+ errors in Item::check_type_xxx() at PS prepare time.
+ */
+ Type_handler_hybrid_field_type(&type_handler_null),
state(NO_VALUE),
/* Don't pretend to be a literal unless value for this item is set. */
item_type(PARAM_ITEM),
+ m_empty_string_is_null(false),
indicator(STMT_INDICATOR_NONE),
- set_param_func(default_set_param_func),
m_out_param_info(NULL),
/*
Set m_is_settable_routine_parameter to "true" by default.
@@ -3455,8 +4079,8 @@ Item_param::Item_param(THD *thd, uint pos_in_query_arg):
m_is_settable_routine_parameter(true),
m_clones(thd->mem_root)
{
- name= (char*) "?";
- /*
+ name= *name_arg;
+ /*
Since we can't say whenever this item can be NULL or cannot be NULL
before mysql_stmt_execute(), so we assuming that it can be NULL until
value is set.
@@ -3470,7 +4094,7 @@ Item_param::Item_param(THD *thd, uint pos_in_query_arg):
bool Item_param::add_as_clone(THD *thd)
{
LEX *lex= thd->lex;
- uint master_pos= pos_in_query + lex->clone_spec_offset;
+ my_ptrdiff_t master_pos= pos_in_query + lex->clone_spec_offset;
List_iterator_fast<Item_param> it(lex->param_list);
Item_param *master_param;
while ((master_param = it++))
@@ -3495,22 +4119,26 @@ void Item_param::sync_clones()
/* Scalar-type members: */
c->maybe_null= maybe_null;
c->null_value= null_value;
- c->max_length= max_length;
- c->decimals= decimals;
+ c->Type_std_attributes::operator=(*this);
+ c->Type_handler_hybrid_field_type::operator=(*this);
+ c->Type_geometry_attributes::operator=(*this);
+
c->state= state;
c->item_type= item_type;
- c->set_param_func= set_param_func;
- c->value= value;
- c->unsigned_flag= unsigned_flag;
+ c->m_empty_string_is_null= m_empty_string_is_null;
+
+ c->value.PValue_simple::operator=(value);
+ c->value.Type_handler_hybrid_field_type::operator=(value);
+ type_handler()->Item_param_setup_conversion(current_thd, c);
+
/* Class-type members: */
- c->decimal_value= decimal_value;
+ c->value.m_decimal= value.m_decimal;
/*
Note that String's assignment op properly sets m_is_alloced to 'false',
which is correct here: c->str_value doesn't own anything.
*/
- c->str_value= str_value;
- c->str_value_ptr= str_value_ptr;
- c->collation= collation;
+ c->value.m_string= value.m_string;
+ c->value.m_string_ptr= value.m_string_ptr;
}
}
@@ -3538,8 +4166,9 @@ void Item_param::set_null()
void Item_param::set_int(longlong i, uint32 max_length_arg)
{
DBUG_ENTER("Item_param::set_int");
+ DBUG_ASSERT(value.type_handler()->cmp_type() == INT_RESULT);
value.integer= (longlong) i;
- state= INT_VALUE;
+ state= SHORT_DATA_VALUE;
collation.set_numeric();
max_length= max_length_arg;
decimals= 0;
@@ -3552,8 +4181,9 @@ void Item_param::set_int(longlong i, uint32 max_length_arg)
void Item_param::set_double(double d)
{
DBUG_ENTER("Item_param::set_double");
+ DBUG_ASSERT(value.type_handler()->cmp_type() == REAL_RESULT);
value.real= d;
- state= REAL_VALUE;
+ state= SHORT_DATA_VALUE;
collation.set_numeric();
max_length= DBL_DIG + 8;
decimals= NOT_FIXED_DEC;
@@ -3580,14 +4210,15 @@ void Item_param::set_decimal(const char *str, ulong length)
{
char *end;
DBUG_ENTER("Item_param::set_decimal");
+ DBUG_ASSERT(value.type_handler()->cmp_type() == DECIMAL_RESULT);
end= (char*) str+length;
- str2my_decimal(E_DEC_FATAL_ERROR, str, &decimal_value, &end);
- state= DECIMAL_VALUE;
- decimals= decimal_value.frac;
+ str2my_decimal(E_DEC_FATAL_ERROR, str, &value.m_decimal, &end);
+ state= SHORT_DATA_VALUE;
+ decimals= value.m_decimal.frac;
collation.set_numeric();
max_length=
- my_decimal_precision_to_length_no_truncation(decimal_value.precision(),
+ my_decimal_precision_to_length_no_truncation(value.m_decimal.precision(),
decimals, unsigned_flag);
maybe_null= 0;
null_value= 0;
@@ -3597,14 +4228,15 @@ void Item_param::set_decimal(const char *str, ulong length)
void Item_param::set_decimal(const my_decimal *dv, bool unsigned_arg)
{
- state= DECIMAL_VALUE;
+ DBUG_ASSERT(value.type_handler()->cmp_type() == DECIMAL_RESULT);
+ state= SHORT_DATA_VALUE;
- my_decimal2decimal(dv, &decimal_value);
+ my_decimal2decimal(dv, &value.m_decimal);
- decimals= (uint8) decimal_value.frac;
+ decimals= (uint8) value.m_decimal.frac;
collation.set_numeric();
unsigned_flag= unsigned_arg;
- max_length= my_decimal_precision_to_length(decimal_value.intg + decimals,
+ max_length= my_decimal_precision_to_length(value.m_decimal.intg + decimals,
decimals, unsigned_flag);
maybe_null= 0;
null_value= 0;
@@ -3614,7 +4246,7 @@ void Item_param::set_decimal(const my_decimal *dv, bool unsigned_arg)
void Item_param::fix_temporal(uint32 max_length_arg, uint decimals_arg)
{
- state= TIME_VALUE;
+ state= SHORT_DATA_VALUE;
collation.set_numeric();
max_length= max_length_arg;
decimals= decimals_arg;
@@ -3627,6 +4259,7 @@ void Item_param::fix_temporal(uint32 max_length_arg, uint decimals_arg)
void Item_param::set_time(const MYSQL_TIME *tm,
uint32 max_length_arg, uint decimals_arg)
{
+ DBUG_ASSERT(value.type_handler()->cmp_type() == TIME_RESULT);
value.time= *tm;
maybe_null= 0;
null_value= 0;
@@ -3651,6 +4284,7 @@ void Item_param::set_time(MYSQL_TIME *tm, timestamp_type time_type,
uint32 max_length_arg)
{
DBUG_ENTER("Item_param::set_time");
+ DBUG_ASSERT(value.type_handler()->cmp_type() == TIME_RESULT);
value.time= *tm;
value.time.time_type= time_type;
@@ -3670,18 +4304,34 @@ void Item_param::set_time(MYSQL_TIME *tm, timestamp_type time_type,
}
-bool Item_param::set_str(const char *str, ulong length)
+bool Item_param::set_str(const char *str, ulong length,
+ CHARSET_INFO *fromcs, CHARSET_INFO *tocs)
{
DBUG_ENTER("Item_param::set_str");
+ DBUG_ASSERT(value.type_handler()->cmp_type() == STRING_RESULT);
/*
Assign string with no conversion: data is converted only after it's
been written to the binary log.
*/
uint dummy_errors;
- if (str_value.copy(str, length, &my_charset_bin, &my_charset_bin,
- &dummy_errors))
+ if (unlikely(value.m_string.copy(str, length, fromcs, tocs, &dummy_errors)))
DBUG_RETURN(TRUE);
- state= STRING_VALUE;
+ /*
+ Set str_value_ptr to make sure it's in sync with str_value.
+ This is needed in case if we're called from Item_param::set_value(),
+ from the code responsible for setting OUT parameters in
+ sp_head::execute_procedure(). This makes sure that
+ Protocol_binary::send_out_parameters() later gets a valid value
+ from Item_param::val_str().
+ Note, for IN parameters, Item_param::convert_str_value() will be called
+ later, which will convert the value from the client character set to the
+ connection character set, and will reset both str_value and str_value_ptr.
+ */
+ value.m_string_ptr.set(value.m_string.ptr(),
+ value.m_string.length(),
+ value.m_string.charset());
+ state= SHORT_DATA_VALUE;
+ collation.set(tocs, DERIVATION_COERCIBLE);
max_length= length;
maybe_null= 0;
null_value= 0;
@@ -3695,6 +4345,7 @@ bool Item_param::set_str(const char *str, ulong length)
bool Item_param::set_longdata(const char *str, ulong length)
{
DBUG_ENTER("Item_param::set_longdata");
+ DBUG_ASSERT(value.type_handler()->cmp_type() == STRING_RESULT);
/*
If client character set is multibyte, end of long data packet
@@ -3705,7 +4356,7 @@ bool Item_param::set_longdata(const char *str, ulong length)
(here), and first have to concatenate all pieces together,
write query to the binary log and only then perform conversion.
*/
- if (str_value.length() + length > max_long_data_size)
+ if (value.m_string.length() + length > max_long_data_size)
{
my_message(ER_UNKNOWN_ERROR,
"Parameter of prepared statement which is set through "
@@ -3715,7 +4366,7 @@ bool Item_param::set_longdata(const char *str, ulong length)
DBUG_RETURN(true);
}
- if (str_value.append(str, length, &my_charset_bin))
+ if (value.m_string.append(str, length, &my_charset_bin))
DBUG_RETURN(TRUE);
state= LONG_DATA_VALUE;
maybe_null= 0;
@@ -3779,53 +4430,16 @@ bool Item_param::set_from_item(THD *thd, Item *item)
else
{
unsigned_flag= item->unsigned_flag;
- set_int(val, MY_INT64_NUM_DECIMAL_DIGITS);
- set_handler_by_result_type(item->result_type());
- DBUG_RETURN(!unsigned_flag && value.integer < 0 ? 1 : 0);
+ set_handler(item->type_handler());
+ DBUG_RETURN(set_limit_clause_param(val));
}
}
struct st_value tmp;
- if (!item->store(&tmp, 0))
+ if (!item->save_in_value(&tmp))
{
- unsigned_flag= item->unsigned_flag;
- switch (item->cmp_type()) {
- case REAL_RESULT:
- set_double(tmp.value.m_double);
- set_handler_by_field_type(MYSQL_TYPE_DOUBLE);
- break;
- case INT_RESULT:
- set_int(tmp.value.m_longlong, MY_INT64_NUM_DECIMAL_DIGITS);
- set_handler_by_field_type(MYSQL_TYPE_LONGLONG);
- break;
- case STRING_RESULT:
- {
- value.cs_info.set(thd, item->collation.collation);
- /*
- Exact value of max_length is not known unless data is converted to
- charset of connection, so we have to set it later.
- */
- set_handler_by_field_type(MYSQL_TYPE_VARCHAR);
-
- if (set_str(tmp.m_string.ptr(), tmp.m_string.length()))
- DBUG_RETURN(1);
- break;
- }
- case DECIMAL_RESULT:
- {
- set_decimal(&tmp.m_decimal, unsigned_flag);
- set_handler_by_field_type(MYSQL_TYPE_NEWDECIMAL);
- break;
- }
- case TIME_RESULT:
- {
- set_time(&tmp.value.m_time, item->max_length, item->decimals);
- set_handler(item->type_handler());
- break;
- }
- case ROW_RESULT:
- DBUG_ASSERT(0);
- set_null();
- }
+ const Type_handler *h= item->type_handler();
+ set_handler(h);
+ DBUG_RETURN(set_value(thd, item, &tmp, h));
}
else
set_null();
@@ -3845,16 +4459,16 @@ void Item_param::reset()
{
DBUG_ENTER("Item_param::reset");
/* Shrink string buffer if it's bigger than max possible CHAR column */
- if (str_value.alloced_length() > MAX_CHAR_WIDTH)
- str_value.free();
+ if (value.m_string.alloced_length() > MAX_CHAR_WIDTH)
+ value.m_string.free();
else
- str_value.length(0);
- str_value_ptr.length(0);
+ value.m_string.length(0);
+ value.m_string_ptr.length(0);
/*
We must prevent all charset conversions until data has been written
to the binary log.
*/
- str_value.set_charset(&my_charset_bin);
+ value.m_string.set_charset(&my_charset_bin);
collation.set(&my_charset_bin, DERIVATION_COERCIBLE);
state= NO_VALUE;
maybe_null= 1;
@@ -3883,19 +4497,9 @@ int Item_param::save_in_field(Field *field, bool no_conversions)
Garbage (e.g. in case of a memory overrun) is handled after the switch.
*/
switch (state) {
- case INT_VALUE:
- return field->store(value.integer, unsigned_flag);
- case REAL_VALUE:
- return field->store(value.real);
- case DECIMAL_VALUE:
- return field->store_decimal(&decimal_value);
- case TIME_VALUE:
- field->store_time_dec(&value.time, decimals);
- return 0;
- case STRING_VALUE:
+ case SHORT_DATA_VALUE:
case LONG_DATA_VALUE:
- return field->store(str_value.ptr(), str_value.length(),
- str_value.charset());
+ return value.type_handler()->Item_save_in_field(this, field, no_conversions);
case NULL_VALUE:
return set_field_to_null_with_conversions(field, no_conversions);
case DEFAULT_VALUE:
@@ -3915,6 +4519,28 @@ int Item_param::save_in_field(Field *field, bool no_conversions)
}
+bool Item_param::can_return_value() const
+{
+ // There's no "default". See comments in Item_param::save_in_field().
+ switch (state) {
+ case SHORT_DATA_VALUE:
+ case LONG_DATA_VALUE:
+ return true;
+ case IGNORE_VALUE:
+ case DEFAULT_VALUE:
+ invalid_default_param();
+ // fall through
+ case NULL_VALUE:
+ return false;
+ case NO_VALUE:
+ DBUG_ASSERT(0); // Should not be possible
+ return false;
+ }
+ DBUG_ASSERT(0); // Garbage
+ return false;
+}
+
+
void Item_param::invalid_default_param() const
{
my_message(ER_INVALID_DEFAULT_PARAM,
@@ -3924,166 +4550,133 @@ void Item_param::invalid_default_param() const
bool Item_param::get_date(MYSQL_TIME *res, ulonglong fuzzydate)
{
- if (state == TIME_VALUE)
+ /*
+ LIMIT clause parameter should not call get_date()
+ For non-LIMIT parameters, handlers must be the same.
+ */
+ DBUG_ASSERT(type_handler()->result_type() ==
+ value.type_handler()->result_type());
+ if (state == SHORT_DATA_VALUE &&
+ value.type_handler()->cmp_type() == TIME_RESULT)
{
*res= value.time;
return 0;
}
- return Item::get_date(res, fuzzydate);
+ return type_handler()->Item_get_date(this, res, fuzzydate);
}
-double Item_param::val_real()
+double Item_param::PValue::val_real() const
{
- // There's no "default". See comments in Item_param::save_in_field().
- switch (state) {
- case REAL_VALUE:
- return value.real;
- case INT_VALUE:
- return (double) value.integer;
- case DECIMAL_VALUE:
+ switch (type_handler()->cmp_type()) {
+ case REAL_RESULT:
+ return real;
+ case INT_RESULT:
+ return (double) integer;
+ case DECIMAL_RESULT:
{
double result;
- my_decimal2double(E_DEC_FATAL_ERROR, &decimal_value, &result);
+ my_decimal2double(E_DEC_FATAL_ERROR, &m_decimal, &result);
return result;
}
- case STRING_VALUE:
- case LONG_DATA_VALUE:
- {
- return double_from_string_with_check(&str_value);
- }
- case TIME_VALUE:
+ case STRING_RESULT:
+ return double_from_string_with_check(&m_string);
+ case TIME_RESULT:
/*
This works for example when user says SELECT ?+0.0 and supplies
time value for the placeholder.
*/
- return TIME_to_double(&value.time);
- case IGNORE_VALUE:
- case DEFAULT_VALUE:
- invalid_default_param();
- // fall through
- case NULL_VALUE:
- return 0.0;
- case NO_VALUE:
- DBUG_ASSERT(0); // Should not be possible
- return 0.0;
+ return TIME_to_double(&time);
+ case ROW_RESULT:
+ DBUG_ASSERT(0);
+ break;
}
- DBUG_ASSERT(0); // Garbage
return 0.0;
-}
+}
-longlong Item_param::val_int()
-{
- // There's no "default". See comments in Item_param::save_in_field().
- switch (state) {
- case REAL_VALUE:
- return Converter_double_to_longlong(value.real, unsigned_flag).result();
- case INT_VALUE:
- return value.integer;
- case DECIMAL_VALUE:
+longlong Item_param::PValue::val_int(const Type_std_attributes *attr) const
+{
+ switch (type_handler()->cmp_type()) {
+ case REAL_RESULT:
+ return Converter_double_to_longlong(real, attr->unsigned_flag).result();
+ case INT_RESULT:
+ return integer;
+ case DECIMAL_RESULT:
{
longlong i;
- my_decimal2int(E_DEC_FATAL_ERROR, &decimal_value, unsigned_flag, &i);
+ my_decimal2int(E_DEC_FATAL_ERROR, &m_decimal, attr->unsigned_flag, &i);
return i;
}
- case STRING_VALUE:
- case LONG_DATA_VALUE:
- {
- return longlong_from_string_with_check(&str_value);
- }
- case TIME_VALUE:
- return (longlong) TIME_to_ulonglong(&value.time);
- case IGNORE_VALUE:
- case DEFAULT_VALUE:
- invalid_default_param();
- // fall through
- case NULL_VALUE:
- return 0;
- case NO_VALUE:
- DBUG_ASSERT(0); // Should not be possible
- return 0;
+ case STRING_RESULT:
+ return longlong_from_string_with_check(&m_string);
+ case TIME_RESULT:
+ return (longlong) TIME_to_ulonglong(&time);
+ case ROW_RESULT:
+ DBUG_ASSERT(0);
+ break;
}
- DBUG_ASSERT(0); // Garbage
return 0;
}
-my_decimal *Item_param::val_decimal(my_decimal *dec)
+my_decimal *Item_param::PValue::val_decimal(my_decimal *dec,
+ const Type_std_attributes *attr)
{
- // There's no "default". See comments in Item_param::save_in_field().
- switch (state) {
- case DECIMAL_VALUE:
- return &decimal_value;
- case REAL_VALUE:
- double2my_decimal(E_DEC_FATAL_ERROR, value.real, dec);
+ switch (type_handler()->cmp_type()) {
+ case DECIMAL_RESULT:
+ return &m_decimal;
+ case REAL_RESULT:
+ double2my_decimal(E_DEC_FATAL_ERROR, real, dec);
return dec;
- case INT_VALUE:
- int2my_decimal(E_DEC_FATAL_ERROR, value.integer, unsigned_flag, dec);
+ case INT_RESULT:
+ int2my_decimal(E_DEC_FATAL_ERROR, integer, attr->unsigned_flag, dec);
return dec;
- case STRING_VALUE:
- case LONG_DATA_VALUE:
- return decimal_from_string_with_check(dec, &str_value);
- case TIME_VALUE:
- {
- return TIME_to_my_decimal(&value.time, dec);
- }
- case IGNORE_VALUE:
- case DEFAULT_VALUE:
- invalid_default_param();
- // fall through
- case NULL_VALUE:
- return 0;
- case NO_VALUE:
- DBUG_ASSERT(0); // Should not be possible
- return 0;
+ case STRING_RESULT:
+ return decimal_from_string_with_check(dec, &m_string);
+ case TIME_RESULT:
+ return TIME_to_my_decimal(&time, dec);
+ case ROW_RESULT:
+ DBUG_ASSERT(0);
+ break;
}
- DBUG_ASSERT(0); // Gabrage
return 0;
}
-String *Item_param::val_str(String* str)
-{
- // There's no "default". See comments in Item_param::save_in_field().
- switch (state) {
- case STRING_VALUE:
- case LONG_DATA_VALUE:
- return &str_value_ptr;
- case REAL_VALUE:
- str->set_real(value.real, NOT_FIXED_DEC, &my_charset_bin);
+String *Item_param::PValue::val_str(String *str,
+ const Type_std_attributes *attr)
+{
+ switch (type_handler()->cmp_type()) {
+ case STRING_RESULT:
+ return &m_string_ptr;
+ case REAL_RESULT:
+ str->set_real(real, NOT_FIXED_DEC, &my_charset_bin);
return str;
- case INT_VALUE:
- str->set(value.integer, &my_charset_bin);
+ case INT_RESULT:
+ str->set(integer, &my_charset_bin);
return str;
- case DECIMAL_VALUE:
- if (my_decimal2string(E_DEC_FATAL_ERROR, &decimal_value,
- 0, 0, 0, str) <= 1)
+ case DECIMAL_RESULT:
+ if (my_decimal2string(E_DEC_FATAL_ERROR, &m_decimal, 0, 0, 0, str) <= 1)
return str;
return NULL;
- case TIME_VALUE:
+ case TIME_RESULT:
{
if (str->reserve(MAX_DATE_STRING_REP_LENGTH))
- break;
- str->length((uint) my_TIME_to_str(&value.time, (char*) str->ptr(),
- decimals));
+ return NULL;
+ str->length((uint) my_TIME_to_str(&time, (char*) str->ptr(),
+ attr->decimals));
str->set_charset(&my_charset_bin);
return str;
}
- case IGNORE_VALUE:
- case DEFAULT_VALUE:
- invalid_default_param();
- // fall through
- case NULL_VALUE:
- return NULL;
- case NO_VALUE:
- DBUG_ASSERT(0); // Should not be possible
- return NULL;
+ case ROW_RESULT:
+ DBUG_ASSERT(0);
+ break;
}
- DBUG_ASSERT(0); // Garbage
return NULL;
}
+
/**
Return Param item values in string format, for generating the dynamic
query used in update/binary logs.
@@ -4095,43 +4688,42 @@ String *Item_param::val_str(String* str)
that binary log contains wrong statement
*/
-const String *Item_param::query_val_str(THD *thd, String* str) const
+const String *Item_param::value_query_val_str(THD *thd, String *str) const
{
- // There's no "default". See comments in Item_param::save_in_field().
- switch (state) {
- case INT_VALUE:
+ switch (value.type_handler()->cmp_type()) {
+ case INT_RESULT:
str->set_int(value.integer, unsigned_flag, &my_charset_bin);
return str;
- case REAL_VALUE:
+ case REAL_RESULT:
str->set_real(value.real, NOT_FIXED_DEC, &my_charset_bin);
return str;
- case DECIMAL_VALUE:
- if (my_decimal2string(E_DEC_FATAL_ERROR, &decimal_value,
+ case DECIMAL_RESULT:
+ if (my_decimal2string(E_DEC_FATAL_ERROR, &value.m_decimal,
0, 0, 0, str) > 1)
return &my_null_string;
return str;
- case TIME_VALUE:
+ case TIME_RESULT:
{
static const uint32 typelen= 9; // "TIMESTAMP" is the longest type name
char *buf, *ptr;
str->length(0);
/*
TODO: in case of error we need to notify replication
- that binary log contains wrong statement
+ that binary log contains wrong statement
*/
if (str->reserve(MAX_DATE_STRING_REP_LENGTH + 3 + typelen))
- break;
+ return NULL;
/* Create date string inplace */
switch (value.time.time_type) {
case MYSQL_TIMESTAMP_DATE:
- str->append(C_STRING_WITH_LEN("DATE"));
+ str->append(STRING_WITH_LEN("DATE"));
break;
case MYSQL_TIMESTAMP_TIME:
- str->append(C_STRING_WITH_LEN("TIME"));
+ str->append(STRING_WITH_LEN("TIME"));
break;
case MYSQL_TIMESTAMP_DATETIME:
- str->append(C_STRING_WITH_LEN("TIMESTAMP"));
+ str->append(STRING_WITH_LEN("TIMESTAMP"));
break;
case MYSQL_TIMESTAMP_ERROR:
case MYSQL_TIMESTAMP_NONE:
@@ -4146,15 +4738,29 @@ const String *Item_param::query_val_str(THD *thd, String* str) const
str->length((uint32) (ptr - buf));
return str;
}
- case STRING_VALUE:
- case LONG_DATA_VALUE:
+ case STRING_RESULT:
{
str->length(0);
append_query_string(value.cs_info.character_set_client, str,
- str_value.ptr(), str_value.length(),
+ value.m_string.ptr(), value.m_string.length(),
thd->variables.sql_mode & MODE_NO_BACKSLASH_ESCAPES);
return str;
}
+ case ROW_RESULT:
+ DBUG_ASSERT(0);
+ break;
+ }
+ return NULL;
+}
+
+
+const String *Item_param::query_val_str(THD *thd, String* str) const
+{
+ // There's no "default". See comments in Item_param::save_in_field().
+ switch (state) {
+ case SHORT_DATA_VALUE:
+ case LONG_DATA_VALUE:
+ return value_query_val_str(thd, str);
case IGNORE_VALUE:
case DEFAULT_VALUE:
return &my_default_string;
@@ -4177,19 +4783,20 @@ const String *Item_param::query_val_str(THD *thd, String* str) const
bool Item_param::convert_str_value(THD *thd)
{
bool rc= FALSE;
- if (state == STRING_VALUE || state == LONG_DATA_VALUE)
+ if ((state == SHORT_DATA_VALUE || state == LONG_DATA_VALUE) &&
+ value.type_handler()->cmp_type() == STRING_RESULT)
{
- rc= value.cs_info.convert_if_needed(thd, &str_value);
+ rc= value.cs_info.convert_if_needed(thd, &value.m_string);
/* Here str_value is guaranteed to be in final_character_set_of_str_value */
/*
str_value_ptr is returned from val_str(). It must be not alloced
to prevent it's modification by val_str() invoker.
*/
- str_value_ptr.set(str_value.ptr(), str_value.length(),
- str_value.charset());
+ value.m_string_ptr.set(value.m_string.ptr(), value.m_string.length(),
+ value.m_string.charset());
/* Synchronize item charset and length with value charset */
- fix_charset_and_length_from_str_value(DERIVATION_COERCIBLE);
+ fix_charset_and_length_from_str_value(value.m_string, DERIVATION_COERCIBLE);
}
return rc;
}
@@ -4198,18 +4805,48 @@ bool Item_param::convert_str_value(THD *thd)
bool Item_param::basic_const_item() const
{
DBUG_ASSERT(fixed || state == NO_VALUE);
- if (state == NO_VALUE || state == TIME_VALUE)
+ if (state == NO_VALUE ||
+ (state == SHORT_DATA_VALUE && type_handler()->cmp_type() == TIME_RESULT))
return FALSE;
return TRUE;
}
+Item *Item_param::value_clone_item(THD *thd)
+{
+ MEM_ROOT *mem_root= thd->mem_root;
+ switch (value.type_handler()->cmp_type()) {
+ case INT_RESULT:
+ return (unsigned_flag ?
+ new (mem_root) Item_uint(thd, name.str, value.integer, max_length) :
+ new (mem_root) Item_int(thd, name.str, value.integer, max_length));
+ case REAL_RESULT:
+ return new (mem_root) Item_float(thd, name.str, value.real, decimals,
+ max_length);
+ case DECIMAL_RESULT:
+ return 0; // Should create Item_decimal. See MDEV-11361.
+ case STRING_RESULT:
+ return new (mem_root) Item_string(thd, name.str,
+ value.m_string.c_ptr_quick(),
+ value.m_string.length(),
+ value.m_string.charset(),
+ collation.derivation,
+ collation.repertoire);
+ case TIME_RESULT:
+ break;
+ case ROW_RESULT:
+ DBUG_ASSERT(0);
+ break;
+ }
+ return 0;
+}
+
+
/* see comments in the header file */
Item *
Item_param::clone_item(THD *thd)
{
- MEM_ROOT *mem_root= thd->mem_root;
// There's no "default". See comments in Item_param::save_in_field().
switch (state) {
case IGNORE_VALUE:
@@ -4217,24 +4854,13 @@ Item_param::clone_item(THD *thd)
invalid_default_param();
// fall through
case NULL_VALUE:
- return new (mem_root) Item_null(thd, name);
- case INT_VALUE:
- return (unsigned_flag ?
- new (mem_root) Item_uint(thd, name, value.integer, max_length) :
- new (mem_root) Item_int(thd, name, value.integer, max_length));
- case REAL_VALUE:
- return new (mem_root) Item_float(thd, name, value.real, decimals,
- max_length);
- case DECIMAL_VALUE:
- return 0; // Should create Item_decimal. See MDEV-11361.
- case STRING_VALUE:
+ return new (thd->mem_root) Item_null(thd, name.str);
+ case SHORT_DATA_VALUE:
case LONG_DATA_VALUE:
- return new (mem_root) Item_string(thd, name, str_value.c_ptr_quick(),
- str_value.length(), str_value.charset(),
- collation.derivation,
- collation.repertoire);
- case TIME_VALUE:
- return 0;
+ {
+ DBUG_ASSERT(type_handler()->cmp_type() == value.type_handler()->cmp_type());
+ return value_clone_item(thd);
+ }
case NO_VALUE:
return 0;
}
@@ -4243,6 +4869,24 @@ Item_param::clone_item(THD *thd)
}
+bool Item_param::value_eq(const Item *item, bool binary_cmp) const
+{
+ switch (value.type_handler()->cmp_type()) {
+ case INT_RESULT:
+ return int_eq(value.integer, item);
+ case REAL_RESULT:
+ return real_eq(value.real, item);
+ case STRING_RESULT:
+ return str_eq(&value.m_string, item, binary_cmp);
+ case DECIMAL_RESULT:
+ case TIME_RESULT:
+ case ROW_RESULT:
+ break;
+ }
+ return false;
+}
+
+
bool
Item_param::eq(const Item *item, bool binary_cmp) const
{
@@ -4257,15 +4901,9 @@ Item_param::eq(const Item *item, bool binary_cmp) const
return false;
case NULL_VALUE:
return null_eq(item);
- case INT_VALUE:
- return int_eq(value.integer, item);
- case REAL_VALUE:
- return real_eq(value.real, item);
- case STRING_VALUE:
+ case SHORT_DATA_VALUE:
case LONG_DATA_VALUE:
- return str_eq(&str_value, item, binary_cmp);
- case DECIMAL_VALUE:
- case TIME_VALUE:
+ return value_eq(item, binary_cmp);
case NO_VALUE:
return false;
}
@@ -4326,18 +4964,14 @@ Item_param::set_param_type_and_swap_value(Item_param *src)
{
Type_std_attributes::set(src);
set_handler(src->type_handler());
- set_param_func= src->set_param_func;
item_type= src->item_type;
maybe_null= src->maybe_null;
null_value= src->null_value;
state= src->state;
fixed= src->fixed;
- value= src->value;
- decimal_value.swap(src->decimal_value);
- str_value.swap(src->str_value);
- str_value_ptr.swap(src->str_value_ptr);
+ value.swap(src->value);
}
@@ -4382,66 +5016,23 @@ bool
Item_param::set_value(THD *thd, sp_rcontext *ctx, Item **it)
{
Item *arg= *it;
-
- if (arg->is_null())
+ struct st_value tmp;
+ /*
+ The OUT parameter is bound to some data type.
+ It's important not to touch m_type_handler,
+ to make sure the next mysql_stmt_execute()
+ correctly fetches the value from the client-server protocol,
+ using set_param_func().
+ */
+ if (arg->save_in_value(&tmp) ||
+ set_value(thd, arg, &tmp, arg->type_handler()))
{
set_null();
- return FALSE;
- }
-
- null_value= FALSE;
- unsigned_flag= arg->unsigned_flag;
-
- switch (arg->result_type()) {
- case STRING_RESULT:
- {
- char str_buffer[STRING_BUFFER_USUAL_SIZE];
- String sv_buffer(str_buffer, sizeof(str_buffer), &my_charset_bin);
- String *sv= arg->val_str(&sv_buffer);
-
- if (!sv)
- return TRUE;
-
- set_str(sv->c_ptr_safe(), sv->length());
- str_value_ptr.set(str_value.ptr(),
- str_value.length(),
- str_value.charset());
- collation.set(str_value.charset(), DERIVATION_COERCIBLE);
- decimals= 0;
- break;
- }
-
- case REAL_RESULT:
- set_double(arg->val_real());
- break;
-
- case INT_RESULT:
- set_int(arg->val_int(), arg->max_length);
- break;
-
- case DECIMAL_RESULT:
- {
- my_decimal dv_buf;
- my_decimal *dv= arg->val_decimal(&dv_buf);
-
- if (!dv)
- return TRUE;
-
- set_decimal(dv, !dv->sign());
- break;
- }
-
- default:
- /* That can not happen. */
-
- DBUG_ASSERT(TRUE); // Abort in debug mode.
-
- set_null(); // Set to NULL in release mode.
- return FALSE;
+ return false;
}
-
- set_handler_by_result_type(arg->result_type());
- return FALSE;
+ /* It is wrapper => other set_* shoud set null_value */
+ DBUG_ASSERT(null_value == false);
+ return false;
}
@@ -4487,9 +5078,9 @@ Item_param::get_out_param_info() const
@param field container for meta-data to be filled
*/
-void Item_param::make_field(THD *thd, Send_field *field)
+void Item_param::make_send_field(THD *thd, Send_field *field)
{
- Item::make_field(thd, field);
+ Item::make_send_field(thd, field);
if (!m_out_param_info)
return;
@@ -4506,7 +5097,6 @@ void Item_param::make_field(THD *thd, Send_field *field)
field->org_col_name= m_out_param_info->org_col_name;
field->length= m_out_param_info->length;
- field->charsetnr= m_out_param_info->charsetnr;
field->flags= m_out_param_info->flags;
field->decimals= m_out_param_info->decimals;
field->type= m_out_param_info->type;
@@ -4688,7 +5278,7 @@ static bool mark_as_dependent(THD *thd, SELECT_LEX *last, SELECT_LEX *current,
ER_THD(thd,ER_WARN_FIELD_RESOLVED),
db_name, (db_name[0] ? "." : ""),
table_name, (table_name [0] ? "." : ""),
- resolved_item->field_name,
+ resolved_item->field_name.str,
current->select_number, last->select_number);
}
DBUG_RETURN(FALSE);
@@ -4778,7 +5368,7 @@ static Item** find_field_in_group_list(Item *find_item, ORDER *group_list)
{
const char *db_name;
const char *table_name;
- const char *field_name;
+ LEX_CSTRING *field_name;
ORDER *found_group= NULL;
int found_match_degree= 0;
char name_buff[SAFE_NAME_LEN+1];
@@ -4788,7 +5378,7 @@ static Item** find_field_in_group_list(Item *find_item, ORDER *group_list)
{
db_name= ((Item_ident*) find_item)->db_name;
table_name= ((Item_ident*) find_item)->table_name;
- field_name= ((Item_ident*) find_item)->field_name;
+ field_name= &((Item_ident*) find_item)->field_name;
}
else
return NULL;
@@ -4801,17 +5391,17 @@ static Item** find_field_in_group_list(Item *find_item, ORDER *group_list)
db_name= name_buff;
}
- DBUG_ASSERT(field_name != 0);
+ DBUG_ASSERT(field_name->str != 0);
for (ORDER *cur_group= group_list ; cur_group ; cur_group= cur_group->next)
{
int cur_match_degree= 0;
/* SELECT list element with explicit alias */
- if ((*(cur_group->item))->name && !table_name &&
+ if ((*(cur_group->item))->name.str && !table_name &&
!(*(cur_group->item))->is_autogenerated_name &&
- !my_strcasecmp(system_charset_info,
- (*(cur_group->item))->name, field_name))
+ !lex_string_cmp(system_charset_info,
+ &(*(cur_group->item))->name, field_name))
{
++cur_match_degree;
}
@@ -4822,12 +5412,12 @@ static Item** find_field_in_group_list(Item *find_item, ORDER *group_list)
Item_ident *cur_field= (Item_ident*) *cur_group->item;
const char *l_db_name= cur_field->db_name;
const char *l_table_name= cur_field->table_name;
- const char *l_field_name= cur_field->field_name;
+ LEX_CSTRING *l_field_name= &cur_field->field_name;
- DBUG_ASSERT(l_field_name != 0);
+ DBUG_ASSERT(l_field_name->str != 0);
- if (!my_strcasecmp(system_charset_info,
- l_field_name, field_name))
+ if (!lex_string_cmp(system_charset_info,
+ l_field_name, field_name))
++cur_match_degree;
else
continue;
@@ -4967,7 +5557,7 @@ resolve_ref_in_select_and_group(THD *thd, Item_ident *ref, SELECT_LEX *select)
the strict mode is enabled.
*/
my_error(ER_NON_GROUPING_FIELD_USED, MYF(0),
- ref->name, "HAVING");
+ ref->name.str, "HAVING");
return NULL;
}
if (select_ref != not_found_item || group_by_ref)
@@ -4978,7 +5568,7 @@ resolve_ref_in_select_and_group(THD *thd, Item_ident *ref, SELECT_LEX *select)
if (!select->ref_pointer_array[counter])
{
my_error(ER_ILLEGAL_REFERENCE, MYF(0),
- ref->name, "forward reference in item list");
+ ref->name.str, "forward reference in item list");
return NULL;
}
DBUG_ASSERT((*select_ref)->fixed);
@@ -5311,15 +5901,15 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference)
*ref= NULL; // Don't call set_properties()
rf= (place == IN_HAVING ?
new (thd->mem_root)
- Item_ref(thd, context, ref, (char*) table_name,
- (char*) field_name, alias_name_used) :
+ Item_ref(thd, context, ref, table_name,
+ &field_name, alias_name_used) :
(!select->group_list.elements ?
new (thd->mem_root)
- Item_direct_ref(thd, context, ref, (char*) table_name,
- (char*) field_name, alias_name_used) :
+ Item_direct_ref(thd, context, ref, table_name,
+ &field_name, alias_name_used) :
new (thd->mem_root)
- Item_outer_ref(thd, context, ref, (char*) table_name,
- (char*) field_name, alias_name_used)));
+ Item_outer_ref(thd, context, ref, table_name,
+ &field_name, alias_name_used)));
*ref= save;
if (!rf)
return -1;
@@ -5363,9 +5953,10 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference)
if (last_checked_context->select_lex->having_fix_field)
{
Item_ref *rf;
- rf= new (thd->mem_root) Item_ref(thd, context, (*from_field)->table->s->db.str,
- (*from_field)->table->alias.c_ptr(),
- (char*) field_name);
+ rf= new (thd->mem_root) Item_ref(thd, context,
+ (*from_field)->table->s->db.str,
+ (*from_field)->table->alias.c_ptr(),
+ &field_name);
if (!rf)
return -1;
thd->change_item_tree(reference, rf);
@@ -5434,6 +6025,12 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
Field *from_field= (Field *)not_found_field;
bool outer_fixed= false;
SELECT_LEX *select= thd->lex->current_select;
+
+ if (select && select->in_tvc)
+ {
+ my_error(ER_FIELD_REFERENCE_IN_TVC, MYF(0), full_name());
+ return(1);
+ }
if (!field) // If field is not checked
{
@@ -5443,6 +6040,7 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
expression to 'reference', i.e. it substitute that expression instead
of this Item_field
*/
+ DBUG_ASSERT(context);
if ((from_field= find_field_in_tables(thd, this,
context->first_name_resolution_table,
context->last_name_resolution_table,
@@ -5482,10 +6080,10 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
Field *new_field= (*((Item_field**)res))->field;
- if (new_field == NULL)
+ if (unlikely(new_field == NULL))
{
/* The column to which we link isn't valid. */
- my_error(ER_BAD_FIELD_ERROR, MYF(0), (*res)->name,
+ my_error(ER_BAD_FIELD_ERROR, MYF(0), (*res)->name.str,
thd->where);
return(1);
}
@@ -5506,8 +6104,7 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
Item_field created by the parser with the new Item_ref.
*/
Item_ref *rf= new (thd->mem_root)
- Item_ref(thd, context, db_name, table_name,
- field_name);
+ Item_ref(thd, context, db_name, table_name, &field_name);
if (!rf)
return 1;
bool err= rf->fix_fields(thd, (Item **) &rf) || rf->check_cols(1);
@@ -5528,7 +6125,7 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
}
}
- if (!select)
+ if (unlikely(!select))
{
my_error(ER_BAD_FIELD_ERROR, MYF(0), full_name(), thd->where);
goto error;
@@ -5581,11 +6178,11 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
set_field(from_field);
}
- else if (thd->mark_used_columns != MARK_COLUMNS_NONE)
+ else if (should_mark_column(thd->column_usage))
{
TABLE *table= field->table;
MY_BITMAP *current_bitmap, *other_bitmap;
- if (thd->mark_used_columns == MARK_COLUMNS_READ)
+ if (thd->column_usage == MARK_COLUMNS_READ)
{
current_bitmap= table->read_set;
other_bitmap= table->write_set;
@@ -5610,16 +6207,16 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (any_privileges)
{
- char *db, *tab;
+ const char *db, *tab;
db= field->table->s->db.str;
tab= field->table->s->table_name.str;
if (!(have_privileges= (get_column_grant(thd, &field->table->grant,
- db, tab, field_name) &
+ db, tab, field_name.str) &
VIEW_ANY_ACL)))
{
my_error(ER_COLUMNACCESS_DENIED_ERROR, MYF(0),
"ANY", thd->security_ctx->priv_user,
- thd->security_ctx->host_or_ip, field_name, tab);
+ thd->security_ctx->host_or_ip, field_name.str, tab);
goto error;
}
}
@@ -5869,7 +6466,8 @@ Item *Item_field::replace_equal_field(THD *thd, uchar *arg)
comparison context, and it's safe to replace it to the constant from
item_equal.
*/
- DBUG_ASSERT(cmp_type() == item_equal->compare_type());
+ DBUG_ASSERT(type_handler()->type_handler_for_comparison()->cmp_type() ==
+ item_equal->compare_type_handler()->cmp_type());
return const_item2;
}
Item_field *subst=
@@ -5883,16 +6481,14 @@ Item *Item_field::replace_equal_field(THD *thd, uchar *arg)
}
-void Item::init_make_field(Send_field *tmp_field,
- enum enum_field_types field_type_arg)
+void Item::init_make_send_field(Send_field *tmp_field,
+ enum enum_field_types field_type_arg)
{
- char *empty_name= (char*) "";
- tmp_field->db_name= empty_name;
- tmp_field->org_table_name= empty_name;
- tmp_field->org_col_name= empty_name;
- tmp_field->table_name= empty_name;
- tmp_field->col_name= name;
- tmp_field->charsetnr= collation.collation->number;
+ tmp_field->db_name= "";
+ tmp_field->org_table_name= "";
+ tmp_field->org_col_name= empty_clex_str;
+ tmp_field->table_name= "";
+ tmp_field->col_name= name;
tmp_field->flags= (maybe_null ? 0 : NOT_NULL_FLAG) |
(my_binary_compare(charset_for_protocol()) ?
BINARY_FLAG : 0);
@@ -5903,15 +6499,15 @@ void Item::init_make_field(Send_field *tmp_field,
tmp_field->flags |= UNSIGNED_FLAG;
}
-void Item::make_field(THD *thd, Send_field *tmp_field)
+void Item::make_send_field(THD *thd, Send_field *tmp_field)
{
- init_make_field(tmp_field, field_type());
+ init_make_send_field(tmp_field, field_type());
}
-void Item_empty_string::make_field(THD *thd, Send_field *tmp_field)
+void Item_empty_string::make_send_field(THD *thd, Send_field *tmp_field)
{
- init_make_field(tmp_field, string_field_type());
+ init_make_send_field(tmp_field, string_type_handler()->field_type());
}
@@ -5933,7 +6529,7 @@ String *Item::check_well_formed_result(String *str, bool send_error)
CHARSET_INFO *cs= str->charset();
uint wlen= str->well_formed_length();
null_value= false;
- if (wlen < str->length())
+ if (unlikely(wlen < str->length()))
{
THD *thd= current_thd;
char hexbuf[7];
@@ -5972,9 +6568,10 @@ String_copier_for_item::copy_with_warn(CHARSET_INFO *dstcs, String *dst,
CHARSET_INFO *srccs, const char *src,
uint32 src_length, uint32 nchars)
{
- if ((dst->copy(dstcs, srccs, src, src_length, nchars, this)))
+ if (unlikely((dst->copy(dstcs, srccs, src, src_length, nchars, this))))
return true; // EOM
- if (const char *pos= well_formed_error_pos())
+ const char *pos;
+ if (unlikely(pos= well_formed_error_pos()))
{
ErrConvString err(pos, src_length - (pos - src), &my_charset_bin);
push_warning_printf(m_thd, Sql_condition::WARN_LEVEL_WARN,
@@ -5985,7 +6582,7 @@ String_copier_for_item::copy_with_warn(CHARSET_INFO *dstcs, String *dst,
err.ptr());
return false;
}
- if (const char *pos= cannot_convert_error_pos())
+ if (unlikely(pos= cannot_convert_error_pos()))
{
char buf[16];
int mblen= my_charlen(srccs, pos, src + src_length);
@@ -6045,180 +6642,16 @@ bool Item::eq_by_collation(Item *item, bool binary_cmp, CHARSET_INFO *cs)
}
-/**
- Create a field to hold a string value from an item.
-
- If too_big_for_varchar() create a blob @n
- If max_length > 0 create a varchar @n
- If max_length == 0 create a CHAR(0)
-
- @param table Table for which the field is created
-*/
-
-Field *Item::make_string_field(TABLE *table)
-{
- Field *field;
- MEM_ROOT *mem_root= table->in_use->mem_root;
-
- DBUG_ASSERT(collation.collation);
- /*
- Note: the following check is repeated in
- subquery_types_allow_materialization():
- */
- if (too_big_for_varchar())
- field= new (mem_root)
- Field_blob(max_length, maybe_null, name,
- collation.collation, TRUE);
- /* Item_type_holder holds the exact type, do not change it */
- else if (max_length > 0 &&
- (type() != Item::TYPE_HOLDER || field_type() != MYSQL_TYPE_STRING))
- field= new (mem_root)
- Field_varstring(max_length, maybe_null, name, table->s,
- collation.collation);
- else
- field= new (mem_root)
- Field_string(max_length, maybe_null, name, collation.collation);
- if (field)
- field->init(table);
- return field;
-}
-
-
-/**
- Create a field based on field_type of argument.
-
- For now, this is only used to create a field for
- IFNULL(x,something) and time functions
-
- @retval
- NULL error
- @retval
- \# Created field
-*/
-
-Field *Item::tmp_table_field_from_field_type(TABLE *table,
- bool fixed_length,
- bool set_blob_packlength)
-{
- /*
- The field functions defines a field to be not null if null_ptr is not 0
- */
- uchar *null_ptr= maybe_null ? (uchar*) "" : 0;
- Field *field;
- MEM_ROOT *mem_root= table->in_use->mem_root;
-
- switch (field_type()) {
- case MYSQL_TYPE_DECIMAL:
- case MYSQL_TYPE_NEWDECIMAL:
- field= Field_new_decimal::create_from_item(mem_root, this);
- break;
- case MYSQL_TYPE_TINY:
- field= new (mem_root)
- Field_tiny((uchar*) 0, max_length, null_ptr, 0, Field::NONE,
- name, 0, unsigned_flag);
- break;
- case MYSQL_TYPE_SHORT:
- field= new (mem_root)
- Field_short((uchar*) 0, max_length, null_ptr, 0, Field::NONE,
- name, 0, unsigned_flag);
- break;
- case MYSQL_TYPE_LONG:
- field= new (mem_root)
- Field_long((uchar*) 0, max_length, null_ptr, 0, Field::NONE,
- name, 0, unsigned_flag);
- break;
-#ifdef HAVE_LONG_LONG
- case MYSQL_TYPE_LONGLONG:
- field= new (mem_root)
- Field_longlong((uchar*) 0, max_length, null_ptr, 0, Field::NONE,
- name, 0, unsigned_flag);
- break;
-#endif
- case MYSQL_TYPE_FLOAT:
- field= new (mem_root)
- Field_float((uchar*) 0, max_length, null_ptr, 0, Field::NONE,
- name, decimals, 0, unsigned_flag);
- break;
- case MYSQL_TYPE_DOUBLE:
- field= new (mem_root)
- Field_double((uchar*) 0, max_length, null_ptr, 0, Field::NONE,
- name, decimals, 0, unsigned_flag);
- break;
- case MYSQL_TYPE_INT24:
- field= new (mem_root)
- Field_medium((uchar*) 0, max_length, null_ptr, 0, Field::NONE,
- name, 0, unsigned_flag);
- break;
- case MYSQL_TYPE_NEWDATE:
- case MYSQL_TYPE_DATE:
- field= new (mem_root)
- Field_newdate(0, null_ptr, 0, Field::NONE, name);
- break;
- case MYSQL_TYPE_TIME:
- field= new_Field_time(mem_root, 0, null_ptr, 0, Field::NONE, name,
- decimals);
- break;
- case MYSQL_TYPE_TIMESTAMP:
- field= new_Field_timestamp(mem_root, 0, null_ptr, 0,
- Field::NONE, name, 0, decimals);
- break;
- case MYSQL_TYPE_DATETIME:
- field= new_Field_datetime(mem_root, 0, null_ptr, 0, Field::NONE, name,
- decimals);
- break;
- case MYSQL_TYPE_YEAR:
- field= new (mem_root)
- Field_year((uchar*) 0, max_length, null_ptr, 0, Field::NONE, name);
- break;
- case MYSQL_TYPE_BIT:
- field= new (mem_root)
- Field_bit_as_char(NULL, max_length, null_ptr, 0, Field::NONE, name);
- break;
- default:
- /* This case should never be chosen */
- DBUG_ASSERT(0);
- /* If something goes awfully wrong, it's better to get a string than die */
- case MYSQL_TYPE_NULL:
- case MYSQL_TYPE_STRING:
- if (fixed_length && !too_big_for_varchar())
- {
- field= new (mem_root)
- Field_string(max_length, maybe_null, name, collation.collation);
- break;
- }
- /* fall through */
- case MYSQL_TYPE_ENUM:
- case MYSQL_TYPE_SET:
- case MYSQL_TYPE_VAR_STRING:
- case MYSQL_TYPE_VARCHAR:
- return make_string_field(table);
- case MYSQL_TYPE_TINY_BLOB:
- case MYSQL_TYPE_MEDIUM_BLOB:
- case MYSQL_TYPE_LONG_BLOB:
- case MYSQL_TYPE_BLOB:
- field= new (mem_root)
- Field_blob(max_length, maybe_null, name,
- collation.collation, set_blob_packlength);
- break; // Blob handled outside of case
-#ifdef HAVE_SPATIAL
- case MYSQL_TYPE_GEOMETRY:
- field= new (mem_root)
- Field_geom(max_length, maybe_null, name, table->s, get_geometry_type());
-#endif /* HAVE_SPATIAL */
- }
- if (field)
- field->init(table);
- return field;
-}
-
-
/* ARGSUSED */
-void Item_field::make_field(THD *thd, Send_field *tmp_field)
+void Item_field::make_send_field(THD *thd, Send_field *tmp_field)
{
- field->make_field(tmp_field);
+ field->make_send_field(tmp_field);
DBUG_ASSERT(tmp_field->table_name != 0);
- if (name)
- tmp_field->col_name=name; // Use user supplied name
+ if (name.str)
+ {
+ DBUG_ASSERT(name.length == strlen(name.str));
+ tmp_field->col_name= name; // Use user supplied name
+ }
if (table_name)
tmp_field->table_name= table_name;
if (db_name)
@@ -6282,6 +6715,11 @@ fast_field_copier Item_field::setup_fast_field_copier(Field *to)
return to->get_fast_field_copier(field);
}
+void Item_field::save_in_result_field(bool no_conversions)
+{
+ bool unused;
+ save_field_in_field(field, &unused, result_field, no_conversions);
+}
/**
Set a field's value from a item.
@@ -6366,54 +6804,62 @@ int Item_null::save_safe_in_field(Field *field)
Note: all Item_XXX::val_str(str) methods must NOT assume that
str != str_value. For example, see fix for bug #44743.
*/
+int Item::save_str_in_field(Field *field, bool no_conversions)
+{
+ String *result;
+ CHARSET_INFO *cs= collation.collation;
+ char buff[MAX_FIELD_WIDTH]; // Alloc buffer for small columns
+ str_value.set_quick(buff, sizeof(buff), cs);
+ result=val_str(&str_value);
+ if (null_value)
+ {
+ str_value.set_quick(0, 0, cs);
+ return set_field_to_null_with_conversions(field, no_conversions);
+ }
-int Item::save_in_field(Field *field, bool no_conversions)
+ /* NOTE: If null_value == FALSE, "result" must be not NULL. */
+
+ field->set_notnull();
+ int error= field->store(result->ptr(),result->length(),cs);
+ str_value.set_quick(0, 0, cs);
+ return error;
+}
+
+
+int Item::save_real_in_field(Field *field, bool no_conversions)
{
- int error;
- if (result_type() == STRING_RESULT)
- {
- String *result;
- CHARSET_INFO *cs= collation.collation;
- char buff[MAX_FIELD_WIDTH]; // Alloc buffer for small columns
- str_value.set_quick(buff, sizeof(buff), cs);
- result=val_str(&str_value);
- if (null_value)
- {
- str_value.set_quick(0, 0, cs);
- return set_field_to_null_with_conversions(field, no_conversions);
- }
+ double nr= val_real();
+ if (null_value)
+ return set_field_to_null_with_conversions(field, no_conversions);
+ field->set_notnull();
+ return field->store(nr);
+}
- /* NOTE: If null_value == FALSE, "result" must be not NULL. */
- field->set_notnull();
- error=field->store(result->ptr(),result->length(),cs);
- str_value.set_quick(0, 0, cs);
- }
- else if (result_type() == REAL_RESULT)
- {
- double nr= val_real();
- if (null_value)
- return set_field_to_null_with_conversions(field, no_conversions);
- field->set_notnull();
- error=field->store(nr);
- }
- else if (result_type() == DECIMAL_RESULT)
- {
- my_decimal decimal_value;
- my_decimal *value= val_decimal(&decimal_value);
- if (null_value)
- return set_field_to_null_with_conversions(field, no_conversions);
- field->set_notnull();
- error=field->store_decimal(value);
- }
- else
- {
- longlong nr=val_int();
- if (null_value)
- return set_field_to_null_with_conversions(field, no_conversions);
- field->set_notnull();
- error=field->store(nr, unsigned_flag);
- }
+int Item::save_decimal_in_field(Field *field, bool no_conversions)
+{
+ my_decimal decimal_value;
+ my_decimal *value= val_decimal(&decimal_value);
+ if (null_value)
+ return set_field_to_null_with_conversions(field, no_conversions);
+ field->set_notnull();
+ return field->store_decimal(value);
+}
+
+
+int Item::save_int_in_field(Field *field, bool no_conversions)
+{
+ longlong nr= val_int();
+ if (null_value)
+ return set_field_to_null_with_conversions(field, no_conversions);
+ field->set_notnull();
+ return field->store(nr, unsigned_flag);
+}
+
+
+int Item::save_in_field(Field *field, bool no_conversions)
+{
+ int error= type_handler()->Item_save_in_field(this, field, no_conversions);
return error ? error : (field->table->in_use->is_error() ? 1 : 0);
}
@@ -6435,11 +6881,46 @@ int Item_string::save_in_field(Field *field, bool no_conversions)
Item *Item_string::clone_item(THD *thd)
{
return new (thd->mem_root)
- Item_string(thd, name, str_value.ptr(),
+ Item_string(thd, name.str, str_value.ptr(),
str_value.length(), collation.collation);
}
+Item_basic_constant *
+Item_string::make_string_literal_concat(THD *thd, const LEX_CSTRING *str)
+{
+ append(str->str, (uint32) str->length);
+ if (!(collation.repertoire & MY_REPERTOIRE_EXTENDED))
+ {
+ // If the string has been pure ASCII so far, check the new part.
+ CHARSET_INFO *cs= thd->variables.collation_connection;
+ collation.repertoire|= my_string_repertoire(cs, str->str, str->length);
+ }
+ return this;
+}
+
+
+/*
+ If "this" is a reasonably short pure ASCII string literal,
+ try to parse known ODBC-style date, time or timestamp literals,
+ e.g:
+ SELECT {d'2001-01-01'};
+ SELECT {t'10:20:30'};
+ SELECT {ts'2001-01-01 10:20:30'};
+*/
+Item *Item_string::make_odbc_literal(THD *thd, const LEX_CSTRING *typestr)
+{
+ enum_field_types type= odbc_temporal_literal_type(typestr);
+ Item *res= type == MYSQL_TYPE_STRING ? this :
+ create_temporal_literal(thd, val_str(NULL), type, false);
+ /*
+ create_temporal_literal() returns NULL if failed to parse the string,
+ or the string format did not match the type, e.g.: {d'2001-01-01 10:10:10'}
+ */
+ return res ? res : this;
+}
+
+
static int save_int_value_in_field (Field *field, longlong nr,
bool null_value, bool unsigned_flag)
{
@@ -6458,13 +6939,13 @@ int Item_int::save_in_field(Field *field, bool no_conversions)
Item *Item_int::clone_item(THD *thd)
{
- return new (thd->mem_root) Item_int(thd, name, value, max_length);
+ return new (thd->mem_root) Item_int(thd, name.str, value, max_length, unsigned_flag);
}
-void Item_datetime::set(longlong packed)
+void Item_datetime::set(longlong packed, enum_mysql_timestamp_type ts_type)
{
- unpack_time(packed, &ltime);
+ unpack_time(packed, &ltime, ts_type);
}
int Item_datetime::save_in_field(Field *field, bool no_conversions)
@@ -6494,9 +6975,9 @@ Item *Item_int_with_ref::clone_item(THD *thd)
*/
return (ref->unsigned_flag ?
new (thd->mem_root)
- Item_uint(thd, ref->name, ref->val_int(), ref->max_length) :
+ Item_uint(thd, ref->name.str, ref->val_int(), ref->max_length) :
new (thd->mem_root)
- Item_int(thd, ref->name, ref->val_int(), ref->max_length));
+ Item_int(thd, ref->name.str, ref->val_int(), ref->max_length));
}
@@ -6524,7 +7005,7 @@ Item *Item_int::neg(THD *thd)
else if (value < 0 && max_length)
max_length--;
value= -value;
- name= 0;
+ name= null_clex_str;
return this;
}
@@ -6532,7 +7013,7 @@ Item *Item_decimal::neg(THD *thd)
{
my_decimal_neg(&decimal_value);
unsigned_flag= 0;
- name= 0;
+ name= null_clex_str;
max_length= my_decimal_precision_to_length_no_truncation(
decimal_value.intg + decimals, decimals, unsigned_flag);
return this;
@@ -6545,7 +7026,8 @@ Item *Item_float::neg(THD *thd)
else if (value < 0 && max_length)
max_length--;
value= -value;
- name= presentation= 0 ;
+ presentation= 0;
+ name= null_clex_str;
return this;
}
@@ -6564,7 +7046,7 @@ Item *Item_uint::neg(THD *thd)
Item *Item_uint::clone_item(THD *thd)
{
- return new (thd->mem_root) Item_uint(thd, name, value, max_length);
+ return new (thd->mem_root) Item_uint(thd, name.str, value, max_length);
}
static uint nr_of_decimals(const char *str, const char *end)
@@ -6621,22 +7103,23 @@ static uint nr_of_decimals(const char *str, const char *end)
Item->name should be fixed to use LEX_STRING eventually.
*/
-Item_float::Item_float(THD *thd, const char *str_arg, uint length):
+Item_float::Item_float(THD *thd, const char *str_arg, size_t length):
Item_num(thd)
{
int error;
char *end_not_used;
value= my_strntod(&my_charset_bin, (char*) str_arg, length, &end_not_used,
&error);
- if (error)
+ if (unlikely(error))
{
char tmp[NAME_LEN + 1];
- my_snprintf(tmp, sizeof(tmp), "%.*s", length, str_arg);
+ my_snprintf(tmp, sizeof(tmp), "%.*s", (int)length, str_arg);
my_error(ER_ILLEGAL_VALUE_FOR_TYPE, MYF(0), "double", tmp);
}
- presentation= name=(char*) str_arg;
+ presentation= name.str= str_arg;
+ name.length= strlen(str_arg);
decimals=(uint8) nr_of_decimals(str_arg, str_arg+length);
- max_length=length;
+ max_length=(uint32)length;
fixed= 1;
}
@@ -6673,10 +7156,9 @@ inline uint char_val(char X)
}
-void Item_hex_constant::hex_string_init(THD *thd, const char *str,
- uint str_length)
+void Item_hex_constant::hex_string_init(THD *thd, const char *str, size_t str_length)
{
- max_length=(str_length+1)/2;
+ max_length=(uint)((str_length+1)/2);
char *ptr=(char*) thd->alloc(max_length+1);
if (!ptr)
{
@@ -6708,6 +7190,22 @@ void Item_hex_hybrid::print(String *str, enum_query_type query_type)
}
+uint Item_hex_hybrid::decimal_precision() const
+{
+ switch (max_length) {// HEX DEC
+ case 0: // ---- ---
+ case 1: return 3; // 0xFF 255
+ case 2: return 5; // 0xFFFF 65535
+ case 3: return 8; // 0xFFFFFF 16777215
+ case 4: return 10; // 0xFFFFFFFF 4294967295
+ case 5: return 13; // 0xFFFFFFFFFF 1099511627775
+ case 6: return 15; // 0xFFFFFFFFFFFF 281474976710655
+ case 7: return 17; // 0xFFFFFFFFFFFFFF 72057594037927935
+ }
+ return 20; // 0xFFFFFFFFFFFFFFFF 18446744073709551615
+}
+
+
void Item_hex_string::print(String *str, enum_query_type query_type)
{
str->append("X'");
@@ -6722,7 +7220,7 @@ void Item_hex_string::print(String *str, enum_query_type query_type)
In number context this is a longlong value.
*/
-Item_bin_string::Item_bin_string(THD *thd, const char *str, uint str_length):
+Item_bin_string::Item_bin_string(THD *thd, const char *str, size_t str_length):
Item_hex_hybrid(thd)
{
const char *end= str + str_length - 1;
@@ -6730,7 +7228,7 @@ Item_bin_string::Item_bin_string(THD *thd, const char *str, uint str_length):
uchar bits= 0;
uint power= 1;
- max_length= (str_length + 7) >> 3;
+ max_length= (uint)((str_length + 7) >> 3);
if (!(ptr= (char*) thd->alloc(max_length + 1)))
return;
str_value.set(ptr, max_length, &my_charset_bin);
@@ -6770,7 +7268,6 @@ bool Item_temporal_literal::eq(const Item *item, bool binary_cmp) const
&((Item_temporal_literal *) item)->cached_time);
}
-
void Item_date_literal::print(String *str, enum_query_type query_type)
{
str->append("DATE'");
@@ -6855,127 +7352,11 @@ bool Item_time_literal::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
Pack data in buffer for sending.
*/
-bool Item_null::send(Protocol *protocol, String *packet)
+bool Item_null::send(Protocol *protocol, st_value *buffer)
{
return protocol->store_null();
}
-/**
- This is only called from items that is not of type item_field.
-*/
-
-bool Item::send(Protocol *protocol, String *buffer)
-{
- bool UNINIT_VAR(result); // Will be set if null_value == 0
- enum_field_types f_type;
-
- switch ((f_type=field_type())) {
- default:
- case MYSQL_TYPE_NULL:
- case MYSQL_TYPE_DECIMAL:
- case MYSQL_TYPE_ENUM:
- case MYSQL_TYPE_SET:
- case MYSQL_TYPE_TINY_BLOB:
- case MYSQL_TYPE_MEDIUM_BLOB:
- case MYSQL_TYPE_LONG_BLOB:
- case MYSQL_TYPE_BLOB:
- case MYSQL_TYPE_GEOMETRY:
- case MYSQL_TYPE_STRING:
- case MYSQL_TYPE_VAR_STRING:
- case MYSQL_TYPE_VARCHAR:
- case MYSQL_TYPE_BIT:
- case MYSQL_TYPE_NEWDECIMAL:
- {
- String *res;
- if ((res=val_str(buffer)))
- {
- DBUG_ASSERT(!null_value);
- result= protocol->store(res->ptr(),res->length(),res->charset());
- }
- else
- {
- DBUG_ASSERT(null_value);
- }
- break;
- }
- case MYSQL_TYPE_TINY:
- {
- longlong nr;
- nr= val_int();
- if (!null_value)
- result= protocol->store_tiny(nr);
- break;
- }
- case MYSQL_TYPE_SHORT:
- case MYSQL_TYPE_YEAR:
- {
- longlong nr;
- nr= val_int();
- if (!null_value)
- result= protocol->store_short(nr);
- break;
- }
- case MYSQL_TYPE_INT24:
- case MYSQL_TYPE_LONG:
- {
- longlong nr;
- nr= val_int();
- if (!null_value)
- result= protocol->store_long(nr);
- break;
- }
- case MYSQL_TYPE_LONGLONG:
- {
- longlong nr;
- nr= val_int();
- if (!null_value)
- result= protocol->store_longlong(nr, unsigned_flag);
- break;
- }
- case MYSQL_TYPE_FLOAT:
- {
- float nr;
- nr= (float) val_real();
- if (!null_value)
- result= protocol->store(nr, decimals, buffer);
- break;
- }
- case MYSQL_TYPE_DOUBLE:
- {
- double nr= val_real();
- if (!null_value)
- result= protocol->store(nr, decimals, buffer);
- break;
- }
- case MYSQL_TYPE_DATETIME:
- case MYSQL_TYPE_DATE:
- case MYSQL_TYPE_TIMESTAMP:
- {
- MYSQL_TIME tm;
- get_date(&tm, sql_mode_for_dates(current_thd));
- if (!null_value)
- {
- if (f_type == MYSQL_TYPE_DATE)
- return protocol->store_date(&tm);
- else
- result= protocol->store(&tm, decimals);
- }
- break;
- }
- case MYSQL_TYPE_TIME:
- {
- MYSQL_TIME tm;
- get_time(&tm);
- if (!null_value)
- result= protocol->store_time(&tm, decimals);
- break;
- }
- }
- if (null_value)
- result= protocol->store_null();
- return result;
-}
-
/**
Check if an item is a constant one and can be cached.
@@ -7030,7 +7411,7 @@ Item* Item::cache_const_expr_transformer(THD *thd, uchar *arg)
if (*(bool*)arg)
{
*((bool*)arg)= FALSE;
- Item_cache *cache= Item_cache::get_cache(thd, this);
+ Item_cache *cache= get_cache(thd);
if (!cache)
return NULL;
cache->setup(thd, this);
@@ -7048,7 +7429,7 @@ bool Item::find_item_processor(void *arg)
return (this == ((Item *) arg));
}
-bool Item_field::send(Protocol *protocol, String *buffer)
+bool Item_field::send(Protocol *protocol, st_value *buffer)
{
return protocol->store(result_field);
}
@@ -7121,7 +7502,7 @@ Item *Item_field::update_value_transformer(THD *thd, uchar *select_arg)
all_fields->push_front((Item*)this, thd->mem_root);
ref= new (thd->mem_root)
Item_ref(thd, &select->context, &ref_pointer_array[el],
- table_name, field_name);
+ table_name, &field_name);
return ref;
}
return this;
@@ -7148,7 +7529,7 @@ Item *get_field_item_for_having(THD *thd, Item *item, st_select_lex *sel)
if (equal_item->used_tables() == map)
{
field_item= (Item_field *)(equal_item->real_item());
- break;
+ break;
}
}
}
@@ -7156,7 +7537,7 @@ Item *get_field_item_for_having(THD *thd, Item *item, st_select_lex *sel)
{
Item_ref *ref= new (thd->mem_root) Item_ref(thd, &sel->context,
NullS, NullS,
- field_item->field_name);
+ &field_item->field_name);
return ref;
}
DBUG_ASSERT(0);
@@ -7238,7 +7619,7 @@ Item *Item_field::derived_field_transformer_for_where(THD *thd, uchar *arg)
Item *producing_item= find_producing_item(this, sel);
if (producing_item)
{
- Item *producing_clone= producing_item->build_clone(thd, thd->mem_root);
+ Item *producing_clone= producing_item->build_clone(thd);
if (producing_clone)
producing_clone->marker|= SUBSTITUTION_FL;
return producing_clone;
@@ -7256,7 +7637,7 @@ Item *Item_direct_view_ref::derived_field_transformer_for_where(THD *thd,
st_select_lex *sel= (st_select_lex *)arg;
Item *producing_item= find_producing_item(this, sel);
DBUG_ASSERT (producing_item != NULL);
- return producing_item->build_clone(thd, thd->mem_root);
+ return producing_item->build_clone(thd);
}
return (*ref);
}
@@ -7304,7 +7685,7 @@ Item *Item_field::derived_grouping_field_transformer_for_where(THD *thd,
if (gr_field)
{
Item *producing_clone=
- gr_field->producing_item->build_clone(thd, thd->mem_root);
+ gr_field->producing_item->build_clone(thd);
if (producing_clone)
producing_clone->marker|= SUBSTITUTION_FL;
return producing_clone;
@@ -7326,7 +7707,7 @@ Item_direct_view_ref::derived_grouping_field_transformer_for_where(THD *thd,
return this;
st_select_lex *sel= (st_select_lex *)arg;
Grouping_tmp_field *gr_field= find_matching_grouping_field(this, sel);
- return gr_field->producing_item->build_clone(thd, thd->mem_root);
+ return gr_field->producing_item->build_clone(thd);
}
void Item_field::print(String *str, enum_query_type query_type)
@@ -7353,7 +7734,7 @@ void Item_temptable_field::print(String *str, enum_query_type query_type)
Item_ref::Item_ref(THD *thd, Name_resolution_context *context_arg,
Item **item, const char *table_name_arg,
- const char *field_name_arg,
+ const LEX_CSTRING *field_name_arg,
bool alias_name_used_arg):
Item_ident(thd, context_arg, NullS, table_name_arg, field_name_arg),
ref(item), reference_trough_name(0)
@@ -7402,7 +7783,8 @@ public:
};
Item_ref::Item_ref(THD *thd, TABLE_LIST *view_arg, Item **item,
- const char *field_name_arg, bool alias_name_used_arg):
+ const LEX_CSTRING *field_name_arg,
+ bool alias_name_used_arg):
Item_ident(thd, view_arg, field_name_arg),
ref(item), reference_trough_name(0)
{
@@ -7503,7 +7885,7 @@ bool Item_ref::fix_fields(THD *thd, Item **reference)
Field *from_field;
ref= 0;
- if (!outer_context)
+ if (unlikely(!outer_context))
{
/* The current reference cannot be resolved in this query. */
my_error(ER_BAD_FIELD_ERROR,MYF(0),
@@ -7651,7 +8033,7 @@ bool Item_ref::fix_fields(THD *thd, Item **reference)
last_checked_context->select_lex->nest_level);
return FALSE;
}
- if (ref == 0)
+ if (unlikely(ref == 0))
{
/* The item was not a table field and not a reference */
my_error(ER_BAD_FIELD_ERROR, MYF(0),
@@ -7684,13 +8066,13 @@ bool Item_ref::fix_fields(THD *thd, Item **reference)
*/
if (!((*ref)->type() == REF_ITEM &&
((Item_ref *)(*ref))->ref_type() == OUTER_REF) &&
- (((*ref)->with_sum_func && name &&
+ (((*ref)->with_sum_func && name.str &&
!(current_sel->linkage != GLOBAL_OPTIONS_TYPE &&
current_sel->having_fix_field)) ||
!(*ref)->fixed))
{
my_error(ER_ILLEGAL_REFERENCE, MYF(0),
- name, ((*ref)->with_sum_func?
+ name.str, ((*ref)->with_sum_func?
"reference to group function":
"forward reference in item list"));
goto error;
@@ -7835,11 +8217,10 @@ void Item_ref::print(String *str, enum_query_type query_type)
if ((*ref)->type() != Item::CACHE_ITEM &&
(*ref)->type() != Item::WINDOW_FUNC_ITEM &&
ref_type() != VIEW_REF &&
- !table_name && name && alias_name_used)
+ !table_name && name.str && alias_name_used)
{
THD *thd= current_thd;
- append_identifier(thd, str, (*ref)->real_item()->name,
- strlen((*ref)->real_item()->name));
+ append_identifier(thd, str, &(*ref)->real_item()->name);
}
else
(*ref)->print(str, query_type);
@@ -7849,11 +8230,11 @@ void Item_ref::print(String *str, enum_query_type query_type)
}
-bool Item_ref::send(Protocol *prot, String *tmp)
+bool Item_ref::send(Protocol *prot, st_value *buffer)
{
if (result_field)
return prot->store(result_field);
- return (*ref)->send(prot, tmp);
+ return (*ref)->send(prot, buffer);
}
@@ -8032,17 +8413,17 @@ void Item_ref::save_org_in_field(Field *field, fast_field_copier optimizer_data)
}
-void Item_ref::make_field(THD *thd, Send_field *field)
+void Item_ref::make_send_field(THD *thd, Send_field *field)
{
- (*ref)->make_field(thd, field);
+ (*ref)->make_send_field(thd, field);
/* Non-zero in case of a view */
- if (name)
+ if (name.str)
field->col_name= name;
if (table_name)
field->table_name= table_name;
if (db_name)
field->db_name= db_name;
- if (orig_field_name)
+ if (orig_field_name.str)
field->org_col_name= orig_field_name;
if (orig_table_name)
field->org_table_name= orig_table_name;
@@ -8149,10 +8530,9 @@ Item_cache_wrapper::Item_cache_wrapper(THD *thd, Item *item_arg):
with_param= orig_item->with_param;
with_field= orig_item->with_field;
name= item_arg->name;
- name_length= item_arg->name_length;
- with_subselect= orig_item->with_subselect;
+ m_with_subquery= orig_item->with_subquery();
- if ((expr_value= Item_cache::get_cache(thd, orig_item)))
+ if ((expr_value= orig_item->get_cache(thd)))
expr_value->setup(thd, orig_item);
fixed= 1;
@@ -8210,7 +8590,7 @@ bool Item_cache_wrapper::fix_fields(THD *thd __attribute__((unused)),
return FALSE;
}
-bool Item_cache_wrapper::send(Protocol *protocol, String *buffer)
+bool Item_cache_wrapper::send(Protocol *protocol, st_value *buffer)
{
if (result_field)
return protocol->store(result_field);
@@ -8541,7 +8921,7 @@ Item* Item_cache_wrapper::get_tmp_table_item(THD *thd)
}
-bool Item_direct_view_ref::send(Protocol *protocol, String *buffer)
+bool Item_direct_view_ref::send(Protocol *protocol, st_value *buffer)
{
if (check_null_ref())
return protocol->store_null();
@@ -8577,12 +8957,11 @@ bool Item_direct_view_ref::fix_fields(THD *thd, Item **reference)
*/
Field *fld= ((Item_field*) ref_item)->field;
DBUG_ASSERT(fld && fld->table);
- if (thd->mark_used_columns == MARK_COLUMNS_READ)
+ if (thd->column_usage == MARK_COLUMNS_READ)
bitmap_set_bit(fld->table->read_set, fld->field_index);
}
}
- else if (!(*ref)->fixed &&
- ((*ref)->fix_fields(thd, ref)))
+ else if ((*ref)->fix_fields_if_needed(thd, ref))
return TRUE;
if (Item_direct_ref::fix_fields(thd, reference))
@@ -8610,7 +8989,7 @@ bool Item_outer_ref::fix_fields(THD *thd, Item **reference)
{
bool err;
/* outer_ref->check_cols() will be made in Item_direct_ref::fix_fields */
- if ((*ref) && !(*ref)->fixed && ((*ref)->fix_fields(thd, reference)))
+ if ((*ref) && (*ref)->fix_fields_if_needed(thd, reference))
return TRUE;
err= Item_direct_ref::fix_fields(thd, reference);
if (!outer_ref)
@@ -8854,27 +9233,32 @@ bool Item_default_value::fix_fields(THD *thd, Item **items)
DEFAULT() do not need table field so should not ask handler to bring
field value (mark column for read)
*/
- enum_mark_columns save_mark_used_columns= thd->mark_used_columns;
- thd->mark_used_columns= MARK_COLUMNS_NONE;
- if (!arg->fixed && arg->fix_fields(thd, &arg))
+ enum_column_usage save_column_usage= thd->column_usage;
+ /*
+ Fields which has defult value could be read, so it is better hide system
+ invisible columns.
+ */
+ thd->column_usage= COLUMNS_WRITE;
+ if (arg->fix_fields_if_needed(thd, &arg))
{
- thd->mark_used_columns= save_mark_used_columns;
+ thd->column_usage= save_column_usage;
goto error;
}
- thd->mark_used_columns= save_mark_used_columns;
+ thd->column_usage= save_column_usage;
real_arg= arg->real_item();
if (real_arg->type() != FIELD_ITEM)
{
- my_error(ER_NO_DEFAULT_FOR_FIELD, MYF(0), arg->name);
+ my_error(ER_NO_DEFAULT_FOR_FIELD, MYF(0), arg->name.str);
goto error;
}
field_arg= (Item_field *)real_arg;
if ((field_arg->field->flags & NO_DEFAULT_VALUE_FLAG))
{
- my_error(ER_NO_DEFAULT_FOR_FIELD, MYF(0), field_arg->field->field_name);
+ my_error(ER_NO_DEFAULT_FOR_FIELD, MYF(0),
+ field_arg->field->field_name.str);
goto error;
}
if (!(def_field= (Field*) thd->alloc(field_arg->field->size_of())))
@@ -8892,7 +9276,7 @@ bool Item_default_value::fix_fields(THD *thd, Item **items)
expression can do it.
*/
fix_session_vcol_expr_for_read(thd, def_field, def_field->default_value);
- if (thd->mark_used_columns != MARK_COLUMNS_NONE)
+ if (should_mark_column(thd->column_usage))
def_field->default_value->expr->update_used_tables();
def_field->move_field(newptr+1, def_field->maybe_null() ? newptr : 0, 1);
}
@@ -8964,7 +9348,7 @@ bool Item_default_value::get_date(MYSQL_TIME *ltime,ulonglong fuzzydate)
return Item_field::get_date(ltime, fuzzydate);
}
-bool Item_default_value::send(Protocol *protocol, String *buffer)
+bool Item_default_value::send(Protocol *protocol, st_value *buffer)
{
calculate();
return Item_field::send(protocol, buffer);
@@ -9071,7 +9455,7 @@ bool Item_ignore_value::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
return TRUE;
}
-bool Item_ignore_value::send(Protocol *protocol, String *buffer)
+bool Item_ignore_value::send(Protocol *protocol, st_value *buffer)
{
DBUG_ASSERT(0); // never should be called
return TRUE;
@@ -9101,7 +9485,7 @@ bool Item_insert_value::fix_fields(THD *thd, Item **items)
if (arg->type() == REF_ITEM)
arg= static_cast<Item_ref *>(arg)->ref[0];
- if (arg->type() != FIELD_ITEM)
+ if (unlikely(arg->type() != FIELD_ITEM))
{
my_error(ER_BAD_FIELD_ERROR, MYF(0), "", "VALUES() function");
return TRUE;
@@ -9126,7 +9510,7 @@ bool Item_insert_value::fix_fields(THD *thd, Item **items)
static uchar null_bit=1;
/* charset doesn't matter here */
Field *tmp_field= new Field_string(0, 0, &null_bit, 1, Field::NONE,
- field_arg->field->field_name, &my_charset_bin);
+ &field_arg->field->field_name, &my_charset_bin);
if (tmp_field)
{
tmp_field->init(field_arg->field->table);
@@ -9140,7 +9524,7 @@ bool Item_insert_value::fix_fields(THD *thd, Item **items)
void Item_insert_value::print(String *str, enum_query_type query_type)
{
- str->append(STRING_WITH_LEN("values("));
+ str->append(STRING_WITH_LEN("value("));
arg->print(str, query_type);
str->append(')');
}
@@ -9176,15 +9560,16 @@ void Item_trigger_field::setup_field(THD *thd, TABLE *table,
So instead we do it in Table_triggers_list::mark_fields_used()
method which is called during execution of these statements.
*/
- enum_mark_columns save_mark_used_columns= thd->mark_used_columns;
- thd->mark_used_columns= MARK_COLUMNS_NONE;
+ enum_column_usage saved_column_usage= thd->column_usage;
+ thd->column_usage= want_privilege == SELECT_ACL ? COLUMNS_READ
+ : COLUMNS_WRITE;
/*
Try to find field by its name and if it will be found
set field_idx properly.
*/
- (void)find_field_in_table(thd, table, field_name, (uint) strlen(field_name),
+ (void)find_field_in_table(thd, table, field_name.str, field_name.length,
0, &field_idx);
- thd->mark_used_columns= save_mark_used_columns;
+ thd->column_usage= saved_column_usage;
triggers= table->triggers;
table_grants= table_grant_info;
}
@@ -9194,8 +9579,8 @@ bool Item_trigger_field::eq(const Item *item, bool binary_cmp) const
{
return item->type() == TRIGGER_FIELD_ITEM &&
row_version == ((Item_trigger_field *)item)->row_version &&
- !my_strcasecmp(system_charset_info, field_name,
- ((Item_trigger_field *)item)->field_name);
+ !lex_string_cmp(system_charset_info, &field_name,
+ &((Item_trigger_field *)item)->field_name);
}
@@ -9211,17 +9596,11 @@ void Item_trigger_field::set_required_privilege(bool rw)
bool Item_trigger_field::set_value(THD *thd, sp_rcontext * /*ctx*/, Item **it)
{
- Item *item= sp_prepare_func_item(thd, it);
+ Item *item= thd->sp_prepare_func_item(it);
- if (!item)
+ if (!item || fix_fields_if_needed(thd, NULL))
return true;
- if (!fixed)
- {
- if (fix_fields(thd, NULL))
- return true;
- }
-
// NOTE: field->table->copy_blobs should be false here, but let's
// remember the value at runtime to avoid subtle bugs.
bool copy_blobs_saved= field->table->copy_blobs;
@@ -9249,7 +9628,7 @@ bool Item_trigger_field::fix_fields(THD *thd, Item **items)
/* Set field. */
- if (field_idx != (uint)-1)
+ if (likely(field_idx != (uint)-1))
{
#ifndef NO_EMBEDDED_ACCESS_CHECKS
/*
@@ -9261,9 +9640,11 @@ bool Item_trigger_field::fix_fields(THD *thd, Item **items)
{
table_grants->want_privilege= want_privilege;
- if (check_grant_column(thd, table_grants, triggers->trigger_table->s->db.str,
- triggers->trigger_table->s->table_name.str, field_name,
- strlen(field_name), thd->security_ctx))
+ if (check_grant_column(thd, table_grants,
+ triggers->trigger_table->s->db.str,
+ triggers->trigger_table->s->table_name.str,
+ field_name.str, field_name.length,
+ thd->security_ctx))
return TRUE;
}
#endif // NO_EMBEDDED_ACCESS_CHECKS
@@ -9275,7 +9656,7 @@ bool Item_trigger_field::fix_fields(THD *thd, Item **items)
return FALSE;
}
- my_error(ER_BAD_FIELD_ERROR, MYF(0), field_name,
+ my_error(ER_BAD_FIELD_ERROR, MYF(0), field_name.str,
(row_version == NEW_ROW) ? "NEW" : "OLD");
return TRUE;
}
@@ -9285,14 +9666,14 @@ void Item_trigger_field::print(String *str, enum_query_type query_type)
{
str->append((row_version == NEW_ROW) ? "NEW" : "OLD", 3);
str->append('.');
- str->append(field_name);
+ str->append(&field_name);
}
bool Item_trigger_field::check_vcol_func_processor(void *arg)
{
const char *ver= row_version == NEW_ROW ? "NEW." : "OLD.";
- return mark_unsupported_function(ver, field_name, arg, VCOL_IMPOSSIBLE);
+ return mark_unsupported_function(ver, field_name.str, arg, VCOL_IMPOSSIBLE);
}
@@ -9327,104 +9708,14 @@ void resolve_const_item(THD *thd, Item **ref, Item *comp_item)
Item *item= *ref;
if (item->basic_const_item())
return; // Can't be better
-
- Item *new_item= NULL;
- Item_result res_type= item_cmp_type(comp_item, item);
- char *name= item->name; // Alloced on THD::mem_root
- MEM_ROOT *mem_root= thd->mem_root;
-
- switch (res_type) {
- case TIME_RESULT:
+ Type_handler_hybrid_field_type cmp(comp_item->type_handler_for_comparison());
+ if (!cmp.aggregate_for_comparison(item->type_handler_for_comparison()))
{
- enum_field_types type= item->field_type_for_temporal_comparison(comp_item);
- longlong value= item->val_temporal_packed(type);
- if (item->null_value)
- new_item= new (mem_root) Item_null(thd, name);
- else
- {
- Item_cache_temporal *cache= new (mem_root) Item_cache_temporal(thd, type);
- cache->store_packed(value, item);
- new_item= cache;
- }
- break;
- }
- case STRING_RESULT:
- {
- char buff[MAX_FIELD_WIDTH];
- String tmp(buff,sizeof(buff),&my_charset_bin),*result;
- result=item->val_str(&tmp);
- if (item->null_value)
- new_item= new (mem_root) Item_null(thd, name);
- else
- {
- uint length= result->length();
- char *tmp_str= thd->strmake(result->ptr(), length);
- new_item= new (mem_root) Item_string(thd, name, tmp_str, length, result->charset());
- }
- break;
- }
- case INT_RESULT:
- {
- longlong result=item->val_int();
- uint length=item->max_length;
- bool null_value=item->null_value;
- new_item= (null_value ? (Item*) new (mem_root) Item_null(thd, name) :
- (Item*) new (mem_root) Item_int(thd, name, result, length));
- break;
- }
- case ROW_RESULT:
- if (item->type() == Item::ROW_ITEM && comp_item->type() == Item::ROW_ITEM)
- {
- /*
- Substitute constants only in Item_row's. Don't affect other Items
- with ROW_RESULT (eg Item_singlerow_subselect).
-
- For such Items more optimal is to detect if it is constant and replace
- it with Item_row. This would optimize queries like this:
- SELECT * FROM t1 WHERE (a,b) = (SELECT a,b FROM t2 LIMIT 1);
- */
- Item_row *item_row= (Item_row*) item;
- Item_row *comp_item_row= (Item_row*) comp_item;
- uint col;
- new_item= 0;
- /*
- If item and comp_item are both Item_row's and have same number of cols
- then process items in Item_row one by one.
- We can't ignore NULL values here as this item may be used with <=>, in
- which case NULL's are significant.
- */
- DBUG_ASSERT(item->result_type() == comp_item->result_type());
- DBUG_ASSERT(item_row->cols() == comp_item_row->cols());
- col= item_row->cols();
- while (col-- > 0)
- resolve_const_item(thd, item_row->addr(col),
- comp_item_row->element_index(col));
- break;
- }
- /* Fallthrough */
- case REAL_RESULT:
- { // It must REAL_RESULT
- double result= item->val_real();
- uint length=item->max_length,decimals=item->decimals;
- bool null_value=item->null_value;
- new_item= (null_value ? (Item*) new (mem_root) Item_null(thd, name) : (Item*)
- new (mem_root) Item_float(thd, name, result, decimals, length));
- break;
- }
- case DECIMAL_RESULT:
- {
- my_decimal decimal_value;
- my_decimal *result= item->val_decimal(&decimal_value);
- uint length= item->max_length, decimals= item->decimals;
- bool null_value= item->null_value;
- new_item= (null_value ?
- (Item*) new (mem_root) Item_null(thd, name) :
- (Item*) new (mem_root) Item_decimal(thd, name, result, length, decimals));
- break;
- }
+ Item *new_item= cmp.type_handler()->
+ make_const_item_for_comparison(thd, item, comp_item);
+ if (new_item)
+ thd->change_item_tree(ref, new_item);
}
- if (new_item)
- thd->change_item_tree(ref, new_item);
}
/**
@@ -9521,35 +9812,6 @@ int stored_field_cmp_to_item(THD *thd, Field *field, Item *item)
return 0;
}
-/**
- Get a cache item of given type.
-
- @param item value to be cached
- @param type required type of cache
-
- @return cache item
-*/
-
-Item_cache* Item_cache::get_cache(THD *thd, const Item *item,
- const Item_result type, const enum_field_types f_type)
-{
- MEM_ROOT *mem_root= thd->mem_root;
- switch (type) {
- case INT_RESULT:
- return new (mem_root) Item_cache_int(thd, f_type);
- case REAL_RESULT:
- return new (mem_root) Item_cache_real(thd);
- case DECIMAL_RESULT:
- return new (mem_root) Item_cache_decimal(thd);
- case STRING_RESULT:
- return new (mem_root) Item_cache_str(thd, item);
- case ROW_RESULT:
- return new (mem_root) Item_cache_row(thd);
- case TIME_RESULT:
- return new (mem_root) Item_cache_temporal(thd, f_type);
- }
- return 0; // Impossible
-}
void Item_cache::store(Item *item)
{
@@ -9669,19 +9931,19 @@ Item *Item_cache_int::convert_to_basic_const_item(THD *thd)
}
-Item_cache_temporal::Item_cache_temporal(THD *thd,
- enum_field_types field_type_arg):
- Item_cache_int(thd, field_type_arg)
+Item_cache_temporal::Item_cache_temporal(THD *thd, const Type_handler *handler)
+ :Item_cache_int(thd, handler)
{
- if (mysql_type_to_time_type(Item_cache_temporal::field_type()) ==
- MYSQL_TIMESTAMP_ERROR)
- set_handler_by_field_type(MYSQL_TYPE_DATETIME);
+ if (mysql_timestamp_type() == MYSQL_TIMESTAMP_ERROR)
+ set_handler(&type_handler_datetime2);
}
longlong Item_cache_temporal::val_datetime_packed()
{
DBUG_ASSERT(fixed == 1);
+ if (Item_cache_temporal::field_type() == MYSQL_TYPE_TIME)
+ return Item::val_datetime_packed(); // TIME-to-DATETIME conversion needed
if ((!value_cached && !cache_value()) || null_value)
{
null_value= TRUE;
@@ -9694,7 +9956,8 @@ longlong Item_cache_temporal::val_datetime_packed()
longlong Item_cache_temporal::val_time_packed()
{
DBUG_ASSERT(fixed == 1);
- DBUG_ASSERT(Item_cache_temporal::field_type() == MYSQL_TYPE_TIME);
+ if (Item_cache_temporal::field_type() != MYSQL_TYPE_TIME)
+ return Item::val_time_packed(); // DATETIME-to-TIME conversion needed
if ((!value_cached && !cache_value()) || null_value)
{
null_value= TRUE;
@@ -9757,21 +10020,18 @@ bool Item_cache_temporal::cache_value()
if (!example)
return false;
value_cached= true;
+ value= example->val_datetime_packed_result();
+ null_value= example->null_value;
+ return true;
+}
- MYSQL_TIME ltime;
- uint fuzzydate= TIME_FUZZY_DATES | TIME_INVALID_DATES;
- if (Item_cache_temporal::field_type() == MYSQL_TYPE_TIME)
- fuzzydate|= TIME_TIME_ONLY;
- value= 0;
- if (!example->get_date_result(&ltime, fuzzydate))
- {
- if (ltime.time_type == MYSQL_TIMESTAMP_TIME &&
- !(fuzzydate & TIME_TIME_ONLY) &&
- convert_time_to_datetime(current_thd, &ltime, fuzzydate))
- return true;
- value= pack_time(&ltime);
- }
+bool Item_cache_time::cache_value()
+{
+ if (!example)
+ return false;
+ value_cached= true;
+ value= example->val_time_packed_result();
null_value= example->null_value;
return true;
}
@@ -9784,21 +10044,10 @@ bool Item_cache_temporal::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
if (!has_value())
{
bzero((char*) ltime,sizeof(*ltime));
- return null_value= true;
+ return (null_value= true);
}
- unpack_time(value, ltime);
- ltime->time_type= mysql_type_to_time_type(field_type());
- if (ltime->time_type == MYSQL_TIMESTAMP_TIME)
- {
- if (fuzzydate & TIME_TIME_ONLY)
- {
- ltime->hour+= (ltime->month*32+ltime->day)*24;
- ltime->month= ltime->day= 0;
- }
- else if (convert_time_to_datetime(current_thd, ltime, fuzzydate))
- return true;
- }
+ unpack_time(value, ltime, mysql_timestamp_type());
return 0;
}
@@ -9826,8 +10075,8 @@ void Item_cache_temporal::store_packed(longlong val_arg, Item *example_arg)
Item *Item_cache_temporal::clone_item(THD *thd)
{
- Item_cache_temporal *item= new (thd->mem_root)
- Item_cache_temporal(thd, Item_cache_temporal::field_type());
+ Item_cache *tmp= type_handler()->Item_get_cache(thd, this);
+ Item_cache_temporal *item= static_cast<Item_cache_temporal*>(tmp);
item->store_packed(value, example);
return item;
}
@@ -9840,26 +10089,32 @@ Item *Item_cache_temporal::convert_to_basic_const_item(THD *thd)
if (!value_cached)
cache_value();
if (null_value)
- new_item= (Item*) new (thd->mem_root) Item_null(thd);
+ return new (thd->mem_root) Item_null(thd);
else
- {
- MYSQL_TIME ltime;
- if (Item_cache_temporal::field_type() == MYSQL_TYPE_TIME)
- {
- unpack_time(val_time_packed(), &ltime);
- new_item= (Item*) new (thd->mem_root) Item_time_literal(thd, &ltime,
- decimals);
- }
- else
- {
- unpack_time(val_datetime_packed(), &ltime);
- new_item= (Item*) new (thd->mem_root) Item_datetime_literal(thd, &ltime,
- decimals);
- }
- }
+ return make_literal(thd);
return new_item;
}
+Item *Item_cache_datetime::make_literal(THD *thd)
+{
+ MYSQL_TIME ltime;
+ unpack_time(val_datetime_packed(), &ltime, MYSQL_TIMESTAMP_DATETIME);
+ return new (thd->mem_root) Item_datetime_literal(thd, &ltime, decimals);
+}
+
+Item *Item_cache_date::make_literal(THD *thd)
+{
+ MYSQL_TIME ltime;
+ unpack_time(val_datetime_packed(), &ltime, MYSQL_TIMESTAMP_DATE);
+ return new (thd->mem_root) Item_date_literal(thd, &ltime);
+}
+
+Item *Item_cache_time::make_literal(THD *thd)
+{
+ MYSQL_TIME ltime;
+ unpack_time(val_time_packed(), &ltime, MYSQL_TIMESTAMP_TIME);
+ return new (thd->mem_root) Item_time_literal(thd, &ltime, decimals);
+}
bool Item_cache_real::cache_value()
{
@@ -10102,7 +10357,7 @@ bool Item_cache_row::setup(THD *thd, Item *item)
{
Item *el= item->element_index(i);
Item_cache *tmp;
- if (!(tmp= values[i]= Item_cache::get_cache(thd, el)))
+ if (!(tmp= values[i]= el->get_cache(thd)))
return 1;
tmp->setup(thd, el);
}
@@ -10205,392 +10460,6 @@ void Item_cache_row::set_null()
};
-Item_type_holder::Item_type_holder(THD *thd, Item *item)
- :Item(thd, item),
- Type_handler_hybrid_real_field_type(get_real_type(item)),
- enum_set_typelib(0),
- geometry_type(Field::GEOM_GEOMETRY)
-{
- DBUG_ASSERT(item->fixed);
- maybe_null= item->maybe_null;
- collation.set(item->collation);
- get_full_info(item);
- /**
- Field::result_merge_type(real_field_type()) should be equal to
- result_type(), with one exception when "this" is a Item_field for
- a BIT field:
- - Field_bit::result_type() returns INT_RESULT, so does its Item_field.
- - Field::result_merge_type(MYSQL_TYPE_BIT) returns STRING_RESULT.
- Perhaps we need a new method in Type_handler to cover these type
- merging rules for UNION.
- */
- DBUG_ASSERT(real_field_type() == MYSQL_TYPE_BIT ||
- Item_type_holder::result_type() ==
- Field::result_merge_type(Item_type_holder::real_field_type()));
- /* fix variable decimals which always is NOT_FIXED_DEC */
- if (Field::result_merge_type(real_field_type()) == INT_RESULT)
- decimals= 0;
- prev_decimal_int_part= item->decimal_int_part();
-#ifdef HAVE_SPATIAL
- if (item->field_type() == MYSQL_TYPE_GEOMETRY)
- geometry_type= item->get_geometry_type();
-#endif /* HAVE_SPATIAL */
-}
-
-
-/**
- Find real field type of item.
-
- @return
- type of field which should be created to store item value
-*/
-
-enum_field_types Item_type_holder::get_real_type(Item *item)
-{
- if (item->type() == REF_ITEM)
- item= item->real_item();
- switch(item->type())
- {
- case FIELD_ITEM:
- {
- /*
- Item_field::field_type ask Field_type() but sometimes field return
- a different type, like for enum/set, so we need to ask real type.
- */
- Field *field= ((Item_field *) item)->field;
- enum_field_types type= field->real_type();
- if (field->is_created_from_null_item)
- return MYSQL_TYPE_NULL;
- /* work around about varchar type field detection */
- if (type == MYSQL_TYPE_STRING && field->type() == MYSQL_TYPE_VAR_STRING)
- return MYSQL_TYPE_VAR_STRING;
- return type;
- }
- case SUM_FUNC_ITEM:
- {
- /*
- Argument of aggregate function sometimes should be asked about field
- type
- */
- Item_sum *item_sum= (Item_sum *) item;
- if (item_sum->keep_field_type())
- return get_real_type(item_sum->get_arg(0));
- break;
- }
- case FUNC_ITEM:
- if (((Item_func *) item)->functype() == Item_func::GUSERVAR_FUNC)
- {
- /*
- There are work around of problem with changing variable type on the
- fly and variable always report "string" as field type to get
- acceptable information for client in send_field, so we make field
- type from expression type.
- */
- switch (item->result_type()) {
- case STRING_RESULT:
- return MYSQL_TYPE_VARCHAR;
- case INT_RESULT:
- return MYSQL_TYPE_LONGLONG;
- case REAL_RESULT:
- return MYSQL_TYPE_DOUBLE;
- case DECIMAL_RESULT:
- return MYSQL_TYPE_NEWDECIMAL;
- case ROW_RESULT:
- case TIME_RESULT:
- DBUG_ASSERT(0);
- return MYSQL_TYPE_VARCHAR;
- }
- }
- break;
- case TYPE_HOLDER:
- /*
- Item_type_holder and Item_blob should not appear in this context.
- In case they for some reasons do, returning field_type() is wrong anyway.
- They must return Item_type_holder::real_field_type() instead, to make
- the code in sql_type.cc and sql_type.h happy, as it expectes
- Field::real_type()-compatible rather than Field::field_type()-compatible
- valies in some places, and may in the future add some asserts preventing
- use of field_type() instead of real_type() and the other way around.
- */
- DBUG_ASSERT(0);
- default:
- break;
- }
- return item->field_type();
-}
-
-/**
- Find field type which can carry current Item_type_holder type and
- type of given Item.
-
- @param thd thread handler
- @param item given item to join its parameters with this item ones
-
- @retval
- TRUE error - types are incompatible
- @retval
- FALSE OK
-*/
-
-bool Item_type_holder::join_types(THD *thd, Item *item)
-{
- uint max_length_orig= max_length;
- uint decimals_orig= decimals;
- DBUG_ENTER("Item_type_holder::join_types");
- DBUG_PRINT("info:", ("was type %d len %d, dec %d name %s",
- real_field_type(), max_length, decimals,
- (name ? name : "<NULL>")));
- DBUG_PRINT("info:", ("in type %d len %d, dec %d",
- get_real_type(item),
- item->max_length, item->decimals));
- set_handler_by_real_type(Field::field_type_merge(real_field_type(),
- get_real_type(item)));
- {
- uint item_decimals= item->decimals;
- /* fix variable decimals which always is NOT_FIXED_DEC */
- if (Field::result_merge_type(real_field_type()) == INT_RESULT)
- item_decimals= 0;
- decimals= MY_MAX(decimals, item_decimals);
- }
-
- if (Item_type_holder::field_type() == FIELD_TYPE_GEOMETRY)
- geometry_type=
- Field_geom::geometry_type_merge(geometry_type, item->get_geometry_type());
-
- if (Field::result_merge_type(real_field_type()) == DECIMAL_RESULT)
- {
- collation.set_numeric();
- decimals= MY_MIN(MY_MAX(decimals, item->decimals), DECIMAL_MAX_SCALE);
- int item_int_part= item->decimal_int_part();
- int item_prec = MY_MAX(prev_decimal_int_part, item_int_part) + decimals;
- int precision= MY_MIN(item_prec, DECIMAL_MAX_PRECISION);
- unsigned_flag&= item->unsigned_flag;
- max_length= my_decimal_precision_to_length_no_truncation(precision,
- decimals,
- unsigned_flag);
- }
-
- switch (Field::result_merge_type(real_field_type()))
- {
- case STRING_RESULT:
- {
- const char *old_cs, *old_derivation;
- uint32 old_max_chars= max_length / collation.collation->mbmaxlen;
- old_cs= collation.collation->name;
- old_derivation= collation.derivation_name();
- if (collation.aggregate(item->collation, MY_COLL_ALLOW_CONV))
- {
- my_error(ER_CANT_AGGREGATE_2COLLATIONS, MYF(0),
- old_cs, old_derivation,
- item->collation.collation->name,
- item->collation.derivation_name(),
- "UNION");
- DBUG_RETURN(TRUE);
- }
- /*
- To figure out max_length, we have to take into account possible
- expansion of the size of the values because of character set
- conversions.
- */
- if (collation.collation != &my_charset_bin)
- {
- max_length= MY_MAX(old_max_chars * collation.collation->mbmaxlen,
- display_length(item) /
- item->collation.collation->mbmaxlen *
- collation.collation->mbmaxlen);
- }
- else
- set_if_bigger(max_length, display_length(item));
- break;
- }
- case REAL_RESULT:
- {
- if (decimals != NOT_FIXED_DEC)
- {
- /*
- For FLOAT(M,D)/DOUBLE(M,D) do not change precision
- if both fields have the same M and D
- */
- if (item->max_length != max_length_orig ||
- item->decimals != decimals_orig)
- {
- int delta1= max_length_orig - decimals_orig;
- int delta2= item->max_length - item->decimals;
- max_length= MY_MAX(delta1, delta2) + decimals;
- if (Item_type_holder::real_field_type() == MYSQL_TYPE_FLOAT &&
- max_length > FLT_DIG + 2)
- {
- max_length= MAX_FLOAT_STR_LENGTH;
- decimals= NOT_FIXED_DEC;
- }
- else if (Item_type_holder::real_field_type() == MYSQL_TYPE_DOUBLE &&
- max_length > DBL_DIG + 2)
- {
- max_length= MAX_DOUBLE_STR_LENGTH;
- decimals= NOT_FIXED_DEC;
- }
- }
- }
- else
- max_length= (Item_type_holder::field_type() == MYSQL_TYPE_FLOAT) ?
- FLT_DIG+6 : DBL_DIG+7;
- break;
- }
- default:
- if (real_field_type() == MYSQL_TYPE_YEAR)
- max_length= MY_MAX(max_length, item->max_length);
- else
- max_length= MY_MAX(max_length, display_length(item));
- };
- maybe_null|= item->maybe_null;
- get_full_info(item);
-
- /* Remember decimal integer part to be used in DECIMAL_RESULT handleng */
- prev_decimal_int_part= decimal_int_part();
- DBUG_PRINT("info", ("become type: %d len: %u dec: %u",
- (int) real_field_type(), max_length, (uint) decimals));
- DBUG_RETURN(FALSE);
-}
-
-/**
- Calculate lenth for merging result for given Item type.
-
- @param item Item for length detection
-
- @return
- length
-*/
-
-uint32 Item_type_holder::display_length(Item *item)
-{
- if (item->type() == Item::FIELD_ITEM)
- return ((Item_field *)item)->max_disp_length();
-
- switch (item->field_type())
- {
- case MYSQL_TYPE_DECIMAL:
- case MYSQL_TYPE_TIMESTAMP:
- case MYSQL_TYPE_DATE:
- case MYSQL_TYPE_TIME:
- case MYSQL_TYPE_DATETIME:
- case MYSQL_TYPE_YEAR:
- case MYSQL_TYPE_NEWDATE:
- case MYSQL_TYPE_VARCHAR:
- case MYSQL_TYPE_BIT:
- case MYSQL_TYPE_NEWDECIMAL:
- case MYSQL_TYPE_ENUM:
- case MYSQL_TYPE_SET:
- case MYSQL_TYPE_TINY_BLOB:
- case MYSQL_TYPE_MEDIUM_BLOB:
- case MYSQL_TYPE_LONG_BLOB:
- case MYSQL_TYPE_BLOB:
- case MYSQL_TYPE_VAR_STRING:
- case MYSQL_TYPE_STRING:
- case MYSQL_TYPE_GEOMETRY:
- return item->max_length;
- case MYSQL_TYPE_TINY:
- return 4;
- case MYSQL_TYPE_SHORT:
- return 6;
- case MYSQL_TYPE_LONG:
- return MY_INT32_NUM_DECIMAL_DIGITS;
- case MYSQL_TYPE_FLOAT:
- return 25;
- case MYSQL_TYPE_DOUBLE:
- return 53;
- case MYSQL_TYPE_NULL:
- return 0;
- case MYSQL_TYPE_LONGLONG:
- return 20;
- case MYSQL_TYPE_INT24:
- return 8;
- default:
- DBUG_ASSERT(0); // we should never go there
- return 0;
- }
-}
-
-
-/**
- Make temporary table field according collected information about type
- of UNION result.
-
- @param table temporary table for which we create fields
-
- @return
- created field
-*/
-
-Field *Item_type_holder::make_field_by_type(TABLE *table)
-{
- /*
- The field functions defines a field to be not null if null_ptr is not 0
- */
- uchar *null_ptr= maybe_null ? (uchar*) "" : 0;
- Field *field;
-
- switch (Item_type_holder::real_field_type()) {
- case MYSQL_TYPE_ENUM:
- DBUG_ASSERT(enum_set_typelib);
- field= new Field_enum((uchar *) 0, max_length, null_ptr, 0,
- Field::NONE, name,
- get_enum_pack_length(enum_set_typelib->count),
- enum_set_typelib, collation.collation);
- if (field)
- field->init(table);
- return field;
- case MYSQL_TYPE_SET:
- DBUG_ASSERT(enum_set_typelib);
- field= new Field_set((uchar *) 0, max_length, null_ptr, 0,
- Field::NONE, name,
- get_set_pack_length(enum_set_typelib->count),
- enum_set_typelib, collation.collation);
- if (field)
- field->init(table);
- return field;
- case MYSQL_TYPE_NULL:
- return make_string_field(table);
- default:
- break;
- }
- return tmp_table_field_from_field_type(table, false, true);
-}
-
-
-/**
- Get full information from Item about enum/set fields to be able to create
- them later.
-
- @param item Item for information collection
-*/
-void Item_type_holder::get_full_info(Item *item)
-{
- if (Item_type_holder::real_field_type() == MYSQL_TYPE_ENUM ||
- Item_type_holder::real_field_type() == MYSQL_TYPE_SET)
- {
- if (item->type() == Item::SUM_FUNC_ITEM &&
- (((Item_sum*)item)->sum_func() == Item_sum::MAX_FUNC ||
- ((Item_sum*)item)->sum_func() == Item_sum::MIN_FUNC))
- item = ((Item_sum*)item)->get_arg(0);
- /*
- We can have enum/set type after merging only if we have one enum|set
- field (or MIN|MAX(enum|set field)) and number of NULL fields
- */
- DBUG_ASSERT((enum_set_typelib &&
- get_real_type(item) == MYSQL_TYPE_NULL) ||
- (!enum_set_typelib &&
- item->real_item()->type() == Item::FIELD_ITEM &&
- (get_real_type(item->real_item()) == MYSQL_TYPE_ENUM ||
- get_real_type(item->real_item()) == MYSQL_TYPE_SET) &&
- ((Field_enum*)((Item_field *) item->real_item())->field)->typelib));
- if (!enum_set_typelib)
- {
- enum_set_typelib= ((Field_enum*)((Item_field *) item->real_item())->field)->typelib;
- }
- }
-}
-
-
double Item_type_holder::val_real()
{
DBUG_ASSERT(0); // should never be called
@@ -10616,6 +10485,12 @@ String *Item_type_holder::val_str(String*)
return 0;
}
+bool Item_type_holder::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+{
+ DBUG_ASSERT(0); // should never be called
+ return true;
+}
+
void Item_result_field::cleanup()
{
DBUG_ENTER("Item_result_field::cleanup()");
@@ -10804,6 +10679,7 @@ Item_field::excl_dep_on_grouping_fields(st_select_lex *sel)
return find_matching_grouping_field(this, sel) != NULL;
}
+
void Item::register_in(THD *thd)
{
next= thd->free_list;