summaryrefslogtreecommitdiff
path: root/sql/item.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/item.cc')
-rw-r--r--sql/item.cc89
1 files changed, 73 insertions, 16 deletions
diff --git a/sql/item.cc b/sql/item.cc
index 0e7a2b50b51..92a15694e89 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -69,7 +69,7 @@ Item::Item():
}
/*
- Constructor used by Item_field, Item_ref & agregate (sum) functions.
+ Constructor used by Item_field, Item_*_ref & agregate (sum) functions.
Used for duplicating lists in processing queries with temporary
tables
*/
@@ -114,7 +114,7 @@ Item_ident::Item_ident(const char *db_name_par,const char *table_name_par,
name = (char*) field_name_par;
}
-// Constructor used by Item_field & Item_ref (see Item comment)
+// Constructor used by Item_field & Item_*_ref (see Item comment)
Item_ident::Item_ident(THD *thd, Item_ident *item)
:Item(thd, item),
orig_db_name(item->orig_db_name),
@@ -837,6 +837,21 @@ void Item_param::set_double(double d)
}
+/*
+ Set parameter value from TIME value.
+
+ SYNOPSIS
+ set_time()
+ tm - datetime value to set (time_type is ignored)
+ type - type of datetime value
+ max_length_arg - max length of datetime value as string
+
+ NOTE
+ If we value to be stored is not normalized, zero value will be stored
+ instead and proper warning will be produced. This function relies on
+ the fact that even wrong value sent over binary protocol fits into
+ MAX_DATE_STRING_REP_LENGTH buffer.
+*/
void Item_param::set_time(TIME *tm, timestamp_type type, uint32 max_length_arg)
{
DBUG_ENTER("Item_param::set_time");
@@ -844,6 +859,17 @@ void Item_param::set_time(TIME *tm, timestamp_type type, uint32 max_length_arg)
value.time= *tm;
value.time.time_type= type;
+ if (value.time.year > 9999 || value.time.month > 12 ||
+ value.time.day > 31 ||
+ type != MYSQL_TIMESTAMP_TIME && value.time.hour > 23 ||
+ value.time.minute > 59 || value.time.second > 59)
+ {
+ char buff[MAX_DATE_STRING_REP_LENGTH];
+ uint length= my_TIME_to_str(&value.time, buff);
+ make_truncated_value_warning(current_thd, buff, length, type);
+ set_zero_time(&value.time, MYSQL_TIMESTAMP_ERROR);
+ }
+
state= TIME_VALUE;
maybe_null= 0;
max_length= max_length_arg;
@@ -1346,6 +1372,7 @@ static void mark_as_dependent(THD *thd, SELECT_LEX *last, SELECT_LEX *current,
bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
{
+ enum_parsing_place place= NO_MATTER;
DBUG_ASSERT(fixed == 0);
if (!field) // If field is not checked
{
@@ -1393,8 +1420,7 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
}
Item_subselect *prev_subselect_item= prev_unit->item;
- enum_parsing_place place=
- prev_subselect_item->parsing_place;
+ place= prev_subselect_item->parsing_place;
/*
check table fields only if subquery used somewhere out of HAVING
or outer SELECT do not use groupping (i.e. tables are
@@ -1462,12 +1488,25 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
"forward reference in item list");
return -1;
}
-
- Item_ref *rf= new Item_ref(last->ref_pointer_array + counter,
- (char *)table_name, (char *)field_name);
+ /*
+ Here, a subset of actions performed by Item_ref::set_properties
+ is not enough. So we pass ptr to NULL into Item_[direct]_ref
+ constructor, so no initialization is performed, and call
+ fix_fields() below.
+ */
+ Item *save= last->ref_pointer_array[counter];
+ last->ref_pointer_array[counter]= NULL;
+ Item_ref *rf= (place == IN_HAVING ?
+ new Item_ref(last->ref_pointer_array + counter,
+ (char *)table_name,
+ (char *)field_name) :
+ new Item_direct_ref(last->ref_pointer_array + counter,
+ (char *)table_name,
+ (char *)field_name));
if (!rf)
return 1;
thd->change_item_tree(ref, rf);
+ last->ref_pointer_array[counter]= save;
/*
rf is Item_ref => never substitute other items (in this case)
during fix_fields() => we can use rf after fix_fields()
@@ -2013,6 +2052,7 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference)
{
DBUG_ASSERT(fixed == 0);
uint counter;
+ enum_parsing_place place= NO_MATTER;
bool not_used;
if (!ref)
{
@@ -2071,8 +2111,7 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference)
// it is primary INSERT st_select_lex => skip first table resolving
table_list= table_list->next;
}
- enum_parsing_place place=
- prev_subselect_item->parsing_place;
+ place= prev_subselect_item->parsing_place;
/*
check table fields only if subquery used somewhere out of HAVING
or SELECT list or outer SELECT do not use groupping (i.e. tables
@@ -2142,6 +2181,19 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference)
}
mark_as_dependent(thd, last, thd->lex->current_select,
this);
+ if (place == IN_HAVING)
+ {
+ Item_ref *rf;
+ if (!(rf= new Item_direct_ref(last->ref_pointer_array + counter,
+ (char *)table_name,
+ (char *)field_name)))
+ return 1;
+ ref= 0; // Safety
+ if (rf->fix_fields(thd, tables, ref) || rf->check_cols(1))
+ return 1;
+ thd->change_item_tree(reference, rf);
+ return 0;
+ }
ref= last->ref_pointer_array + counter;
}
else if (!ref)
@@ -2177,19 +2229,24 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference)
"forward reference in item list"));
return 1;
}
+
+ set_properties();
+
+ if (ref && (*ref)->check_cols(1))
+ return 1;
+ return 0;
+}
+
+void Item_ref::set_properties()
+{
max_length= (*ref)->max_length;
maybe_null= (*ref)->maybe_null;
decimals= (*ref)->decimals;
collation.set((*ref)->collation);
with_sum_func= (*ref)->with_sum_func;
fixed= 1;
-
- if (ref && (*ref)->check_cols(1))
- return 1;
- return 0;
}
-
void Item_ref::print(String *str)
{
if (ref && *ref)
@@ -2235,7 +2292,7 @@ bool Item_default_value::fix_fields(THD *thd,
fixed= 1;
return 0;
}
- if (arg->fix_fields(thd, table_list, &arg))
+ if (!arg->fixed && arg->fix_fields(thd, table_list, &arg))
return 1;
if (arg->type() == REF_ITEM)
@@ -2282,7 +2339,7 @@ bool Item_insert_value::fix_fields(THD *thd,
Item **items)
{
DBUG_ASSERT(fixed == 0);
- if (arg->fix_fields(thd, table_list, &arg))
+ if (!arg->fixed && arg->fix_fields(thd, table_list, &arg))
return 1;
if (arg->type() == REF_ITEM)