summaryrefslogtreecommitdiff
path: root/sql/item.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/item.cc')
-rw-r--r--sql/item.cc1807
1 files changed, 657 insertions, 1150 deletions
diff --git a/sql/item.cc b/sql/item.cc
index 6d999daf801..7d3f8788c3f 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -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);
@@ -302,6 +311,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 (!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 (!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;
@@ -419,21 +478,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);
}
@@ -471,7 +542,7 @@ 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);
@@ -508,14 +579,13 @@ Item::Item(THD *thd):
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),
@@ -532,49 +602,6 @@ Item::Item(THD *thd, Item *item):
}
-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)
{
@@ -597,11 +624,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.str, name.length);
}
}
@@ -640,7 +668,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;
}
@@ -660,24 +691,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.
@@ -746,29 +759,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= *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),
+ 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),
+ 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= *field_name_arg;
}
@@ -859,7 +874,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;
@@ -876,7 +892,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);
@@ -1004,7 +1021,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;
}
}
@@ -1035,13 +1052,86 @@ bool Item::check_cols(uint c)
}
+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_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_scalar(const char *opname) const
+{
+ 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, uint 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;
}
@@ -1083,13 +1173,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)));
}
@@ -1099,28 +1189,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));
}
@@ -1138,8 +1213,9 @@ 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 &&
+ name.length == item->name.length &&
+ !my_strcasecmp(system_charset_info, name.str, item->name.str);
}
@@ -1481,24 +1557,18 @@ bool mark_unsupported_function(const char *w1, const char *w2,
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);
@@ -1583,16 +1653,26 @@ bool Item_sp_variable::is_null()
return this_item()->is_null();
}
+void Item_sp_variable::make_field(THD *thd, Send_field *field)
+{
+ Item *it= this_item();
+
+ it->make_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 LEX_CSTRING *sp_var_name,
uint sp_var_idx,
enum_field_types sp_var_type,
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),
m_var_idx(sp_var_idx)
{
@@ -1604,11 +1684,19 @@ Item_splocal::Item_splocal(THD *thd, const LEX_STRING &sp_var_name,
}
+bool Item_splocal::fix_fields(THD *thd, Item **ref)
+{
+ Item *item= thd->spcont->get_item(m_var_idx);
+ 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);
-
+ DBUG_ASSERT(fixed);
return m_thd->spcont->get_item(m_var_idx);
}
@@ -1616,7 +1704,7 @@ const Item *
Item_splocal::this_item() const
{
DBUG_ASSERT(m_sp == m_thd->spcont->sp);
-
+ DBUG_ASSERT(fixed);
return m_thd->spcont->get_item(m_var_idx);
}
@@ -1625,7 +1713,7 @@ Item **
Item_splocal::this_item_addr(THD *thd, Item **)
{
DBUG_ASSERT(m_sp == thd->spcont->sp);
-
+ DBUG_ASSERT(fixed);
return thd->spcont->get_item_addr(m_var_idx);
}
@@ -1645,17 +1733,195 @@ bool Item_splocal::set_value(THD *thd, sp_rcontext *ctx, Item **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)
+{
+ Item *item= thd->spcont->get_item(m_var_idx)->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->sp);
+ DBUG_ASSERT(fixed);
+ return m_thd->spcont->get_item(m_var_idx)->element_index(m_field_idx);
+}
+
+
+const Item *
+Item_splocal_row_field::this_item() const
+{
+ DBUG_ASSERT(m_sp == m_thd->spcont->sp);
+ DBUG_ASSERT(fixed);
+ return m_thd->spcont->get_item(m_var_idx)->element_index(m_field_idx);
+}
+
+
+Item **
+Item_splocal_row_field::this_item_addr(THD *thd, Item **)
+{
+ DBUG_ASSERT(m_sp == thd->spcont->sp);
+ DBUG_ASSERT(fixed);
+ return thd->spcont->get_item(m_var_idx)->addr(m_field_idx);
+}
+
+
+void Item_splocal_row_field::print(String *str, enum_query_type)
+{
+ str->reserve(m_name.length + m_field_name.length + 8);
+ str->append(m_name.str, m_name.length);
+ str->append('.');
+ str->append(m_field_name.str, m_field_name.length);
+ 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 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)
+{
+ m_thd= thd;
+ Item *item, *row= m_thd->spcont->get_item(m_var_idx);
+ if (row->element_index_by_name(&m_field_idx, m_field_name))
+ {
+ my_error(ER_ROW_VARIABLE_DOES_NOT_HAVE_FIELD, MYF(0),
+ m_name.str, m_field_name.str);
+ return true;
+ }
+ item= row->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)
+{
+ // +16 should be enough for .NNN@[""]
+ if (str->reserve(m_name.length + 2 * m_field_name.length + 16))
+ return;
+ str->qs_append(m_name.str, m_name.length);
+ str->qs_append('.');
+ str->qs_append(m_field_name.str, m_field_name.length);
+ str->qs_append('@');
+ str->qs_append(m_var_idx);
+ str->qs_append("[\"", 2);
+ str->qs_append(m_field_name.str, m_field_name.length);
+ 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);
+}
+
+
/*****************************************************************************
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()
{
@@ -1823,7 +2089,7 @@ bool Item_name_const::fix_fields(THD *thd, Item **ref)
}
if (is_autogenerated_name)
{
- set_name(thd, item_name->ptr(), (uint) item_name->length(),
+ set_name(thd, item_name->c_ptr(), (uint) item_name->length(),
system_charset_info);
}
collation.set(value_item->collation.collation, DERIVATION_IMPLICIT);
@@ -1854,7 +2120,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)
@@ -1971,14 +2237,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
@@ -1986,7 +2252,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)
@@ -2191,9 +2458,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;
@@ -2238,10 +2505,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)
{
Item **arg, *safe_args[2]= {NULL, NULL};
@@ -2400,7 +2667,6 @@ void Item_ident_for_show::make_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 ?
@@ -2411,7 +2677,7 @@ 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)
{
@@ -2420,7 +2686,8 @@ Item_field::Item_field(THD *thd, 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= "";
+ orig_field_name= null_clex_str;
with_field= 1;
}
@@ -2434,7 +2701,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)
{
@@ -2460,14 +2728,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;
@@ -2476,7 +2745,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)
@@ -2562,15 +2831,11 @@ 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);
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);
@@ -2590,7 +2855,7 @@ 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;
}
@@ -2629,15 +2894,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
{
@@ -2645,11 +2910,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;
}
@@ -2686,7 +2951,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;
@@ -2720,7 +2985,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.str, field_name.length);
}
/* ARGSUSED */
@@ -2851,8 +3116,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 (!my_strcasecmp(system_charset_info, item_field->name.str,
+ field_name.str) &&
(!item_field->table_name || !table_name ||
(!my_strcasecmp(table_alias_charset, item_field->table_name,
table_name) &&
@@ -2979,7 +3244,12 @@ Item_int::Item_int(THD *thd, const char *str_arg, uint 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;
}
@@ -3009,7 +3279,7 @@ 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;
}
@@ -3050,7 +3320,8 @@ Item_decimal::Item_decimal(THD *thd, const char *str_arg, uint length,
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 +
@@ -3090,7 +3361,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;
@@ -3182,7 +3454,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);
}
@@ -3207,7 +3479,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);
}
@@ -3318,7 +3590,7 @@ 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 ******************************/
@@ -3337,10 +3609,20 @@ default_set_param_func(Item_param *param,
}
-Item_param::Item_param(THD *thd, uint pos_in_query_arg):
+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),
@@ -3356,8 +3638,8 @@ Item_param::Item_param(THD *thd, uint pos_in_query_arg):
*/
m_is_settable_routine_parameter(true)
{
- 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.
@@ -3616,47 +3898,10 @@ bool Item_param::set_from_item(THD *thd, Item *item)
}
}
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();
- }
+ if (item->type_handler()->Item_param_set_from_value(thd, this, item, &tmp))
+ DBUG_RETURN(true);
}
else
set_null();
@@ -4048,19 +4293,19 @@ Item_param::clone_item(THD *thd)
invalid_default_param();
// fall through
case NULL_VALUE:
- return new (mem_root) Item_null(thd, name);
+ return new (mem_root) Item_null(thd, name.str);
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));
+ 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_VALUE:
- return new (mem_root) Item_float(thd, name, value.real, decimals,
+ return new (mem_root) Item_float(thd, name.str, value.real, decimals,
max_length);
case DECIMAL_VALUE:
return 0; // Should create Item_decimal. See MDEV-11361.
case STRING_VALUE:
case LONG_DATA_VALUE:
- return new (mem_root) Item_string(thd, name, str_value.c_ptr_quick(),
+ return new (mem_root) Item_string(thd, name.str, str_value.c_ptr_quick(),
str_value.length(), str_value.charset(),
collation.derivation,
collation.repertoire);
@@ -4336,7 +4581,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;
@@ -4694,7 +4938,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);
@@ -4784,7 +5028,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];
@@ -4794,7 +5038,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;
@@ -4807,17 +5051,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 &&
+ if ((*(cur_group->item))->name.str &&
!(*(cur_group->item))->is_autogenerated_name &&
!my_strcasecmp(system_charset_info,
- (*(cur_group->item))->name, field_name))
+ (*(cur_group->item))->name.str, field_name->str))
{
++cur_match_degree;
}
@@ -4828,12 +5072,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))
+ l_field_name->str, field_name->str))
++cur_match_degree;
else
continue;
@@ -4969,7 +5213,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)
@@ -4980,7 +5224,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);
@@ -5313,15 +5557,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;
@@ -5365,9 +5609,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);
@@ -5485,7 +5730,7 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
if (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 +5751,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);
@@ -5605,16 +5849,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;
}
}
@@ -5676,6 +5920,7 @@ error:
return TRUE;
}
+
/*
@brief
Mark virtual columns as used in a partitioning expression
@@ -5866,7 +6111,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,13 +6129,11 @@ 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)
{
- 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);
@@ -5908,7 +6152,7 @@ void Item::make_field(THD *thd, Send_field *tmp_field)
void Item_empty_string::make_field(THD *thd, Send_field *tmp_field)
{
- init_make_field(tmp_field, string_field_type());
+ init_make_field(tmp_field, string_type_handler()->field_type());
}
@@ -6042,180 +6286,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)
{
field->make_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)
@@ -6363,54 +6443,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);
}
@@ -6432,7 +6520,7 @@ 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);
}
@@ -6455,7 +6543,7 @@ 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);
}
@@ -6491,9 +6579,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));
}
@@ -6521,7 +6609,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;
}
@@ -6529,7 +6617,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;
@@ -6542,7 +6630,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;
}
@@ -6561,7 +6650,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)
@@ -6631,7 +6720,8 @@ Item_float::Item_float(THD *thd, const char *str_arg, uint length):
my_snprintf(tmp, sizeof(tmp), "%.*s", 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;
fixed= 1;
@@ -6705,6 +6795,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'");
@@ -6852,127 +6958,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.
@@ -7026,7 +7016,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);
@@ -7044,7 +7034,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);
}
@@ -7117,7 +7107,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;
@@ -7144,7 +7134,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;
}
}
}
@@ -7152,7 +7142,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);
@@ -7311,6 +7301,26 @@ void Item_field::print(String *str, enum_query_type query_type)
}
+bool Item_field_row::element_index_by_name(uint *idx,
+ const LEX_CSTRING &name) const
+{
+ Field *field;
+ for (uint i= 0; (field= get_row_field(i)); i++)
+ {
+ // Use the same comparison style with sp_context::find_variable()
+ if (!my_strnncoll(system_charset_info,
+ (const uchar *) field->field_name.str,
+ field->field_name.length,
+ (const uchar *) name.str, name.length))
+ {
+ *idx= i;
+ return false;
+ }
+ }
+ return true;
+}
+
+
void Item_temptable_field::print(String *str, enum_query_type query_type)
{
/*
@@ -7323,7 +7333,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)
@@ -7368,7 +7378,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)
{
@@ -7650,13 +7661,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;
@@ -7798,11 +7809,11 @@ void Item_ref::print(String *str, enum_query_type query_type)
if (ref)
{
if ((*ref)->type() != Item::CACHE_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.str,
+ (*ref)->real_item()->name.length);
}
else
(*ref)->print(str, query_type);
@@ -7812,11 +7823,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);
}
@@ -7999,13 +8010,13 @@ void Item_ref::make_field(THD *thd, Send_field *field)
{
(*ref)->make_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;
@@ -8111,10 +8122,9 @@ Item_cache_wrapper::Item_cache_wrapper(THD *thd, Item *item_arg):
with_sum_func= orig_item->with_sum_func;
with_field= orig_item->with_field;
name= item_arg->name;
- name_length= item_arg->name_length;
with_subselect= orig_item->with_subselect;
- 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;
@@ -8172,7 +8182,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);
@@ -8503,7 +8513,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();
@@ -8818,14 +8828,15 @@ bool Item_default_value::fix_fields(THD *thd, Item **items)
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())))
@@ -8905,7 +8916,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);
@@ -9012,7 +9023,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;
@@ -9066,7 +9077,7 @@ bool Item_insert_value::fix_fields(THD *thd, Item **items)
{
Field *tmp_field= field_arg->field;
/* charset doesn't matter here, it's to avoid sigsegv only */
- tmp_field= new Field_null(0, 0, Field::NONE, field_arg->field->field_name,
+ tmp_field= new Field_null(0, 0, Field::NONE, &field_arg->field->field_name,
&my_charset_bin);
if (tmp_field)
{
@@ -9123,7 +9134,7 @@ void Item_trigger_field::setup_field(THD *thd, TABLE *table,
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;
triggers= table->triggers;
@@ -9135,8 +9146,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);
+ !my_strcasecmp(system_charset_info, field_name.str,
+ ((Item_trigger_field *)item)->field_name.str);
}
@@ -9202,9 +9213,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
@@ -9216,7 +9229,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;
}
@@ -9226,14 +9239,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);
}
@@ -9270,101 +9283,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()))
{
- bool is_null;
- Item **ref_copy= ref;
- /* the following call creates a constant and puts it in new_item */
- enum_field_types type= item->field_type_for_temporal_comparison(comp_item);
- get_datetime_value(thd, &ref_copy, &new_item, type, &is_null);
- if (is_null)
- new_item= new (mem_root) Item_null(thd, name);
- 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);
}
/**
@@ -9461,41 +9387,6 @@ int stored_field_cmp_to_item(THD *thd, Field *field, Item *item)
return 0;
}
-Item_cache* Item_cache::get_cache(THD *thd, const Item *item)
-{
- return get_cache(thd, item, item->cmp_type());
-}
-
-
-/**
- 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)
-{
- MEM_ROOT *mem_root= thd->mem_root;
- switch (type) {
- case INT_RESULT:
- return new (mem_root) Item_cache_int(thd, item->field_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, item->field_type());
- }
- return 0; // Impossible
-}
void Item_cache::store(Item *item)
{
@@ -9613,13 +9504,11 @@ 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);
}
@@ -9727,7 +9616,7 @@ bool Item_cache_temporal::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
}
unpack_time(value, ltime);
- ltime->time_type= mysql_type_to_time_type(field_type());
+ ltime->time_type= mysql_timestamp_type();
if (ltime->time_type == MYSQL_TIMESTAMP_TIME)
{
ltime->hour+= (ltime->month*32+ltime->day)*24;
@@ -9762,7 +9651,7 @@ 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_temporal(thd, Item_cache_temporal::type_handler());
item->store_packed(value, example);
return item;
}
@@ -10020,7 +9909,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);
}
@@ -10123,388 +10012,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)
- {
- 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:
- 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