summaryrefslogtreecommitdiff
path: root/sql/item.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/item.cc')
-rw-r--r--sql/item.cc123
1 files changed, 114 insertions, 9 deletions
diff --git a/sql/item.cc b/sql/item.cc
index 7db1a448e55..35e1312b540 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -228,7 +228,7 @@ 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) <=
+ str_to_TIME_with_warn(res->ptr(),res->length(),ltime,fuzzydate) <=
TIMESTAMP_DATETIME_ERROR)
{
bzero((char*) ltime,sizeof(*ltime));
@@ -247,7 +247,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;
@@ -255,7 +255,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;
}
@@ -628,7 +628,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)
{
@@ -736,6 +738,69 @@ 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);
+ break;
+ case INT_RESULT:
+ set_int(*(longlong*)entry->value, 21);
+ 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
@@ -762,13 +827,20 @@ void Item_param::reset()
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) {
@@ -808,6 +880,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) {
@@ -2345,6 +2428,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);
}
@@ -2364,6 +2448,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()];
@@ -2389,7 +2474,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) ||
@@ -2398,7 +2483,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) ||
@@ -2427,7 +2512,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;
@@ -2436,6 +2521,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()
{