summaryrefslogtreecommitdiff
path: root/sql/item.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/item.cc')
-rw-r--r--sql/item.cc142
1 files changed, 129 insertions, 13 deletions
diff --git a/sql/item.cc b/sql/item.cc
index 8dfe40abea8..8dfb8fb5587 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -230,8 +230,8 @@ bool Item::get_date(TIME *ltime,uint fuzzydate)
char buff[40];
String tmp(buff,sizeof(buff), &my_charset_bin),*res;
if (!(res=val_str(&tmp)) ||
- str_to_TIME(res->ptr(),res->length(),ltime,fuzzydate) <=
- TIMESTAMP_DATETIME_ERROR)
+ str_to_datetime_with_warn(res->ptr(), res->length(),
+ ltime, fuzzydate) <= MYSQL_TIMESTAMP_ERROR)
{
bzero((char*) ltime,sizeof(*ltime));
return 1;
@@ -249,7 +249,7 @@ bool Item::get_time(TIME *ltime)
char buff[40];
String tmp(buff,sizeof(buff),&my_charset_bin),*res;
if (!(res=val_str(&tmp)) ||
- str_to_time(res->ptr(),res->length(),ltime))
+ str_to_time_with_warn(res->ptr(), res->length(), ltime))
{
bzero((char*) ltime,sizeof(*ltime));
return 1;
@@ -257,7 +257,7 @@ bool Item::get_time(TIME *ltime)
return 0;
}
-CHARSET_INFO * Item::default_charset() const
+CHARSET_INFO *Item::default_charset()
{
return current_thd->variables.collation_connection;
}
@@ -658,7 +658,9 @@ default_set_param_func(Item_param *param,
Item_param::Item_param(unsigned pos_in_query_arg) :
state(NO_VALUE),
item_result_type(STRING_RESULT),
- item_type(STRING_ITEM),
+ /* Don't pretend to be a literal unless value for this item is set. */
+ item_type(PARAM_ITEM),
+ param_type(MYSQL_TYPE_STRING),
pos_in_query(pos_in_query_arg),
set_param_func(default_set_param_func)
{
@@ -766,6 +768,73 @@ bool Item_param::set_longdata(const char *str, ulong length)
/*
+ Set parameter value from user variable value.
+
+ SYNOPSIS
+ set_from_user_var
+ thd Current thread
+ entry User variable structure (NULL means use NULL value)
+
+ RETURN
+ 0 OK
+ 1 Out of memort
+*/
+
+bool Item_param::set_from_user_var(THD *thd, const user_var_entry *entry)
+{
+ DBUG_ENTER("Item_param::set_from_user_var");
+ if (entry && entry->value)
+ {
+ item_result_type= entry->type;
+ switch (entry->type) {
+ case REAL_RESULT:
+ set_double(*(double*)entry->value);
+ item_type= Item::REAL_ITEM;
+ item_result_type= REAL_RESULT;
+ break;
+ case INT_RESULT:
+ set_int(*(longlong*)entry->value, 21);
+ item_type= Item::INT_ITEM;
+ item_result_type= INT_RESULT;
+ break;
+ case STRING_RESULT:
+ {
+ CHARSET_INFO *fromcs= entry->collation.collation;
+ CHARSET_INFO *tocs= thd->variables.collation_connection;
+ uint32 dummy_offset;
+
+ value.cs_info.character_set_client= fromcs;
+ /*
+ Setup source and destination character sets so that they
+ are different only if conversion is necessary: this will
+ make later checks easier.
+ */
+ value.cs_info.final_character_set_of_str_value=
+ String::needs_conversion(0, fromcs, tocs, &dummy_offset) ?
+ tocs : fromcs;
+ /*
+ Exact value of max_length is not known unless data is converted to
+ charset of connection, so we have to set it later.
+ */
+ item_type= Item::STRING_ITEM;
+ item_result_type= STRING_RESULT;
+
+ if (set_str((const char *)entry->value, entry->length))
+ DBUG_RETURN(1);
+ break;
+ }
+ default:
+ DBUG_ASSERT(0);
+ set_null();
+ }
+ }
+ else
+ set_null();
+
+ DBUG_RETURN(0);
+}
+
+/*
Resets parameter after execution.
SYNOPSIS
@@ -783,21 +852,29 @@ void Item_param::reset()
str_value.free();
else
str_value.length(0);
+ str_value_ptr.length(0);
/*
- We must prevent all charset conversions unless data of str_value
- has been written to the binary log.
+ We must prevent all charset conversions untill data has been written
+ to the binary log.
*/
str_value.set_charset(&my_charset_bin);
state= NO_VALUE;
maybe_null= 1;
null_value= 0;
+ /*
+ Don't reset item_type to PARAM_ITEM: it's only needed to guard
+ us from item optimizations at prepare stage, when item doesn't yet
+ contain a literal of some kind.
+ In all other cases when this object is accessed its value is
+ set (this assumption is guarded by 'state' and
+ DBUG_ASSERTS(state != NO_VALUE) in all Item_param::get_*
+ methods).
+ */
}
int Item_param::save_in_field(Field *field, bool no_conversions)
{
- DBUG_ASSERT(current_thd->command == COM_EXECUTE);
-
field->set_notnull();
switch (state) {
@@ -837,6 +914,17 @@ bool Item_param::get_time(TIME *res)
}
+bool Item_param::get_date(TIME *res, uint fuzzydate)
+{
+ if (state == TIME_VALUE)
+ {
+ *res= value.time;
+ return 0;
+ }
+ return Item::get_date(res, fuzzydate);
+}
+
+
double Item_param::val()
{
switch (state) {
@@ -896,7 +984,7 @@ String *Item_param::val_str(String* str)
switch (state) {
case STRING_VALUE:
case LONG_DATA_VALUE:
- return &str_value;
+ return &str_value_ptr;
case REAL_VALUE:
str->set(value.real, NOT_FIXED_DEC, &my_charset_bin);
return str;
@@ -1010,6 +1098,12 @@ bool Item_param::convert_str_value(THD *thd)
}
max_length= str_value.length();
decimals= 0;
+ /*
+ 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());
}
return rc;
}
@@ -2368,6 +2462,7 @@ Item_type_holder::Item_type_holder(THD *thd, Item *item)
field_example= ((Item_field*) item)->field;
else
field_example= 0;
+ max_length= real_length(item);
collation.set(item->collation);
}
@@ -2387,6 +2482,7 @@ static Item_result type_convertor[4][4]=
bool Item_type_holder::join_types(THD *thd, Item *item)
{
+ uint32 new_length= real_length(item);
bool change_field= 0, skip_store_field= 0;
Item_result new_type= type_convertor[item_type][item->result_type()];
@@ -2412,7 +2508,7 @@ bool Item_type_holder::join_types(THD *thd, Item *item)
// size/type should be changed
if (change_field ||
(new_type != item_type) ||
- (max_length < item->max_length) ||
+ (max_length < new_length) ||
((new_type == INT_RESULT) &&
(decimals < item->decimals)) ||
(!maybe_null && item->maybe_null) ||
@@ -2421,7 +2517,7 @@ bool Item_type_holder::join_types(THD *thd, Item *item)
{
// new field has some parameters worse then current
skip_store_field|= (change_field &&
- (max_length > item->max_length) ||
+ (max_length > new_length) ||
((new_type == INT_RESULT) &&
(decimals > item->decimals)) ||
(maybe_null && !item->maybe_null) ||
@@ -2450,7 +2546,7 @@ bool Item_type_holder::join_types(THD *thd, Item *item)
return 1;
}
- max_length= max(max_length, item->max_length);
+ max_length= max(max_length, new_length);
decimals= max(decimals, item->decimals);
maybe_null|= item->maybe_null;
item_type= new_type;
@@ -2459,6 +2555,26 @@ bool Item_type_holder::join_types(THD *thd, Item *item)
return 0;
}
+uint32 Item_type_holder::real_length(Item *item)
+{
+ if (item->type() == Item::FIELD_ITEM)
+ {
+ return ((Item_field *)item)->max_disp_length();
+ }
+ switch (item->result_type())
+ {
+ case STRING_RESULT:
+ return item->max_length;
+ case REAL_RESULT:
+ return 53;
+ case INT_RESULT:
+ return 20;
+ case ROW_RESULT:
+ default:
+ DBUG_ASSERT(0); // we should never go there
+ return 0;
+ }
+}
double Item_type_holder::val()
{