summaryrefslogtreecommitdiff
path: root/sql/item.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/item.cc')
-rw-r--r--sql/item.cc1013
1 files changed, 879 insertions, 134 deletions
diff --git a/sql/item.cc b/sql/item.cc
index 0046f53c6fb..ea0d21ad300 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -34,23 +34,69 @@ void item_init(void)
item_user_lock_init();
}
-Item::Item()
+Item::Item():
+ fixed(0)
{
- marker=0;
- binary=maybe_null=null_value=with_sum_func=unsigned_flag=0;
- name=0;
- decimals=0; max_length=0;
- next=current_thd->free_list; // Put in free list
- current_thd->free_list=this;
+ marker= 0;
+ maybe_null=null_value=with_sum_func=unsigned_flag=0;
+ coercibility=COER_NOCOLL;
+ name= 0;
+ decimals= 0; max_length= 0;
+ THD *thd= current_thd;
+ next= thd->free_list; // Put in free list
+ thd->free_list= this;
+ loop_id= 0;
}
-void Item::set_name(char *str,uint length)
+/*
+ Constructor used by Item_field, Item_ref & agregate (sum) functions.
+ Used for duplicating lists in processing queries with temporary
+ tables
+*/
+Item::Item(THD *thd, Item &item):
+ loop_id(0),
+ str_value(item.str_value),
+ name(item.name),
+ max_length(item.max_length),
+ marker(item.marker),
+ decimals(item.decimals),
+ maybe_null(item.maybe_null),
+ null_value(item.null_value),
+ unsigned_flag(item.unsigned_flag),
+ with_sum_func(item.with_sum_func),
+ fixed(item.fixed),
+ coercibility(item.coercibility)
+{
+ next=thd->free_list; // Put in free list
+ thd->free_list= this;
+}
+
+// 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)
+{}
+
+bool Item::check_cols(uint c)
+{
+ if (c != 1)
+ {
+ my_error(ER_CARDINALITY_COL, MYF(0), c);
+ return 1;
+ }
+ return 0;
+}
+
+void Item::set_name(const char *str,uint length)
{
if (!length)
- name=str; // Used by AS
+ name= (char*) str; // Used by AS
else
{
- while (length && !isgraph(*str))
+ while (length && !my_isgraph(system_charset_info,*str))
{ // Fix problem with yacc
length--;
str++;
@@ -66,7 +112,7 @@ void Item::set_name(char *str,uint length)
bool Item::eq(const Item *item, bool binary_cmp) const
{
return type() == item->type() && name && item->name &&
- !my_strcasecmp(name,item->name);
+ !my_strcasecmp(system_charset_info,name,item->name);
}
bool Item_string::eq(const Item *item, bool binary_cmp) const
@@ -74,8 +120,8 @@ bool Item_string::eq(const Item *item, bool binary_cmp) const
if (type() == item->type())
{
if (binary_cmp)
- return !stringcmp(&str_value, &item->str_value);
- return !sortcmp(&str_value, &item->str_value);
+ return !sortcmp(&str_value, &item->str_value, &my_charset_bin);
+ return !sortcmp(&str_value, &item->str_value, charset());
}
return 0;
}
@@ -89,7 +135,7 @@ bool Item_string::eq(const Item *item, bool binary_cmp) const
bool Item::get_date(TIME *ltime,bool fuzzydate)
{
char buff[40];
- String tmp(buff,sizeof(buff)),*res;
+ String tmp(buff,sizeof(buff), &my_charset_bin),*res;
if (!(res=val_str(&tmp)) ||
str_to_TIME(res->ptr(),res->length(),ltime,fuzzydate) == TIMESTAMP_NONE)
{
@@ -107,7 +153,7 @@ bool Item::get_date(TIME *ltime,bool fuzzydate)
bool Item::get_time(TIME *ltime)
{
char buff[40];
- String tmp(buff,sizeof(buff)),*res;
+ String tmp(buff,sizeof(buff),&my_charset_bin),*res;
if (!(res=val_str(&tmp)) ||
str_to_time(res->ptr(),res->length(),ltime))
{
@@ -117,11 +163,24 @@ bool Item::get_time(TIME *ltime)
return 0;
}
+CHARSET_INFO * Item::default_charset() const
+{
+ return current_thd->db_charset;
+}
+
Item_field::Item_field(Field *f) :Item_ident(NullS,f->table_name,f->field_name)
{
set_field(f);
+ coercibility= COER_IMPLICIT;
+ fixed= 1; // This item is not needed in fix_fields
}
+// Constructor need to process subselect with temporary tables (see Item)
+Item_field::Item_field(THD *thd, Item_field &item):
+ Item_ident(thd, item),
+ field(item.field),
+ result_field(item.result_field)
+{ coercibility= COER_IMPLICIT; }
void Item_field::set_field(Field *field_par)
{
@@ -131,8 +190,9 @@ void Item_field::set_field(Field *field_par)
decimals= field->decimals();
table_name=field_par->table_name;
field_name=field_par->field_name;
- binary=field_par->binary();
unsigned_flag=test(field_par->flags & UNSIGNED_FLAG);
+ set_charset(field_par->charset());
+ coercibility= COER_IMPLICIT;
}
const char *Item_ident::full_name() const
@@ -140,7 +200,7 @@ const char *Item_ident::full_name() const
char *tmp;
if (!table_name)
return field_name ? field_name : name ? name : "tmp_field";
- if (db_name)
+ if (db_name && db_name[0])
{
tmp=(char*) sql_alloc((uint) strlen(db_name)+(uint) strlen(table_name)+
(uint) strlen(field_name)+3);
@@ -160,6 +220,7 @@ String *Item_field::val_str(String *str)
{
if ((null_value=field->is_null()))
return 0;
+ str->set_charset(str_value.charset());
return field->val_str(str,&str_value);
}
@@ -182,6 +243,7 @@ String *Item_field::str_result(String *str)
{
if ((null_value=result_field->is_null()))
return 0;
+ str->set_charset(str_value.charset());
return result_field->val_str(str,&str_value);
}
@@ -239,13 +301,20 @@ table_map Item_field::used_tables() const
{
if (field->table->const_table)
return 0; // const item
- return field->table->map;
+ return (depended_from ? RAND_TABLE_BIT : field->table->map);
}
+Item *Item_field::get_tmp_table_item(THD *thd)
+{
+ Item_field *new_item= new Item_field(thd, *this);
+ if (new_item)
+ new_item->field= new_item->result_field;
+ return new_item;
+}
String *Item_int::val_str(String *str)
{
- str->set(value);
+ str->set(value, default_charset());
return str;
}
@@ -253,7 +322,7 @@ void Item_int::print(String *str)
{
if (!name)
{
- str_value.set(value);
+ str_value.set(value, default_charset());
name=str_value.c_ptr();
}
str->append(name);
@@ -261,7 +330,7 @@ void Item_int::print(String *str)
String *Item_uint::val_str(String *str)
{
- str->set((ulonglong) value);
+ str->set((ulonglong) value, default_charset());
return str;
}
@@ -269,7 +338,7 @@ void Item_uint::print(String *str)
{
if (!name)
{
- str_value.set((ulonglong) value);
+ str_value.set((ulonglong) value, default_charset());
name=str_value.c_ptr();
}
str->append(name);
@@ -278,7 +347,7 @@ void Item_uint::print(String *str)
String *Item_real::val_str(String *str)
{
- str->set(value,decimals);
+ str->set(value,decimals,default_charset());
return str;
}
@@ -298,6 +367,136 @@ String *Item_null::val_str(String *str)
{ null_value=1; return 0;}
+/* Item_param related */
+void Item_param::set_null()
+{
+ maybe_null=null_value=1;
+}
+
+void Item_param::set_int(longlong i)
+{
+ int_value=(longlong)i;
+ item_type = INT_ITEM;
+}
+
+void Item_param::set_double(double value)
+{
+ real_value=value;
+ item_type = REAL_ITEM;
+}
+
+
+void Item_param::set_value(const char *str, uint length)
+{
+ str_value.set(str,length,default_charset());
+ item_type = STRING_ITEM;
+}
+
+
+void Item_param::set_time(TIME *tm, timestamp_type type)
+{
+ ltime.year= tm->year;
+ ltime.month= tm->month;
+ ltime.day= tm->day;
+
+ ltime.hour= tm->hour;
+ ltime.minute= tm->minute;
+ ltime.second= tm->second;
+
+ ltime.second_part= tm->second_part;
+
+ ltime.time_type= type;
+
+ item_is_time= true;
+ item_type= STRING_ITEM;
+}
+
+
+void Item_param::set_longdata(const char *str, ulong length)
+{
+ str_value.append(str,length);
+ long_data_supplied= 1;
+}
+
+
+int Item_param::save_in_field(Field *field, bool no_conversions)
+{
+ if (null_value)
+ return (int) set_field_to_null(field);
+
+ field->set_notnull();
+ if (item_result_type == INT_RESULT)
+ {
+ longlong nr=val_int();
+ return (field->store(nr)) ? -1 : 0;
+ }
+ if (item_result_type == REAL_RESULT)
+ {
+ double nr=val();
+ return (field->store(nr)) ? -1 : 0;
+ }
+ if (item_is_time)
+ {
+ field->store_time(&ltime, ltime.time_type);
+ return 0;
+ }
+ String *result=val_str(&str_value);
+ return (field->store(result->ptr(),result->length(),field->charset())) ? -1 : 0;
+}
+
+bool Item_param::get_time(TIME *res)
+{
+ *res=ltime;
+ return 0;
+}
+
+double Item_param::val()
+{
+ int err;
+ switch (item_result_type) {
+ case STRING_RESULT:
+ return (double) my_strntod(str_value.charset(), (char*) str_value.ptr(),
+ str_value.length(), (char**) 0, &err);
+ case INT_RESULT:
+ return (double)int_value;
+ default:
+ return real_value;
+ }
+}
+
+
+longlong Item_param::val_int()
+{
+ int err;
+ switch (item_result_type) {
+ case STRING_RESULT:
+ return my_strntoll(str_value.charset(),
+ str_value.ptr(),str_value.length(),10,
+ (char**) 0,&err);
+ case REAL_RESULT:
+ return (longlong) (real_value+(real_value > 0 ? 0.5 : -0.5));
+ default:
+ return int_value;
+ }
+}
+
+
+String *Item_param::val_str(String* str)
+{
+ switch (item_result_type) {
+ case INT_RESULT:
+ str->set(int_value, default_charset());
+ return str;
+ case REAL_RESULT:
+ str->set(real_value, 2, default_charset());
+ return str;
+ default:
+ return (String*) &str_value;
+ }
+}
+/* End of Item_param related */
+
+
void Item_copy_string::copy()
{
String *res=item->val_str(&str_value);
@@ -315,23 +514,210 @@ String *Item_copy_string::val_str(String *str)
}
/*
-** Functions to convert item to field (for send_fields)
+ Functions to convert item to field (for send_fields)
*/
/* ARGSUSED */
bool Item::fix_fields(THD *thd,
- struct st_table_list *list)
+ struct st_table_list *list,
+ Item ** ref)
{
+ fixed= 1;
return 0;
}
-bool Item_field::fix_fields(THD *thd,TABLE_LIST *tables)
+bool Item_asterisk_remover::fix_fields(THD *thd,
+ struct st_table_list *list,
+ Item ** ref)
+{
+ DBUG_ENTER("Item_asterisk_remover::fix_fields");
+
+ bool res= 1;
+ if (item)
+ if (item->type() == Item::FIELD_ITEM &&
+ ((Item_field*) item)->field_name[0] == '*')
+ {
+ Item_field *fitem= (Item_field*) item;
+ if (list)
+ if (!list->next || fitem->db_name || fitem->table_name)
+ {
+ TABLE_LIST *table= find_table_in_list(list,
+ fitem->db_name,
+ fitem->table_name);
+ if (table)
+ {
+ TABLE * tb= table->table;
+ if (find_table_in_list(table->next, fitem->db_name,
+ fitem->table_name) != 0 ||
+ tb->fields == 1)
+ {
+ if ((item= new Item_field(tb->field[0])))
+ {
+ res= 0;
+ tb->field[0]->query_id= thd->query_id;
+ tb->used_keys&= tb->field[0]->part_of_key;
+ tb->used_fields= tb->fields;
+ }
+ else
+ thd->fatal_error(); // can't create Item => out of memory
+ }
+ else
+ my_error(ER_CARDINALITY_COL, MYF(0), 1);
+ }
+ else
+ my_error(ER_BAD_TABLE_ERROR, MYF(0), fitem->table_name);
+ }
+ else
+ my_error(ER_CARDINALITY_COL, MYF(0), 1);
+ else
+ my_error(ER_NO_TABLES_USED, MYF(0));
+ }
+ else
+ res= item->fix_fields(thd, list, &item);
+ else
+ thd->fatal_error(); // no item given => out of memory
+ DBUG_RETURN(res);
+}
+
+bool Item_ref_on_list_position::fix_fields(THD *thd,
+ struct st_table_list *tables,
+ Item ** reference)
+{
+ if (select_lex->item_list.elements <= pos)
+ {
+ ref= 0;
+ my_error(ER_CARDINALITY_COL, MYF(0), pos);
+ return 1;
+ }
+ ref= select_lex->ref_pointer_array + pos;
+ return Item_ref_null_helper::fix_fields(thd, tables, reference);
+}
+
+double Item_ref_null_helper::val()
+{
+ double tmp= (*ref)->val_result();
+ owner->was_null|= null_value= (*ref)->null_value;
+ return tmp;
+}
+longlong Item_ref_null_helper::val_int()
+{
+ 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)
+{
+ 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, bool fuzzydate)
+{
+ return (owner->was_null|= null_value= (*ref)->get_date(ltime, fuzzydate));
+}
+
+bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
{
if (!field) // If field is not checked
{
- Field *tmp;
- if (!(tmp=find_field_in_tables(thd,this,tables)))
- return 1;
+ TABLE_LIST *where= 0;
+ Field *tmp= (Field *)not_found_field;
+ if (outer_resolving ||
+ (tmp= find_field_in_tables(thd, this, tables, &where, 0)) ==
+ not_found_field)
+ {
+ /*
+ We can't find table field in table list of current select,
+ consequently we have to find it in outer subselect(s).
+ We can't join lists of outer & current select, because of scope
+ of view rules. For example if both tables (outer & current) have
+ field 'field' it is not mistake to refer to this field without
+ mention of table name, but if we join tables in one list it will
+ cause error ER_NON_UNIQ_ERROR in find_field_in_tables.
+ */
+ SELECT_LEX *last= 0;
+#ifdef EMBEDDED_LIBRARY
+ thd->net.last_errno= 0;
+#endif
+ Item **refer= (Item **)not_found_item;
+ uint counter;
+ // Prevent using outer fields in subselects, that is not supported now
+ SELECT_LEX *cursel=(SELECT_LEX *) thd->lex.current_select;
+ if (outer_resolving ||
+ cursel->master_unit()->first_select()->linkage != DERIVED_TABLE_TYPE)
+ for (SELECT_LEX *sl=(outer_resolving?cursel:cursel->outer_select());
+ sl;
+ sl= sl->outer_select())
+ {
+ if ((tmp= find_field_in_tables(thd, this,
+ (last= sl)->get_table_list(), &where,
+ 0)) != not_found_field)
+ break;
+ if ((refer= find_item_in_list(this, sl->item_list, &counter,
+ REPORT_EXCEPT_NOT_FOUND)) !=
+ (Item **)not_found_item)
+ break;
+ if (sl->master_unit()->first_select()->linkage ==
+ DERIVED_TABLE_TYPE)
+ break; // do not look over derived table
+ }
+ if (!tmp)
+ return -1;
+ else if (!refer)
+ return 1;
+ else if (tmp == not_found_field && refer == (Item **)not_found_item)
+ {
+ // call to return error code
+ find_field_in_tables(thd, this, tables, &where, 1);
+ return -1;
+ }
+ else if (refer != (Item **)not_found_item)
+ {
+ if (!(*refer)->fixed)
+ {
+ my_error(ER_ILLEGAL_REFERENCE, MYF(0), name,
+ "forward reference in item list");
+ return -1;
+ }
+
+ Item_ref *r;
+ *ref= r= new Item_ref(last->ref_pointer_array + counter
+ , (char *)table_name,
+ (char *)field_name);
+ if (!r)
+ return 1;
+ if (r->fix_fields(thd, tables, ref) || r->check_cols(1))
+ return 1;
+ // store pointer on SELECT_LEX from which item is dependent
+ r->depended_from= last;
+ cursel->mark_as_dependent(last);
+ return 0;
+ }
+ else
+ {
+ // store pointer on SELECT_LEX from wich item is dependent
+ depended_from= last;
+ /*
+ Mark all selects from resolved to 1 before select where was
+ found table as depended (of select where was found table)
+ */
+ thd->lex.current_select->mark_as_dependent(last);
+ if (depended_from->having_fix_field)
+ {
+ Item_ref *rf;
+ *ref= rf= new Item_ref((where->db[0]?where->db:0),
+ (char *)where->alias,
+ (char *)field_name);
+ if (!rf)
+ return 1;
+ (rf)->outer_resolving= outer_resolving;
+ return rf->fix_fields(thd, tables, ref) || rf->check_cols(1);
+ }
+ }
+ }
+ else if (!tmp)
+ return -1;
+
set_field(tmp);
}
else if (thd && thd->set_query_id && field->query_id != thd->query_id)
@@ -342,15 +728,21 @@ bool Item_field::fix_fields(THD *thd,TABLE_LIST *tables)
table->used_fields++;
table->used_keys&=field->part_of_key;
}
+ fixed= 1;
return 0;
}
void Item::init_make_field(Send_field *tmp_field,
enum enum_field_types field_type)
-{
- tmp_field->table_name=(char*) "";
- tmp_field->col_name=name;
+{
+ char *empty_name= (char*) "";
+ tmp_field->db_name= empty_name;
+ tmp_field->org_table_name= empty_name;
+ tmp_field->org_col_name= empty_name;
+ tmp_field->table_name= empty_name;
+ tmp_field->col_name= name;
+ tmp_field->charsetnr= charset()->number;
tmp_field->flags=maybe_null ? 0 : NOT_NULL_FLAG;
tmp_field->type=field_type;
tmp_field->length=max_length;
@@ -359,65 +751,24 @@ void Item::init_make_field(Send_field *tmp_field,
tmp_field->flags |= UNSIGNED_FLAG;
}
-/* ARGSUSED */
-void Item_field::make_field(Send_field *tmp_field)
-{
- field->make_field(tmp_field);
- if (name)
- tmp_field->col_name=name; // Use user supplied name
-}
-
-void Item_int::make_field(Send_field *tmp_field)
-{
- init_make_field(tmp_field,FIELD_TYPE_LONGLONG);
-}
-
-void Item_uint::make_field(Send_field *tmp_field)
-{
- init_make_field(tmp_field,FIELD_TYPE_LONGLONG);
- tmp_field->flags|= UNSIGNED_FLAG;
- unsigned_flag=1;
-}
-
-void Item_real::make_field(Send_field *tmp_field)
-{
- init_make_field(tmp_field,FIELD_TYPE_DOUBLE);
-}
-
-void Item_string::make_field(Send_field *tmp_field)
-{
- init_make_field(tmp_field,FIELD_TYPE_STRING);
-}
-
-void Item_datetime::make_field(Send_field *tmp_field)
+void Item::make_field(Send_field *tmp_field)
{
- init_make_field(tmp_field,FIELD_TYPE_DATETIME);
+ init_make_field(tmp_field, field_type());
}
-
-void Item_null::make_field(Send_field *tmp_field)
+enum_field_types Item::field_type() const
{
- init_make_field(tmp_field,FIELD_TYPE_NULL);
- tmp_field->length=4;
+ return ((result_type() == STRING_RESULT) ? FIELD_TYPE_VAR_STRING :
+ (result_type() == INT_RESULT) ? FIELD_TYPE_LONGLONG :
+ FIELD_TYPE_DOUBLE);
}
-
-void Item_func::make_field(Send_field *tmp_field)
-{
- init_make_field(tmp_field, ((result_type() == STRING_RESULT) ?
- FIELD_TYPE_VAR_STRING :
- (result_type() == INT_RESULT) ?
- FIELD_TYPE_LONGLONG : FIELD_TYPE_DOUBLE));
-}
-
-void Item_avg_field::make_field(Send_field *tmp_field)
-{
- init_make_field(tmp_field,FIELD_TYPE_DOUBLE);
-}
-
-void Item_std_field::make_field(Send_field *tmp_field)
+/* ARGSUSED */
+void Item_field::make_field(Send_field *tmp_field)
{
- init_make_field(tmp_field,FIELD_TYPE_DOUBLE);
+ field->make_field(tmp_field);
+ if (name)
+ tmp_field->col_name=name; // Use user supplied name
}
/*
@@ -440,7 +791,7 @@ void Item_field::save_org_in_field(Field *to)
}
}
-bool Item_field::save_in_field(Field *to, bool no_conversions)
+int Item_field::save_in_field(Field *to, bool no_conversions)
{
if (result_field->is_null())
{
@@ -456,6 +807,7 @@ bool Item_field::save_in_field(Field *to, bool no_conversions)
return 0;
}
+
/*
Store null in field
@@ -472,7 +824,7 @@ bool Item_field::save_in_field(Field *to, bool no_conversions)
1 Field doesn't support NULL values and can't handle 'field = NULL'
*/
-bool Item_null::save_in_field(Field *field, bool no_conversions)
+int Item_null::save_in_field(Field *field, bool no_conversions)
{
return set_field_to_null_with_conversions(field, no_conversions);
}
@@ -490,27 +842,29 @@ bool Item_null::save_in_field(Field *field, bool no_conversions)
1 Field doesn't support NULL values
*/
-bool Item_null::save_safe_in_field(Field *field)
+int Item_null::save_safe_in_field(Field *field)
{
return set_field_to_null(field);
}
-bool Item::save_in_field(Field *field, bool no_conversions)
+int Item::save_in_field(Field *field, bool no_conversions)
{
+ int error;
if (result_type() == STRING_RESULT ||
result_type() == REAL_RESULT &&
field->result_type() == STRING_RESULT)
{
String *result;
+ CHARSET_INFO *cs=charset();
char buff[MAX_FIELD_WIDTH]; // Alloc buffer for small columns
- str_value.set_quick(buff,sizeof(buff));
+ 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);
field->set_notnull();
- field->store(result->ptr(),result->length());
- str_value.set_quick(0, 0);
+ error=field->store(result->ptr(),result->length(),cs);
+ str_value.set_quick(0, 0, cs);
}
else if (result_type() == REAL_RESULT)
{
@@ -518,7 +872,7 @@ bool Item::save_in_field(Field *field, bool no_conversions)
if (null_value)
return set_field_to_null(field);
field->set_notnull();
- field->store(nr);
+ error=field->store(nr);
}
else
{
@@ -526,41 +880,40 @@ bool Item::save_in_field(Field *field, bool no_conversions)
if (null_value)
return set_field_to_null_with_conversions(field, no_conversions);
field->set_notnull();
- field->store(nr);
+ error=field->store(nr);
}
- return 0;
+ return (error) ? -1 : 0;
}
-bool Item_string::save_in_field(Field *field, bool no_conversions)
+int Item_string::save_in_field(Field *field, bool no_conversions)
{
String *result;
result=val_str(&str_value);
if (null_value)
return set_field_to_null(field);
field->set_notnull();
- field->store(result->ptr(),result->length());
- return 0;
+ return (field->store(result->ptr(),result->length(),charset())) ? -1 : 0;
}
-bool Item_int::save_in_field(Field *field, bool no_conversions)
+
+int Item_int::save_in_field(Field *field, bool no_conversions)
{
longlong nr=val_int();
if (null_value)
return set_field_to_null(field);
field->set_notnull();
- field->store(nr);
- return 0;
+ return (field->store(nr)) ? -1 : 0;
}
-bool Item_real::save_in_field(Field *field, bool no_conversions)
+
+int Item_real::save_in_field(Field *field, bool no_conversions)
{
double nr=val();
if (null_value)
return set_field_to_null(field);
field->set_notnull();
- field->store(nr);
- return 0;
+ return (field->store(nr)) ? -1 : 0;
}
/****************************************************************************
@@ -583,7 +936,7 @@ Item_varbinary::Item_varbinary(const char *str, uint str_length)
char *ptr=(char*) sql_alloc(max_length+1);
if (!ptr)
return;
- str_value.set(ptr,max_length);
+ str_value.set(ptr,max_length,&my_charset_bin);
char *end=ptr+max_length;
if (max_length*2 != str_length)
*ptr++=char_val(*str++); // Not even, assume 0 prefix
@@ -593,7 +946,6 @@ Item_varbinary::Item_varbinary(const char *str, uint str_length)
str+=2;
}
*ptr=0; // Keep purify happy
- binary=1; // Binary is default
}
longlong Item_varbinary::val_int()
@@ -608,46 +960,135 @@ longlong Item_varbinary::val_int()
}
-bool Item_varbinary::save_in_field(Field *field, bool no_conversions)
+int Item_varbinary::save_in_field(Field *field, bool no_conversions)
{
+ int error;
field->set_notnull();
if (field->result_type() == STRING_RESULT)
{
- field->store(str_value.ptr(),str_value.length());
+ error=field->store(str_value.ptr(),str_value.length(),charset());
}
else
{
longlong nr=val_int();
- field->store(nr);
+ error=field->store(nr);
}
- return 0;
+ return (error) ? -1 : 0;
}
-void Item_varbinary::make_field(Send_field *tmp_field)
+/*
+ Pack data in buffer for sending
+*/
+
+bool Item_null::send(Protocol *protocol, String *packet)
{
- init_make_field(tmp_field,FIELD_TYPE_STRING);
+ return protocol->store_null();
}
/*
-** pack data in buffer for sending
+ This is only called from items that is not of type item_field
*/
-bool Item::send(THD *thd, String *packet)
+bool Item::send(Protocol *protocol, String *buffer)
{
- char buff[MAX_FIELD_WIDTH];
- CONVERT *convert;
- String s(buff,sizeof(buff)),*res;
- if (!(res=val_str(&s)))
- return net_store_null(packet);
- if ((convert=thd->variables.convert_set))
- return convert->store(packet,res->ptr(),res->length());
- return net_store_data(packet,res->ptr(),res->length());
+ bool result;
+ enum_field_types type;
+ LINT_INIT(result);
+
+ switch ((type=field_type())) {
+ default:
+ case MYSQL_TYPE_NULL:
+ case MYSQL_TYPE_DECIMAL:
+ case MYSQL_TYPE_ENUM:
+ case MYSQL_TYPE_SET:
+ case MYSQL_TYPE_TINY_BLOB:
+ case MYSQL_TYPE_MEDIUM_BLOB:
+ case MYSQL_TYPE_LONG_BLOB:
+ case MYSQL_TYPE_BLOB:
+ case MYSQL_TYPE_GEOMETRY:
+ case MYSQL_TYPE_STRING:
+ case MYSQL_TYPE_VAR_STRING:
+ {
+ String *res;
+ if ((res=val_str(buffer)))
+ result= protocol->store(res->ptr(),res->length());
+ break;
+ }
+ case MYSQL_TYPE_TINY:
+ {
+ longlong nr;
+ nr= val_int();
+ if (!null_value)
+ result= protocol->store_tiny(nr);
+ break;
+ }
+ case MYSQL_TYPE_SHORT:
+ {
+ longlong nr;
+ nr= val_int();
+ if (!null_value)
+ result= protocol->store_short(nr);
+ break;
+ }
+ case MYSQL_TYPE_INT24:
+ case MYSQL_TYPE_LONG:
+ {
+ longlong nr;
+ nr= val_int();
+ if (!null_value)
+ result= protocol->store_long(nr);
+ break;
+ }
+ case MYSQL_TYPE_LONGLONG:
+ {
+ longlong nr;
+ nr= val_int();
+ if (!null_value)
+ result= protocol->store_longlong(nr, unsigned_flag);
+ break;
+ }
+ case MYSQL_TYPE_DOUBLE:
+ {
+ double nr;
+ nr= val();
+ if (!null_value)
+ result= protocol->store(nr, decimals, buffer);
+ break;
+ }
+ case MYSQL_TYPE_DATETIME:
+ case MYSQL_TYPE_DATE:
+ case MYSQL_TYPE_TIMESTAMP:
+ {
+ TIME tm;
+ get_date(&tm, 1);
+ if (!null_value)
+ {
+ if (type == MYSQL_TYPE_DATE)
+ return protocol->store_date(&tm);
+ else
+ result= protocol->store(&tm);
+ }
+ break;
+ }
+ case MYSQL_TYPE_TIME:
+ {
+ TIME tm;
+ get_time(&tm);
+ if (!null_value)
+ result= protocol->store_time(&tm);
+ break;
+ }
+ }
+ if (null_value)
+ result= protocol->store_null();
+ return result;
}
-bool Item_null::send(THD *thd, String *packet)
+
+bool Item_field::send(Protocol *protocol, String *buffer)
{
- return net_store_null(packet);
+ return protocol->store(result_field);
}
/*
@@ -655,21 +1096,186 @@ bool Item_null::send(THD *thd, String *packet)
Find field in select list having the same name
*/
-bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables)
+bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference)
{
+ uint counter;
if (!ref)
{
- if (!(ref=find_item_in_list(this,thd->lex.select->item_list)))
+ TABLE_LIST *where= 0;
+ SELECT_LEX *sl= (outer_resolving?
+ thd->lex.current_select->select_lex():
+ thd->lex.current_select->outer_select());
+ /*
+ Finding only in current select will be performed for selects that have
+ not outer one and for derived tables (which not support using outer
+ fields for now)
+ */
+ if (outer_resolving ||
+ (ref= find_item_in_list(this,
+ *(thd->lex.current_select->get_item_list()),
+ &counter,
+ ((sl &&
+ thd->lex.current_select->master_unit()->
+ first_select()->linkage !=
+ DERIVED_TABLE_TYPE) ?
+ REPORT_EXCEPT_NOT_FOUND :
+ REPORT_ALL_ERRORS))) ==
+ (Item **)not_found_item)
+ {
+ Field *tmp= (Field*) not_found_field;
+ /*
+ We can't find table field in table list of current select,
+ consequently we have to find it in outer subselect(s).
+ We can't join lists of outer & current select, because of scope
+ of view rules. For example if both tables (outer & current) have
+ field 'field' it is not mistake to refer to this field without
+ mention of table name, but if we join tables in one list it will
+ cause error ER_NON_UNIQ_ERROR in find_item_in_list.
+ */
+ SELECT_LEX *last=0;
+ for ( ; sl ; sl= sl->outer_select())
+ {
+ if ((ref= find_item_in_list(this, (last= sl)->item_list,
+ &counter,
+ REPORT_EXCEPT_NOT_FOUND)) !=
+ (Item **)not_found_item)
+ break;
+ if ((tmp= find_field_in_tables(thd, this,
+ sl->get_table_list(), &where,
+ 0)) != not_found_field)
+ break;
+ if (sl->master_unit()->first_select()->linkage ==
+ DERIVED_TABLE_TYPE)
+ break; // do not look over derived table
+ }
+
+ if (!ref)
+ return 1;
+ else if (!tmp)
+ return -1;
+ else if (ref == (Item **)not_found_item && tmp == not_found_field)
+ {
+ // Call to report error
+ find_item_in_list(this,
+ *(thd->lex.current_select->get_item_list()),
+ &counter,
+ REPORT_ALL_ERRORS);
+ ref= 0;
+ return 1;
+ }
+ else if (tmp != not_found_field)
+ {
+ ref= 0; // To prevent "delete *ref;" on ~Item_erf() of this item
+ Item_field* f;
+ if (!((*reference)= f= new Item_field(tmp)))
+ return 1;
+ // store pointer on SELECT_LEX from wich item is dependent
+ f->depended_from= last;
+ thd->lex.current_select->mark_as_dependent(last);
+ return 0;
+ }
+ else
+ {
+ if (!(*ref)->fixed)
+ {
+ my_error(ER_ILLEGAL_REFERENCE, MYF(0), name,
+ "forward reference in item list");
+ return -1;
+ }
+ /*
+ depended_from: pointer on SELECT_LEX from wich item is dependent
+ */
+ ref= (depended_from= last)->ref_pointer_array + counter;
+ thd->lex.current_select->mark_as_dependent(last);
+ }
+ }
+ else if (!ref)
return 1;
- max_length= (*ref)->max_length;
- maybe_null= (*ref)->maybe_null;
- decimals= (*ref)->decimals;
- binary= (*ref)->binary;
+ else
+ {
+ if (!(*ref)->fixed)
+ {
+ my_error(ER_ILLEGAL_REFERENCE, MYF(0), name,
+ "forward reference in item list");
+ return -1;
+ }
+ ref= thd->lex.current_select->ref_pointer_array + counter;
+ }
}
+
+ if (((*ref)->with_sum_func &&
+ (depended_from ||
+ !(thd->lex.current_select->linkage != GLOBAL_OPTIONS_TYPE &&
+ thd->lex.current_select->select_lex()->having_fix_field))) ||
+ !(*ref)->fixed)
+ {
+ my_error(ER_ILLEGAL_REFERENCE, MYF(0), name,
+ ((*ref)->with_sum_func?
+ "reference on group function":
+ "forward reference in item list"));
+ return 1;
+ }
+ max_length= (*ref)->max_length;
+ maybe_null= (*ref)->maybe_null;
+ decimals= (*ref)->decimals;
+ set_charset((*ref)->charset());
+ fixed= 1;
+
+ if (ref && (*ref)->check_cols(1))
+ return 1;
return 0;
}
+bool Item_default_value::eq(const Item *item, bool binary_cmp) const
+{
+ return item->type() == DEFAULT_VALUE_ITEM &&
+ ((Item_default_value *)item)->arg->eq(arg, binary_cmp);
+}
+
+
+bool Item_default_value::fix_fields(THD *thd, struct st_table_list *table_list, Item **items)
+{
+ 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
+ */
+ if (arg->type() == REF_ITEM)
+ {
+ Item_ref *ref= (Item_ref *)arg;
+ if (ref->ref[0]->type() != FIELD_ITEM)
+ {
+ return 1;
+ }
+ arg= ref->ref[0];
+ }
+ Item_field *field_arg= (Item_field *)arg;
+ Field *def_field= (Field*) sql_alloc(field_arg->field->size_of());
+ if (!def_field)
+ return 1;
+ memcpy(def_field, field_arg->field, field_arg->field->size_of());
+ def_field->move_field(def_field->table->default_values() -
+ def_field->table->record[0]);
+ set_field(def_field);
+ return 0;
+}
+
+void Item_default_value::print(String *str)
+{
+ if (!arg)
+ {
+ str->append("DEFAULT");
+ return;
+ }
+ str->append("DEFAULT(");
+ arg->print(str);
+ str->append(')');
+}
+
/*
If item is a const function, calculate it and return a const item
The original item is freed if not returned
@@ -681,6 +1287,8 @@ Item_result item_cmp_type(Item_result a,Item_result b)
return STRING_RESULT;
else if (a == INT_RESULT && b == INT_RESULT)
return INT_RESULT;
+ else if (a == ROW_RESULT || b == ROW_RESULT)
+ return ROW_RESULT;
else
return REAL_RESULT;
}
@@ -697,7 +1305,7 @@ Item *resolve_const_item(Item *item,Item *comp_item)
if (res_type == STRING_RESULT)
{
char buff[MAX_FIELD_WIDTH];
- String tmp(buff,sizeof(buff)),*result;
+ String tmp(buff,sizeof(buff),&my_charset_bin),*result;
result=item->val_str(&tmp);
if (item->null_value)
{
@@ -711,7 +1319,7 @@ Item *resolve_const_item(Item *item,Item *comp_item)
#ifdef DELETE_ITEMS
delete item;
#endif
- return new Item_string(name,tmp_str,length);
+ return new Item_string(name,tmp_str,length,result->charset());
}
if (res_type == INT_RESULT)
{
@@ -752,13 +1360,13 @@ bool field_is_equal_to_item(Field *field,Item *item)
{
char item_buff[MAX_FIELD_WIDTH];
char field_buff[MAX_FIELD_WIDTH];
- String item_tmp(item_buff,sizeof(item_buff)),*item_result;
- String field_tmp(field_buff,sizeof(field_buff));
+ String item_tmp(item_buff,sizeof(item_buff),&my_charset_bin),*item_result;
+ String field_tmp(field_buff,sizeof(field_buff),&my_charset_bin);
item_result=item->val_str(&item_tmp);
if (item->null_value)
return 1; // This must be true
field->val_str(&field_tmp,&field_tmp);
- return !stringcmp(&field_tmp,item_result);
+ return !sortcmp(&field_tmp,item_result,&my_charset_bin);
}
if (res_type == INT_RESULT)
return 1; // Both where of type int
@@ -768,6 +1376,143 @@ bool field_is_equal_to_item(Field *field,Item *item)
return result == field->val_real();
}
+Item_cache* Item_cache::get_cache(Item_result type)
+{
+ switch (type)
+ {
+ case INT_RESULT:
+ return new Item_cache_int();
+ case REAL_RESULT:
+ return new Item_cache_real();
+ case STRING_RESULT:
+ return new Item_cache_str();
+ case ROW_RESULT:
+ return new Item_cache_row();
+ default:
+ // should never be in real life
+ DBUG_ASSERT(0);
+ return 0;
+ }
+}
+
+void Item_cache_str::store(Item *item)
+{
+ str_value.set(buffer, sizeof(buffer), item->charset());
+ value= item->str_result(&str_value);
+ if ((null_value= item->null_value))
+ value= 0;
+ else if (value != &str_value)
+ {
+ /*
+ We copy string value to avoid changing value if 'item' is table field
+ in queries like following (where t1.c is varchar):
+ select a,
+ (select a,b,c from t1 where t1.a=t2.a) = ROW(a,2,'a'),
+ (select c from t1 where a=t2.a)
+ from t2;
+ */
+ str_value.copy(*value);
+ value= &str_value;
+ }
+
+}
+double Item_cache_str::val()
+{
+ int err;
+ if (value)
+ return my_strntod(value->charset(), (char*) value->ptr(),
+ value->length(), (char**) 0, &err);
+ else
+ return (double)0;
+}
+longlong Item_cache_str::val_int()
+{
+ int err;
+ if (value)
+ return my_strntoll(value->charset(), value->ptr(),
+ value->length(), 10, (char**) 0, &err);
+ else
+ return (longlong)0;
+}
+
+bool Item_cache_row::allocate(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)
+{
+ if (!values && allocate(item->cols()))
+ return 1;
+ for (uint i= 0; i < item_count; i++)
+ {
+ Item *el= item->el(i);
+ Item_cache *tmp;
+ if (!(tmp= values[i]= Item_cache::get_cache(el->result_type())))
+ return 1;
+ tmp->setup(el);
+ }
+ return 0;
+}
+
+void Item_cache_row::store(Item * item)
+{
+ null_value= 0;
+ item->bring_value();
+ for (uint i= 0; i < item_count; i++)
+ {
+ values[i]->store(item->el(i));
+ null_value|= values[i]->null_value;
+ }
+}
+
+void Item_cache_row::illegal_method_call(const char *method)
+{
+ DBUG_ENTER("Item_cache_row::illegal_method_call");
+ DBUG_PRINT("error", ("!!! %s method was called for row item", method));
+ DBUG_ASSERT(0);
+ my_error(ER_CARDINALITY_COL, MYF(0), 1);
+ DBUG_VOID_RETURN;
+}
+
+bool Item_cache_row::check_cols(uint c)
+{
+ if (c != item_count)
+ {
+ my_error(ER_CARDINALITY_COL, MYF(0), c);
+ return 1;
+ }
+ return 0;
+}
+
+bool Item_cache_row::null_inside()
+{
+ for (uint i= 0; i < item_count; i++)
+ {
+ if (values[i]->cols() > 1)
+ {
+ if (values[i]->null_inside())
+ return 1;
+ }
+ else
+ {
+ values[i]->val_int();
+ if (values[i]->null_value)
+ return 1;
+ }
+ }
+ return 0;
+}
+
+void Item_cache_row::bring_value()
+{
+ for (uint i= 0; i < item_count; i++)
+ values[i]->bring_value();
+ return;
+}
/*****************************************************************************
** Instantiate templates