summaryrefslogtreecommitdiff
path: root/sql/item.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/item.cc')
-rw-r--r--sql/item.cc245
1 files changed, 197 insertions, 48 deletions
diff --git a/sql/item.cc b/sql/item.cc
index d0502b30d88..5f31f3fa6ec 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -104,21 +104,49 @@ void Item::print_item_w_name(String *str)
Item_ident::Item_ident(const char *db_name_par,const char *table_name_par,
const char *field_name_par)
- :db_name(db_name_par),table_name(table_name_par),field_name(field_name_par),
- depended_from(0)
+ :orig_db_name(db_name_par), orig_table_name(table_name_par),
+ orig_field_name(field_name_par), changed_during_fix_field(0),
+ db_name(db_name_par), table_name(table_name_par),
+ field_name(field_name_par), cached_field_index(NO_CACHED_FIELD_INDEX),
+ cached_table(0), depended_from(0)
{
name = (char*) field_name_par;
}
// Constructor used by Item_field & Item_ref (see Item comment)
-Item_ident::Item_ident(THD *thd, Item_ident *item):
- Item(thd, item),
- db_name(item->db_name),
- table_name(item->table_name),
- field_name(item->field_name),
- depended_from(item->depended_from)
+Item_ident::Item_ident(THD *thd, Item_ident *item)
+ :Item(thd, item),
+ orig_db_name(item->orig_db_name),
+ orig_table_name(item->orig_table_name),
+ orig_field_name(item->orig_field_name),
+ changed_during_fix_field(0),
+ db_name(item->db_name),
+ table_name(item->table_name),
+ field_name(item->field_name),
+ cached_field_index(item->cached_field_index),
+ cached_table(item->cached_table),
+ depended_from(item->depended_from)
{}
+void Item_ident::cleanup()
+{
+ DBUG_ENTER("Item_ident::cleanup");
+ DBUG_PRINT("enter", ("b:%s(%s), t:%s(%s), f:%s(%s)",
+ db_name, orig_db_name,
+ table_name, orig_table_name,
+ field_name, orig_field_name));
+ Item::cleanup();
+ if (changed_during_fix_field)
+ {
+ *changed_during_fix_field= this;
+ changed_during_fix_field= 0;
+ }
+ db_name= orig_db_name;
+ table_name= orig_table_name;
+ field_name= orig_field_name;
+ DBUG_VOID_RETURN;
+}
+
bool Item_ident::remove_dependence_processor(byte * arg)
{
DBUG_ENTER("Item_ident::remove_dependence_processor");
@@ -177,12 +205,13 @@ bool Item::eq(const Item *item, bool binary_cmp) const
!my_strcasecmp(system_charset_info,name,item->name);
}
+
bool Item_string::eq(const Item *item, bool binary_cmp) const
{
if (type() == item->type())
{
if (binary_cmp)
- return !sortcmp(&str_value, &item->str_value, &my_charset_bin);
+ return !stringcmp(&str_value, &item->str_value);
return !sortcmp(&str_value, &item->str_value, collation.collation);
}
return 0;
@@ -318,11 +347,21 @@ bool DTCollation::aggregate(DTCollation &dt)
return 0;
}
-Item_field::Item_field(Field *f) :Item_ident(NullS,f->table_name,f->field_name)
+Item_field::Item_field(Field *f)
+ :Item_ident(NullS, f->table_name, f->field_name)
{
set_field(f);
collation.set(DERIVATION_IMPLICIT);
- fixed= 1; // This item is not needed in fix_fields
+ fixed= 1;
+}
+
+Item_field::Item_field(THD *thd, Field *f)
+ :Item_ident(NullS, thd->strdup(f->table_name),
+ thd->strdup(f->field_name))
+{
+ set_field(f);
+ collation.set(DERIVATION_IMPLICIT);
+ fixed= 1;
}
// Constructor need to process subselect with temporary tables (see Item)
@@ -370,6 +409,7 @@ const char *Item_ident::full_name() const
/* ARGSUSED */
String *Item_field::val_str(String *str)
{
+ DBUG_ASSERT(fixed == 1);
if ((null_value=field->is_null()))
return 0;
str->set_charset(str_value.charset());
@@ -378,6 +418,7 @@ String *Item_field::val_str(String *str)
double Item_field::val()
{
+ DBUG_ASSERT(fixed == 1);
if ((null_value=field->is_null()))
return 0.0;
return field->val_real();
@@ -385,6 +426,7 @@ double Item_field::val()
longlong Item_field::val_int()
{
+ DBUG_ASSERT(fixed == 1);
if ((null_value=field->is_null()))
return 0;
return field->val_int();
@@ -469,9 +511,8 @@ bool Item_field::eq(const Item *item, bool binary_cmp) const
(!my_strcasecmp(table_alias_charset, item_field->table_name,
table_name) &&
(!item_field->db_name ||
- (item_field->db_name && !my_strcasecmp(table_alias_charset,
- item_field->db_name,
- db_name))))));
+ (item_field->db_name && !strcmp(item_field->db_name,
+ db_name))))));
}
@@ -494,6 +535,8 @@ Item *Item_field::get_tmp_table_item(THD *thd)
String *Item_int::val_str(String *str)
{
+ // following assert is redundant, because fixed=1 assigned in constructor
+ DBUG_ASSERT(fixed == 1);
str->set(value, &my_charset_bin);
return str;
}
@@ -508,6 +551,8 @@ void Item_int::print(String *str)
String *Item_uint::val_str(String *str)
{
+ // following assert is redundant, because fixed=1 assigned in constructor
+ DBUG_ASSERT(fixed == 1);
str->set((ulonglong) value, &my_charset_bin);
return str;
}
@@ -523,6 +568,8 @@ void Item_uint::print(String *str)
String *Item_real::val_str(String *str)
{
+ // following assert is redundant, because fixed=1 assigned in constructor
+ DBUG_ASSERT(fixed == 1);
str->set(value,decimals,&my_charset_bin);
return str;
}
@@ -539,14 +586,57 @@ void Item_string::print(String *str)
bool Item_null::eq(const Item *item, bool binary_cmp) const
{ return item->type() == type(); }
-double Item_null::val() { null_value=1; return 0.0; }
-longlong Item_null::val_int() { null_value=1; return 0; }
+double Item_null::val()
+{
+ // following assert is redundant, because fixed=1 assigned in constructor
+ DBUG_ASSERT(fixed == 1);
+ null_value=1;
+ return 0.0;
+}
+longlong Item_null::val_int()
+{
+ // following assert is redundant, because fixed=1 assigned in constructor
+ DBUG_ASSERT(fixed == 1);
+ null_value=1;
+ return 0;
+}
/* ARGSUSED */
String *Item_null::val_str(String *str)
-{ null_value=1; return 0;}
+{
+ // following assert is redundant, because fixed=1 assigned in constructor
+ DBUG_ASSERT(fixed == 1);
+ null_value=1;
+ return 0;
+}
+
+
+/*********************** Item_param related ******************************/
+
+/*
+ Default function of Item_param::set_param_func, so in case
+ of malformed packet the server won't SIGSEGV
+*/
+
+static void
+default_set_param_func(Item_param *param,
+ uchar **pos __attribute__((unused)),
+ ulong len __attribute__((unused)))
+{
+ param->set_null();
+}
+Item_param::Item_param(unsigned position) :
+ value_is_set(FALSE),
+ item_result_type(STRING_RESULT),
+ item_type(STRING_ITEM),
+ item_is_time(FALSE),
+ long_data_supplied(FALSE),
+ pos_in_query(position),
+ set_param_func(default_set_param_func)
+{
+ name= (char*) "?";
+}
-/* Item_param related */
void Item_param::set_null()
{
DBUG_ENTER("Item_param::set_null");
@@ -602,7 +692,7 @@ void Item_param::set_time(TIME *tm, timestamp_type type)
ltime.time_type= type;
- item_is_time= true;
+ item_is_time= TRUE;
item_type= STRING_ITEM;
value_is_set= 1;
}
@@ -642,7 +732,7 @@ int Item_param::save_in_field(Field *field, bool no_conversions)
return 0;
}
String *result=val_str(&str_value);
- return (field->store(result->ptr(),result->length(),field->charset())) ? -1 : 0;
+ return field->store(result->ptr(),result->length(),field->charset());
}
bool Item_param::get_time(TIME *res)
@@ -653,6 +743,7 @@ bool Item_param::get_time(TIME *res)
double Item_param::val()
{
+ DBUG_ASSERT(value_is_set == 1);
int err;
switch (item_result_type) {
case STRING_RESULT:
@@ -668,8 +759,9 @@ double Item_param::val()
longlong Item_param::val_int()
{
- int err;
- switch (item_result_type) {
+ DBUG_ASSERT(value_is_set == 1);
+ int err;
+ switch (item_result_type) {
case STRING_RESULT:
return my_strntoll(str_value.charset(),
str_value.ptr(),str_value.length(),10,
@@ -684,6 +776,7 @@ longlong Item_param::val_int()
String *Item_param::val_str(String* str)
{
+ DBUG_ASSERT(value_is_set == 1);
switch (item_result_type) {
case INT_RESULT:
str->set(int_value, &my_charset_bin);
@@ -702,12 +795,12 @@ String *Item_param::val_str(String* str)
*/
String *Item_param::query_val_str(String* str)
-{
+{
+ DBUG_ASSERT(value_is_set == 1);
switch (item_result_type) {
case INT_RESULT:
case REAL_RESULT:
return val_str(str);
- break;
default:
str->set("'", 1, default_charset());
@@ -775,11 +868,22 @@ void Item_copy_string::copy()
/* ARGSUSED */
String *Item_copy_string::val_str(String *str)
{
+ // Item_copy_string is used without fix_fields call
if (null_value)
return (String*) 0;
return &str_value;
}
+
+int Item_copy_string::save_in_field(Field *field, bool no_conversions)
+{
+ if (null_value)
+ return set_field_to_null(field);
+ field->set_notnull();
+ return field->store(str_value.ptr(),str_value.length(),
+ collation.collation);
+}
+
/*
Functions to convert item to field (for send_fields)
*/
@@ -789,28 +893,40 @@ bool Item::fix_fields(THD *thd,
struct st_table_list *list,
Item ** ref)
{
+
+ // We do not check fields which are fixed during construction
+ DBUG_ASSERT(fixed == 0 || basic_const_item());
fixed= 1;
return 0;
}
double Item_ref_null_helper::val()
{
+ DBUG_ASSERT(fixed == 1);
double tmp= (*ref)->val_result();
owner->was_null|= null_value= (*ref)->null_value;
return tmp;
}
+
+
longlong Item_ref_null_helper::val_int()
{
+ DBUG_ASSERT(fixed == 1);
longlong tmp= (*ref)->val_int_result();
owner->was_null|= null_value= (*ref)->null_value;
return tmp;
}
+
+
String* Item_ref_null_helper::val_str(String* s)
{
+ DBUG_ASSERT(fixed == 1);
String* tmp= (*ref)->str_result(s);
owner->was_null|= null_value= (*ref)->null_value;
return tmp;
}
+
+
bool Item_ref_null_helper::get_date(TIME *ltime, uint fuzzydate)
{
return (owner->was_null|= null_value= (*ref)->get_date(ltime, fuzzydate));
@@ -850,6 +966,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)
{
+ DBUG_ASSERT(fixed == 0);
if (!field) // If field is not checked
{
TABLE_LIST *where= 0;
@@ -896,6 +1013,8 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
table_list, &where,
0)) != not_found_field)
{
+ if (!tmp)
+ return -1;
prev_subselect_item->used_tables_cache|= tmp->table->map;
prev_subselect_item->const_item_cache= 0;
break;
@@ -955,8 +1074,13 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
ref,
(char *)table_name,
(char *)field_name);
+ register_item_tree_changing(ref);
if (!rf)
return 1;
+ /*
+ rf is Item_ref => never substitute other items (in this case)
+ during fix_fields() => we can use rf after fix_fields()
+ */
if (rf->fix_fields(thd, tables, ref) || rf->check_cols(1))
return 1;
@@ -975,6 +1099,10 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
(char *)field_name);
if (!rf)
return 1;
+ /*
+ rf is Item_ref => never substitute other items (in this case)
+ during fix_fields() => we can use rf after fix_fields()
+ */
return rf->fix_fields(thd, tables, ref) || rf->check_cols(1);
}
}
@@ -998,8 +1126,15 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
void Item_field::cleanup()
{
+ DBUG_ENTER("Item_field::cleanup");
Item_ident::cleanup();
+ /*
+ Even if this object was created by direct link to field in setup_wild()
+ it will be linked correctly next tyme by name of field and table alias.
+ I.e. we can drop 'field'.
+ */
field= result_field= 0;
+ DBUG_VOID_RETURN;
}
void Item::init_make_field(Send_field *tmp_field,
@@ -1213,7 +1348,7 @@ int Item::save_in_field(Field *field, bool no_conversions)
String *result;
CHARSET_INFO *cs= collation.collation;
char buff[MAX_FIELD_WIDTH]; // Alloc buffer for small columns
- str_value.set_quick(buff,sizeof(buff),cs);
+ str_value.set_quick(buff, sizeof(buff), cs);
result=val_str(&str_value);
if (null_value)
return set_field_to_null_with_conversions(field, no_conversions);
@@ -1237,7 +1372,7 @@ int Item::save_in_field(Field *field, bool no_conversions)
field->set_notnull();
error=field->store(nr);
}
- return (error) ? -1 : 0;
+ return error;
}
@@ -1248,8 +1383,7 @@ int Item_string::save_in_field(Field *field, bool no_conversions)
if (null_value)
return set_field_to_null(field);
field->set_notnull();
- return (field->store(result->ptr(),result->length(),collation.collation)) ?
- -1 : 0;
+ return field->store(result->ptr(),result->length(),collation.collation);
}
int Item_uint::save_in_field(Field *field, bool no_conversions)
@@ -1268,9 +1402,13 @@ int Item_int::save_in_field(Field *field, bool no_conversions)
if (null_value)
return set_field_to_null(field);
field->set_notnull();
- return (field->store(nr)) ? -1 : 0;
+ return field->store(nr);
}
+Item_num *Item_uint::neg()
+{
+ return new Item_real(name, - ((double) value), 0, max_length);
+}
int Item_real::save_in_field(Field *field, bool no_conversions)
{
@@ -1278,7 +1416,7 @@ int Item_real::save_in_field(Field *field, bool no_conversions)
if (null_value)
return set_field_to_null(field);
field->set_notnull();
- return (field->store(nr)) ? -1 : 0;
+ return field->store(nr);
}
/****************************************************************************
@@ -1313,10 +1451,13 @@ Item_varbinary::Item_varbinary(const char *str, uint str_length)
}
*ptr=0; // Keep purify happy
collation.set(&my_charset_bin, DERIVATION_COERCIBLE);
+ fixed= 1;
}
longlong Item_varbinary::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));
@@ -1340,7 +1481,7 @@ int Item_varbinary::save_in_field(Field *field, bool no_conversions)
longlong nr=val_int();
error=field->store(nr);
}
- return (error) ? -1 : 0;
+ return error;
}
@@ -1473,6 +1614,7 @@ bool Item_field::send(Protocol *protocol, String *buffer)
bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference)
{
+ DBUG_ASSERT(fixed == 0);
uint counter;
if (!ref)
{
@@ -1578,6 +1720,7 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference)
Item_field* fld;
if (!((*reference)= fld= new Item_field(tmp)))
return 1;
+ register_item_tree_changing(reference);
mark_as_dependent(thd, last, thd->lex->current_select, fld);
return 0;
}
@@ -1642,9 +1785,11 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference)
void Item_ref::cleanup()
{
+ DBUG_ENTER("Item_ref::cleanup");
Item_ident::cleanup();
if (hook_ptr)
*hook_ptr= orig_item;
+ DBUG_VOID_RETURN;
}
@@ -1683,16 +1828,19 @@ bool Item_default_value::eq(const Item *item, bool binary_cmp) const
}
-bool Item_default_value::fix_fields(THD *thd, struct st_table_list *table_list, Item **items)
+bool Item_default_value::fix_fields(THD *thd,
+ struct st_table_list *table_list,
+ Item **items)
{
+ DBUG_ASSERT(fixed == 0);
if (!arg)
- return false;
- bool res= arg->fix_fields(thd, table_list, items);
- if (res)
- return res;
- /* arg->type() can be only REF_ITEM or FIELD_ITEM for it defined as
- simple_ident in sql_yacc.yy
- */
+ {
+ fixed= 1;
+ return 0;
+ }
+ if (arg->fix_fields(thd, table_list, &arg))
+ return 1;
+
if (arg->type() == REF_ITEM)
{
Item_ref *ref= (Item_ref *)arg;
@@ -1710,6 +1858,7 @@ bool Item_default_value::fix_fields(THD *thd, struct st_table_list *table_list,
def_field->move_field(def_field->table->default_values -
def_field->table->record[0]);
set_field(def_field);
+ fixed= 1;
return 0;
}
@@ -1736,13 +1885,10 @@ bool Item_insert_value::fix_fields(THD *thd,
struct st_table_list *table_list,
Item **items)
{
- bool res= arg->fix_fields(thd, table_list, items);
- if (res)
- return res;
- /*
- arg->type() can be only REF_ITEM or FIELD_ITEM as arg is
- a simple_ident in sql_yacc.yy
- */
+ DBUG_ASSERT(fixed == 0);
+ if (arg->fix_fields(thd, table_list, &arg))
+ return 1;
+
if (arg->type() == REF_ITEM)
{
Item_ref *ref= (Item_ref *)arg;
@@ -1770,6 +1916,7 @@ bool Item_insert_value::fix_fields(THD *thd,
set_field(new Field_null(0, 0, Field::NONE, tmp_field->field_name,
tmp_field->table, &my_charset_bin));
}
+ fixed= 1;
return 0;
}
@@ -1855,7 +2002,7 @@ bool field_is_equal_to_item(Field *field,Item *item)
if (item->null_value)
return 1; // This must be true
field->val_str(&field_tmp,&field_tmp);
- return !sortcmp(&field_tmp,item_result,&my_charset_bin);
+ return !stringcmp(&field_tmp,item_result);
}
if (res_type == INT_RESULT)
return 1; // Both where of type int
@@ -1933,7 +2080,8 @@ void Item_cache_str::store(Item *item)
double Item_cache_str::val()
-{
+{
+ DBUG_ASSERT(fixed == 1);
int err;
if (value)
return my_strntod(value->charset(), (char*) value->ptr(),
@@ -1945,6 +2093,7 @@ double Item_cache_str::val()
longlong Item_cache_str::val_int()
{
+ DBUG_ASSERT(fixed == 1);
int err;
if (value)
return my_strntoll(value->charset(), value->ptr(),