summaryrefslogtreecommitdiff
path: root/sql/item.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/item.cc')
-rw-r--r--sql/item.cc2502
1 files changed, 1210 insertions, 1292 deletions
diff --git a/sql/item.cc b/sql/item.cc
index 719bdcfaf89..46e6e2cc838 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -19,9 +19,8 @@
#ifdef USE_PRAGMA_IMPLEMENTATION
#pragma implementation // gcc: Class implementation
#endif
-#include "my_global.h" /* NO_EMBEDDED_ACCESS_CHECKS */
+#include <my_global.h> /* NO_EMBEDDED_ACCESS_CHECKS */
#include "sql_priv.h"
-#include "unireg.h" // REQUIRED: for other includes
#include <mysql.h>
#include <m_ctype.h>
#include "my_dir.h"
@@ -41,13 +40,11 @@
// REPORT_EXCEPT_NOT_FOUND,
// find_item_in_list,
// RESOLVED_AGAINST_ALIAS, ...
-#include "log_event.h" // append_query_string
#include "sql_expression_cache.h"
const String my_null_string("NULL", 4, default_charset_info);
-static int save_field_in_field(Field *from, bool *null_value,
- Field *to, bool no_conversions);
+static int save_field_in_field(Field *, bool *, Field *, bool);
/**
@@ -59,133 +56,16 @@ bool cmp_items(Item *a, Item *b)
return a->eq(b, FALSE);
}
-/****************************************************************************/
-
-/* Hybrid_type_traits {_real} */
-
-void Hybrid_type_traits::fix_length_and_dec(Item *item, Item *arg) const
-{
- item->decimals= NOT_FIXED_DEC;
- item->max_length= item->float_length(arg->decimals);
-}
-
-static const Hybrid_type_traits real_traits_instance;
-
-const Hybrid_type_traits *Hybrid_type_traits::instance()
-{
- return &real_traits_instance;
-}
-
-
-my_decimal *
-Hybrid_type_traits::val_decimal(Hybrid_type *val, my_decimal *to) const
-{
- double2my_decimal(E_DEC_FATAL_ERROR, val->real, val->dec_buf);
- return val->dec_buf;
-}
-
-
-String *
-Hybrid_type_traits::val_str(Hybrid_type *val, String *to, uint8 decimals) const
-{
- to->set_real(val->real, decimals, &my_charset_bin);
- return to;
-}
-
-/* Hybrid_type_traits_decimal */
-static const Hybrid_type_traits_decimal decimal_traits_instance;
-
-const Hybrid_type_traits_decimal *Hybrid_type_traits_decimal::instance()
-{
- return &decimal_traits_instance;
-}
-
-
-void
-Hybrid_type_traits_decimal::fix_length_and_dec(Item *item, Item *arg) const
-{
- item->decimals= arg->decimals;
- item->max_length= min(arg->max_length + DECIMAL_LONGLONG_DIGITS,
- DECIMAL_MAX_STR_LENGTH);
-}
-
-
-void Hybrid_type_traits_decimal::set_zero(Hybrid_type *val) const
-{
- my_decimal_set_zero(&val->dec_buf[0]);
- val->used_dec_buf_no= 0;
-}
-
-
-void Hybrid_type_traits_decimal::add(Hybrid_type *val, Field *f) const
-{
- my_decimal_add(E_DEC_FATAL_ERROR,
- &val->dec_buf[val->used_dec_buf_no ^ 1],
- &val->dec_buf[val->used_dec_buf_no],
- f->val_decimal(&val->dec_buf[2]));
- val->used_dec_buf_no^= 1;
-}
-
/**
- @todo
- what is '4' for scale?
+ Set max_sum_func_level if it is needed
*/
-void Hybrid_type_traits_decimal::div(Hybrid_type *val, ulonglong u) const
-{
- int2my_decimal(E_DEC_FATAL_ERROR, u, TRUE, &val->dec_buf[2]);
- /* XXX: what is '4' for scale? */
- my_decimal_div(E_DEC_FATAL_ERROR,
- &val->dec_buf[val->used_dec_buf_no ^ 1],
- &val->dec_buf[val->used_dec_buf_no],
- &val->dec_buf[2], 4);
- val->used_dec_buf_no^= 1;
-}
-
-
-longlong
-Hybrid_type_traits_decimal::val_int(Hybrid_type *val, bool unsigned_flag) const
-{
- longlong result;
- my_decimal2int(E_DEC_FATAL_ERROR, &val->dec_buf[val->used_dec_buf_no],
- unsigned_flag, &result);
- return result;
-}
-
-
-double
-Hybrid_type_traits_decimal::val_real(Hybrid_type *val) const
-{
- my_decimal2double(E_DEC_FATAL_ERROR, &val->dec_buf[val->used_dec_buf_no],
- &val->real);
- return val->real;
-}
-
-
-String *
-Hybrid_type_traits_decimal::val_str(Hybrid_type *val, String *to,
- uint8 decimals) const
-{
- my_decimal_round(E_DEC_FATAL_ERROR, &val->dec_buf[val->used_dec_buf_no],
- decimals, FALSE, &val->dec_buf[2]);
- my_decimal2string(E_DEC_FATAL_ERROR, &val->dec_buf[2], 0, 0, 0, to);
- return to;
-}
-
-/* Hybrid_type_traits_integer */
-static const Hybrid_type_traits_integer integer_traits_instance;
-
-const Hybrid_type_traits_integer *Hybrid_type_traits_integer::instance()
+inline void set_max_sum_func_level(THD *thd, SELECT_LEX *select)
{
- return &integer_traits_instance;
-}
-
-void
-Hybrid_type_traits_integer::fix_length_and_dec(Item *item, Item *arg) const
-{
- item->decimals= 0;
- item->max_length= MY_INT64_NUM_DECIMAL_DIGITS;
- item->unsigned_flag= 0;
+ if (thd->lex->in_sum_func &&
+ thd->lex->in_sum_func->nest_level >= select->nest_level)
+ set_if_bigger(thd->lex->in_sum_func->max_sum_func_level,
+ select->nest_level - 1);
}
/*****************************************************************************
@@ -198,7 +78,7 @@ Hybrid_type_traits_integer::fix_length_and_dec(Item *item, Item *arg) const
void item_init(void)
{
- item_user_lock_init();
+ item_func_sleep_init();
uuid_short_init();
}
@@ -226,7 +106,6 @@ bool Item::val_bool()
return val_real() != 0.0;
case ROW_RESULT:
case TIME_RESULT:
- case IMPOSSIBLE_RESULT:
DBUG_ASSERT(0);
return 0; // Wrong (but safe)
}
@@ -234,6 +113,82 @@ bool Item::val_bool()
}
+/**
+ 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))
+ {
+ MYSQL_TIME tmp;
+ if (time_to_datetime_with_warn(thd, ltime, &tmp, fuzzydate))
+ return null_value= true;
+ *ltime= tmp;
+ }
+ return false;
+}
+
+
+/**
+ Get date/time/datetime.
+ If DATETIME or DATE result is returned, it's converted to TIME.
+*/
+bool Item::get_time_with_conversion(THD *thd, MYSQL_TIME *ltime,
+ ulonglong fuzzydate)
+{
+ if (get_date(ltime, fuzzydate))
+ return true;
+ if (ltime->time_type != MYSQL_TIMESTAMP_TIME)
+ {
+ MYSQL_TIME ltime2;
+ if ((thd->variables.old_behavior & OLD_MODE_ZERO_DATE_TIME_CAST) &&
+ (ltime->year || ltime->day || ltime->month))
+ {
+ /*
+ Old mode conversion from DATETIME with non-zero YYYYMMDD part
+ to TIME works very inconsistently. Possible variants:
+ - truncate the YYYYMMDD part
+ - add (MM*33+DD)*24 to hours
+ - add (MM*31+DD)*24 to hours
+ Let's return TRUE here, to disallow equal field propagation.
+ Note, If we start to use this method in more pieces of the code other
+ than equal field propagation, we should probably return
+ TRUE only if some flag in fuzzydate is set.
+ */
+ return true;
+ }
+ if (datetime_to_time_with_warn(thd, ltime, &ltime2, TIME_SECOND_PART_DIGITS))
+ {
+ /*
+ If the time difference between CURRENT_DATE and ltime
+ did not fit into the supported TIME range, then we set the
+ difference to the maximum possible value in the supported TIME range
+ */
+ DBUG_ASSERT(0);
+ return (null_value= true);
+ }
+ *ltime= ltime2;
+ }
+ return false;
+}
+
+
/*
For the items which don't have its own fast val_str_ascii()
implementation we provide a generic slower version,
@@ -313,11 +268,29 @@ String *Item::val_string_from_decimal(String *str)
}
+/*
+ All val_xxx_from_date() must call this method, to expose consistent behaviour
+ regarding SQL_MODE when converting DATE/DATETIME to other data types.
+*/
+bool Item::get_temporal_with_sql_mode(MYSQL_TIME *ltime)
+{
+ return get_date(ltime, field_type() == MYSQL_TYPE_TIME
+ ? TIME_TIME_ONLY
+ : sql_mode_for_dates(current_thd));
+}
+
+
+bool Item::is_null_from_temporal()
+{
+ MYSQL_TIME ltime;
+ return get_temporal_with_sql_mode(&ltime);
+}
+
+
String *Item::val_string_from_date(String *str)
{
MYSQL_TIME ltime;
- if (get_date(&ltime,
- field_type() == MYSQL_TYPE_TIME ? TIME_TIME_ONLY : 0) ||
+ if (get_temporal_with_sql_mode(&ltime) ||
str->alloc(MAX_DATE_STRING_REP_LENGTH))
{
null_value= 1;
@@ -356,17 +329,7 @@ my_decimal *Item::val_decimal_from_string(my_decimal *decimal_value)
if (!(res= val_str(&str_value)))
return 0;
- if (str2my_decimal(E_DEC_FATAL_ERROR & ~E_DEC_BAD_NUM,
- res->ptr(), res->length(), res->charset(),
- decimal_value) & E_DEC_BAD_NUM)
- {
- ErrConvString err(res);
- push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_TRUNCATED_WRONG_VALUE,
- ER(ER_TRUNCATED_WRONG_VALUE), "DECIMAL",
- err.ptr());
- }
- return decimal_value;
+ return decimal_from_string_with_check(decimal_value, res);
}
@@ -374,7 +337,7 @@ my_decimal *Item::val_decimal_from_date(my_decimal *decimal_value)
{
DBUG_ASSERT(fixed == 1);
MYSQL_TIME ltime;
- if (get_date(&ltime, 0))
+ if (get_temporal_with_sql_mode(&ltime))
{
my_decimal_set_zero(decimal_value);
null_value= 1; // set NULL, stop processing
@@ -401,18 +364,26 @@ longlong Item::val_int_from_date()
{
DBUG_ASSERT(fixed == 1);
MYSQL_TIME ltime;
- if (get_date(&ltime, 0))
+ if (get_temporal_with_sql_mode(&ltime))
return 0;
longlong v= TIME_to_ulonglong(&ltime);
return ltime.neg ? -v : v;
}
+longlong Item::val_int_from_real()
+{
+ DBUG_ASSERT(fixed == 1);
+ bool error;
+ return double_to_longlong(val_real(), false /*unsigned_flag*/, &error);
+}
+
+
double Item::val_real_from_date()
{
DBUG_ASSERT(fixed == 1);
MYSQL_TIME ltime;
- if (get_date(&ltime, 0))
+ if (get_temporal_with_sql_mode(&ltime))
return 0;
return TIME_to_double(&ltime);
}
@@ -454,9 +425,7 @@ int Item::save_time_in_field(Field *field)
int Item::save_date_in_field(Field *field)
{
MYSQL_TIME ltime;
- if (get_date(&ltime, (current_thd->variables.sql_mode &
- (MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE |
- MODE_INVALID_DATES))))
+ if (get_date(&ltime, sql_mode_for_dates(current_thd)))
return set_field_to_null_with_conversions(field, 0);
field->set_notnull();
return field->store_time_dec(&ltime, decimals);
@@ -494,23 +463,21 @@ int Item::save_str_value_in_field(Field *field, String *result)
}
-Item::Item():
+Item::Item(THD *thd):
is_expensive_cache(-1), rsize(0), name(0), orig_name(0), name_length(0),
- fixed(0), is_autogenerated_name(TRUE),
- collation(&my_charset_bin, DERIVATION_COERCIBLE)
+ fixed(0), is_autogenerated_name(TRUE)
{
+ DBUG_ASSERT(thd);
marker= 0;
- maybe_null=null_value=with_sum_func=with_field=unsigned_flag=0;
+ maybe_null=null_value=with_sum_func=with_field=0;
in_rollup= 0;
- decimals= 0; max_length= 0;
with_subselect= 0;
with_param= 0;
- cmp_context= IMPOSSIBLE_RESULT;
- /* 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 */
- THD *thd= current_thd;
next= thd->free_list;
thd->free_list= this;
/*
@@ -536,28 +503,24 @@ Item::Item():
tables.
*/
Item::Item(THD *thd, Item *item):
+ Type_std_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),
- max_length(item->max_length),
name_length(item->name_length),
- decimals(item->decimals),
marker(item->marker),
maybe_null(item->maybe_null),
in_rollup(item->in_rollup),
null_value(item->null_value),
- unsigned_flag(item->unsigned_flag),
with_sum_func(item->with_sum_func),
with_param(item->with_param),
with_field(item->with_field),
fixed(item->fixed),
is_autogenerated_name(item->is_autogenerated_name),
- with_subselect(item->has_subquery()),
- collation(item->collation),
- cmp_context(item->cmp_context)
+ with_subselect(item->has_subquery())
{
next= thd->free_list; // Put in free list
thd->free_list= this;
@@ -573,47 +536,37 @@ uint Item::decimal_precision() const
uint prec=
my_decimal_length_to_precision(max_char_length(), decimals,
unsigned_flag);
- return min(prec, DECIMAL_MAX_PRECISION);
+ return MY_MIN(prec, DECIMAL_MAX_PRECISION);
}
- return min(max_char_length(), DECIMAL_MAX_PRECISION);
-}
-
-
-#if MARIADB_VERSION_ID < 1000000
-static uint ms_to_precision(uint ms)
-{
- uint cut, precision;
- for (cut= 10, precision= 6 ; precision > 0 ; cut*= 10, precision--)
- {
- if (ms % cut)
- return precision;
- }
- return 0;
+ 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;
}
-#else
-#error Change the code to use MYSQL_TIME_STATUS::precision instead.
-#endif
-uint Item::temporal_precision(enum_field_types type)
+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;
- int was_cut;
+ MYSQL_TIME_STATUS status;
DBUG_ASSERT(fixed);
if ((tmp= val_str(&buf)) &&
- (type == MYSQL_TYPE_TIME ?
+ !(type_arg == MYSQL_TYPE_TIME ?
str_to_time(tmp->charset(), tmp->ptr(), tmp->length(),
- &ltime, TIME_TIME_ONLY, &was_cut) :
+ &ltime, TIME_TIME_ONLY, &status) :
str_to_datetime(tmp->charset(), tmp->ptr(), tmp->length(),
- &ltime, TIME_FUZZY_DATES, &was_cut)) >
- MYSQL_TIMESTAMP_ERROR)
- return min(ms_to_precision(ltime.second_part), TIME_SECOND_PART_DIGITS);
+ &ltime, TIME_FUZZY_DATES, &status)))
+ return MY_MIN(status.precision, TIME_SECOND_PART_DIGITS);
}
- return min(decimals, TIME_SECOND_PART_DIGITS);
+ return MY_MIN(decimals, TIME_SECOND_PART_DIGITS);
}
@@ -650,7 +603,6 @@ void Item::print_value(String *str)
break;
case ROW_RESULT:
case TIME_RESULT:
- case IMPOSSIBLE_RESULT:
DBUG_ASSERT(0);
}
}
@@ -661,7 +613,7 @@ void Item::cleanup()
{
DBUG_ENTER("Item::cleanup");
DBUG_PRINT("enter", ("this: %p", this));
- fixed=0;
+ fixed= 0;
marker= 0;
join_tab_idx= MAX_TABLES;
if (orig_name)
@@ -731,14 +683,17 @@ Item_result Item::cmp_type() const
case MYSQL_TYPE_GEOMETRY:
return STRING_RESULT;
case MYSQL_TYPE_TIMESTAMP:
+ case MYSQL_TYPE_TIMESTAMP2:
case MYSQL_TYPE_DATE:
case MYSQL_TYPE_TIME:
+ case MYSQL_TYPE_TIME2:
case MYSQL_TYPE_DATETIME:
+ case MYSQL_TYPE_DATETIME2:
case MYSQL_TYPE_NEWDATE:
return TIME_RESULT;
};
DBUG_ASSERT(0);
- return IMPOSSIBLE_RESULT;
+ return STRING_RESULT;
}
/**
@@ -770,11 +725,11 @@ Item_result Item::cmp_type() const
pointer to newly allocated item is returned.
*/
-Item* Item::transform(Item_transformer transformer, uchar *arg)
+Item* Item::transform(THD *thd, Item_transformer transformer, uchar *arg)
{
- DBUG_ASSERT(!current_thd->stmt_arena->is_stmt_prepare());
+ DBUG_ASSERT(!thd->stmt_arena->is_stmt_prepare());
- return (this->*transformer)(arg);
+ return (this->*transformer)(thd, arg);
}
@@ -797,7 +752,7 @@ Item* Item::set_expr_cache(THD *thd)
{
DBUG_ENTER("Item::set_expr_cache");
Item_cache_wrapper *wrapper;
- if ((wrapper= new Item_cache_wrapper(this)) &&
+ if ((wrapper= new (thd->mem_root) Item_cache_wrapper(thd, this)) &&
!wrapper->fix_fields(thd, (Item**)&wrapper))
{
if (wrapper->set_cache(thd))
@@ -808,10 +763,11 @@ Item* Item::set_expr_cache(THD *thd)
}
-Item_ident::Item_ident(Name_resolution_context *context_arg,
+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)
- :orig_db_name(db_name_arg), orig_table_name(table_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),
db_name(db_name_arg), table_name(table_name_arg),
field_name(field_name_arg),
@@ -823,8 +779,9 @@ Item_ident::Item_ident(Name_resolution_context *context_arg,
}
-Item_ident::Item_ident(TABLE_LIST *view_arg, const char *field_name_arg)
- :orig_db_name(NullS), orig_table_name(view_arg->table_name),
+Item_ident::Item_ident(THD *thd, TABLE_LIST *view_arg, const char *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),
@@ -841,7 +798,7 @@ Item_ident::Item_ident(TABLE_LIST *view_arg, const char *field_name_arg)
*/
Item_ident::Item_ident(THD *thd, Item_ident *item)
- :Item(thd, item),
+ :Item_result_field(thd, item),
orig_db_name(item->orig_db_name),
orig_table_name(item->orig_table_name),
orig_field_name(item->orig_field_name),
@@ -860,7 +817,7 @@ void Item_ident::cleanup()
{
DBUG_ENTER("Item_ident::cleanup");
bool was_fixed= fixed;
- Item::cleanup();
+ Item_result_field::cleanup();
db_name= orig_db_name;
table_name= orig_table_name;
field_name= orig_field_name;
@@ -871,7 +828,7 @@ void Item_ident::cleanup()
We can trust that depended_from set correctly only if this item
was fixed
*/
- can_be_depended= test(depended_from);
+ can_be_depended= MY_TEST(depended_from);
}
DBUG_VOID_RETURN;
}
@@ -889,10 +846,15 @@ bool Item_ident::remove_dependence_processor(uchar * arg)
bool Item_ident::collect_outer_ref_processor(uchar *param)
{
Collect_deps_prm *prm= (Collect_deps_prm *)param;
- if (depended_from &&
+ if (depended_from &&
depended_from->nest_level_base == prm->nest_level_base &&
depended_from->nest_level < prm->nest_level)
- prm->parameters->add_unique(this, &cmp_items);
+ {
+ if (prm->collect)
+ prm->parameters->add_unique(this, &cmp_items);
+ else
+ prm->count++;
+ }
return FALSE;
}
@@ -1042,10 +1004,15 @@ void Item::set_name(const char *str, uint length, CHARSET_INFO *cs)
name_length= 0;
return;
}
- if (cs->ctype)
- {
- const char *str_start= str;
+ const char *str_start= str;
+ if (!cs->ctype || cs->mbminlen > 1)
+ {
+ str+= cs->cset->scan(cs, str, str + length, MY_SEQ_SPACES);
+ length-= str - str_start;
+ }
+ else
+ {
/*
This will probably need a better implementation in the future:
a function in CHARSET_INFO structure.
@@ -1055,21 +1022,24 @@ void Item::set_name(const char *str, uint length, CHARSET_INFO *cs)
length--;
str++;
}
- if (str != str_start && !is_autogenerated_name)
- {
- char buff[SAFE_NAME_LEN];
- strmake(buff, str_start,
- min(sizeof(buff)-1, length + (int) (str-str_start)));
-
- if (length == 0)
- push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_NAME_BECOMES_EMPTY, ER(ER_NAME_BECOMES_EMPTY),
- buff);
- else
- push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_REMOVED_SPACES, ER(ER_REMOVED_SPACES),
- buff);
- }
+ }
+ if (str != str_start && !is_autogenerated_name)
+ {
+ char buff[SAFE_NAME_LEN];
+ THD *thd= current_thd;
+
+ strmake(buff, str_start,
+ MY_MIN(sizeof(buff)-1, length + (int) (str-str_start)));
+
+ if (length == 0)
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
+ ER_NAME_BECOMES_EMPTY,
+ ER_THD(thd, ER_NAME_BECOMES_EMPTY),
+ buff);
+ else
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
+ ER_REMOVED_SPACES, ER_THD(thd, ER_REMOVED_SPACES),
+ buff);
}
if (!my_charset_same(cs, system_charset_info))
{
@@ -1080,7 +1050,7 @@ void Item::set_name(const char *str, uint length, CHARSET_INFO *cs)
name_length= res_length;
}
else
- name= sql_strmake(str, (name_length= min(length,MAX_ALIAS_NAME)));
+ name= sql_strmake(str, (name_length= MY_MIN(length,MAX_ALIAS_NAME)));
}
@@ -1133,9 +1103,11 @@ bool Item::eq(const Item *item, bool binary_cmp) const
}
-Item *Item::safe_charset_converter(CHARSET_INFO *tocs)
+Item *Item::safe_charset_converter(THD *thd, CHARSET_INFO *tocs)
{
- Item_func_conv_charset *conv= new Item_func_conv_charset(this, tocs, 1);
+ 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;
}
@@ -1147,7 +1119,7 @@ Item *Item::safe_charset_converter(CHARSET_INFO *tocs)
Example:
Item_singlerow_subselect has "Item_cache **row".
Creating of Item_func_conv_charset followed by THD::change_item_tree()
- should not change row[i] from Item_cache directly to Item_func_conv_charset, because Item_singlerow_subselect
+ should not change row[i] from Item_cache directly to Item_func_conv_charset,
because Item_singlerow_subselect later calls Item_cache-specific methods,
e.g. row[i]->store() and row[i]->cache_value().
@@ -1160,18 +1132,18 @@ Item *Item::safe_charset_converter(CHARSET_INFO *tocs)
TODO: we should eventually check all other use cases of change_item_tree().
Perhaps some more potentially dangerous substitution examples exist.
*/
-Item *Item_cache::safe_charset_converter(CHARSET_INFO *tocs)
+Item *Item_cache::safe_charset_converter(THD *thd, CHARSET_INFO *tocs)
{
if (!example)
- return Item::safe_charset_converter(tocs);
- Item *conv= example->safe_charset_converter(tocs);
+ return Item::safe_charset_converter(thd, tocs);
+ Item *conv= example->safe_charset_converter(thd, tocs);
if (conv == example)
return this;
Item_cache *cache;
- if (!conv || conv->fix_fields(current_thd, (Item **) NULL) ||
- !(cache= new Item_cache_str(conv)))
+ if (!conv || conv->fix_fields(thd, (Item **) NULL) ||
+ !(cache= new (thd->mem_root) Item_cache_str(thd, conv)))
return NULL; // Safe conversion is not possible, or OEM
- cache->setup(conv);
+ cache->setup(thd, conv);
cache->fixed= false; // Make Item::fix_fields() happy
return cache;
}
@@ -1188,7 +1160,7 @@ Item *Item_cache::safe_charset_converter(CHARSET_INFO *tocs)
the latter returns a non-fixed Item, so val_str() crashes afterwards.
Override Item_num method, to return a fixed item.
*/
-Item *Item_num::safe_charset_converter(CHARSET_INFO *tocs)
+Item *Item_num::safe_charset_converter(THD *thd, CHARSET_INFO *tocs)
{
/*
Item_num returns pure ASCII result,
@@ -1198,114 +1170,59 @@ Item *Item_num::safe_charset_converter(CHARSET_INFO *tocs)
if (!(tocs->state & MY_CS_NONASCII))
return this;
- Item_string *conv;
- uint conv_errors;
- char buf[64], buf2[64];
- String tmp(buf, sizeof(buf), &my_charset_bin);
- String cstr(buf2, sizeof(buf2), &my_charset_bin);
- String *ostr= val_str(&tmp);
- char *ptr;
- cstr.copy(ostr->ptr(), ostr->length(), ostr->charset(), tocs, &conv_errors);
- if (conv_errors || !(conv= new Item_string(cstr.ptr(), cstr.length(),
- cstr.charset(),
- collation.derivation)))
- {
- /*
- Safe conversion is not possible (or EOM).
- We could not convert a string into the requested character set
- without data loss. The target charset does not cover all the
- characters from the string. Operation cannot be done correctly.
- */
- return NULL;
- }
- if (!(ptr= current_thd->strmake(cstr.ptr(), cstr.length())))
- return NULL;
- conv->str_value.set(ptr, cstr.length(), cstr.charset());
- /* Ensure that no one is going to change the result string */
- conv->str_value.mark_as_const();
- conv->fix_char_length(max_char_length());
+ Item *conv;
+ if ((conv= const_charset_converter(thd, tocs, true)))
+ conv->fix_char_length(max_char_length());
return conv;
}
-Item *Item_static_float_func::safe_charset_converter(CHARSET_INFO *tocs)
-{
- Item_string *conv;
- char buf[64];
- String *s, tmp(buf, sizeof(buf), &my_charset_bin);
- s= val_str(&tmp);
- if ((conv= new Item_static_string_func(func_name, s->ptr(), s->length(),
- s->charset())))
- {
- conv->str_value.copy();
- conv->str_value.mark_as_const();
- }
- return conv;
-}
+/**
+ Create character set converter for constant items
+ using Item_null, Item_string or Item_static_string_func.
+ @param tocs Character set to to convert the string to.
+ @param lossless Whether data loss is acceptable.
+ @param func_name Function name, or NULL.
-Item *Item_string::safe_charset_converter(CHARSET_INFO *tocs)
+ @return this, if conversion is not needed,
+ NULL, if safe conversion is not possible, or
+ a new item representing the converted constant.
+*/
+Item *Item::const_charset_converter(THD *thd, CHARSET_INFO *tocs,
+ bool lossless,
+ const char *func_name)
{
- Item_string *conv;
- uint conv_errors;
- char *ptr;
- String tmp, cstr, *ostr= val_str(&tmp);
- cstr.copy(ostr->ptr(), ostr->length(), ostr->charset(), tocs, &conv_errors);
- if (conv_errors || !(conv= new Item_string(cstr.ptr(), cstr.length(),
- cstr.charset(),
- collation.derivation)))
- {
- /*
- Safe conversion is not possible (or EOM).
- We could not convert a string into the requested character set
- without data loss. The target charset does not cover all the
- characters from the string. Operation cannot be done correctly.
- */
- return NULL;
- }
- if (!(ptr= current_thd->strmake(cstr.ptr(), cstr.length())))
- return NULL;
- conv->str_value.set(ptr, cstr.length(), cstr.charset());
- /* Ensure that no one is going to change the result string */
- conv->str_value.mark_as_const();
- return conv;
-}
+ DBUG_ASSERT(const_item());
+ DBUG_ASSERT(fixed);
+ StringBuffer<64>tmp;
+ String *s= val_str(&tmp);
+ MEM_ROOT *mem_root= thd->mem_root;
+ if (!s)
+ return new (mem_root) Item_null(thd, (char *) func_name, tocs);
-Item *Item_param::safe_charset_converter(CHARSET_INFO *tocs)
-{
- if (const_item())
+ if (!needs_charset_converter(s->length(), tocs))
{
- uint cnv_errors;
- String *ostr= val_str(&cnvstr);
- if (null_value)
- {
- Item_null *n= new Item_null();
- return n ? n->safe_charset_converter(tocs) : NULL;
- }
- cnvitem->str_value.copy(ostr->ptr(), ostr->length(),
- ostr->charset(), tocs, &cnv_errors);
- if (cnv_errors)
- return NULL;
- cnvitem->str_value.mark_as_const();
- cnvitem->max_length= cnvitem->str_value.numchars() * tocs->mbmaxlen;
- return cnvitem;
+ if (collation.collation == &my_charset_bin && tocs != &my_charset_bin &&
+ !this->check_well_formed_result(s, true))
+ return NULL;
+ return this;
}
- return Item::safe_charset_converter(tocs);
-}
-
-Item *Item_static_string_func::safe_charset_converter(CHARSET_INFO *tocs)
-{
- Item_string *conv;
uint conv_errors;
- String tmp, cstr, *ostr= val_str(&tmp);
- cstr.copy(ostr->ptr(), ostr->length(), ostr->charset(), tocs, &conv_errors);
- if (conv_errors ||
- !(conv= new Item_static_string_func(func_name,
- cstr.ptr(), cstr.length(),
- cstr.charset(),
- collation.derivation)))
+ Item_string *conv= (func_name ?
+ new (mem_root)
+ Item_static_string_func(thd, func_name,
+ s, tocs, &conv_errors,
+ collation.derivation,
+ collation.repertoire) :
+ new (mem_root)
+ Item_string(thd, s, tocs, &conv_errors,
+ collation.derivation,
+ collation.repertoire));
+
+ if (!conv || (conv_errors && lossless))
{
/*
Safe conversion is not possible (or EOM).
@@ -1315,23 +1232,28 @@ Item *Item_static_string_func::safe_charset_converter(CHARSET_INFO *tocs)
*/
return NULL;
}
- conv->str_value.copy();
- /* Ensure that no one is going to change the result string */
- conv->str_value.mark_as_const();
+ if (s->charset() == &my_charset_bin && tocs != &my_charset_bin &&
+ !conv->check_well_formed_result(true))
+ return NULL;
return conv;
}
-bool Item_string::eq(const Item *item, bool binary_cmp) const
+Item *Item_param::safe_charset_converter(THD *thd, CHARSET_INFO *tocs)
{
- if (type() == item->type() && item->basic_const_item())
- {
- if (binary_cmp)
- return !stringcmp(&str_value, &item->str_value);
- return (collation.collation == item->collation.collation &&
- !sortcmp(&str_value, &item->str_value, collation.collation));
- }
- return 0;
+ /*
+ Return "this" if in prepare. result_type may change at execition time,
+ to it's possible that the converter will not be needed at all:
+
+ PREPARE stmt FROM 'SELECT * FROM t1 WHERE field = ?';
+ SET @arg= 1;
+ EXECUTE stmt USING @arg;
+
+ In the above example result_type is STRING_RESULT at prepare time,
+ and INT_RESULT at execution time.
+ */
+ return !const_item() || state == NULL_VALUE ?
+ this : const_charset_converter(thd, tocs, true);
}
@@ -1365,7 +1287,7 @@ bool Item::get_date(MYSQL_TIME *ltime,ulonglong fuzzydate)
ltime, fuzzydate,
field_name_or_null()))
goto err;
- break;
+ return null_value= false;
}
case REAL_RESULT:
{
@@ -1373,7 +1295,7 @@ bool Item::get_date(MYSQL_TIME *ltime,ulonglong fuzzydate)
if (null_value || double_to_datetime_with_warn(value, ltime, fuzzydate,
field_name_or_null()))
goto err;
- break;
+ return null_value= false;
}
case DECIMAL_RESULT:
{
@@ -1382,7 +1304,7 @@ bool Item::get_date(MYSQL_TIME *ltime,ulonglong fuzzydate)
decimal_to_datetime_with_warn(res, ltime, fuzzydate,
field_name_or_null()))
goto err;
- break;
+ return null_value= false;
}
case STRING_RESULT:
{
@@ -1390,23 +1312,44 @@ bool Item::get_date(MYSQL_TIME *ltime,ulonglong fuzzydate)
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) <= MYSQL_TIMESTAMP_ERROR)
+ ltime, fuzzydate))
goto err;
- break;
+ return null_value= false;
}
default:
+ null_value= true;
DBUG_ASSERT(0);
}
- return null_value= 0;
-
err:
+ return null_value|= make_zero_date(ltime, fuzzydate);
+}
+
+
+bool Item::make_zero_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+{
/*
if the item was not null and convertion failed, we return a zero date
if allowed, otherwise - null.
*/
bzero((char*) ltime,sizeof(*ltime));
- return null_value|= !(fuzzydate & TIME_FUZZY_DATES);
+ if (fuzzydate & TIME_TIME_ONLY)
+ {
+ /*
+ In the following scenario:
+ - The caller expected to get a TIME value
+ - Item returned a not NULL string or numeric value
+ - But then conversion from string or number to TIME failed
+ we need to change the default time_type from MYSQL_TIMESTAMP_DATE
+ (which was set in bzero) to MYSQL_TIMESTAMP_TIME and therefore
+ return TIME'00:00:00' rather than DATE'0000-00-00'.
+ If we don't do this, methods like Item::get_time_with_conversion()
+ will erroneously subtract CURRENT_DATE from '0000-00-00 00:00:00'
+ and return TIME'-838:59:59' instead of TIME'00:00:00' as a result.
+ */
+ ltime->time_type= MYSQL_TIMESTAMP_TIME;
+ }
+ return !(fuzzydate & TIME_FUZZY_DATES);
}
bool Item::get_seconds(ulonglong *sec, ulong *sec_part)
@@ -1464,9 +1407,9 @@ int Item::save_in_field_no_warnings(Field *field, bool no_conversions)
Item_sp_variable methods
*****************************************************************************/
-Item_sp_variable::Item_sp_variable(char *sp_var_name_str,
- uint sp_var_name_length)
- :m_thd(0)
+Item_sp_variable::Item_sp_variable(THD *thd, char *sp_var_name_str,
+ uint sp_var_name_length):
+ Item(thd), m_thd(0)
#ifndef DBUG_OFF
, m_sp(0)
#endif
@@ -1574,17 +1517,17 @@ bool Item_sp_variable::is_null()
Item_splocal methods
*****************************************************************************/
-Item_splocal::Item_splocal(const LEX_STRING &sp_var_name,
+Item_splocal::Item_splocal(THD *thd, const LEX_STRING &sp_var_name,
uint sp_var_idx,
enum_field_types sp_var_type,
- uint pos_in_q, uint len_in_q)
- :Item_sp_variable(sp_var_name.str, sp_var_name.length),
- m_var_idx(sp_var_idx),
- limit_clause_param(FALSE),
- pos_in_query(pos_in_q), len_in_query(len_in_q)
+ uint pos_in_q, uint len_in_q):
+ Item_sp_variable(thd, sp_var_name.str, sp_var_name.length),
+ Rewritable_query_parameter(pos_in_q, len_in_q),
+ m_var_idx(sp_var_idx)
{
maybe_null= TRUE;
+ sp_var_type= real_type_to_type(sp_var_type);
m_type= sp_map_item_type(sp_var_type);
m_field_type= sp_var_type;
m_result_type= sp_map_result_type(sp_var_type);
@@ -1636,9 +1579,9 @@ bool Item_splocal::set_value(THD *thd, sp_rcontext *ctx, Item **it)
Item_case_expr methods
*****************************************************************************/
-Item_case_expr::Item_case_expr(uint case_expr_id)
- :Item_sp_variable( C_STRING_WITH_LEN("case_expr")),
- m_case_expr_id(case_expr_id)
+Item_case_expr::Item_case_expr(THD *thd, uint case_expr_id):
+ Item_sp_variable(thd, C_STRING_WITH_LEN("case_expr")),
+ m_case_expr_id(case_expr_id)
{
}
@@ -1726,13 +1669,17 @@ bool Item_name_const::is_null()
}
-Item_name_const::Item_name_const(Item *name_arg, Item *val):
- value_item(val), name_item(name_arg)
+Item_name_const::Item_name_const(THD *thd, Item *name_arg, Item *val):
+ Item(thd), value_item(val), name_item(name_arg)
{
+ StringBuffer<128> name_buffer;
+ String *name_str;
Item::maybe_null= TRUE;
valid_args= true;
- if (!name_item->basic_const_item())
+ if (!name_item->basic_const_item() ||
+ !(name_str= name_item->val_str(&name_buffer))) // Can't have a NULL name
goto err;
+ set_name(name_str->ptr(), name_str->length(), name_str->charset());
if (value_item->basic_const_item())
return; // ok
@@ -1794,25 +1741,18 @@ Item::Type Item_name_const::type() const
bool Item_name_const::fix_fields(THD *thd, Item **ref)
{
- char buf[128];
- String *item_name;
- String s(buf, sizeof(buf), &my_charset_bin);
- s.length(0);
-
if (value_item->fix_fields(thd, &value_item) ||
name_item->fix_fields(thd, &name_item) ||
!value_item->const_item() ||
- !name_item->const_item() ||
- !(item_name= name_item->val_str(&s))) // Can't have a NULL name
+ !name_item->const_item())
{
my_error(ER_RESERVED_SYNTAX, MYF(0), "NAME_CONST");
return TRUE;
}
- if (is_autogenerated_name)
- {
- set_name(item_name->ptr(), (uint) item_name->length(), system_charset_info);
- }
- collation.set(value_item->collation.collation, DERIVATION_IMPLICIT);
+ if (value_item->collation.derivation == DERIVATION_NUMERIC)
+ collation.set_numeric();
+ else
+ collation.set(value_item->collation.collation, DERIVATION_IMPLICIT);
max_length= value_item->max_length;
decimals= value_item->decimals;
fixed= 1;
@@ -1838,9 +1778,10 @@ void Item_name_const::print(String *str, enum_query_type query_type)
class Item_aggregate_ref : public Item_ref
{
public:
- Item_aggregate_ref(Name_resolution_context *context_arg, Item **item,
- const char *table_name_arg, const char *field_name_arg)
- :Item_ref(context_arg, item, table_name_arg, field_name_arg) {}
+ Item_aggregate_ref(THD *thd, Name_resolution_context *context_arg,
+ Item **item, const char *table_name_arg,
+ const char *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)
{
@@ -1858,76 +1799,105 @@ public:
@param thd Thread handler
@param ref_pointer_array Pointer to array of reference fields
- @param fields All fields in select
+ @param fields All fields in select
@param ref Pointer to item
- @param skip_registered <=> function be must skipped for registered
- SUM items
+ @param split_flags Zero or more of the following flags
+ SPLIT_FUNC_SKIP_REGISTERED:
+ Function be must skipped for registered SUM
+ SUM items
+ SPLIT_SUM_SELECT
+ We are called on the select level and have to
+ register items operated on sum function
@note
- This is from split_sum_func2() for items that should be split
-
All found SUM items are added FIRST in the fields list and
we replace the item with a reference.
+ If this is an item in the SELECT list then we also have to split out
+ all arguments to functions used together with the sum function.
+ For example in case of SELECT A*sum(B) we have to split out both
+ A and sum(B).
+ This is not needed for ORDER BY, GROUP BY or HAVING as all references
+ to items in the select list are already of type REF
+
thd->fatal_error() may be called if we are out of memory
*/
void Item::split_sum_func2(THD *thd, Item **ref_pointer_array,
List<Item> &fields, Item **ref,
- bool skip_registered)
+ uint split_flags)
{
- /* An item of type Item_sum is registered <=> ref_by != 0 */
- if (type() == SUM_FUNC_ITEM && skip_registered &&
- ((Item_sum *) this)->ref_by)
- return;
- if ((type() != SUM_FUNC_ITEM && with_sum_func) ||
- (type() == FUNC_ITEM &&
- (((Item_func *) this)->functype() == Item_func::ISNOTNULLTEST_FUNC ||
- ((Item_func *) this)->functype() == Item_func::TRIG_COND_FUNC)))
+ if (unlikely(type() == SUM_FUNC_ITEM))
{
- /* Will split complicated items and ignore simple ones */
- split_sum_func(thd, ref_pointer_array, fields);
+ /* An item of type Item_sum is registered if ref_by != 0 */
+ if ((split_flags & SPLIT_SUM_SKIP_REGISTERED) &&
+ ((Item_sum *) this)->ref_by)
+ return;
}
- else if ((type() == SUM_FUNC_ITEM || (used_tables() & ~PARAM_TABLE_BIT)) &&
- type() != SUBSELECT_ITEM &&
- (type() != REF_ITEM ||
- ((Item_ref*)this)->ref_type() == Item_ref::VIEW_REF))
+ else
{
- /*
- Replace item with a reference so that we can easily calculate
- it (in case of sum functions) or copy it (in case of fields)
-
- The test above is to ensure we don't do a reference for things
- that are constants (PARAM_TABLE_BIT is in effect a constant)
- or already referenced (for example an item in HAVING)
- Exception is Item_direct_view_ref which we need to convert to
- Item_ref to allow fields from view being stored in tmp table.
- */
- Item_aggregate_ref *item_ref;
- uint el= fields.elements;
- DBUG_ASSERT(fields.elements <=
- thd->lex->current_select->ref_pointer_array_size);
- /*
- If this is an item_ref, get the original item
- This is a safety measure if this is called for things that is
- already a reference.
- */
- Item *real_itm= real_item();
+ /* Not a SUM() function */
+ if (unlikely((!with_sum_func && !(split_flags & SPLIT_SUM_SELECT))))
+ {
+ /*
+ This is not a SUM function and there are no SUM functions inside.
+ Nothing more to do.
+ */
+ return;
+ }
+ if (likely(with_sum_func ||
+ (type() == FUNC_ITEM &&
+ (((Item_func *) this)->functype() ==
+ Item_func::ISNOTNULLTEST_FUNC ||
+ ((Item_func *) this)->functype() ==
+ Item_func::TRIG_COND_FUNC))))
+ {
+ /* Will call split_sum_func2() for all items */
+ split_sum_func(thd, ref_pointer_array, fields, split_flags);
+ return;
+ }
- ref_pointer_array[el]= real_itm;
- if (!(item_ref= new Item_aggregate_ref(&thd->lex->current_select->context,
- ref_pointer_array + el, 0, name)))
- return; // fatal_error is set
- if (type() == SUM_FUNC_ITEM)
- item_ref->depended_from= ((Item_sum *) this)->depended_from();
- fields.push_front(real_itm);
- thd->change_item_tree(ref, item_ref);
+ if (unlikely((!(used_tables() & ~PARAM_TABLE_BIT) ||
+ type() == SUBSELECT_ITEM ||
+ (type() == REF_ITEM &&
+ ((Item_ref*)this)->ref_type() != Item_ref::VIEW_REF))))
+ return;
}
+
+ /*
+ Replace item with a reference so that we can easily calculate
+ it (in case of sum functions) or copy it (in case of fields)
+
+ The test above is to ensure we don't do a reference for things
+ that are constants (PARAM_TABLE_BIT is in effect a constant)
+ or already referenced (for example an item in HAVING)
+ Exception is Item_direct_view_ref which we need to convert to
+ Item_ref to allow fields from view being stored in tmp table.
+ */
+ Item_aggregate_ref *item_ref;
+ uint el= fields.elements;
+ /*
+ If this is an item_ref, get the original item
+ This is a safety measure if this is called for things that is
+ already a reference.
+ */
+ Item *real_itm= real_item();
+
+ ref_pointer_array[el]= real_itm;
+ if (!(item_ref= (new (thd->mem_root)
+ Item_aggregate_ref(thd,
+ &thd->lex->current_select->context,
+ ref_pointer_array + el, 0, name))))
+ return; // fatal_error is set
+ if (type() == SUM_FUNC_ITEM)
+ item_ref->depended_from= ((Item_sum *) this)->depended_from();
+ fields.push_front(real_itm);
+ thd->change_item_tree(ref, item_ref);
}
static bool
-left_is_superset(DTCollation *left, DTCollation *right)
+left_is_superset(const DTCollation *left, const DTCollation *right)
{
/* Allow convert to Unicode */
if (left->collation->state & MY_CS_UNICODE &&
@@ -1986,7 +1956,7 @@ left_is_superset(DTCollation *left, DTCollation *right)
@endcode
*/
-bool DTCollation::aggregate(DTCollation &dt, uint flags)
+bool DTCollation::aggregate(const DTCollation &dt, uint flags)
{
if (!my_charset_same(collation, dt.collation))
{
@@ -2118,8 +2088,9 @@ void my_coll_agg_error(Item** args, uint count, const char *fname,
}
-bool agg_item_collations(DTCollation &c, const char *fname,
- Item **av, uint count, uint flags, int item_sep)
+bool Item_func_or_sum::agg_item_collations(DTCollation &c, const char *fname,
+ Item **av, uint count,
+ uint flags, int item_sep)
{
uint i;
Item **arg;
@@ -2164,17 +2135,14 @@ bool agg_item_collations(DTCollation &c, const char *fname,
}
-bool agg_item_collations_for_comparison(DTCollation &c, const char *fname,
- Item **av, uint count, uint flags)
-{
- return (agg_item_collations(c, fname, av, count,
- flags | MY_COLL_DISALLOW_NONE, 1));
-}
-
-
-bool agg_item_set_converter(DTCollation &coll, const char *fname,
- Item **args, uint nargs, uint flags, int item_sep)
+bool Item_func_or_sum::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())
+ return false;
Item **arg, *safe_args[2]= {NULL, NULL};
/*
@@ -2190,7 +2158,6 @@ bool agg_item_set_converter(DTCollation &coll, const char *fname,
safe_args[1]= args[item_sep];
}
- THD *thd= current_thd;
bool res= FALSE;
uint i;
@@ -2205,34 +2172,11 @@ bool agg_item_set_converter(DTCollation &coll, const char *fname,
for (i= 0, arg= args; i < nargs; i++, arg+= item_sep)
{
- Item* conv;
- uint32 dummy_offset;
- if (!String::needs_conversion(1, (*arg)->collation.collation,
- coll.collation,
- &dummy_offset))
+ Item* conv= (*arg)->safe_charset_converter(thd, coll.collation);
+ if (conv == *arg)
continue;
-
- /*
- No needs to add converter if an "arg" is NUMERIC or DATETIME
- value (which is pure ASCII) and at the same time target DTCollation
- is ASCII-compatible. For example, no needs to rewrite:
- SELECT * FROM t1 WHERE datetime_field = '2010-01-01';
- to
- SELECT * FROM t1 WHERE CONVERT(datetime_field USING cs) = '2010-01-01';
-
- TODO: avoid conversion of any values with
- repertoire ASCII and 7bit-ASCII-compatible,
- not only numeric/datetime origin.
- */
- if ((*arg)->collation.derivation == DERIVATION_NUMERIC &&
- (*arg)->collation.repertoire == MY_REPERTOIRE_ASCII &&
- !((*arg)->collation.collation->state & MY_CS_NONASCII) &&
- !(coll.collation->state & MY_CS_NONASCII))
- continue;
-
- if (!(conv= (*arg)->safe_charset_converter(coll.collation)) &&
- ((*arg)->collation.repertoire == MY_REPERTOIRE_ASCII))
- conv= new Item_func_conv_charset(*arg, coll.collation, 1);
+ if (!conv && ((*arg)->collation.repertoire == MY_REPERTOIRE_ASCII))
+ conv= new (thd->mem_root) Item_func_conv_charset(thd, *arg, coll.collation, 1);
if (!conv)
{
@@ -2246,8 +2190,6 @@ bool agg_item_set_converter(DTCollation &coll, const char *fname,
res= TRUE;
break; // we cannot return here, we need to restore "arena".
}
- if ((*arg)->type() == Item::FIELD_ITEM)
- ((Item_field *)(*arg))->no_const_subst= 1;
/*
If in statement prepare, then we create a converter for two
constant items, do it once and then reuse it.
@@ -2275,46 +2217,6 @@ bool agg_item_set_converter(DTCollation &coll, const char *fname,
}
-/*
- Collect arguments' character sets together.
- We allow to apply automatic character set conversion in some cases.
- The conditions when conversion is possible are:
- - arguments A and B have different charsets
- - A wins according to coercibility rules
- (i.e. a column is stronger than a string constant,
- an explicit COLLATE clause is stronger than a column)
- - character set of A is either superset for character set of B,
- or B is a string constant which can be converted into the
- character set of A without data loss.
-
- If all of the above is true, then it's possible to convert
- B into the character set of A, and then compare according
- to the collation of A.
-
- For functions with more than two arguments:
-
- collect(A,B,C) ::= collect(collect(A,B),C)
-
- Since this function calls THD::change_item_tree() on the passed Item **
- pointers, it is necessary to pass the original Item **'s, not copies.
- Otherwise their values will not be properly restored (see BUG#20769).
- If the items are not consecutive (eg. args[2] and args[5]), use the
- item_sep argument, ie.
-
- agg_item_charsets(coll, fname, &args[2], 2, flags, 3)
-
-*/
-
-bool agg_item_charsets(DTCollation &coll, const char *fname,
- Item **args, uint nargs, uint flags, int item_sep)
-{
- if (agg_item_collations(coll, fname, args, nargs, flags, item_sep))
- return TRUE;
-
- return agg_item_set_converter(coll, fname, args, nargs, flags, item_sep);
-}
-
-
void Item_ident_for_show::make_field(Send_field *tmp_field)
{
tmp_field->table_name= tmp_field->org_table_name= table_name;
@@ -2330,9 +2232,9 @@ void Item_ident_for_show::make_field(Send_field *tmp_field)
/**********************************************/
-Item_field::Item_field(Field *f)
- :Item_ident(0, NullS, *f->table_name, f->field_name),
- item_equal(0), no_const_subst(0),
+Item_field::Item_field(THD *thd, Field *f)
+ :Item_ident(thd, 0, NullS, *f->table_name, f->field_name),
+ item_equal(0),
have_privileges(0), any_privileges(0)
{
set_field(f);
@@ -2354,8 +2256,8 @@ Item_field::Item_field(Field *f)
Item_field::Item_field(THD *thd, Name_resolution_context *context_arg,
Field *f)
- :Item_ident(context_arg, f->table->s->db.str, *f->table_name, f->field_name),
- item_equal(0), no_const_subst(0),
+ :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)
{
/*
@@ -2394,14 +2296,14 @@ Item_field::Item_field(THD *thd, Name_resolution_context *context_arg,
}
-Item_field::Item_field(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)
- :Item_ident(context_arg, db_arg,table_name_arg,field_name_arg),
- field(0), result_field(0), item_equal(0), no_const_subst(0),
+ :Item_ident(thd, context_arg, db_arg, table_name_arg, field_name_arg),
+ field(0), item_equal(0),
have_privileges(0), any_privileges(0)
{
- SELECT_LEX *select= current_thd->lex->current_select;
+ SELECT_LEX *select= thd->lex->current_select;
collation.set(DERIVATION_IMPLICIT);
if (select && select->parsing_place != IN_HAVING)
select->select_n_where_fields++;
@@ -2415,9 +2317,7 @@ Item_field::Item_field(Name_resolution_context *context_arg,
Item_field::Item_field(THD *thd, Item_field *item)
:Item_ident(thd, item),
field(item->field),
- result_field(item->result_field),
item_equal(item->item_equal),
- no_const_subst(item->no_const_subst),
have_privileges(item->have_privileges),
any_privileges(item->any_privileges)
{
@@ -2489,7 +2389,7 @@ void Item_field::set_field(Field *field_par)
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=test(field_par->flags & UNSIGNED_FLAG);
+ 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());
@@ -2529,23 +2429,45 @@ bool Item_field::update_table_bitmaps_processor(uchar *arg)
return FALSE;
}
+static inline void set_field_to_new_field(Field **field, Field **new_field)
+{
+ if (*field && (*field)->table == new_field[0]->table)
+ {
+ Field *newf= new_field[(*field)->field_index];
+ if ((*field)->ptr == newf->ptr)
+ *field= newf;
+ }
+}
+
+bool Item_field::switch_to_nullable_fields_processor(uchar *arg)
+{
+ Field **new_fields= (Field **)arg;
+ set_field_to_new_field(&field, new_fields);
+ set_field_to_new_field(&result_field, new_fields);
+ maybe_null= field && field->maybe_null();
+ return 0;
+}
+
const char *Item_ident::full_name() const
{
char *tmp;
if (!table_name || !field_name)
return field_name ? field_name : name ? name : "tmp_field";
+
if (db_name && db_name[0])
{
- tmp=(char*) sql_alloc((uint) strlen(db_name)+(uint) strlen(table_name)+
- (uint) strlen(field_name)+3);
+ 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);
}
else
{
if (table_name[0])
{
- tmp= (char*) sql_alloc((uint) strlen(table_name) +
- (uint) strlen(field_name) + 2);
+ THD *thd= current_thd;
+ tmp= (char*) thd->alloc((uint) strlen(table_name) +
+ (uint) strlen(field_name) + 2);
strxmov(tmp, table_name, ".", field_name, NullS);
}
else
@@ -2585,7 +2507,14 @@ void Item_ident::print(String *str, enum_query_type query_type)
}
if (db_name && db_name[0] && !alias_name_used)
{
- if (!(cached_table && cached_table->belong_to_view &&
+ /*
+ When printing EXPLAIN, don't print database name when it's the same as
+ current database.
+ */
+ bool skip_db= (query_type & QT_ITEM_IDENT_SKIP_CURRENT_DATABASE) &&
+ thd->db && !strcmp(thd->db, db_name);
+ if (!skip_db &&
+ !(cached_table && cached_table->belong_to_view &&
cached_table->belong_to_view->compact_view_format))
{
append_identifier(thd, str, d_name, (uint)strlen(d_name));
@@ -2706,28 +2635,8 @@ my_decimal *Item_field::val_decimal_result(my_decimal *decimal_value)
bool Item_field::val_bool_result()
{
if ((null_value= result_field->is_null()))
- return FALSE;
- switch (result_field->result_type()) {
- case INT_RESULT:
- return result_field->val_int() != 0;
- case DECIMAL_RESULT:
- {
- my_decimal decimal_value;
- my_decimal *val= result_field->val_decimal(&decimal_value);
- if (val)
- return !my_decimal_is_zero(val);
- return 0;
- }
- case REAL_RESULT:
- case STRING_RESULT:
- return result_field->val_real() != 0.0;
- case ROW_RESULT:
- case TIME_RESULT:
- case IMPOSSIBLE_RESULT:
- DBUG_ASSERT(0);
- return 0; // Shut up compiler
- }
- return 0;
+ return false;
+ return result_field->val_bool();
}
@@ -2739,11 +2648,11 @@ bool Item_field::is_null_result()
bool Item_field::eq(const Item *item, bool binary_cmp) const
{
- Item *real_item= ((Item *) item)->real_item();
- if (real_item->type() != FIELD_ITEM)
+ Item *real_item2= ((Item *) item)->real_item();
+ if (real_item2->type() != FIELD_ITEM)
return 0;
- Item_field *item_field= (Item_field*) real_item;
+ Item_field *item_field= (Item_field*) real_item2;
if (item_field->field && field)
return item_field->field == field;
/*
@@ -2779,7 +2688,8 @@ table_map Item_field::all_used_tables() const
return (get_depended_from() ? OUTER_REF_TABLE_BIT : field->table->map);
}
-void Item_field::fix_after_pullout(st_select_lex *new_parent, Item **ref)
+void Item_field::fix_after_pullout(st_select_lex *new_parent, Item **ref,
+ bool merge)
{
if (new_parent == get_depended_from())
depended_from= NULL;
@@ -2823,6 +2733,19 @@ void Item_field::fix_after_pullout(st_select_lex *new_parent, Item **ref)
if (!need_change)
return;
+ if (!merge)
+ {
+ /*
+ It is transformation without merge.
+ This field was "outer" for the inner SELECT where it was taken and
+ moved up.
+ "Outer" fields uses normal SELECT_LEX context of upper SELECTs for
+ name resolution, so we can switch everything to it safely.
+ */
+ this->context= &new_parent->context;
+ return;
+ }
+
Name_resolution_context *ctx= new Name_resolution_context();
if (context->select_lex == new_parent)
{
@@ -2859,7 +2782,7 @@ void Item_field::fix_after_pullout(st_select_lex *new_parent, Item **ref)
Item *Item_field::get_tmp_table_item(THD *thd)
{
- Item_field *new_item= new Item_field(thd, this);
+ Item_field *new_item= new (thd->mem_root) Item_temptable_field(thd, this);
if (new_item)
new_item->field= new_item->result_field;
return new_item;
@@ -2877,7 +2800,8 @@ 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(const char *str_arg, uint length)
+Item_int::Item_int(THD *thd, const char *str_arg, uint length):
+ Item_num(thd)
{
char *end_ptr= (char*) str_arg + length;
int error;
@@ -2910,15 +2834,15 @@ void Item_int::print(String *str, enum_query_type query_type)
}
-Item_uint::Item_uint(const char *str_arg, uint length):
- Item_int(str_arg, length)
+Item_uint::Item_uint(THD *thd, const char *str_arg, uint length):
+ Item_int(thd, str_arg, length)
{
unsigned_flag= 1;
}
-Item_uint::Item_uint(const char *str_arg, longlong i, uint length):
- Item_int(str_arg, i, length)
+Item_uint::Item_uint(THD *thd, const char *str_arg, longlong i, uint length):
+ Item_int(thd, str_arg, i, length)
{
unsigned_flag= 1;
}
@@ -2941,8 +2865,9 @@ void Item_uint::print(String *str, enum_query_type query_type)
}
-Item_decimal::Item_decimal(const char *str_arg, uint length,
- CHARSET_INFO *charset)
+Item_decimal::Item_decimal(THD *thd, const char *str_arg, uint length,
+ CHARSET_INFO *charset):
+ Item_num(thd)
{
str2my_decimal(E_DEC_FATAL_ERROR, str_arg, length, charset, &decimal_value);
name= (char*) str_arg;
@@ -2954,7 +2879,8 @@ Item_decimal::Item_decimal(const char *str_arg, uint length,
unsigned_flag);
}
-Item_decimal::Item_decimal(longlong val, bool unsig)
+Item_decimal::Item_decimal(THD *thd, longlong val, bool unsig):
+ Item_num(thd)
{
int2my_decimal(E_DEC_FATAL_ERROR, val, unsig, &decimal_value);
decimals= (uint8) decimal_value.frac;
@@ -2966,7 +2892,8 @@ Item_decimal::Item_decimal(longlong val, bool unsig)
}
-Item_decimal::Item_decimal(double val, int precision, int scale)
+Item_decimal::Item_decimal(THD *thd, double val, int precision, int scale):
+ Item_num(thd)
{
double2my_decimal(E_DEC_FATAL_ERROR, val, &decimal_value);
decimals= (uint8) decimal_value.frac;
@@ -2978,8 +2905,9 @@ Item_decimal::Item_decimal(double val, int precision, int scale)
}
-Item_decimal::Item_decimal(const char *str, const my_decimal *val_arg,
- uint decimal_par, uint length)
+Item_decimal::Item_decimal(THD *thd, const char *str, const my_decimal *val_arg,
+ uint decimal_par, uint length):
+ Item_num(thd)
{
my_decimal2decimal(val_arg, &decimal_value);
name= (char*) str;
@@ -2989,7 +2917,8 @@ Item_decimal::Item_decimal(const char *str, const my_decimal *val_arg,
}
-Item_decimal::Item_decimal(my_decimal *value_par)
+Item_decimal::Item_decimal(THD *thd, my_decimal *value_par):
+ Item_num(thd)
{
my_decimal2decimal(value_par, &decimal_value);
decimals= (uint8) decimal_value.frac;
@@ -3001,7 +2930,8 @@ Item_decimal::Item_decimal(my_decimal *value_par)
}
-Item_decimal::Item_decimal(const uchar *bin, int precision, int scale)
+Item_decimal::Item_decimal(THD *thd, const uchar *bin, int precision, int scale):
+ Item_num(thd)
{
binary2my_decimal(E_DEC_FATAL_ERROR, bin,
&decimal_value, precision, scale);
@@ -3070,11 +3000,18 @@ 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,
+ max_length);
+}
+
+
String *Item_float::val_str(String *str)
{
// following assert is redundant, because fixed=1 assigned in constructor
DBUG_ASSERT(fixed == 1);
- str->set_real(value,decimals,&my_charset_bin);
+ str->set_real(value, decimals, &my_charset_numeric);
return str;
}
@@ -3088,6 +3025,13 @@ 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,
+ max_length);
+}
+
+
void Item_string::print(String *str, enum_query_type query_type)
{
const bool print_introducer=
@@ -3121,25 +3065,7 @@ void Item_string::print(String *str, enum_query_type query_type)
}
else
{
- if (my_charset_same(str_value.charset(), system_charset_info))
- str_value.print(str); // already in system_charset_info
- else // need to convert
- {
- THD *thd= current_thd;
- LEX_STRING utf8_lex_str;
-
- thd->convert_string(&utf8_lex_str,
- system_charset_info,
- str_value.c_ptr_safe(),
- str_value.length(),
- str_value.charset());
-
- String utf8_str(utf8_lex_str.str,
- utf8_lex_str.length,
- system_charset_info);
-
- utf8_str.print(str);
- }
+ str_value.print(str, system_charset_info);
}
}
else
@@ -3152,66 +3078,10 @@ void Item_string::print(String *str, enum_query_type query_type)
}
-double
-double_from_string_with_check(CHARSET_INFO *cs, const char *cptr,
- const char *end)
-{
- int error;
- char *end_of_num= (char*) end;
- double tmp;
-
- tmp= my_strntod(cs, (char*) cptr, end - cptr, &end_of_num, &error);
- if (error || (end != end_of_num &&
- !check_if_only_end_space(cs, end_of_num, end)))
- {
- ErrConvString err(cptr, end - cptr, cs);
- /*
- We can use err.ptr() here as ErrConvString is guranteed to put an
- end \0 here.
- */
- push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_TRUNCATED_WRONG_VALUE,
- ER(ER_TRUNCATED_WRONG_VALUE), "DOUBLE",
- err.ptr());
- }
- return tmp;
-}
-
-
double Item_string::val_real()
{
DBUG_ASSERT(fixed == 1);
- return double_from_string_with_check(str_value.charset(),
- str_value.ptr(),
- str_value.ptr() +
- str_value.length());
-}
-
-
-longlong
-longlong_from_string_with_check(CHARSET_INFO *cs, const char *cptr,
- const char *end)
-{
- int err;
- longlong tmp;
- char *end_of_num= (char*) end;
-
- tmp= (*(cs->cset->strtoll10))(cs, cptr, &end_of_num, &err);
- /*
- TODO: Give error if we wanted a signed integer and we got an unsigned
- one
- */
- if (!current_thd->no_errors &&
- (err > 0 ||
- (end != end_of_num && !check_if_only_end_space(cs, end_of_num, end))))
- {
- ErrConvString err(cptr, end - cptr, cs);
- push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_TRUNCATED_WRONG_VALUE,
- ER(ER_TRUNCATED_WRONG_VALUE), "INTEGER",
- err.ptr());
- }
- return tmp;
+ return double_from_string_with_check(&str_value);
}
@@ -3222,8 +3092,7 @@ longlong_from_string_with_check(CHARSET_INFO *cs, const char *cptr,
longlong Item_string::val_int()
{
DBUG_ASSERT(fixed == 1);
- return longlong_from_string_with_check(str_value.charset(), str_value.ptr(),
- str_value.ptr()+ str_value.length());
+ return longlong_from_string_with_check(&str_value);
}
@@ -3233,10 +3102,6 @@ my_decimal *Item_string::val_decimal(my_decimal *decimal_value)
}
-bool Item_null::eq(const Item *item, bool binary_cmp) const
-{ return item->type() == type(); }
-
-
double Item_null::val_real()
{
// following assert is redundant, because fixed=1 assigned in constructor
@@ -3266,12 +3131,25 @@ my_decimal *Item_null::val_decimal(my_decimal *decimal_value)
}
-Item *Item_null::safe_charset_converter(CHARSET_INFO *tocs)
+bool Item_null::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+{
+ // following assert is redundant, because fixed=1 assigned in constructor
+ DBUG_ASSERT(fixed == 1);
+ make_zero_date(ltime, fuzzydate);
+ return (null_value= true);
+}
+
+
+Item *Item_null::safe_charset_converter(THD *thd, CHARSET_INFO *tocs)
{
- collation.set(tocs);
return this;
}
+Item *Item_null::clone_item(THD *thd)
+{
+ return new (thd->mem_root) Item_null(thd, name);
+}
+
/*********************** Item_param related ******************************/
/**
@@ -3288,15 +3166,15 @@ default_set_param_func(Item_param *param,
}
-Item_param::Item_param(uint pos_in_query_arg) :
+Item_param::Item_param(THD *thd, uint pos_in_query_arg):
+ Item_basic_value(thd),
+ Rewritable_query_parameter(pos_in_query_arg, 1),
state(NO_VALUE),
item_result_type(STRING_RESULT),
/* Don't pretend to be a literal unless value for this item is set. */
item_type(PARAM_ITEM),
param_type(MYSQL_TYPE_VARCHAR),
- pos_in_query(pos_in_query_arg),
set_param_func(default_set_param_func),
- limit_clause_param(FALSE),
m_out_param_info(NULL)
{
name= (char*) "?";
@@ -3306,8 +3184,6 @@ Item_param::Item_param(uint pos_in_query_arg) :
value is set.
*/
maybe_null= 1;
- cnvitem= new Item_string("", 0, &my_charset_bin, DERIVATION_COERCIBLE);
- cnvstr.set(cnvbuf, sizeof(cnvbuf), &my_charset_bin);
}
@@ -3412,14 +3288,10 @@ void Item_param::set_time(MYSQL_TIME *tm, timestamp_type time_type,
value.time= *tm;
value.time.time_type= time_type;
- if (value.time.year > 9999 || value.time.month > 12 ||
- value.time.day > 31 ||
- (time_type != MYSQL_TIMESTAMP_TIME && value.time.hour > 23) ||
- value.time.minute > 59 || value.time.second > 59 ||
- value.time.second_part > TIME_MAX_SECOND_PART)
+ if (check_datetime_range(&value.time))
{
ErrConvTime str(&value.time);
- make_truncated_value_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ make_truncated_value_warning(current_thd, Sql_condition::WARN_LEVEL_WARN,
&str, time_type, 0);
set_zero_time(&value.time, MYSQL_TIMESTAMP_ERROR);
}
@@ -3523,7 +3395,7 @@ bool Item_param::set_from_user_var(THD *thd, const user_var_entry *entry)
break;
case STRING_RESULT:
{
- CHARSET_INFO *fromcs= entry->collation.collation;
+ CHARSET_INFO *fromcs= entry->charset();
CHARSET_INFO *tocs= thd->variables.collation_connection;
uint32 dummy_offset;
@@ -3563,7 +3435,6 @@ bool Item_param::set_from_user_var(THD *thd, const user_var_entry *entry)
}
case ROW_RESULT:
case TIME_RESULT:
- case IMPOSSIBLE_RESULT:
DBUG_ASSERT(0);
set_null();
}
@@ -3668,17 +3539,14 @@ double Item_param::val_real()
case STRING_VALUE:
case LONG_DATA_VALUE:
{
- int dummy_err;
- char *end_not_used;
- return my_strntod(str_value.charset(), (char*) str_value.ptr(),
- str_value.length(), &end_not_used, &dummy_err);
+ return double_from_string_with_check(&str_value);
}
case TIME_VALUE:
/*
This works for example when user says SELECT ?+0.0 and supplies
time value for the placeholder.
*/
- return ulonglong2double(TIME_to_ulonglong(&value.time));
+ return TIME_to_double(&value.time);
case NULL_VALUE:
return 0.0;
default:
@@ -3707,9 +3575,7 @@ longlong Item_param::val_int()
case STRING_VALUE:
case LONG_DATA_VALUE:
{
- int dummy_err;
- return my_strntoll(str_value.charset(), str_value.ptr(),
- str_value.length(), 10, (char**) 0, &dummy_err);
+ return longlong_from_string_with_check(&str_value);
}
case TIME_VALUE:
return (longlong) TIME_to_ulonglong(&value.time);
@@ -3735,13 +3601,10 @@ my_decimal *Item_param::val_decimal(my_decimal *dec)
return dec;
case STRING_VALUE:
case LONG_DATA_VALUE:
- string2my_decimal(E_DEC_FATAL_ERROR, &str_value, dec);
- return dec;
+ return decimal_from_string_with_check(dec, &str_value);
case TIME_VALUE:
{
- longlong i= (longlong) TIME_to_ulonglong(&value.time);
- int2my_decimal(E_DEC_FATAL_ERROR, i, 0, dec);
- return dec;
+ return TIME_to_my_decimal(&value.time, dec);
}
case NULL_VALUE:
return 0;
@@ -3835,8 +3698,9 @@ const String *Item_param::query_val_str(THD *thd, String* str) const
case LONG_DATA_VALUE:
{
str->length(0);
- append_query_string(thd, value.cs_info.character_set_client, &str_value,
- str);
+ append_query_string(value.cs_info.character_set_client, str,
+ str_value.ptr(), str_value.length(),
+ thd->variables.sql_mode & MODE_NO_BACKSLASH_ESCAPES);
break;
}
case NULL_VALUE:
@@ -3875,18 +3739,14 @@ bool Item_param::convert_str_value(THD *thd)
str_value.set_charset(value.cs_info.final_character_set_of_str_value);
/* Here str_value is guaranteed to be in final_character_set_of_str_value */
- max_length= str_value.numchars() * str_value.charset()->mbmaxlen;
-
- /* For the strings converted to numeric form within some functions */
- decimals= NOT_FIXED_DEC;
/*
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());
- /* Synchronize item charset with value charset */
- collation.set(str_value.charset(), DERIVATION_COERCIBLE);
+ /* Synchronize item charset and length with value charset */
+ fix_charset_and_length_from_str_value(DERIVATION_COERCIBLE);
}
return rc;
}
@@ -3900,23 +3760,28 @@ bool Item_param::basic_const_item() const
}
+/* see comments in the header file */
+
Item *
-Item_param::clone_item()
+Item_param::clone_item(THD *thd)
{
- /* see comments in the header file */
+ MEM_ROOT *mem_root= thd->mem_root;
switch (state) {
case NULL_VALUE:
- return new Item_null(name);
+ return new (mem_root) Item_null(thd, name);
case INT_VALUE:
return (unsigned_flag ?
- new Item_uint(name, value.integer, max_length) :
- new Item_int(name, value.integer, max_length));
+ 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 Item_float(name, value.real, decimals, max_length);
+ return new (mem_root) Item_float(thd, name, value.real, decimals,
+ max_length);
case STRING_VALUE:
case LONG_DATA_VALUE:
- return new Item_string(name, str_value.c_ptr_quick(), str_value.length(),
- str_value.charset());
+ 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:
break;
case NO_VALUE:
@@ -3928,30 +3793,21 @@ Item_param::clone_item()
bool
-Item_param::eq(const Item *arg, bool binary_cmp) const
+Item_param::eq(const Item *item, bool binary_cmp) const
{
- Item *item;
- if (!basic_const_item() || !arg->basic_const_item() || arg->type() != type())
+ if (!basic_const_item())
return FALSE;
- /*
- We need to cast off const to call val_int(). This should be OK for
- a basic constant.
- */
- item= (Item*) arg;
switch (state) {
case NULL_VALUE:
- return TRUE;
+ return null_eq(item);
case INT_VALUE:
- return value.integer == item->val_int() &&
- unsigned_flag == item->unsigned_flag;
+ return int_eq(value.integer, item);
case REAL_VALUE:
- return value.real == item->val_real();
+ return real_eq(value.real, item);
case STRING_VALUE:
case LONG_DATA_VALUE:
- if (binary_cmp)
- return !stringcmp(&str_value, &item->str_value);
- return !sortcmp(&str_value, &item->str_value, collation.collation);
+ return str_eq(&str_value, item, binary_cmp);
default:
break;
}
@@ -4001,17 +3857,14 @@ void Item_param::print(String *str, enum_query_type query_type)
void
Item_param::set_param_type_and_swap_value(Item_param *src)
{
- unsigned_flag= src->unsigned_flag;
+ Type_std_attributes::set(src);
param_type= src->param_type;
set_param_func= src->set_param_func;
item_type= src->item_type;
item_result_type= src->item_result_type;
- collation.set(src->collation);
maybe_null= src->maybe_null;
null_value= src->null_value;
- max_length= src->max_length;
- decimals= src->decimals;
state= src->state;
value= src->value;
@@ -4169,6 +4022,13 @@ void Item_param::make_field(Send_field *field)
field->type= m_out_param_info->type;
}
+bool Item_param::append_for_log(THD *thd, String *str)
+{
+ StringBuffer<STRING_BUFFER_USUAL_SIZE> buf;
+ const String *val= query_val_str(thd, &buf);
+ return str->append(*val);
+}
+
/****************************************************************************
Item_copy_string
@@ -4186,8 +4046,8 @@ double Item_copy_string::val_real()
longlong Item_copy_string::val_int()
{
int err;
- return null_value ? LL(0) : my_strntoll(str_value.charset(),str_value.ptr(),
- str_value.length(),10, (char**) 0,
+ return null_value ? 0 : my_strntoll(str_value.charset(),str_value.ptr(),
+ str_value.length(), 10, (char**) 0,
&err);
}
@@ -4333,12 +4193,13 @@ static bool mark_as_dependent(THD *thd, SELECT_LEX *last, SELECT_LEX *current,
resolved_item->db_name : "");
const char *table_name= (resolved_item->table_name ?
resolved_item->table_name : "");
- push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
- ER_WARN_FIELD_RESOLVED, ER(ER_WARN_FIELD_RESOLVED),
- db_name, (db_name[0] ? "." : ""),
- table_name, (table_name [0] ? "." : ""),
- resolved_item->field_name,
- current->select_number, last->select_number);
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
+ ER_WARN_FIELD_RESOLVED,
+ ER_THD(thd,ER_WARN_FIELD_RESOLVED),
+ db_name, (db_name[0] ? "." : ""),
+ table_name, (table_name [0] ? "." : ""),
+ resolved_item->field_name,
+ current->select_number, last->select_number);
}
DBUG_RETURN(FALSE);
}
@@ -4595,9 +4456,10 @@ resolve_ref_in_select_and_group(THD *thd, Item_ident *ref, SELECT_LEX *select)
!((*group_by_ref)->eq(*select_ref, 0)))
{
ambiguous_fields= TRUE;
- push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_NON_UNIQ_ERROR,
- ER(ER_NON_UNIQ_ERROR), ref->full_name(),
- current_thd->where);
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
+ ER_NON_UNIQ_ERROR,
+ ER_THD(thd,ER_NON_UNIQ_ERROR), ref->full_name(),
+ thd->where);
}
}
@@ -4719,7 +4581,7 @@ bool is_outer_table(TABLE_LIST *table, SELECT_LEX *select)
@retval
0 column fully fixed and fix_fields() should return FALSE
@retval
- -1 error occured
+ -1 error occurred
*/
int
@@ -4806,7 +4668,7 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference)
if (select->join)
{
marker= select->cur_pos_in_select_list;
- select->join->non_agg_fields.push_back(this);
+ select->join->non_agg_fields.push_back(this, thd->mem_root);
}
else
{
@@ -4842,10 +4704,10 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference)
fix_inner_refs() function.
*/
;
- if (!(rf= new Item_outer_ref(context, this)))
+ if (!(rf= new (thd->mem_root) Item_outer_ref(thd, context, this)))
return -1;
thd->change_item_tree(reference, rf);
- select->inner_refs_list.push_back(rf);
+ select->inner_refs_list.push_back(rf, thd->mem_root);
rf->in_sum_func= thd->lex->in_sum_func;
}
/*
@@ -4872,10 +4734,7 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference)
else
{
Item::Type ref_type= (*reference)->type();
- prev_subselect_item->used_tables_cache|=
- (*reference)->used_tables();
- prev_subselect_item->const_item_cache&=
- (*reference)->const_item();
+ prev_subselect_item->used_tables_and_const_cache_join(*reference);
mark_as_dependent(thd, last_checked_context->select_lex,
context->select_lex, this,
((ref_type == REF_ITEM || ref_type == FIELD_ITEM) ?
@@ -4907,8 +4766,7 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference)
if (ref != not_found_item)
{
DBUG_ASSERT(*ref && (*ref)->fixed);
- prev_subselect_item->used_tables_cache|= (*ref)->used_tables();
- prev_subselect_item->const_item_cache&= (*ref)->const_item();
+ prev_subselect_item->used_tables_and_const_cache_join(*ref);
break;
}
}
@@ -4959,20 +4817,24 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference)
save= *ref;
*ref= NULL; // Don't call set_properties()
rf= (place == IN_HAVING ?
- new Item_ref(context, ref, (char*) table_name,
- (char*) field_name, alias_name_used) :
+ new (thd->mem_root)
+ Item_ref(thd, context, ref, (char*) table_name,
+ (char*) field_name, alias_name_used) :
(!select->group_list.elements ?
- new Item_direct_ref(context, ref, (char*) table_name,
- (char*) field_name, alias_name_used) :
- new Item_outer_ref(context, ref, (char*) table_name,
- (char*) field_name, alias_name_used)));
+ new (thd->mem_root)
+ Item_direct_ref(thd, context, ref, (char*) table_name,
+ (char*) field_name, alias_name_used) :
+ new (thd->mem_root)
+ Item_outer_ref(thd, context, ref, (char*) table_name,
+ (char*) field_name, alias_name_used)));
*ref= save;
if (!rf)
return -1;
if (place != IN_HAVING && select->group_list.elements)
{
- outer_context->select_lex->inner_refs_list.push_back((Item_outer_ref*)rf);
+ outer_context->select_lex->inner_refs_list.push_back((Item_outer_ref*)rf,
+ thd->mem_root);
((Item_outer_ref*)rf)->in_sum_func= thd->lex->in_sum_func;
}
thd->change_item_tree(reference, rf);
@@ -4984,6 +4846,11 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference)
if (rf->fix_fields(thd, reference) || rf->check_cols(1))
return -1;
+ /*
+ We can not "move" aggregate function in the place where
+ its arguments are not defined.
+ */
+ set_max_sum_func_level(thd, select);
mark_as_dependent(thd, last_checked_context->select_lex,
context->select_lex, rf,
rf);
@@ -4992,13 +4859,18 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference)
}
else
{
+ /*
+ We can not "move" aggregate function in the place where
+ its arguments are not defined.
+ */
+ set_max_sum_func_level(thd, select);
mark_as_dependent(thd, last_checked_context->select_lex,
context->select_lex,
this, (Item_ident*)*reference);
if (last_checked_context->select_lex->having_fix_field)
{
Item_ref *rf;
- rf= new Item_ref(context, (*from_field)->table->s->db.str,
+ rf= new (thd->mem_root) Item_ref(thd, context, (*from_field)->table->s->db.str,
(*from_field)->table->alias.c_ptr(),
(char*) field_name);
if (!rf)
@@ -5094,7 +4966,8 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
{
uint counter;
enum_resolution_type resolution;
- Item** res= find_item_in_list(this, thd->lex->current_select->item_list,
+ Item** res= find_item_in_list(this,
+ thd->lex->current_select->item_list,
&counter, REPORT_EXCEPT_NOT_FOUND,
&resolution);
if (!res)
@@ -5118,10 +4991,15 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
{
/* The column to which we link isn't valid. */
my_error(ER_BAD_FIELD_ERROR, MYF(0), (*res)->name,
- current_thd->where);
+ thd->where);
return(1);
}
+ /*
+ We can not "move" aggregate function in the place where
+ its arguments are not defined.
+ */
+ set_max_sum_func_level(thd, thd->lex->current_select);
set_field(new_field);
return 0;
}
@@ -5132,11 +5010,13 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
Item_ref to point to the Item in the select list and replace the
Item_field created by the parser with the new Item_ref.
*/
- Item_ref *rf= new Item_ref(context, db_name,table_name,field_name);
+ Item_ref *rf= new (thd->mem_root)
+ Item_ref(thd, context, db_name, table_name,
+ field_name);
if (!rf)
return 1;
- bool ret= rf->fix_fields(thd, (Item **) &rf) || rf->check_cols(1);
- if (ret)
+ bool err= rf->fix_fields(thd, (Item **) &rf) || rf->check_cols(1);
+ if (err)
return TRUE;
SELECT_LEX *select= thd->lex->current_select;
@@ -5144,6 +5024,11 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
select->parsing_place == IN_GROUP_BY &&
alias_name_used ? *rf->ref : rf);
+ /*
+ We can not "move" aggregate function in the place where
+ its arguments are not defined.
+ */
+ set_max_sum_func_level(thd, thd->lex->current_select);
return FALSE;
}
}
@@ -5245,7 +5130,7 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
thd->lex->current_select->cur_pos_in_select_list != UNDEF_POS &&
thd->lex->current_select->join)
{
- thd->lex->current_select->join->non_agg_fields.push_back(this);
+ thd->lex->current_select->join->non_agg_fields.push_back(this, thd->mem_root);
marker= thd->lex->current_select->cur_pos_in_select_list;
}
mark_non_agg_field:
@@ -5281,7 +5166,7 @@ mark_non_agg_field:
else
{
if (outer_fixed)
- thd->lex->in_sum_func->outer_fields.push_back(this);
+ thd->lex->in_sum_func->outer_fields.push_back(this, thd->mem_root);
else if (thd->lex->in_sum_func->nest_level !=
thd->lex->current_select->nest_level)
select_lex->set_non_agg_field_used(true);
@@ -5310,13 +5195,6 @@ bool Item_field::vcol_in_partition_func_processor(uchar *int_arg)
}
-Item *Item_field::safe_charset_converter(CHARSET_INFO *tocs)
-{
- no_const_subst= 1;
- return Item::safe_charset_converter(tocs);
-}
-
-
void Item_field::cleanup()
{
DBUG_ENTER("Item_field::cleanup");
@@ -5327,7 +5205,7 @@ void Item_field::cleanup()
it will be linked correctly next time by name of field and table alias.
I.e. we can drop 'field'.
*/
- field= result_field= 0;
+ field= 0;
item_equal= NULL;
null_value= FALSE;
DBUG_VOID_RETURN;
@@ -5373,75 +5251,6 @@ Item_equal *Item_field::find_item_equal(COND_EQUAL *cond_equal)
/**
- Check whether a field item can be substituted for an equal item
-
- @details
- The function checks whether a substitution of a field item for
- an equal item is valid.
-
- @param arg *arg != NULL <-> the field is in the context
- where substitution for an equal item is valid
-
- @note
- The following statement is not always true:
- @n
- x=y => F(x)=F(x/y).
- @n
- This means substitution of an item for an equal item not always
- yields an equavalent condition. Here's an example:
- @code
- 'a'='a '
- (LENGTH('a')=1) != (LENGTH('a ')=2)
- @endcode
- Such a substitution is surely valid if either the substituted
- field is not of a STRING type or if it is an argument of
- a comparison predicate.
-
- @retval
- TRUE substitution is valid
- @retval
- FALSE otherwise
-*/
-
-bool Item_field::subst_argument_checker(uchar **arg)
-{
- return *arg &&
- (*arg == (uchar *) Item::ANY_SUBST ||
- result_type() != STRING_RESULT ||
- (field->flags & BINARY_FLAG));
-}
-
-
-/**
- Convert a numeric value to a zero-filled string
-
- @param[in,out] item the item to operate on
- @param field The field that this value is equated to
-
- This function converts a numeric value to a string. In this conversion
- the zero-fill flag of the field is taken into account.
- This is required so the resulting string value can be used instead of
- the field reference when propagating equalities.
-*/
-
-static void convert_zerofill_number_to_string(Item **item, Field_num *field)
-{
- char buff[MAX_FIELD_WIDTH],*pos;
- String tmp(buff,sizeof(buff), field->charset()), *res;
-
- res= (*item)->val_str(&tmp);
- if ((*item)->is_null())
- *item= new Item_null();
- else
- {
- field->prepend_zeros(res);
- pos= (char *) sql_strmake (res->ptr(), res->length());
- *item= new Item_string(pos, res->length(), field->charset());
- }
-}
-
-
-/**
Set a pointer to the multiple equality the field reference belongs to
(if any).
@@ -5465,47 +5274,44 @@ static void convert_zerofill_number_to_string(Item **item, Field_num *field)
- pointer to the field item, otherwise.
*/
-Item *Item_field::equal_fields_propagator(uchar *arg)
+Item *Item_field::propagate_equal_fields(THD *thd,
+ const Context &ctx,
+ COND_EQUAL *arg)
{
- if (no_const_subst)
+ if (!(item_equal= find_item_equal(arg)))
return this;
- item_equal= find_item_equal((COND_EQUAL *) arg);
- Item *item= 0;
- if (item_equal)
- item= item_equal->get_const();
- /*
- Disable const propagation for items used in different comparison contexts.
- This must be done because, for example, Item_hex_string->val_int() is not
- the same as (Item_hex_string->val_str() in BINARY column)->val_int().
- We cannot simply disable the replacement in a particular context (
- e.g. <bin_col> = <int_col> AND <bin_col> = <hex_string>) since
- Items don't know the context they are in and there are functions like
- IF (<hex_string>, 'yes', 'no').
- */
- if (!item || !has_compatible_context(item))
- item= this;
- else if (field && (field->flags & ZEROFILL_FLAG) && IS_NUM(field->type()))
+ if (!field->can_be_substituted_to_equal_item(ctx, item_equal))
{
- if (item && (cmp_context == STRING_RESULT || cmp_context == IMPOSSIBLE_RESULT))
- convert_zerofill_number_to_string(&item, (Field_num *)field);
- else
- item= this;
+ item_equal= NULL;
+ return this;
}
- return item;
-}
-
-
-/**
- Mark the item to not be part of substitution if it's not a binary item.
-
- See comments in Arg_comparator::set_compare_func() for details.
-*/
+ Item *item= item_equal->get_const();
+ if (!item)
+ {
+ /*
+ The found Item_equal is Okey, but it does not have a constant
+ item yet. Keep this->item_equal point to the found Item_equal.
+ */
+ return this;
+ }
+ if (!(item= field->get_equal_const_item(thd, ctx, item)))
+ {
+ /*
+ Could not do safe conversion from the original constant item
+ to a field-compatible constant item.
+ For example, we tried to optimize:
+ WHERE date_column=' garbage ' AND LENGTH(date_column)=8;
+ to
+ WHERE date_column=' garbage ' AND LENGTH(DATE'XXXX-YY-ZZ');
+ but failed to create a valid DATE literal from the given string literal.
-bool Item_field::set_no_const_sub(uchar *arg)
-{
- if (field->charset() != &my_charset_bin)
- no_const_subst=1;
- return FALSE;
+ Do not do constant propagation in such cases and unlink
+ "this" from the found Item_equal (as this equality not usefull).
+ */
+ item_equal= NULL;
+ return this;
+ }
+ return item;
}
@@ -5535,17 +5341,28 @@ bool Item_field::set_no_const_sub(uchar *arg)
- this - otherwise.
*/
-Item *Item_field::replace_equal_field(uchar *arg)
+Item *Item_field::replace_equal_field(THD *thd, uchar *arg)
{
REPLACE_EQUAL_FIELD_ARG* param= (REPLACE_EQUAL_FIELD_ARG*)arg;
if (item_equal && item_equal == param->item_equal)
{
- Item *const_item= item_equal->get_const();
- if (const_item)
+ Item *const_item2= item_equal->get_const();
+ if (const_item2)
{
- if (!has_compatible_context(const_item))
- return this;
- return const_item;
+ /*
+ Currently we don't allow to create Item_equal with compare_type()
+ different from its Item_field's cmp_type().
+ Field_xxx::test_if_equality_guarantees_uniqueness() prevent this.
+ Also, Item_field::propagate_equal_fields() does not allow to assign
+ this->item_equal to any instances of Item_equal if "this" is used
+ in a non-native comparison context, or with an incompatible collation.
+ So the fact that we have (item_equal != NULL) means that the currently
+ processed function (the owner of "this") uses the field in its native
+ comparison context, and it's safe to replace it to the constant from
+ item_equal.
+ */
+ DBUG_ASSERT(cmp_type() == item_equal->compare_type());
+ return const_item2;
}
Item_field *subst=
(Item_field *)(item_equal->get_first(param->context_tab, this));
@@ -5584,17 +5401,6 @@ void Item::make_field(Send_field *tmp_field)
}
-enum_field_types Item::string_field_type() const
-{
- enum_field_types f_type= MYSQL_TYPE_VAR_STRING;
- if (max_length >= 16777216)
- f_type= MYSQL_TYPE_LONG_BLOB;
- else if (max_length >= 65536)
- f_type= MYSQL_TYPE_MEDIUM_BLOB;
- return f_type;
-}
-
-
void Item_empty_string::make_field(Send_field *tmp_field)
{
init_make_field(tmp_field, string_field_type());
@@ -5610,7 +5416,6 @@ enum_field_types Item::field_type() const
case REAL_RESULT: return MYSQL_TYPE_DOUBLE;
case ROW_RESULT:
case TIME_RESULT:
- case IMPOSSIBLE_RESULT:
DBUG_ASSERT(0);
return MYSQL_TYPE_VARCHAR;
}
@@ -5634,10 +5439,7 @@ String *Item::check_well_formed_result(String *str, bool send_error)
{
/* Check whether we got a well-formed string */
CHARSET_INFO *cs= str->charset();
- int well_formed_error;
- uint wlen= cs->cset->well_formed_len(cs,
- str->ptr(), str->ptr() + str->length(),
- str->length(), &well_formed_error);
+ uint wlen= str->well_formed_length();
null_value= false;
if (wlen < str->length())
{
@@ -5652,8 +5454,7 @@ String *Item::check_well_formed_result(String *str, bool send_error)
cs->csname, hexbuf);
return 0;
}
- if ((thd->variables.sql_mode &
- (MODE_STRICT_TRANS_TABLES | MODE_STRICT_ALL_TABLES)))
+ if (thd->is_strict_mode())
{
null_value= 1;
str= 0;
@@ -5662,12 +5463,53 @@ String *Item::check_well_formed_result(String *str, bool send_error)
{
str->length(wlen);
}
- push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_INVALID_CHARACTER_STRING,
- ER(ER_INVALID_CHARACTER_STRING), cs->csname, hexbuf);
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
+ ER_INVALID_CHARACTER_STRING,
+ ER_THD(thd, ER_INVALID_CHARACTER_STRING), cs->csname,
+ hexbuf);
}
return str;
}
+
+/**
+ Copy a string with optional character set conversion.
+*/
+bool
+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)))
+ return true; // EOM
+ if (const char *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,
+ ER_INVALID_CHARACTER_STRING,
+ ER_THD(m_thd, ER_INVALID_CHARACTER_STRING),
+ srccs == &my_charset_bin ?
+ dstcs->csname : srccs->csname,
+ err.ptr());
+ return false;
+ }
+ if (const char *pos= cannot_convert_error_pos())
+ {
+ char buf[16];
+ int mblen= srccs->cset->charlen(srccs, (const uchar *) pos,
+ (const uchar *) src + src_length);
+ DBUG_ASSERT(mblen > 0 && mblen * 2 + 1 <= (int) sizeof(buf));
+ octet2hex(buf, pos, mblen);
+ push_warning_printf(m_thd, Sql_condition::WARN_LEVEL_WARN,
+ ER_CANNOT_CONVERT_CHARACTER,
+ ER_THD(m_thd, ER_CANNOT_CONVERT_CHARACTER),
+ srccs->csname, buf, dstcs->csname);
+ return false;
+ }
+ return false;
+}
+
+
/*
Compare two items using a given collation
@@ -5725,22 +5567,26 @@ bool Item::eq_by_collation(Item *item, bool binary_cmp, CHARSET_INFO *cs)
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 Field_blob(max_length, maybe_null, name,
- collation.collation, TRUE);
+ 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 Field_varstring(max_length, maybe_null, name, table->s,
- collation.collation);
+ field= new (mem_root)
+ Field_varstring(max_length, maybe_null, name, table->s,
+ collation.collation);
else
- field= new Field_string(max_length, maybe_null, name,
- collation.collation);
+ field= new (mem_root)
+ Field_string(max_length, maybe_null, name, collation.collation);
if (field)
field->init(table);
return field;
@@ -5759,83 +5605,94 @@ Field *Item::make_string_field(TABLE *table)
\# Created field
*/
-Field *Item::tmp_table_field_from_field_type(TABLE *table, bool fixed_length)
+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(this);
+ field= Field_new_decimal::create_from_item(mem_root, this);
break;
case MYSQL_TYPE_TINY:
- field= new Field_tiny((uchar*) 0, max_length, null_ptr, 0, Field::NONE,
- name, 0, unsigned_flag);
+ 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 Field_short((uchar*) 0, max_length, null_ptr, 0, Field::NONE,
- name, 0, unsigned_flag);
+ 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 Field_long((uchar*) 0, max_length, null_ptr, 0, Field::NONE,
- name, 0, unsigned_flag);
+ 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 Field_longlong((uchar*) 0, max_length, null_ptr, 0, Field::NONE,
- name, 0, unsigned_flag);
+ 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 Field_float((uchar*) 0, max_length, null_ptr, 0, Field::NONE,
- name, decimals, 0, unsigned_flag);
+ 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 Field_double((uchar*) 0, max_length, null_ptr, 0, Field::NONE,
- name, decimals, 0, unsigned_flag);
+ 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 Field_medium((uchar*) 0, max_length, null_ptr, 0, Field::NONE,
- name, 0, unsigned_flag);
+ 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 Field_newdate(0, null_ptr, 0, Field::NONE, name, &my_charset_bin);
+ field= new (mem_root)
+ Field_newdate(0, null_ptr, 0, Field::NONE, name);
break;
case MYSQL_TYPE_TIME:
- field= new_Field_time(0, null_ptr, 0, Field::NONE, name,
- decimals, &my_charset_bin);
+ field= new_Field_time(mem_root, 0, null_ptr, 0, Field::NONE, name,
+ decimals);
break;
case MYSQL_TYPE_TIMESTAMP:
- field= new_Field_timestamp(0, null_ptr, 0,
- Field::NONE, name, 0, decimals, &my_charset_bin);
+ field= new_Field_timestamp(mem_root, 0, null_ptr, 0,
+ Field::NONE, name, 0, decimals);
break;
case MYSQL_TYPE_DATETIME:
- field= new_Field_datetime(0, null_ptr, 0, Field::NONE, name,
- decimals, &my_charset_bin);
+ field= new_Field_datetime(mem_root, 0, null_ptr, 0, Field::NONE, name,
+ decimals);
break;
case MYSQL_TYPE_YEAR:
- field= new Field_year((uchar*) 0, max_length, null_ptr, 0, Field::NONE,
- name);
+ field= new (mem_root)
+ Field_year((uchar*) 0, max_length, null_ptr, 0, Field::NONE, name);
break;
case MYSQL_TYPE_BIT:
- field= new Field_bit_as_char(NULL, max_length, null_ptr, 0,
- Field::NONE, name);
+ 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_STRING:
case MYSQL_TYPE_NULL:
+ case MYSQL_TYPE_STRING:
if (fixed_length && !too_big_for_varchar())
{
- field= new Field_string(max_length, maybe_null, name,
- collation.collation);
+ field= new (mem_root)
+ Field_string(max_length, maybe_null, name, collation.collation);
break;
}
/* fall through */
@@ -5848,16 +5705,14 @@ Field *Item::tmp_table_field_from_field_type(TABLE *table, bool fixed_length)
case MYSQL_TYPE_MEDIUM_BLOB:
case MYSQL_TYPE_LONG_BLOB:
case MYSQL_TYPE_BLOB:
- if (this->type() == Item::TYPE_HOLDER)
- field= new Field_blob(max_length, maybe_null, name, collation.collation,
- 1);
- else
- field= new Field_blob(max_length, maybe_null, name, collation.collation);
+ 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 Field_geom(max_length, maybe_null,
- name, table->s, get_geometry_type());
+ field= new (mem_root)
+ Field_geom(max_length, maybe_null, name, table->s, get_geometry_type());
#endif /* HAVE_SPATIAL */
}
if (field)
@@ -5931,13 +5786,51 @@ static int save_field_in_field(Field *from, bool *null_value,
}
+static int memcpy_field_value(Field *to, Field *from)
+{
+ if (to->ptr != from->ptr)
+ memcpy(to->ptr,from->ptr, to->pack_length());
+ return 0;
+}
+
+fast_field_copier Item_field::setup_fast_field_copier(Field *to)
+{
+ DBUG_ENTER("Item_field::setup_fast_field_copier");
+ DBUG_RETURN(memcpy_field_possible(to, field) ?
+ &memcpy_field_value :
+ &field_conv_incompatible);
+}
+
+
/**
Set a field's value from a item.
*/
-void Item_field::save_org_in_field(Field *to)
+void Item_field::save_org_in_field(Field *to,
+ fast_field_copier fast_field_copier_func)
{
- save_field_in_field(field, &null_value, to, TRUE);
+ DBUG_ENTER("Item_field::save_org_in_field");
+ DBUG_PRINT("enter", ("setup: 0x%lx data: 0x%lx",
+ (ulong) to, (ulong) fast_field_copier_func));
+ if (fast_field_copier_func)
+ {
+ if (field->is_null())
+ {
+ null_value= TRUE;
+ set_field_to_null_with_conversions(to, TRUE);
+ DBUG_VOID_RETURN;
+ }
+ to->set_notnull();
+ if (to == field)
+ {
+ null_value= 0;
+ DBUG_VOID_RETURN;
+ }
+ (*fast_field_copier_func)(to, field);
+ }
+ else
+ save_field_in_field(field, &null_value, to, TRUE);
+ DBUG_VOID_RETURN;
}
@@ -6052,6 +5945,14 @@ 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(),
+ str_value.length(), collation.collation);
+}
+
+
static int save_int_value_in_field (Field *field, longlong nr,
bool null_value, bool unsigned_flag)
{
@@ -6068,6 +5969,12 @@ 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);
+}
+
+
void Item_datetime::set(longlong packed)
{
unpack_time(packed, &ltime);
@@ -6091,25 +5998,7 @@ int Item_decimal::save_in_field(Field *field, bool no_conversions)
}
-bool Item_int::eq(const Item *arg, bool binary_cmp) const
-{
- /* No need to check for null value as basic constant can't be NULL */
- if (arg->basic_const_item() && arg->type() == type())
- {
- /*
- We need to cast off const to call val_int(). This should be OK for
- a basic constant.
- */
- Item *item= (Item*) arg;
- return (item->val_int() == value &&
- ((longlong) value >= 0 ||
- (item->unsigned_flag == unsigned_flag)));
- }
- return FALSE;
-}
-
-
-Item *Item_int_with_ref::clone_item()
+Item *Item_int_with_ref::clone_item(THD *thd)
{
DBUG_ASSERT(ref->const_item());
/*
@@ -6117,18 +6006,25 @@ Item *Item_int_with_ref::clone_item()
parameter markers.
*/
return (ref->unsigned_flag ?
- new Item_uint(ref->name, ref->val_int(), ref->max_length) :
- new Item_int(ref->name, ref->val_int(), ref->max_length));
+ new (thd->mem_root)
+ Item_uint(thd, ref->name, ref->val_int(), ref->max_length) :
+ new (thd->mem_root)
+ Item_int(thd, ref->name, ref->val_int(), ref->max_length));
}
-Item_num *Item_uint::neg()
+Item_num *Item_uint::neg(THD *thd)
{
- Item_decimal *item= new Item_decimal(value, 1);
- return item->neg();
+ Item_decimal *item= new (thd->mem_root) Item_decimal(thd, value, 1);
+ return item->neg(thd);
}
+Item *Item_uint::clone_item(THD *thd)
+{
+ return new (thd->mem_root) Item_uint(thd, name, value, max_length);
+}
+
static uint nr_of_decimals(const char *str, const char *end)
{
const char *decimal_point;
@@ -6183,7 +6079,8 @@ 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(const char *str_arg, uint length)
+Item_float::Item_float(THD *thd, const char *str_arg, uint length):
+ Item_num(thd)
{
int error;
char *end_not_used;
@@ -6226,27 +6123,6 @@ void Item_float::print(String *str, enum_query_type query_type)
}
-/*
- hex item
- In string context this is a binary string.
- In number context this is a longlong value.
-*/
-
-bool Item_float::eq(const Item *arg, bool binary_cmp) const
-{
- if (arg->basic_const_item() && arg->type() == type())
- {
- /*
- We need to cast off const to call val_int(). This should be OK for
- a basic constant.
- */
- Item *item= (Item*) arg;
- return item->val_real() == value;
- }
- return FALSE;
-}
-
-
inline uint char_val(char X)
{
return (uint) (X >= '0' && X <= '9' ? X-'0' :
@@ -6255,10 +6131,11 @@ inline uint char_val(char X)
}
-void Item_hex_constant::hex_string_init(const char *str, uint str_length)
+void Item_hex_constant::hex_string_init(THD *thd, const char *str,
+ uint str_length)
{
max_length=(str_length+1)/2;
- char *ptr=(char*) sql_alloc(max_length+1);
+ char *ptr=(char*) thd->alloc(max_length+1);
if (!ptr)
{
str_value.set("", 0, &my_charset_bin);
@@ -6284,7 +6161,7 @@ longlong Item_hex_hybrid::val_int()
// following assert is redundant, because fixed=1 assigned in constructor
DBUG_ASSERT(fixed == 1);
char *end=(char*) str_value.ptr()+str_value.length(),
- *ptr=end-min(str_value.length(),sizeof(longlong));
+ *ptr=end-MY_MIN(str_value.length(),sizeof(longlong));
ulonglong value=0;
for (; ptr != end ; ptr++)
@@ -6302,8 +6179,6 @@ int Item_hex_hybrid::save_in_field(Field *field, bool no_conversions)
ulonglong nr;
uint32 length= str_value.length();
- if (!length)
- return 1;
if (length > 8)
{
@@ -6320,7 +6195,7 @@ int Item_hex_hybrid::save_in_field(Field *field, bool no_conversions)
warn:
if (!field->store((longlong) nr, TRUE))
- field->set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE,
+ field->set_warning(Sql_condition::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE,
1);
return 1;
}
@@ -6328,7 +6203,7 @@ warn:
void Item_hex_hybrid::print(String *str, enum_query_type query_type)
{
- uint32 len= min(str_value.length(), sizeof(longlong));
+ uint32 len= MY_MIN(str_value.length(), sizeof(longlong));
const char *ptr= str_value.ptr() + str_value.length() - len;
str->append("0x");
str->append_hex(ptr, len);
@@ -6343,47 +6218,22 @@ void Item_hex_string::print(String *str, enum_query_type query_type)
}
-bool Item_hex_constant::eq(const Item *arg, bool binary_cmp) const
-{
- if (arg->basic_const_item() && arg->type() == type() &&
- arg->cast_to_int_type() == cast_to_int_type())
- {
- if (binary_cmp)
- return !stringcmp(&str_value, &arg->str_value);
- return !sortcmp(&str_value, &arg->str_value, collation.collation);
- }
- return FALSE;
-}
-
-
-Item *Item_hex_constant::safe_charset_converter(CHARSET_INFO *tocs)
-{
- Item_string *conv;
- String tmp, *str= val_str(&tmp);
-
- if (!(conv= new Item_string(str->ptr(), str->length(), tocs)))
- return NULL;
- conv->str_value.copy();
- conv->str_value.mark_as_const();
- return conv;
-}
-
-
/*
bin item.
In string context this is a binary string.
In number context this is a longlong value.
*/
-Item_bin_string::Item_bin_string(const char *str, uint str_length)
+Item_bin_string::Item_bin_string(THD *thd, const char *str, uint str_length):
+ Item_hex_hybrid(thd)
{
const char *end= str + str_length - 1;
+ char *ptr;
uchar bits= 0;
uint power= 1;
max_length= (str_length + 7) >> 3;
- char *ptr= (char*) sql_alloc(max_length + 1);
- if (!ptr)
+ if (!(ptr= (char*) thd->alloc(max_length + 1)))
return;
str_value.set(ptr, max_length, &my_charset_bin);
@@ -6413,6 +6263,96 @@ Item_bin_string::Item_bin_string(const char *str, uint str_length)
}
+bool Item_temporal_literal::eq(const Item *item, bool binary_cmp) const
+{
+ return
+ item->basic_const_item() && type() == item->type() &&
+ field_type() == ((Item_temporal_literal *) item)->field_type() &&
+ !my_time_compare(&cached_time,
+ &((Item_temporal_literal *) item)->cached_time);
+}
+
+
+void Item_date_literal::print(String *str, enum_query_type query_type)
+{
+ str->append("DATE'");
+ char buf[MAX_DATE_STRING_REP_LENGTH];
+ my_date_to_str(&cached_time, buf);
+ str->append(buf);
+ str->append('\'');
+}
+
+
+Item *Item_date_literal::clone_item(THD *thd)
+{
+ return new (thd->mem_root) Item_date_literal(thd, &cached_time);
+}
+
+
+bool Item_date_literal::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
+{
+ DBUG_ASSERT(fixed);
+ fuzzy_date |= sql_mode_for_dates(current_thd);
+ *ltime= cached_time;
+ return (null_value= check_date_with_warn(ltime, fuzzy_date,
+ MYSQL_TIMESTAMP_ERROR));
+}
+
+
+void Item_datetime_literal::print(String *str, enum_query_type query_type)
+{
+ str->append("TIMESTAMP'");
+ char buf[MAX_DATE_STRING_REP_LENGTH];
+ my_datetime_to_str(&cached_time, buf, decimals);
+ str->append(buf);
+ str->append('\'');
+}
+
+
+Item *Item_datetime_literal::clone_item(THD *thd)
+{
+ return new (thd->mem_root) Item_datetime_literal(thd, &cached_time, decimals);
+}
+
+
+bool Item_datetime_literal::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
+{
+ DBUG_ASSERT(fixed);
+ fuzzy_date |= sql_mode_for_dates(current_thd);
+ *ltime= cached_time;
+ return (null_value= check_date_with_warn(ltime, fuzzy_date,
+ MYSQL_TIMESTAMP_ERROR));
+}
+
+
+void Item_time_literal::print(String *str, enum_query_type query_type)
+{
+ str->append("TIME'");
+ char buf[MAX_DATE_STRING_REP_LENGTH];
+ my_time_to_str(&cached_time, buf, decimals);
+ str->append(buf);
+ str->append('\'');
+}
+
+
+Item *Item_time_literal::clone_item(THD *thd)
+{
+ return new (thd->mem_root) Item_time_literal(thd, &cached_time, decimals);
+}
+
+
+bool Item_time_literal::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
+{
+ DBUG_ASSERT(fixed);
+ *ltime= cached_time;
+ if (fuzzy_date & TIME_TIME_ONLY)
+ return (null_value= false);
+ return (null_value= check_date_with_warn(ltime, fuzzy_date,
+ MYSQL_TIMESTAMP_ERROR));
+}
+
+
+
/**
Pack data in buffer for sending.
*/
@@ -6514,7 +6454,7 @@ bool Item::send(Protocol *protocol, String *buffer)
case MYSQL_TYPE_TIMESTAMP:
{
MYSQL_TIME tm;
- get_date(&tm, sql_mode_for_dates());
+ get_date(&tm, sql_mode_for_dates(current_thd));
if (!null_value)
{
if (f_type == MYSQL_TYPE_DATE)
@@ -6563,6 +6503,7 @@ bool Item::cache_const_expr_analyzer(uchar **arg)
item->type() == Item::NULL_ITEM || /* Item_name_const hack */
item->type() == Item::FIELD_ITEM ||
item->type() == SUBSELECT_ITEM ||
+ item->type() == CACHE_ITEM ||
/*
Do not cache GET_USER_VAR() function as its const_item() may
return TRUE for the current thread but it still may change
@@ -6586,21 +6527,28 @@ bool Item::cache_const_expr_analyzer(uchar **arg)
@return this otherwise.
*/
-Item* Item::cache_const_expr_transformer(uchar *arg)
+Item* Item::cache_const_expr_transformer(THD *thd, uchar *arg)
{
if (*(bool*)arg)
{
*((bool*)arg)= FALSE;
- Item_cache *cache= Item_cache::get_cache(this);
+ Item_cache *cache= Item_cache::get_cache(thd, this);
if (!cache)
return NULL;
- cache->setup(this);
+ cache->setup(thd, this);
cache->store(this);
return cache;
}
return this;
}
+/**
+ Find Item by reference in the expression
+*/
+bool Item::find_item_processor(uchar *arg)
+{
+ return (this == ((Item *) arg));
+}
bool Item_field::send(Protocol *protocol, String *buffer)
{
@@ -6608,6 +6556,18 @@ bool Item_field::send(Protocol *protocol, String *buffer)
}
+Item* Item::propagate_equal_fields_and_change_item_tree(THD *thd,
+ const Context &ctx,
+ COND_EQUAL *cond,
+ Item **place)
+{
+ Item *item= propagate_equal_fields(thd, ctx, cond);
+ if (item && item != this)
+ thd->change_item_tree(place, item);
+ return item;
+}
+
+
void Item_field::update_null_value()
{
/*
@@ -6641,12 +6601,12 @@ void Item_field::update_null_value()
UPDATE statement.
RETURN
- 0 if error occured
+ 0 if error occurred
ref if all conditions are met
this field otherwise
*/
-Item *Item_field::update_value_transformer(uchar *select_arg)
+Item *Item_field::update_value_transformer(THD *thd, uchar *select_arg)
{
SELECT_LEX *select= (SELECT_LEX*)select_arg;
DBUG_ASSERT(fixed);
@@ -6661,9 +6621,10 @@ Item *Item_field::update_value_transformer(uchar *select_arg)
Item_ref *ref;
ref_pointer_array[el]= (Item*)this;
- all_fields->push_front((Item*)this);
- ref= new Item_ref(&select->context, ref_pointer_array + el,
- table_name, field_name);
+ 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);
return ref;
}
return this;
@@ -6682,12 +6643,22 @@ void Item_field::print(String *str, enum_query_type query_type)
}
-Item_ref::Item_ref(Name_resolution_context *context_arg,
+void Item_temptable_field::print(String *str, enum_query_type query_type)
+{
+ /*
+ Item_ident doesn't have references to the underlying Field/TABLE objects,
+ so it's ok to use the following:
+ */
+ Item_ident::print(str, 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,
- bool alias_name_used_arg)
- :Item_ident(context_arg, NullS, table_name_arg, field_name_arg),
- result_field(0), ref(item), reference_trough_name(0)
+ bool alias_name_used_arg):
+ Item_ident(thd, context_arg, NullS, table_name_arg, field_name_arg),
+ ref(item), reference_trough_name(0)
{
alias_name_used= alias_name_used_arg;
/*
@@ -6732,10 +6703,10 @@ public:
}
};
-Item_ref::Item_ref(TABLE_LIST *view_arg, Item **item,
- const char *field_name_arg, bool alias_name_used_arg)
- :Item_ident(view_arg, field_name_arg),
- result_field(NULL), ref(item), reference_trough_name(0)
+Item_ref::Item_ref(THD *thd, TABLE_LIST *view_arg, Item **item,
+ const char *field_name_arg, bool alias_name_used_arg):
+ Item_ident(thd, view_arg, field_name_arg),
+ ref(item), reference_trough_name(0)
{
alias_name_used= alias_name_used_arg;
/*
@@ -6868,8 +6839,7 @@ bool Item_ref::fix_fields(THD *thd, Item **reference)
if (ref != not_found_item)
{
DBUG_ASSERT(*ref && (*ref)->fixed);
- prev_subselect_item->used_tables_cache|= (*ref)->used_tables();
- prev_subselect_item->const_item_cache&= (*ref)->const_item();
+ prev_subselect_item->used_tables_and_const_cache_join(*ref);
break;
}
/*
@@ -6913,10 +6883,7 @@ bool Item_ref::fix_fields(THD *thd, Item **reference)
if (from_field == view_ref_found)
{
Item::Type refer_type= (*reference)->type();
- prev_subselect_item->used_tables_cache|=
- (*reference)->used_tables();
- prev_subselect_item->const_item_cache&=
- (*reference)->const_item();
+ prev_subselect_item->used_tables_and_const_cache_join(*reference);
DBUG_ASSERT((*reference)->type() == REF_ITEM);
mark_as_dependent(thd, last_checked_context->select_lex,
context->select_lex, this,
@@ -6969,7 +6936,7 @@ bool Item_ref::fix_fields(THD *thd, Item **reference)
if (from_field != not_found_field)
{
Item_field* fld;
- if (!(fld= new Item_field(from_field)))
+ if (!(fld= new (thd->mem_root) Item_field(thd, from_field)))
goto error;
thd->change_item_tree(reference, fld);
mark_as_dependent(thd, last_checked_context->select_lex,
@@ -7009,19 +6976,6 @@ bool Item_ref::fix_fields(THD *thd, Item **reference)
last_checked_context->select_lex->nest_level);
}
}
- else if (ref_type() != VIEW_REF)
- {
- /*
- It could be that we're referring to something that's in ancestor selects.
- We must make an appropriate mark_as_dependent() call for each such
- outside reference.
- */
- Dependency_marker dep_marker;
- dep_marker.current_select= current_sel;
- dep_marker.thd= thd;
- (*ref)->walk(&Item::enumerate_field_refs_processor, FALSE,
- (uchar*)&dep_marker);
- }
DBUG_ASSERT(*ref);
/*
@@ -7058,10 +7012,8 @@ error:
void Item_ref::set_properties()
{
- max_length= (*ref)->max_length;
+ Type_std_attributes::set(*ref);
maybe_null= (*ref)->maybe_null;
- decimals= (*ref)->decimals;
- collation.set((*ref)->collation);
/*
We have to remember if we refer to a sum function, to ensure that
split_sum_func() doesn't try to change the reference.
@@ -7069,7 +7021,6 @@ void Item_ref::set_properties()
with_sum_func= (*ref)->with_sum_func;
with_param= (*ref)->with_param;
with_field= (*ref)->with_field;
- unsigned_flag= (*ref)->unsigned_flag;
fixed= 1;
if (alias_name_used)
return;
@@ -7084,7 +7035,6 @@ void Item_ref::cleanup()
{
DBUG_ENTER("Item_ref::cleanup");
Item_ident::cleanup();
- result_field= 0;
if (reference_trough_name)
{
/* We have to reset the reference as it may been freed */
@@ -7098,7 +7048,7 @@ void Item_ref::cleanup()
Transform an Item_ref object with a transformer callback function.
The function first applies the transform method to the item
- referenced by this Item_reg object. If this returns a new item the
+ referenced by this Item_ref object. If this returns a new item the
old item is substituted for a new one. After this the transformer
is applied to the Item_ref object.
@@ -7111,13 +7061,13 @@ void Item_ref::cleanup()
@retval NULL Out of memory error
*/
-Item* Item_ref::transform(Item_transformer transformer, uchar *arg)
+Item* Item_ref::transform(THD *thd, Item_transformer transformer, uchar *arg)
{
- DBUG_ASSERT(!current_thd->stmt_arena->is_stmt_prepare());
+ DBUG_ASSERT(!thd->stmt_arena->is_stmt_prepare());
DBUG_ASSERT((*ref) != NULL);
/* Transform the object we are referencing. */
- Item *new_item= (*ref)->transform(transformer, arg);
+ Item *new_item= (*ref)->transform(thd, transformer, arg);
if (!new_item)
return NULL;
@@ -7128,10 +7078,10 @@ Item* Item_ref::transform(Item_transformer transformer, uchar *arg)
change records at each execution.
*/
if (*ref != new_item)
- current_thd->change_item_tree(ref, new_item);
+ thd->change_item_tree(ref, new_item);
/* Transform the item ref object. */
- return (this->*transformer)(arg);
+ return (this->*transformer)(thd, arg);
}
@@ -7157,7 +7107,7 @@ Item* Item_ref::transform(Item_transformer transformer, uchar *arg)
@return Item returned as the result of transformation of the Item_ref object
*/
-Item* Item_ref::compile(Item_analyzer analyzer, uchar **arg_p,
+Item* Item_ref::compile(THD *thd, Item_analyzer analyzer, uchar **arg_p,
Item_transformer transformer, uchar *arg_t)
{
/* Analyze this Item object. */
@@ -7169,13 +7119,13 @@ Item* Item_ref::compile(Item_analyzer analyzer, uchar **arg_p,
if (*arg_p)
{
uchar *arg_v= *arg_p;
- Item *new_item= (*ref)->compile(analyzer, &arg_v, transformer, arg_t);
+ Item *new_item= (*ref)->compile(thd, analyzer, &arg_v, transformer, arg_t);
if (new_item && *ref != new_item)
- current_thd->change_item_tree(ref, new_item);
+ thd->change_item_tree(ref, new_item);
}
/* Transform this Item object. */
- return (this->*transformer)(arg_t);
+ return (this->*transformer)(thd, arg_t);
}
@@ -7269,26 +7219,8 @@ bool Item_ref::val_bool_result()
if (result_field)
{
if ((null_value= result_field->is_null()))
- return 0;
- switch (result_field->result_type()) {
- case INT_RESULT:
- return result_field->val_int() != 0;
- case DECIMAL_RESULT:
- {
- my_decimal decimal_value;
- my_decimal *val= result_field->val_decimal(&decimal_value);
- if (val)
- return !my_decimal_is_zero(val);
- return 0;
- }
- case REAL_RESULT:
- case STRING_RESULT:
- return result_field->val_real() != 0.0;
- case ROW_RESULT:
- case TIME_RESULT:
- case IMPOSSIBLE_RESULT:
- DBUG_ASSERT(0);
- }
+ return false;
+ return result_field->val_bool();
}
return val_bool();
}
@@ -7393,9 +7325,9 @@ int Item_ref::save_in_field(Field *to, bool no_conversions)
}
-void Item_ref::save_org_in_field(Field *field)
+void Item_ref::save_org_in_field(Field *field, fast_field_copier optimizer_data)
{
- (*ref)->save_org_in_field(field);
+ (*ref)->save_org_in_field(field, optimizer_data);
}
@@ -7421,7 +7353,7 @@ Item *Item_ref::get_tmp_table_item(THD *thd)
if (!result_field)
return (*ref)->get_tmp_table_item(thd);
- Item_field *item= new Item_field(result_field);
+ Item_field *item= new (thd->mem_root) Item_field(thd, result_field);
if (item)
{
item->table_name= table_name;
@@ -7506,24 +7438,21 @@ Item_cache_wrapper::~Item_cache_wrapper()
DBUG_ASSERT(expr_cache == 0);
}
-Item_cache_wrapper::Item_cache_wrapper(Item *item_arg)
-:orig_item(item_arg), expr_cache(NULL), expr_value(NULL)
+Item_cache_wrapper::Item_cache_wrapper(THD *thd, Item *item_arg):
+ Item_result_field(thd), orig_item(item_arg), expr_cache(NULL), expr_value(NULL)
{
DBUG_ASSERT(orig_item->fixed);
- max_length= orig_item->max_length;
+ Type_std_attributes::set(orig_item);
maybe_null= orig_item->maybe_null;
- decimals= orig_item->decimals;
- collation.set(orig_item->collation);
with_sum_func= orig_item->with_sum_func;
with_param= orig_item->with_param;
with_field= orig_item->with_field;
- unsigned_flag= orig_item->unsigned_flag;
name= item_arg->name;
name_length= item_arg->name_length;
with_subselect= orig_item->with_subselect;
- if ((expr_value= Item_cache::get_cache(orig_item)))
- expr_value->setup(orig_item);
+ if ((expr_value= Item_cache::get_cache(thd, orig_item)))
+ expr_value->setup(thd, orig_item);
fixed= 1;
}
@@ -7545,7 +7474,14 @@ void Item_cache_wrapper::init_on_demand()
void Item_cache_wrapper::print(String *str, enum_query_type query_type)
{
- str->append(func_name());
+ if (query_type & QT_ITEM_CACHE_WRAPPER_SKIP_DETAILS)
+ {
+ /* Don't print the cache in EXPLAIN EXTENDED */
+ orig_item->print(str, query_type);
+ return;
+ }
+
+ str->append("<expr_cache>");
if (expr_cache)
{
init_on_demand();
@@ -7621,6 +7557,19 @@ bool Item_cache_wrapper::set_cache(THD *thd)
DBUG_RETURN(expr_cache == NULL);
}
+Expression_cache_tracker* Item_cache_wrapper::init_tracker(MEM_ROOT *mem_root)
+{
+ if (expr_cache)
+ {
+ Expression_cache_tracker* tracker=
+ new(mem_root) Expression_cache_tracker(expr_cache);
+ if (tracker)
+ ((Expression_cache_tmptable *)expr_cache)->set_tracker(tracker);
+ return tracker;
+ }
+ return NULL;
+}
+
/**
Check if the current values of the parameters are in the expression cache
@@ -7883,11 +7832,11 @@ int Item_cache_wrapper::save_in_field(Field *to, bool no_conversions)
}
-Item* Item_cache_wrapper::get_tmp_table_item(THD *thd_arg)
+Item* Item_cache_wrapper::get_tmp_table_item(THD *thd)
{
if (!orig_item->with_sum_func && !orig_item->const_item())
- return new Item_field(result_field);
- return copy_or_same(thd_arg);
+ return new (thd->mem_root) Item_temptable_field(thd, result_field);
+ return copy_or_same(thd);
}
@@ -7971,18 +7920,20 @@ bool Item_outer_ref::fix_fields(THD *thd, Item **reference)
}
-void Item_outer_ref::fix_after_pullout(st_select_lex *new_parent, Item **ref)
+void Item_outer_ref::fix_after_pullout(st_select_lex *new_parent,
+ Item **ref_arg, bool merge)
{
if (get_depended_from() == new_parent)
{
- *ref= outer_ref;
- (*ref)->fix_after_pullout(new_parent, ref);
+ *ref_arg= outer_ref;
+ (*ref_arg)->fix_after_pullout(new_parent, ref_arg, merge);
}
}
-void Item_ref::fix_after_pullout(st_select_lex *new_parent, Item **refptr)
+void Item_ref::fix_after_pullout(st_select_lex *new_parent, Item **refptr,
+ bool merge)
{
- (*ref)->fix_after_pullout(new_parent, ref);
+ (*ref)->fix_after_pullout(new_parent, ref, merge);
if (get_depended_from() == new_parent)
depended_from= NULL;
}
@@ -8010,12 +7961,12 @@ bool Item_outer_ref::check_inner_refs_processor(uchar *arg)
{
List_iterator_fast<Item_outer_ref> *it=
((List_iterator_fast<Item_outer_ref> *) arg);
- Item_outer_ref *ref;
- while ((ref= (*it)++))
+ Item_outer_ref *tmp_ref;
+ while ((tmp_ref= (*it)++))
{
- if (ref == this)
+ if (tmp_ref == this)
{
- ref->found_in_group_by= 1;
+ tmp_ref->found_in_group_by= 1;
break;
}
}
@@ -8066,43 +8017,6 @@ Item_equal *Item_direct_view_ref::find_item_equal(COND_EQUAL *cond_equal)
/**
- Check whether a reference to field item can be substituted for an equal item
-
- @details
- The function checks whether a substitution of a reference to field item for
- an equal item is valid.
-
- @param arg *arg != NULL <-> the reference is in the context
- where substitution for an equal item is valid
-
- @note
- See also the note for Item_field::subst_argument_checker
-
- @retval
- TRUE substitution is valid
- @retval
- FALSE otherwise
-*/
-bool Item_direct_view_ref::subst_argument_checker(uchar **arg)
-{
- bool res= FALSE;
- if (*arg)
- {
- Item *item= real_item();
- if (item->type() == FIELD_ITEM &&
- (*arg == (uchar *) Item::ANY_SUBST ||
- result_type() != STRING_RESULT ||
- (((Item_field *) item)->field->flags & BINARY_FLAG)))
- res= TRUE;
- }
- /* Block any substitution into the wrapped object */
- if (*arg)
- *arg= NULL;
- return res;
-}
-
-
-/**
Set a pointer to the multiple equality the view field reference belongs to
(if any).
@@ -8122,7 +8036,7 @@ bool Item_direct_view_ref::subst_argument_checker(uchar **arg)
of the compile method.
@note
- The function calls Item_field::equal_fields_propagator for the field item
+ The function calls Item_field::propagate_equal_fields() for the field item
this->real_item() to do the job. Then it takes the pointer to equal_item
from this field item and assigns it to this->item_equal.
@@ -8131,12 +8045,14 @@ bool Item_direct_view_ref::subst_argument_checker(uchar **arg)
- pointer to the field item, otherwise.
*/
-Item *Item_direct_view_ref::equal_fields_propagator(uchar *arg)
+Item *Item_direct_view_ref::propagate_equal_fields(THD *thd,
+ const Context &ctx,
+ COND_EQUAL *cond)
{
Item *field_item= real_item();
if (field_item->type() != FIELD_ITEM)
return this;
- Item *item= field_item->equal_fields_propagator(arg);
+ Item *item= field_item->propagate_equal_fields(thd, ctx, cond);
set_item_equal(field_item->get_item_equal());
field_item->set_item_equal(NULL);
if (item != field_item)
@@ -8156,7 +8072,7 @@ Item *Item_direct_view_ref::equal_fields_propagator(uchar *arg)
object belongs to unless item_equal contains a constant item. In this
case the function returns this constant item (if the substitution does
not require conversion).
- If the Item_direct_view_item object does not refer any Item_equal object
+ If the Item_direct_view_ref object does not refer any Item_equal object
'this' is returned .
@param arg NULL or points to so some item of the Item_equal type
@@ -8175,13 +8091,13 @@ Item *Item_direct_view_ref::equal_fields_propagator(uchar *arg)
- this - otherwise.
*/
-Item *Item_direct_view_ref::replace_equal_field(uchar *arg)
+Item *Item_direct_view_ref::replace_equal_field(THD *thd, uchar *arg)
{
Item *field_item= real_item();
if (field_item->type() != FIELD_ITEM)
return this;
field_item->set_item_equal(item_equal);
- Item *item= field_item->replace_equal_field(arg);
+ Item *item= field_item->replace_equal_field(thd, arg);
field_item->set_item_equal(0);
return item != field_item ? item : this;
}
@@ -8223,9 +8139,10 @@ bool Item_default_value::fix_fields(THD *thd, Item **items)
my_error(ER_NO_DEFAULT_FOR_FIELD, MYF(0), field_arg->field->field_name);
goto error;
}
- if (!(def_field= (Field*) sql_alloc(field_arg->field->size_of())))
+ if (!(def_field= (Field*) thd->alloc(field_arg->field->size_of())))
goto error;
- memcpy((void *)def_field, (void *)field_arg->field, field_arg->field->size_of());
+ memcpy((void *)def_field, (void *)field_arg->field,
+ field_arg->field->size_of());
def_field->move_field_offset((my_ptrdiff_t)
(def_field->table->s->default_values -
def_field->table->record[0]));
@@ -8255,38 +8172,42 @@ int Item_default_value::save_in_field(Field *field_arg, bool no_conversions)
{
if (!arg)
{
+ TABLE *table= field_arg->table;
+ THD *thd= table->in_use;
+
if (field_arg->flags & NO_DEFAULT_VALUE_FLAG &&
field_arg->real_type() != MYSQL_TYPE_ENUM)
{
if (field_arg->reset())
{
my_message(ER_CANT_CREATE_GEOMETRY_OBJECT,
- ER(ER_CANT_CREATE_GEOMETRY_OBJECT), MYF(0));
+ ER_THD(thd, ER_CANT_CREATE_GEOMETRY_OBJECT), MYF(0));
return -1;
}
if (context->error_processor == &view_error_processor)
{
- TABLE_LIST *view= field_arg->table->pos_in_table_list->top_table();
- push_warning_printf(field_arg->table->in_use,
- MYSQL_ERROR::WARN_LEVEL_WARN,
+ TABLE_LIST *view= table->pos_in_table_list->top_table();
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
ER_NO_DEFAULT_FOR_VIEW_FIELD,
- ER(ER_NO_DEFAULT_FOR_VIEW_FIELD),
+ ER_THD(thd, ER_NO_DEFAULT_FOR_VIEW_FIELD),
view->view_db.str,
view->view_name.str);
}
else
{
- push_warning_printf(field_arg->table->in_use,
- MYSQL_ERROR::WARN_LEVEL_WARN,
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
ER_NO_DEFAULT_FOR_FIELD,
- ER(ER_NO_DEFAULT_FOR_FIELD),
+ ER_THD(thd, ER_NO_DEFAULT_FOR_FIELD),
field_arg->field_name);
}
return 1;
}
field_arg->set_default();
- return 0;
+ return
+ !field_arg->is_null() &&
+ field_arg->validate_value_in_record_with_warn(thd, table->record[0]) &&
+ thd->is_error() ? -1 : 0;
}
return Item_field::save_in_field(field_arg, no_conversions);
}
@@ -8297,9 +8218,10 @@ int Item_default_value::save_in_field(Field *field_arg, bool no_conversions)
same time it can replace some nodes in the tree.
*/
-Item *Item_default_value::transform(Item_transformer transformer, uchar *args)
+Item *Item_default_value::transform(THD *thd, Item_transformer transformer,
+ uchar *args)
{
- DBUG_ASSERT(!current_thd->stmt_arena->is_stmt_prepare());
+ DBUG_ASSERT(!thd->stmt_arena->is_stmt_prepare());
/*
If the value of arg is NULL, then this object represents a constant,
@@ -8308,7 +8230,7 @@ Item *Item_default_value::transform(Item_transformer transformer, uchar *args)
if (!arg)
return 0;
- Item *new_item= arg->transform(transformer, args);
+ Item *new_item= arg->transform(thd, transformer, args);
if (!new_item)
return 0;
@@ -8319,8 +8241,8 @@ Item *Item_default_value::transform(Item_transformer transformer, uchar *args)
change records at each execution.
*/
if (arg != new_item)
- current_thd->change_item_tree(&arg, new_item);
- return (this->*transformer)(args);
+ thd->change_item_tree(&arg, new_item);
+ return (this->*transformer)(thd, args);
}
@@ -8358,10 +8280,11 @@ bool Item_insert_value::fix_fields(THD *thd, Item **items)
if (field_arg->field->table->insert_values)
{
- Field *def_field= (Field*) sql_alloc(field_arg->field->size_of());
+ Field *def_field= (Field*) thd->alloc(field_arg->field->size_of());
if (!def_field)
return TRUE;
- memcpy((void *)def_field, (void *)field_arg->field, field_arg->field->size_of());
+ memcpy((void *)def_field, (void *)field_arg->field,
+ field_arg->field->size_of());
def_field->move_field_offset((my_ptrdiff_t)
(def_field->table->insert_values -
def_field->table->record[0]));
@@ -8477,6 +8400,7 @@ bool Item_trigger_field::set_value(THD *thd, sp_rcontext * /*ctx*/, Item **it)
int err_code= item->save_in_field(field, 0);
field->table->copy_blobs= copy_blobs_saved;
+ field->set_explicit_default(item);
return err_code < 0;
}
@@ -8563,11 +8487,13 @@ Item_result item_cmp_type(Item_result a,Item_result b)
void resolve_const_item(THD *thd, Item **ref, Item *comp_item)
{
Item *item= *ref;
- Item *new_item= NULL;
if (item->basic_const_item())
return; // Can't be better
- Item_result res_type=item_cmp_type(comp_item->cmp_type(), item->cmp_type());
+
+ Item *new_item= NULL;
+ Item_result res_type= item_cmp_type(comp_item, item);
char *name=item->name; // Alloced by sql_alloc
+ MEM_ROOT *mem_root= thd->mem_root;
switch (res_type) {
case TIME_RESULT:
@@ -8575,9 +8501,10 @@ void resolve_const_item(THD *thd, Item **ref, Item *comp_item)
bool is_null;
Item **ref_copy= ref;
/* the following call creates a constant and puts it in new_item */
- get_datetime_value(thd, &ref_copy, &new_item, comp_item, &is_null);
+ 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 Item_null(name);
+ new_item= new (mem_root) Item_null(thd, name);
break;
}
case STRING_RESULT:
@@ -8586,12 +8513,12 @@ void resolve_const_item(THD *thd, Item **ref, Item *comp_item)
String tmp(buff,sizeof(buff),&my_charset_bin),*result;
result=item->val_str(&tmp);
if (item->null_value)
- new_item= new Item_null(name);
+ new_item= new (mem_root) Item_null(thd, name);
else
{
uint length= result->length();
char *tmp_str= sql_strmake(result->ptr(), length);
- new_item= new Item_string(name, tmp_str, length, result->charset());
+ new_item= new (mem_root) Item_string(thd, name, tmp_str, length, result->charset());
}
break;
}
@@ -8600,15 +8527,15 @@ void resolve_const_item(THD *thd, Item **ref, Item *comp_item)
longlong result=item->val_int();
uint length=item->max_length;
bool null_value=item->null_value;
- new_item= (null_value ? (Item*) new Item_null(name) :
- (Item*) new Item_int(name, result, length));
+ 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_rows. Don't affect other Items
+ 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
@@ -8620,7 +8547,7 @@ void resolve_const_item(THD *thd, Item **ref, Item *comp_item)
uint col;
new_item= 0;
/*
- If item and comp_item are both Item_rows and have same number of cols
+ 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.
@@ -8639,8 +8566,8 @@ void resolve_const_item(THD *thd, Item **ref, Item *comp_item)
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 Item_null(name) : (Item*)
- new Item_float(name, result, decimals, length));
+ 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:
@@ -8650,13 +8577,10 @@ void resolve_const_item(THD *thd, Item **ref, Item *comp_item)
uint length= item->max_length, decimals= item->decimals;
bool null_value= item->null_value;
new_item= (null_value ?
- (Item*) new Item_null(name) :
- (Item*) new Item_decimal(name, result, length, decimals));
+ (Item*) new (mem_root) Item_null(thd, name) :
+ (Item*) new (mem_root) Item_decimal(thd, name, result, length, decimals));
break;
}
- case IMPOSSIBLE_RESULT:
- DBUG_ASSERT(0);
- break;
}
if (new_item)
thd->change_item_tree(ref, new_item);
@@ -8689,6 +8613,28 @@ int stored_field_cmp_to_item(THD *thd, Field *field, Item *item)
{
Item_result res_type=item_cmp_type(field->result_type(),
item->result_type());
+ /*
+ We have to check field->cmp_type() instead of res_type,
+ as result_type() - and thus res_type - can never be TIME_RESULT (yet).
+ */
+ if (field->cmp_type() == TIME_RESULT)
+ {
+ MYSQL_TIME field_time, item_time, item_time2, *item_time_cmp= &item_time;
+ if (field->type() == MYSQL_TYPE_TIME)
+ {
+ field->get_time(&field_time);
+ item->get_time(&item_time);
+ }
+ else
+ {
+ field->get_date(&field_time, TIME_INVALID_DATES);
+ item->get_date(&item_time, TIME_INVALID_DATES);
+ if (item_time.time_type == MYSQL_TIMESTAMP_TIME)
+ if (time_to_datetime(thd, &item_time, item_time_cmp= &item_time2))
+ return 1;
+ }
+ return my_time_compare(&field_time, item_time_cmp);
+ }
if (res_type == STRING_RESULT)
{
char item_buff[MAX_FIELD_WIDTH];
@@ -8704,26 +8650,6 @@ int stored_field_cmp_to_item(THD *thd, Field *field, Item *item)
if (item->null_value)
return 0;
String *field_result= field->val_str(&field_tmp);
-
- enum_field_types field_type= field->type();
-
- if (field_type == MYSQL_TYPE_DATE || field_type == MYSQL_TYPE_DATETIME ||
- field_type == MYSQL_TYPE_TIMESTAMP)
- {
- enum_mysql_timestamp_type type= MYSQL_TIMESTAMP_ERROR;
-
- if (field_type == MYSQL_TYPE_DATE)
- type= MYSQL_TIMESTAMP_DATE;
- else
- type= MYSQL_TIMESTAMP_DATETIME;
-
- const char *field_name= field->field_name;
- MYSQL_TIME field_time, item_time;
- get_mysql_time_from_str(thd, field_result, type, field_name, &field_time);
- get_mysql_time_from_str(thd, item_result, type, field_name, &item_time);
-
- return my_time_compare(&field_time, &item_time);
- }
return sortcmp(field_result, item_result, field->charset());
}
if (res_type == INT_RESULT)
@@ -8739,25 +8665,6 @@ int stored_field_cmp_to_item(THD *thd, Field *field, Item *item)
return my_decimal_cmp(field_val, item_val);
}
/*
- We have to check field->cmp_type() instead of res_type,
- as result_type() - and thus res_type - can never be TIME_RESULT (yet).
- */
- if (field->cmp_type() == TIME_RESULT)
- {
- MYSQL_TIME field_time, item_time;
- if (field->type() == MYSQL_TYPE_TIME)
- {
- field->get_time(&field_time);
- item->get_time(&item_time);
- }
- else
- {
- field->get_date(&field_time, TIME_INVALID_DATES);
- item->get_date(&item_time, TIME_INVALID_DATES);
- }
- return my_time_compare(&field_time, &item_time);
- }
- /*
The patch for Bug#13463415 started using this function for comparing
BIGINTs. That uncovered a bug in Visual Studio 32bit optimized mode.
Prefixing the auto variables with volatile fixes the problem....
@@ -8773,9 +8680,9 @@ int stored_field_cmp_to_item(THD *thd, Field *field, Item *item)
return 0;
}
-Item_cache* Item_cache::get_cache(const Item *item)
+Item_cache* Item_cache::get_cache(THD *thd, const Item *item)
{
- return get_cache(item, item->cmp_type());
+ return get_cache(thd, item, item->cmp_type());
}
@@ -8788,24 +8695,23 @@ Item_cache* Item_cache::get_cache(const Item *item)
@return cache item
*/
-Item_cache* Item_cache::get_cache(const Item *item, const Item_result type)
+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 Item_cache_int(item->field_type());
+ return new (mem_root) Item_cache_int(thd, item->field_type());
case REAL_RESULT:
- return new Item_cache_real();
+ return new (mem_root) Item_cache_real(thd);
case DECIMAL_RESULT:
- return new Item_cache_decimal();
+ return new (mem_root) Item_cache_decimal(thd);
case STRING_RESULT:
- return new Item_cache_str(item);
+ return new (mem_root) Item_cache_str(thd, item);
case ROW_RESULT:
- return new Item_cache_row();
+ return new (mem_root) Item_cache_row(thd);
case TIME_RESULT:
- return new Item_cache_temporal(item->field_type());
- case IMPOSSIBLE_RESULT:
- DBUG_ASSERT(0);
- break;
+ return new (mem_root) Item_cache_temporal(thd, item->field_type());
}
return 0; // Impossible
}
@@ -8907,17 +8813,34 @@ int Item_cache_int::save_in_field(Field *field, bool no_conversions)
}
-Item_cache_temporal::Item_cache_temporal(enum_field_types field_type_arg):
- Item_cache_int(field_type_arg)
+Item_cache_temporal::Item_cache_temporal(THD *thd,
+ enum_field_types field_type_arg):
+ Item_cache_int(thd, field_type_arg)
{
if (mysql_type_to_time_type(cached_field_type) == MYSQL_TIMESTAMP_ERROR)
cached_field_type= MYSQL_TYPE_DATETIME;
}
-longlong Item_cache_temporal::val_temporal_packed()
+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;
+ return 0;
+ }
+ return value;
+}
+
+
+longlong Item_cache_temporal::val_time_packed()
{
DBUG_ASSERT(fixed == 1);
+ 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;
@@ -9025,16 +8948,25 @@ int Item_cache_temporal::save_in_field(Field *field, bool no_conversions)
}
-void Item_cache_temporal::store_packed(longlong val_arg, Item *example)
+void Item_cache_temporal::store_packed(longlong val_arg, Item *example_arg)
{
/* An explicit values is given, save it. */
- store(example);
+ store(example_arg);
value_cached= true;
value= val_arg;
null_value= false;
}
+Item *Item_cache_temporal::clone_item(THD *thd)
+{
+ Item_cache_temporal *item= new (thd->mem_root)
+ Item_cache_temporal(thd, cached_field_type);
+ item->store_packed(value, example);
+ return item;
+}
+
+
bool Item_cache_real::cache_value()
{
if (!example)
@@ -9163,28 +9095,18 @@ bool Item_cache_str::cache_value()
double Item_cache_str::val_real()
{
DBUG_ASSERT(fixed == 1);
- int err_not_used;
- char *end_not_used;
if (!has_value())
return 0.0;
- if (value)
- return my_strntod(value->charset(), (char*) value->ptr(),
- value->length(), &end_not_used, &err_not_used);
- return (double) 0;
+ return value ? double_from_string_with_check(value) : 0.0;
}
longlong Item_cache_str::val_int()
{
DBUG_ASSERT(fixed == 1);
- int err;
if (!has_value())
return 0;
- if (value)
- return my_strntoll(value->charset(), value->ptr(),
- value->length(), 10, (char**) 0, &err);
- else
- return (longlong)0;
+ return value ? longlong_from_string_with_check(value) : 0;
}
@@ -9202,11 +9124,7 @@ my_decimal *Item_cache_str::val_decimal(my_decimal *decimal_val)
DBUG_ASSERT(fixed == 1);
if (!has_value())
return NULL;
- if (value)
- string2my_decimal(E_DEC_FATAL_ERROR, value, decimal_val);
- else
- decimal_val= 0;
- return decimal_val;
+ return value ? decimal_from_string_with_check(decimal_val, value) : 0;
}
@@ -9220,27 +9138,26 @@ int Item_cache_str::save_in_field(Field *field, bool no_conversions)
}
-bool Item_cache_row::allocate(uint num)
+bool Item_cache_row::allocate(THD *thd, uint num)
{
item_count= num;
- THD *thd= current_thd;
return (!(values=
(Item_cache **) thd->calloc(sizeof(Item_cache *)*item_count)));
}
-bool Item_cache_row::setup(Item * item)
+bool Item_cache_row::setup(THD *thd, Item *item)
{
example= item;
- if (!values && allocate(item->cols()))
+ if (!values && allocate(thd, item->cols()))
return 1;
for (uint i= 0; i < item_count; i++)
{
Item *el= item->element_index(i);
Item_cache *tmp;
- if (!(tmp= values[i]= Item_cache::get_cache(el)))
+ if (!(tmp= values[i]= Item_cache::get_cache(thd, el)))
return 1;
- tmp->setup(el);
+ tmp->setup(thd, el);
}
return 0;
}
@@ -9342,7 +9259,10 @@ void Item_cache_row::set_null()
Item_type_holder::Item_type_holder(THD *thd, Item *item)
- :Item(thd, item), enum_set_typelib(0), fld_type(get_real_type(item))
+ :Item(thd, item),
+ enum_set_typelib(0),
+ fld_type(get_real_type(item)),
+ geometry_type(Field::GEOM_GEOMETRY)
{
DBUG_ASSERT(item->fixed);
maybe_null= item->maybe_null;
@@ -9431,7 +9351,6 @@ enum_field_types Item_type_holder::get_real_type(Item *item)
return MYSQL_TYPE_NEWDECIMAL;
case ROW_RESULT:
case TIME_RESULT:
- case IMPOSSIBLE_RESULT:
DBUG_ASSERT(0);
return MYSQL_TYPE_VAR_STRING;
}
@@ -9473,7 +9392,7 @@ bool Item_type_holder::join_types(THD *thd, Item *item)
/* fix variable decimals which always is NOT_FIXED_DEC */
if (Field::result_merge_type(fld_type) == INT_RESULT)
item_decimals= 0;
- decimals= max(decimals, item_decimals);
+ decimals= MY_MAX(decimals, item_decimals);
}
if (fld_type == FIELD_TYPE_GEOMETRY)
@@ -9483,10 +9402,10 @@ bool Item_type_holder::join_types(THD *thd, Item *item)
if (Field::result_merge_type(fld_type) == DECIMAL_RESULT)
{
collation.set_numeric();
- decimals= min(max(decimals, item->decimals), DECIMAL_MAX_SCALE);
+ decimals= MY_MIN(MY_MAX(decimals, item->decimals), DECIMAL_MAX_SCALE);
int item_int_part= item->decimal_int_part();
- int item_prec = max(prev_decimal_int_part, item_int_part) + decimals;
- int precision= min(item_prec, DECIMAL_MAX_PRECISION);
+ 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,
@@ -9517,7 +9436,7 @@ bool Item_type_holder::join_types(THD *thd, Item *item)
*/
if (collation.collation != &my_charset_bin)
{
- max_length= max(old_max_chars * collation.collation->mbmaxlen,
+ max_length= MY_MAX(old_max_chars * collation.collation->mbmaxlen,
display_length(item) /
item->collation.collation->mbmaxlen *
collation.collation->mbmaxlen);
@@ -9539,7 +9458,7 @@ bool Item_type_holder::join_types(THD *thd, Item *item)
{
int delta1= max_length_orig - decimals_orig;
int delta2= item->max_length - item->decimals;
- max_length= max(delta1, delta2) + decimals;
+ max_length= MY_MAX(delta1, delta2) + decimals;
if (fld_type == MYSQL_TYPE_FLOAT && max_length > FLT_DIG + 2)
{
max_length= MAX_FLOAT_STR_LENGTH;
@@ -9557,7 +9476,10 @@ bool Item_type_holder::join_types(THD *thd, Item *item)
break;
}
default:
- max_length= max(max_length, display_length(item));
+ if (fld_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);
@@ -9670,7 +9592,7 @@ Field *Item_type_holder::make_field_by_type(TABLE *table)
default:
break;
}
- return tmp_table_field_from_field_type(table, 0);
+ return tmp_table_field_from_field_type(table, false, true);
}
@@ -9844,7 +9766,15 @@ const char *dbug_print_item(Item *item)
str.length(0);
if (!item)
return "(Item*)NULL";
- item->print(&str ,QT_ORDINARY);
+
+ THD *thd= current_thd;
+ ulonglong save_option_bits= thd->variables.option_bits;
+ thd->variables.option_bits &= ~OPTION_QUOTE_SHOW_CREATE;
+
+ item->print(&str, QT_EXPLAIN);
+
+ thd->variables.option_bits= save_option_bits;
+
if (str.c_ptr_safe() == buf)
return buf;
else
@@ -9852,15 +9782,3 @@ const char *dbug_print_item(Item *item)
}
#endif /*DBUG_OFF*/
-
-/*****************************************************************************
-** Instantiate templates
-*****************************************************************************/
-
-#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
-template class List<Item>;
-template class List_iterator<Item>;
-template class List_iterator_fast<Item>;
-template class List_iterator_fast<Item_field>;
-template class List<List_item>;
-#endif