diff --git a/sql/item.h b/sql/item.h index d4400f1058d..035f491b349 100644 --- a/sql/item.h +++ b/sql/item.h @@ -126,8 +126,8 @@ public: top AND/OR ctructure of WHERE clause to protect it of optimisation changes in prepared statements */ - Item(THD *thd, Item &item); - virtual ~Item() { name=0; cleanup(); } /*lint -e1509 */ + Item(THD *thd, Item *item); + virtual ~Item() { name=0; } /*lint -e1509 */ void set_name(const char *str,uint length, CHARSET_INFO *cs); void init_make_field(Send_field *tmp_field,enum enum_field_types type); virtual void cleanup() { fixed=0; } @@ -206,6 +206,7 @@ public: virtual Item *get_tmp_table_item(THD *thd) { return copy_or_same(thd); } CHARSET_INFO *default_charset() const; + virtual CHARSET_INFO *compare_collation() { return NULL; } virtual bool walk(Item_processor processor, byte *arg) { @@ -239,6 +240,11 @@ public: /* Used in sql_select.cc:eliminate_not_funcs() */ virtual Item *neg_transformer() { return NULL; } + void delete_self() + { + cleanup(); + delete this; + } }; @@ -304,7 +310,10 @@ public: inline void make_field(Send_field *field) { - this_item()->make_field(field); + Item *it= this_item(); + + it->set_name(m_name.str, m_name.length, system_charset_info); + it->make_field(field); } inline Item_result result_type() const @@ -326,6 +335,11 @@ public: { str->append(m_name.str, m_name.length); } + + inline bool send(Protocol *protocol, String *str) + { + return this_item()->send(protocol, str); + } }; @@ -339,7 +353,7 @@ public: st_select_lex *depended_from; Item_ident(const char *db_name_par,const char *table_name_par, const char *field_name_par); - Item_ident(THD *thd, Item_ident &item); + Item_ident(THD *thd, Item_ident *item); const char *full_name() const; bool remove_dependence_processor(byte * arg); @@ -362,7 +376,7 @@ public: item_equal(0) { collation.set(DERIVATION_IMPLICIT); } // Constructor need to process subselect with temporary tables (see Item) - Item_field(THD *thd, Item_field &item); + Item_field(THD *thd, Item_field *item); Item_field(Field *field); enum Type type() const { return FIELD_ITEM; } bool eq(const Item *item, bool binary_cmp) const; @@ -393,6 +407,7 @@ public: bool get_time(TIME *ltime); bool is_null() { return field->is_null(); } Item *get_tmp_table_item(THD *thd); + void cleanup(); Item_equal *find_item_equal(COND_EQUAL *cond_equal); Item *equal_fields_propagator(byte *arg); bool replace_equal_field_processor(byte *arg); @@ -583,7 +598,7 @@ public: CHARSET_INFO *cs, Derivation dv= DERIVATION_COERCIBLE) { collation.set(cs, dv); - str_value.set(str,length,cs); + str_value.set_or_copy_aligned(str,length,cs); /* We have to have a different max_length than 'length' here to ensure that we get the right length if we do use the item @@ -599,12 +614,11 @@ public: CHARSET_INFO *cs, Derivation dv= DERIVATION_COERCIBLE) { collation.set(cs, dv); - str_value.set(str,length,cs); + str_value.set_or_copy_aligned(str,length,cs); max_length= str_value.numchars()*cs->mbmaxlen; set_name(name_par,0,cs); decimals=NOT_FIXED_DEC; } - ~Item_string() {} enum Type type() const { return STRING_ITEM; } double val() { @@ -671,7 +685,6 @@ class Item_varbinary :public Item { public: Item_varbinary(const char *str,uint str_length); - ~Item_varbinary() {} enum Type type() const { return VARBIN_ITEM; } double val() { return (double) Item_varbinary::val_int(); } longlong val_int(); @@ -688,8 +701,8 @@ public: Field *result_field; /* Save result here */ Item_result_field() :result_field(0) {} // Constructor used for Item_sum/Item_cond_and/or (see Item comment) - Item_result_field(THD *thd, Item_result_field &item): - Item(thd, item), result_field(item.result_field) + Item_result_field(THD *thd, Item_result_field *item): + Item(thd, item), result_field(item->result_field) {} ~Item_result_field() {} /* Required with gcc 2.95 */ Field *get_tmp_table_field() { return result_field; } @@ -708,20 +721,25 @@ public: class Item_ref :public Item_ident { public: - Field *result_field; /* Save result here */ + Field *result_field; /* Save result here */ Item **ref; - Item_ref(const char *db_par, const char *table_name_par, - const char *field_name_par) - :Item_ident(db_par,table_name_par,field_name_par),ref(0) {} - Item_ref(Item **item, const char *table_name_par, const char *field_name_par) - :Item_ident(NullS,table_name_par,field_name_par),ref(item) {} + Item **hook_ptr; /* These two to restore */ + Item *orig_item; /* things in 'cleanup()' */ + Item_ref(Item **hook, Item *original,const char *db_par, + const char *table_name_par, const char *field_name_par) + :Item_ident(db_par,table_name_par,field_name_par),ref(0), hook_ptr(hook), + orig_item(original) {} + Item_ref(Item **item, Item **hook, + const char *table_name_par, const char *field_name_par) + :Item_ident(NullS,table_name_par,field_name_par), + ref(item), hook_ptr(hook), orig_item(hook ? *hook:0) {} // Constructor need to process subselect with temporary tables (see Item) - Item_ref(THD *thd, Item_ref &item) - :Item_ident(thd, item), ref(item.ref) {} + Item_ref(THD *thd, Item_ref *item, Item **hook) + :Item_ident(thd, item), ref(item->ref), + hook_ptr(hook), orig_item(hook ? *hook : 0) {} enum Type type() const { return REF_ITEM; } bool eq(const Item *item, bool binary_cmp) const { return ref && (*ref)->eq(item, binary_cmp); } - ~Item_ref() { if (ref && (*ref) && (*ref) != this) delete *ref; } double val() { double tmp=(*ref)->val_result(); @@ -766,6 +784,7 @@ public: } Item *real_item() { return *ref; } void print(String *str); + void cleanup(); }; class Item_in_subselect; @@ -776,7 +795,7 @@ protected: public: Item_ref_null_helper(Item_in_subselect* master, Item **item, const char *table_name_par, const char *field_name_par): - Item_ref(item, table_name_par, field_name_par), owner(master) {} + Item_ref(item, NULL, table_name_par, field_name_par), owner(master) {} double val(); longlong val_int(); String* val_str(String* s); @@ -840,7 +859,6 @@ public: name=item->name; cached_field_type= item->field_type(); } - ~Item_copy_string() { delete item; } enum Type type() const { return COPY_STR_ITEM; } enum Item_result result_type () const { return STRING_RESULT; } enum_field_types field_type() const { return cached_field_type; } @@ -997,13 +1015,15 @@ public: void set_used_tables(table_map map) { used_table_map= map; } virtual bool allocate(uint i) { return 0; }; - virtual bool setup(Item *item) { example= item; return 0; }; - virtual void store(Item *)= 0; - void set_len_n_dec(uint32 max_len, uint8 dec) + virtual bool setup(Item *item) { - max_length= max_len; - decimals= dec; - } + example= item; + max_length= item->max_length; + decimals= item->decimals; + collation.set(item->collation); + return 0; + }; + virtual void store(Item *)= 0; enum Type type() const { return CACHE_ITEM; } static Item_cache* get_cache(Item_result type); table_map used_tables() const { return used_table_map; } @@ -1028,7 +1048,7 @@ class Item_cache_real: public Item_cache double value; public: Item_cache_real(): Item_cache() {} - + void store(Item *item); double val() { return value; } longlong val_int() { return (longlong) (value+(value > 0 ? 0.5 : -0.5)); } @@ -1101,6 +1121,11 @@ public: bool check_cols(uint c); bool null_inside(); void bring_value(); + void cleanup() + { + Item_cache::cleanup(); + values= 0; + } }; @@ -1111,6 +1136,7 @@ class Item_type_holder: public Item { protected: Item_result item_type; + Item_result orig_type; Field *field_example; public: Item_type_holder(THD*, Item*); @@ -1122,6 +1148,11 @@ public: String *val_str(String*); bool join_types(THD *thd, Item *); Field *example() { return field_example; } + void cleanup() + { + Item::cleanup(); + item_type= orig_type; + } }; diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 67603eeeccd..6bcec4fef17 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -301,10 +301,11 @@ typedef struct st_qsel_param { uint imerge_cost_buff_size; /* size of the buffer */ } PARAM; -static SEL_TREE * get_mm_parts(PARAM *param,Field *field, +static SEL_TREE * get_mm_parts(PARAM *param,COND *cond_func,Field *field, Item_func::Functype type,Item *value, Item_result cmp_type); -static SEL_ARG *get_mm_leaf(PARAM *param,Field *field,KEY_PART *key_part, +static SEL_ARG *get_mm_leaf(PARAM *param,COND *cond_func,Field *field, + KEY_PART *key_part, Item_func::Functype type,Item *value); static SEL_TREE *get_mm_tree(PARAM *param,COND *cond); static ha_rows check_quick_select(PARAM *param,uint index,SEL_ARG *key_tree); @@ -612,14 +613,25 @@ SQL_SELECT::SQL_SELECT() :quick(0),cond(0),free_cond(0) } -SQL_SELECT::~SQL_SELECT() +void SQL_SELECT::cleanup() { delete quick; + quick= 0; if (free_cond) + { + free_cond=0; delete cond; + cond= 0; + } close_cached_file(&file); } + +SQL_SELECT::~SQL_SELECT() +{ + cleanup(); +} + #undef index // Fix for Unixware 7 QUICK_SELECT_I::QUICK_SELECT_I() @@ -1746,7 +1758,8 @@ static SEL_TREE *get_mm_tree(PARAM *param,COND *cond) static SEL_TREE * -get_mm_parts(PARAM *param, Field *field, Item_func::Functype type, +get_mm_parts(PARAM *param, COND *cond_func, Field *field, + Item_func::Functype type, Item *value, Item_result cmp_type) { DBUG_ENTER("get_mm_parts"); @@ -1768,7 +1781,8 @@ get_mm_parts(PARAM *param, Field *field, Item_func::Functype type, DBUG_RETURN(0); // OOM if (!value || !(value->used_tables() & ~param->read_tables)) { - sel_arg=get_mm_leaf(param,key_part->field,key_part,type,value); + sel_arg=get_mm_leaf(param,cond_func, + key_part->field,key_part,type,value); if (!sel_arg) continue; if (sel_arg->type == SEL_ARG::IMPOSSIBLE) @@ -1794,7 +1808,7 @@ get_mm_parts(PARAM *param, Field *field, Item_func::Functype type, static SEL_ARG * -get_mm_leaf(PARAM *param, Field *field, KEY_PART *key_part, +get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part, Item_func::Functype type,Item *value) { uint maybe_null=(uint) field->real_maybe_null(), copies; @@ -1803,6 +1817,32 @@ get_mm_leaf(PARAM *param, Field *field, KEY_PART *key_part, char *str, *str2; DBUG_ENTER("get_mm_leaf"); + if (!value) // IS NULL or IS NOT NULL + { + if (field->table->outer_join) // Can't use a key on this + DBUG_RETURN(0); + if (!maybe_null) // Not null field + DBUG_RETURN(type == Item_func::ISNULL_FUNC ? &null_element : 0); + if (!(tree=new SEL_ARG(field,is_null_string,is_null_string))) + DBUG_RETURN(0); // out of memory + if (type == Item_func::ISNOTNULL_FUNC) + { + tree->min_flag=NEAR_MIN; /* IS NOT NULL -> X > NULL */ + tree->max_flag=NO_MAX_RANGE; + } + DBUG_RETURN(tree); + } + + /* + We can't use an index when comparing strings of + different collations + */ + if (field->result_type() == STRING_RESULT && + value->result_type() == STRING_RESULT && + key_part->image_type == Field::itRAW && + ((Field_str*)field)->charset() != conf_func->compare_collation()) + DBUG_RETURN(0); + if (type == Item_func::LIKE_FUNC) { bool like_error; @@ -1866,22 +1906,6 @@ get_mm_leaf(PARAM *param, Field *field, KEY_PART *key_part, DBUG_RETURN(new SEL_ARG(field,min_str,max_str)); } - if (!value) // IS NULL or IS NOT NULL - { - if (field->table->outer_join) // Can't use a key on this - DBUG_RETURN(0); - if (!maybe_null) // Not null field - DBUG_RETURN(type == Item_func::ISNULL_FUNC ? &null_element : 0); - if (!(tree=new SEL_ARG(field,is_null_string,is_null_string))) - DBUG_RETURN(0); // out of memory - if (type == Item_func::ISNOTNULL_FUNC) - { - tree->min_flag=NEAR_MIN; /* IS NOT NULL -> X > NULL */ - tree->max_flag=NO_MAX_RANGE; - } - DBUG_RETURN(tree); - } - if (!field->optimize_range(param->real_keynr[key_part->key]) && type != Item_func::EQ_FUNC && type != Item_func::EQUAL_FUNC) @@ -1895,7 +1919,7 @@ get_mm_leaf(PARAM *param, Field *field, KEY_PART *key_part, value->result_type() != STRING_RESULT && field->cmp_type() != value->result_type()) DBUG_RETURN(0); - + if (value->save_in_field(field, 1) > 0) { /* This happens when we try to insert a NULL field in a not null column */ @@ -3097,6 +3121,7 @@ check_quick_select(PARAM *param,uint idx,SEL_ARG *tree) param->table->quick_rows[key]=records; param->table->quick_key_parts[key]=param->max_key_part+1; } + DBUG_PRINT("exit", ("Records: %lu", (ulong) records)); DBUG_RETURN(records); } @@ -3440,8 +3465,30 @@ QUICK_RANGE_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table, key_part->part_length+=HA_KEY_BLOB_LENGTH; key_part->null_bit= key_info->key_part[part].null_bit; } - if (!insert_dynamic(&quick->ranges,(gptr)&range)) - return quick; + if (insert_dynamic(&quick->ranges,(gptr)&range)) + goto err; + + /* + Add a NULL range if REF_OR_NULL optimization is used. + For example: + if we have "WHERE A=2 OR A IS NULL" we created the (A=2) range above + and have ref->null_ref_key set. Will create a new NULL range here. + */ + if (ref->null_ref_key) + { + QUICK_RANGE *null_range; + + *ref->null_ref_key= 1; // Set null byte then create a range + if (!(null_range= new QUICK_RANGE(ref->key_buff, ref->key_length, + ref->key_buff, ref->key_length, + EQ_RANGE))) + goto err; + *ref->null_ref_key= 0; // Clear null byte + if (insert_dynamic(&quick->ranges,(gptr)&null_range)) + goto err; + } + + return quick; err: delete quick; @@ -3584,12 +3631,7 @@ int QUICK_RANGE_SELECT::get_next() int result; if (range) { // Already read through key -/* result=((range->flag & EQ_RANGE) ? - file->index_next_same(record, (byte*) range->min_key, - range->min_length) : - file->index_next(record)); -*/ - result=((range->flag & (EQ_RANGE | GEOM_FLAG) ) ? + result=((range->flag & (EQ_RANGE | GEOM_FLAG)) ? file->index_next_same(record, (byte*) range->min_key, range->min_length) : file->index_next(record)); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index ba911f47490..6f9353eefd4 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -24,8 +24,6 @@ #include "mysql_priv.h" #include "sql_select.h" -#include "opt_ft.h" - #include #include #include @@ -89,7 +87,7 @@ static int do_select(JOIN *join,List *fields,TABLE *tmp_table, Procedure *proc); static int sub_select_cache(JOIN *join,JOIN_TAB *join_tab,bool end_of_records); static int sub_select(JOIN *join,JOIN_TAB *join_tab,bool end_of_records); -static int flush_cached_records(JOIN *join,JOIN_TAB *join_tab,bool skipp_last); +static int flush_cached_records(JOIN *join,JOIN_TAB *join_tab,bool skip_last); static int end_send(JOIN *join, JOIN_TAB *join_tab, bool end_of_records); static int end_send_group(JOIN *join, JOIN_TAB *join_tab,bool end_of_records); static int end_write(JOIN *join, JOIN_TAB *join_tab, bool end_of_records); @@ -182,7 +180,6 @@ int handle_select(THD *thd, LEX *lex, select_result *result) register SELECT_LEX *select_lex = &lex->select_lex; DBUG_ENTER("handle_select"); - fix_tables_pointers(lex->all_selects_list); if (select_lex->next_select()) res=mysql_union(thd, lex, result, &lex->unit); else @@ -309,7 +306,7 @@ JOIN::prepare(Item ***rref_pointer_array, /* Check that all tables, fields, conds and order are ok */ - if (setup_tables(tables_list) || + if (setup_tables(tables_list, 0) || setup_wild(thd, tables_list, fields_list, &all_fields, wild_num) || select_lex->setup_ref_array(thd, og_num) || setup_fields(thd, (*rref_pointer_array), tables_list, fields_list, 1, @@ -939,8 +936,10 @@ JOIN::optimize() as in other cases the join is done before the sort. */ if (const_tables != tables && - (order || group_list) && join_tab[const_tables].type != JT_ALL && + (order || group_list) && + join_tab[const_tables].type != JT_ALL && join_tab[const_tables].type != JT_FT && + join_tab[const_tables].type != JT_REF_OR_NULL && (order && simple_order || group_list && simple_group)) { if (add_ref_to_table_cond(thd,&join_tab[const_tables])) @@ -1094,7 +1093,7 @@ JOIN::reinit() if (unit->select_limit_cnt == HA_POS_ERROR) select_lex->options&= ~OPTION_FOUND_ROWS; - if (setup_tables(tables_list)) + if (setup_tables(tables_list, 1)) DBUG_RETURN(1); /* Reset of sum functions */ @@ -1590,12 +1589,7 @@ JOIN::cleanup() JOIN_TAB *tab, *end; for (tab= join_tab, end= tab+tables ; tab != end ; tab++) { - delete tab->select; - delete tab->quick; - tab->select=0; - tab->quick=0; - x_free(tab->cache.buff); - tab->cache.buff= 0; + tab->cleanup(); } } tmp_join->tmp_join= 0; @@ -1659,13 +1653,14 @@ mysql_select(THD *thd, Item ***rref_pointer_array, goto err; } } - free_join= 0; } + free_join= 0; join->select_options= select_options; } else { - join= new JOIN(thd, fields, select_options, result); + if (!(join= new JOIN(thd, fields, select_options, result))) + DBUG_RETURN(-1); thd->proc_info="init"; thd->used_tables=0; // Updated by setup_fields if (join->prepare(rref_pointer_array, tables, wild_num, @@ -1726,8 +1721,8 @@ static ha_rows get_quick_record_count(THD *thd, SQL_SELECT *select, { select->head=table; table->reginfo.impossible_range=0; - if ((error=select->test_quick_select(thd, *(key_map *)keys,(table_map) 0,limit)) - == 1) + if ((error=select->test_quick_select(thd, *(key_map *)keys,(table_map) 0, + limit)) == 1) DBUG_RETURN(select->quick->records); if (error == -1) { @@ -2210,7 +2205,7 @@ merge_key_fields(KEY_FIELD *start,KEY_FIELD *new_fields,KEY_FIELD *end, */ static void -add_key_field(KEY_FIELD **key_fields,uint and_level, +add_key_field(KEY_FIELD **key_fields,uint and_level, COND *cond, Field *field,bool eq_func,Item **value, uint num_values, table_map usable_tables) { @@ -2277,6 +2272,17 @@ add_key_field(KEY_FIELD **key_fields,uint and_level, (*value)->result_type() != STRING_RESULT && field->cmp_type() != (*value)->result_type()) return; + + /* + We can't use indexes if the effective collation + of the operation differ from the field collation. + */ + if (field->result_type() == STRING_RESULT && + (*value)->result_type() == STRING_RESULT && + field->cmp_type() == STRING_RESULT && + ((Field_str*)field)->charset() != cond->compare_collation()) + return; + } } DBUG_ASSERT(num_values == 1); @@ -3441,7 +3447,7 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, KEYUSE *org_keyuse, { /* Must read with repeat */ j->type= null_ref_key ? JT_REF_OR_NULL : JT_REF; - j->null_ref_key= null_ref_key; + j->ref.null_ref_key= null_ref_key; } else if (ref_key == j->ref.key_copy) { @@ -3920,6 +3926,41 @@ bool error_if_full_join(JOIN *join) } +/* + cleanup JOIN_TAB + + SYNOPSIS + JOIN_TAB::cleanup() +*/ + +void JOIN_TAB::cleanup() +{ + delete select; + select= 0; + delete quick; + quick= 0; + x_free(cache.buff); + cache.buff= 0; + if (table) + { + if (table->key_read) + { + table->key_read= 0; + table->file->extra(HA_EXTRA_NO_KEYREAD); + } + /* Don't free index if we are using read_record */ + if (!read_record.table) + table->file->index_end(); + /* + We need to reset this for next select + (Tested in part_of_refkey) + */ + table->reginfo.join_tab= 0; + } + end_read_record(&read_record); +} + + /* Free resources of given join @@ -3954,11 +3995,6 @@ JOIN::join_free(bool full) { if (tab->table) { - if (tab->table->key_read) - { - tab->table->key_read= 0; - tab->table->file->extra(HA_EXTRA_NO_KEYREAD); - } /* Don't free index if we are using read_record */ if (!tab->read_record.table) tab->table->file->index_end(); @@ -3969,29 +4005,7 @@ JOIN::join_free(bool full) { for (tab= join_tab, end= tab+tables; tab != end; tab++) { - delete tab->select; - delete tab->quick; - tab->select=0; - tab->quick=0; - x_free(tab->cache.buff); - tab->cache.buff= 0; - if (tab->table) - { - if (tab->table->key_read) - { - tab->table->key_read= 0; - tab->table->file->extra(HA_EXTRA_NO_KEYREAD); - } - /* Don't free index if we are using read_record */ - if (!tab->read_record.table) - tab->table->file->index_end(); - /* - We need to reset this for next select - (Tested in part_of_refkey) - */ - tab->table->reginfo.join_tab= 0; - } - end_read_record(&tab->read_record); + tab->cleanup(); } table= 0; } @@ -5237,17 +5251,9 @@ remove_eq_conds(COND *cond,Item::cond_result *cond_value) { Item *new_item=remove_eq_conds(item,&tmp_cond_value); if (!new_item) - { -#ifdef DELETE_ITEMS - delete item; // This may be shared -#endif li.remove(); - } else if (item != new_item) { -#ifdef DELETE_ITEMS - delete item; // This may be shared -#endif VOID(li.replace(new_item)); should_fix_fields=1; } @@ -6604,14 +6610,14 @@ sub_select(JOIN *join,JOIN_TAB *join_tab,bool end_of_records) static int -flush_cached_records(JOIN *join,JOIN_TAB *join_tab,bool skipp_last) +flush_cached_records(JOIN *join,JOIN_TAB *join_tab,bool skip_last) { int error; READ_RECORD *info; if (!join_tab->cache.records) return 0; /* Nothing to do */ - if (skipp_last) + if (skip_last) (void) store_record_in_cache(&join_tab->cache); // Must save this for later if (join_tab->use_quick == 2) { @@ -6645,21 +6651,21 @@ flush_cached_records(JOIN *join,JOIN_TAB *join_tab,bool skipp_last) } SQL_SELECT *select=join_tab->select; if (!error && (!join_tab->cache.select || - !join_tab->cache.select->skipp_record())) + !join_tab->cache.select->skip_record())) { uint i; reset_cache(&join_tab->cache); - for (i=(join_tab->cache.records- (skipp_last ? 1 : 0)) ; i-- > 0 ;) + for (i=(join_tab->cache.records- (skip_last ? 1 : 0)) ; i-- > 0 ;) { read_cached_record(join_tab); - if (!select || !select->skipp_record()) + if (!select || !select->skip_record()) if ((error=(join_tab->next_select)(join,join_tab+1,0)) < 0) return error; /* purecov: inspected */ } } } while (!(error=info->read_record(info))); - if (skipp_last) + if (skip_last) read_cached_record(join_tab); // Restore current record reset_cache(&join_tab->cache); join_tab->cache.records=0; join_tab->cache.ptr_record= (uint) ~0; @@ -7066,12 +7072,12 @@ join_read_always_key_or_null(JOIN_TAB *tab) int res; /* First read according to key which is NOT NULL */ - *tab->null_ref_key=0; + *tab->ref.null_ref_key= 0; // Clear null byte if ((res= join_read_always_key(tab)) >= 0) return res; /* Then read key with null value */ - *tab->null_ref_key= 1; + *tab->ref.null_ref_key= 1; // Set null byte return safe_index_read(tab); } @@ -7085,10 +7091,10 @@ join_read_next_same_or_null(READ_RECORD *info) JOIN_TAB *tab= info->table->reginfo.join_tab; /* Test if we have already done a read after null key */ - if (*tab->null_ref_key) + if (*tab->ref.null_ref_key) return -1; // All keys read - *tab->null_ref_key= 1; // Read null key - return safe_index_read(tab); + *tab->ref.null_ref_key= 1; // Set null byte + return safe_index_read(tab); // then read null keys } @@ -8061,8 +8067,9 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order, For impossible ranges (like when doing a lookup on NULL on a NOT NULL field, quick will contain an empty record set. */ - if (!(select->quick=get_ft_or_quick_select_for_ref(tab->join->thd, - table, tab))) + if (!(select->quick= tab->type == JT_FT ? + new FT_SELECT(thd, table, tab->ref.key) : + get_quick_select_for_ref(thd, table, &tab->ref))) goto err; } } @@ -8070,9 +8077,12 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order, table->file->info(HA_STATUS_VARIABLE); // Get record count table->sort.found_records=filesort(thd, table,sortorder, length, select, filesort_limit, &examined_rows); - tab->records=table->sort.found_records; // For SQL_CALC_ROWS - delete select; // filesort did select - tab->select=0; + tab->records= table->sort.found_records; // For SQL_CALC_ROWS + if (select) + { + select->cleanup(); // filesort did select + tab->select= 0; + } tab->select_cond=0; tab->type=JT_ALL; // Read with normal read_record tab->read_first_record= join_init_read_record; @@ -9155,7 +9165,7 @@ setup_copy_fields(THD *thd, TMP_TABLE_PARAM *param, if (pos->type() == Item::FIELD_ITEM) { Item_field *item; - if (!(item= new Item_field(thd, *((Item_field*) pos)))) + if (!(item= new Item_field(thd, ((Item_field*) pos)))) goto err; pos= item; if (item->field->flags & BLOB_FLAG) @@ -10056,20 +10066,23 @@ int mysql_explain_union(THD *thd, SELECT_LEX_UNIT *unit, select_result *result) sl; sl= sl->next_select()) { + // drop UNCACHEABLE_EXPLAIN, because it is for internal usage only + uint8 uncacheable= (sl->uncacheable & ~UNCACHEABLE_EXPLAIN); + res= mysql_explain_select(thd, sl, (((&thd->lex->select_lex)==sl)? - ((thd->lex->all_selects_list != sl)?"PRIMARY": - "SIMPLE"): + ((thd->lex->all_selects_list != sl) ? + primary_key_name : "SIMPLE"): ((sl == first)? ((sl->linkage == DERIVED_TABLE_TYPE) ? "DERIVED": - ((sl->uncacheable & UNCACHEABLE_DEPENDENT)? + ((uncacheable & UNCACHEABLE_DEPENDENT) ? "DEPENDENT SUBQUERY": - (sl->uncacheable?"UNCACHEABLE SUBQUERY": + (uncacheable?"UNCACHEABLE SUBQUERY": "SUBQUERY"))): - ((sl->uncacheable & UNCACHEABLE_DEPENDENT)? + ((uncacheable & UNCACHEABLE_DEPENDENT) ? "DEPENDENT UNION": - sl->uncacheable?"UNCACHEABLE UNION": + uncacheable?"UNCACHEABLE UNION": "UNION"))), result); if (res)