diff options
Diffstat (limited to 'sql/item.cc')
-rw-r--r-- | sql/item.cc | 1013 |
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(<ime, 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 |