diff --git a/sql/filesort.cc b/sql/filesort.cc index a1c7b5f421fd2140bef2c2469cbda4ded5815bfa..1967c08962236313a2201bcc6e41c7e7165430e6 100644 --- a/sql/filesort.cc +++ b/sql/filesort.cc @@ -48,7 +48,8 @@ static int merge_index(SORTPARAM *param,uchar *sort_buffer, BUFFPEK *buffpek, uint maxbuffer,IO_CACHE *tempfile, IO_CACHE *outfile); -static bool save_index(SORTPARAM *param,uchar **sort_keys, uint count); +static bool save_index(SORTPARAM *param,uchar **sort_keys, uint count, + FILESORT_INFO *table_sort); static uint sortlength(SORT_FIELD *sortorder, uint s_length, bool *multi_byte_charset); static SORT_ADDON_FIELD *get_addon_fields(THD *thd, Field **ptabfield, @@ -85,7 +86,9 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length, #ifdef SKIP_DBUG_IN_FILESORT DBUG_PUSH(""); /* No DBUG here */ #endif - + FILESORT_INFO table_sort; + bzero(&table_sort, sizeof(FILESORT_INFO)); + outfile= table->sort.io_cache; my_b_clear(&tempfile); my_b_clear(&buffpek_pointers); @@ -107,14 +110,15 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length, param.sort_length, ¶m.addon_length); } - table->sort.addon_buf= 0; - table->sort.addon_length= param.addon_length; - table->sort.addon_field= param.addon_field; - table->sort.unpack= unpack_addon_fields; + + table_sort.addon_buf= 0; + table_sort.addon_length= param.addon_length; + table_sort.addon_field= param.addon_field; + table_sort.unpack= unpack_addon_fields; if (param.addon_field) { param.res_length= param.addon_length; - if (!(table->sort.addon_buf= (byte *) my_malloc(param.addon_length, + if (!(table_sort.addon_buf= (byte *) my_malloc(param.addon_length, MYF(MY_WME)))) goto err; } @@ -193,7 +197,7 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length, if (maxbuffer == 0) // The whole set is in memory { - if (save_index(¶m,sort_keys,(uint) records)) + if (save_index(¶m,sort_keys,(uint) records, &table_sort)) goto err; } else @@ -256,6 +260,8 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length, #ifdef SKIP_DBUG_IN_FILESORT DBUG_POP(); /* Ok to DBUG */ #endif + memcpy(&table->sort, &table_sort, sizeof(FILESORT_INFO)); + table->sort.io_cache= outfile; DBUG_PRINT("exit",("records: %ld",records)); DBUG_RETURN(error ? HA_POS_ERROR : records); } /* filesort */ @@ -359,12 +365,24 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select, current_thd->variables.read_buff_size); } + READ_RECORD read_record_info; + if (quick_select) + { + if (select->quick->reset()) + DBUG_RETURN(HA_POS_ERROR); + init_read_record(&read_record_info, current_thd, select->quick->head, + select, 1, 1); + } + for (;;) { if (quick_select) { - if ((error=select->quick->get_next())) - break; + if ((error= read_record_info.read_record(&read_record_info))) + { + error= HA_ERR_END_OF_FILE; + break; + } file->position(sort_form->record[0]); } else /* Not quick-select */ @@ -392,6 +410,7 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select, if (error && error != HA_ERR_RECORD_DELETED) break; } + if (*killed) { DBUG_PRINT("info",("Sort killed by user")); @@ -425,8 +444,14 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select, else file->unlock_row(); } - (void) file->extra(HA_EXTRA_NO_CACHE); /* End cacheing of records */ - file->rnd_end(); + if (quick_select) + end_read_record(&read_record_info); + else + { + (void) file->extra(HA_EXTRA_NO_CACHE); /* End cacheing of records */ + file->rnd_end(); + } + DBUG_PRINT("test",("error: %d indexpos: %d",error,indexpos)); if (error != HA_ERR_END_OF_FILE) { @@ -664,8 +689,8 @@ static void make_sortkey(register SORTPARAM *param, return; } - -static bool save_index(SORTPARAM *param, uchar **sort_keys, uint count) +static bool save_index(SORTPARAM *param, uchar **sort_keys, uint count, + FILESORT_INFO *table_sort) { uint offset,res_length; byte *to; @@ -676,7 +701,7 @@ static bool save_index(SORTPARAM *param, uchar **sort_keys, uint count) offset= param->rec_length-res_length; if ((ha_rows) count > param->max_rows) count=(uint) param->max_rows; - if (!(to= param->sort_form->sort.record_pointers= + if (!(to= table_sort->record_pointers= (byte*) my_malloc(res_length*count, MYF(MY_WME)))) DBUG_RETURN(1); /* purecov: inspected */ for (uchar **end= sort_keys+count ; sort_keys != end ; sort_keys++) diff --git a/sql/opt_range.cc b/sql/opt_range.cc index a2c29a1ff6f314405454ed0a8fc3503d4f036b3f..91b3fa6616960da1b0eac9fdf786c72a567d07aa 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -649,27 +649,32 @@ QUICK_RANGE_SELECT::~QUICK_RANGE_SELECT() } -QUICK_INDEX_MERGE_SELECT::QUICK_INDEX_MERGE_SELECT(THD *thd, TABLE *table) - :cur_quick_it(quick_selects), index_merge(thd) +QUICK_INDEX_MERGE_SELECT::QUICK_INDEX_MERGE_SELECT(THD *thd_param, TABLE *table) + :cur_quick_it(quick_selects), thd(thd_param), unique(NULL) { index= MAX_KEY; head= table; + reset_called= false; init_sql_alloc(&alloc,1024,0); } int QUICK_INDEX_MERGE_SELECT::init() { - int error; cur_quick_it.rewind(); cur_quick_select= cur_quick_it++; - if ((error= index_merge.init(head))) - return error; return cur_quick_select->init(); } -void QUICK_INDEX_MERGE_SELECT::reset() +int QUICK_INDEX_MERGE_SELECT::reset() { - cur_quick_select->reset(); + int result; + DBUG_ENTER("QUICK_INDEX_MERGE_SELECT::reset"); + if (reset_called) + DBUG_RETURN(0); + + reset_called= true; + result = cur_quick_select->reset() && prepare_unique(); + DBUG_RETURN(result); } bool @@ -1150,12 +1155,6 @@ imerge_fail:; ("Failed to allocate index merge structures," "falling back to full scan.")); } - else - { - /* with 'using filesort' quick->reset() is not called */ - quick->reset(); - } - goto end; } } @@ -1170,9 +1169,9 @@ imerge_fail:; DBUG_EXECUTE("info", { if (quick_imerge) - print_quick_sel_imerge(quick_imerge, &needed_reg); + print_quick_sel_imerge(quick_imerge, needed_reg); else - print_quick_sel_range((QUICK_RANGE_SELECT*)quick, &needed_reg); + print_quick_sel_range((QUICK_RANGE_SELECT*)quick, needed_reg); } ); @@ -1721,6 +1720,7 @@ tree_and(PARAM *param,SEL_TREE *tree1,SEL_TREE *tree2) uint flag=0; if (*key1 || *key2) { + trees_have_key = true; if (*key1 && !(*key1)->simple_key()) flag|=CLONE_KEY1_MAYBE; if (*key2 && !(*key2)->simple_key()) @@ -3079,165 +3079,24 @@ QUICK_RANGE_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table, return 0; } -INDEX_MERGE::INDEX_MERGE(THD *thd_arg) : - dont_save(false), thd(thd_arg) -{} - -String *INDEX_MERGE::Item_rowid::val_str(String *str) -{ - str->set_quick((char*)head->file->ref, head->file->ref_length, collation.collation); - return str; -} - - -/* - Initialize index_merge operation. - RETURN - 0 - OK - other - error. -*/ - -int INDEX_MERGE::init(TABLE *table) -{ - DBUG_ENTER("INDEX_MERGE::init"); - - head= table; - if (!(rowid_item= new Item_rowid(table))) - DBUG_RETURN(1); - - tmp_table_param.copy_field= 0; - tmp_table_param.end_write_records= HA_POS_ERROR; - tmp_table_param.group_length= table->file->ref_length; - tmp_table_param.group_parts= 1; - tmp_table_param.group_null_parts= 0; - tmp_table_param.hidden_field_count= 0; - tmp_table_param.field_count= 0; - tmp_table_param.func_count= 1; - tmp_table_param.sum_func_count= 0; - tmp_table_param.quick_group= 1; - - bzero(&order, sizeof(ORDER)); - order.item= (Item**)&rowid_item; - order.asc= 1; - - fields.push_back(rowid_item); - - temp_table= create_tmp_table(thd, - &tmp_table_param, - fields, - &order, - false, - 0, - SELECT_DISTINCT, - HA_POS_ERROR, - (char *)""); - DBUG_RETURN(!temp_table); -} +#define MEM_STRIP_BUF_SIZE current_thd->variables.sortbuff_size /* - Check if record with ROWID record_pos has already been processed and - if not - store the ROWID value. - - RETURN - 0 - record has not been processed yet - 1 - record has already been processed. - -1 - an error occurred and query processing should be terminated. - Error code is stored in INDEX_MERGE::error + Fetch all row ids into unique. */ - -int INDEX_MERGE::check_record_in() -{ - return (dont_save)? - check_record() : - put_record(); -} - - -/* - Stop remembering records in check(). - (this should be called just before the last key scan) - - RETURN - 0 - OK - 1 - error occurred initializing table index. -*/ - -int INDEX_MERGE::start_last_quick_select() -{ - int result= 0; - if (!temp_table->uniques) - { - dont_save= true; - result= temp_table->file->index_init(0); - } - return result; -} - - -inline int INDEX_MERGE::put_record() +int QUICK_INDEX_MERGE_SELECT::prepare_unique() { - DBUG_ENTER("INDEX_MERGE::put_record"); + int result; + DBUG_ENTER("QUICK_INDEX_MERGE_SELECT::prepare_unique"); - copy_funcs(tmp_table_param.items_to_copy); - - if ((error= temp_table->file->write_row(temp_table->record[0]))) - { - if (error == HA_ERR_FOUND_DUPP_KEY || - error == HA_ERR_FOUND_DUPP_UNIQUE) - DBUG_RETURN(1); - - DBUG_PRINT("info", - ("Error writing row to temp. table: %d, converting to myisam", - error)); - if (create_myisam_from_heap(current_thd, temp_table, &tmp_table_param, - error,1)) - { - DBUG_PRINT("info", ("Table conversion failed, bailing out")); - DBUG_RETURN(-1); - } - } - - DBUG_RETURN(0); -} - -inline int INDEX_MERGE::check_record() -{ - int result= 1; - DBUG_ENTER("INDEX_MERGE::check_record"); - - if ((error= temp_table->file->index_read(temp_table->record[0], - head->file->ref, - head->file->ref_length, - HA_READ_KEY_EXACT))) - { - if (error != HA_ERR_KEY_NOT_FOUND) - result= -1; - else - result= 0; - } - - DBUG_RETURN(result); -} - -INDEX_MERGE::~INDEX_MERGE() -{ - if (temp_table) - { - DBUG_PRINT("info", ("Freeing temp. table")); - free_tmp_table(current_thd, temp_table); - } - /* rowid_item is freed automatically */ - list_node* node; - node= fields.first_node(); - fields.remove(&node); -} - -int QUICK_INDEX_MERGE_SELECT::get_next() -{ - int result; - int put_result; - DBUG_ENTER("QUICK_INDEX_MERGE_SELECT::get_next"); - + /* we're going to just read rowids */ + head->file->extra(HA_EXTRA_KEYREAD); + + unique= new Unique(refposcmp2, (void *) &head->file->ref_length, + head->file->ref_length, + MEM_STRIP_BUF_SIZE); + if (!unique) + DBUG_RETURN(1); do { while ((result= cur_quick_select->get_next()) == HA_ERR_END_OF_FILE) @@ -3245,31 +3104,50 @@ int QUICK_INDEX_MERGE_SELECT::get_next() cur_quick_select= cur_quick_it++; if (!cur_quick_select) break; - cur_quick_select->init(); - cur_quick_select->reset(); - - if (last_quick_select == cur_quick_select) - { - if ((result= index_merge.start_last_quick_select())) - DBUG_RETURN(result); - } + if (cur_quick_select->reset()) + DBUG_RETURN(1); } if (result) - { + { /* table read error (including HA_ERR_END_OF_FILE on last quick select in index_merge) */ - DBUG_RETURN(result); + if (result != HA_ERR_END_OF_FILE) + { + DBUG_RETURN(result); + } + else + break; } + if (thd->killed) + DBUG_RETURN(1); + cur_quick_select->file->position(cur_quick_select->record); - put_result= index_merge.check_record_in(); - }while(put_result == 1); /* While record is processed */ + if (unique->unique_add((char*)cur_quick_select->file->ref)) + DBUG_RETURN(1); + + }while(true); - DBUG_RETURN((put_result != -1) ? result : index_merge.error); + /* ok, all row ids are in Unique */ + result= unique->get(head); + + /* index_merge currently doesn't support "using index" at all */ + head->file->extra(HA_EXTRA_NO_KEYREAD); + DBUG_RETURN(result); +} + +int QUICK_INDEX_MERGE_SELECT::get_next() +{ + DBUG_ENTER("QUICK_INDEX_MERGE_SELECT::get_next"); + + DBUG_PRINT("QUICK_INDEX_MERGE_SELECT", + ("ERROR: index merge error: get_next should not be called ")); + DBUG_ASSERT(0); + DBUG_RETURN(HA_ERR_END_OF_FILE); } /* get next possible record using quick-struct */ diff --git a/sql/opt_range.h b/sql/opt_range.h index c5e9956ceef04bf9af65b2b44a532375de61a9cc..e312dd39bada68ab98370720ac891b170edbdee8 100644 --- a/sql/opt_range.h +++ b/sql/opt_range.h @@ -65,7 +65,6 @@ class QUICK_RANGE :public Sql_alloc { } }; -class INDEX_MERGE; /* Quick select interface. @@ -149,64 +148,6 @@ class QUICK_RANGE_SELECT : public QUICK_SELECT_I int get_type() { return QS_TYPE_RANGE; } }; -/* - Helper class for keeping track of rows that have been passed to output - in index_merge access method. - - NOTES - Current implementation uses a temporary table to store ROWIDs of rows that - have been passed to output. In the future it might be changed to use more - efficient mechanisms, like Unique class. -*/ - -class INDEX_MERGE -{ -public: - INDEX_MERGE(THD *thd_arg); - ~INDEX_MERGE(); - - int init(TABLE *table); - int check_record_in(); - int start_last_quick_select(); - int error; -private: - /* The only field in temporary table */ - class Item_rowid : public Item_str_func - { - TABLE *head; /* source table */ - public: - Item_rowid(TABLE *table) : head(table) - { - max_length= table->file->ref_length; - collation.set(&my_charset_bin); - }; - const char *func_name() const { return "rowid"; } - bool const_item() const { return 0; } - String *val_str(String *); - void fix_length_and_dec() - {} - }; - - /* Check if record has been processed and save it if it wasn't */ - inline int put_record(); - - /* Check if record has been processed without saving it */ - inline int check_record(); - - /* If true, check_record_in does't store ROWIDs it is passed. */ - bool dont_save; - - THD *thd; - TABLE *head; /* source table */ - TABLE *temp_table; /* temp. table used for values storage */ - TMP_TABLE_PARAM tmp_table_param; /* temp. table creation parameters */ - Item_rowid *rowid_item; /* the only field in temp. table */ - List<Item> fields; /* temp. table fields list - (the only element is rowid_item) */ - ORDER order; /* key for temp. table (rowid_item) */ -}; - - /* Index merge quick select. It is implemented as a container for several QUICK_RANGE_SELECTs. @@ -219,7 +160,7 @@ class QUICK_INDEX_MERGE_SELECT : public QUICK_SELECT_I ~QUICK_INDEX_MERGE_SELECT(); int init(); - void reset(void); + int reset(void); int get_next(); bool reverse_sorted() { return false; } bool unique_key_range() { return false; } @@ -234,20 +175,15 @@ class QUICK_INDEX_MERGE_SELECT : public QUICK_SELECT_I List_iterator_fast<QUICK_RANGE_SELECT> cur_quick_it; QUICK_RANGE_SELECT* cur_quick_select; - /* - Last element in quick_selects list. - INDEX_MERGE::start_last_quick_select is called before retrieving - rows for it. - */ + /* last element in quick_selects list. */ QUICK_RANGE_SELECT* last_quick_select; - /* - Used to keep track of what records have been already passed to output - when doing index_merge access (NULL means no index_merge) - */ - INDEX_MERGE index_merge; + Unique *unique; + MEM_ROOT alloc; - MEM_ROOT alloc; + THD *thd; + int prepare_unique(); + bool reset_called; }; class QUICK_SELECT_DESC: public QUICK_RANGE_SELECT @@ -263,7 +199,7 @@ class QUICK_SELECT_DESC: public QUICK_RANGE_SELECT #ifdef NOT_USED bool test_if_null_range(QUICK_RANGE *range, uint used_key_parts); #endif - void reset(void) { next=0; rev_it.rewind(); } + int reset(void) { next=0; rev_it.rewind(); return 0; } List<QUICK_RANGE> rev_ranges; List_iterator<QUICK_RANGE> rev_it; }; diff --git a/sql/records.cc b/sql/records.cc index b29b113a1bc2c0dcc9a6ae0373b8c379954fc782..02c0cc8cba95a9e2873dd24a78c7ea1b94959036 100644 --- a/sql/records.cc +++ b/sql/records.cc @@ -97,7 +97,8 @@ void init_read_record(READ_RECORD *info,THD *thd, TABLE *table, } } } - else if (select && select->quick) + else if (select && select->quick && + (select->quick->get_type() != QUICK_SELECT_I::QS_TYPE_INDEX_MERGE)) { DBUG_PRINT("info",("using rr_quick")); info->read_record=rr_quick; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 662b288c7c2bd901476d608606b247e52e35b84f..28ce25762f33ab86f739d4d4059aa08e006f81f3 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -5998,8 +5998,8 @@ test_if_quick_select(JOIN_TAB *tab) static int join_init_read_record(JOIN_TAB *tab) { - if (tab->select && tab->select->quick) - tab->select->quick->reset(); + if (tab->select && tab->select->quick && tab->select->quick->reset()) + return 1; init_read_record(&tab->read_record, tab->join->thd, tab->table, tab->select,1,1); return (*tab->read_record.read_record)(&tab->read_record); diff --git a/sql/sql_select.h b/sql/sql_select.h index 53339f7238a014beaa358996ad470e2629b8e66a..d1d194913919ebc0543c15953dec9cc50601b698 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -316,6 +316,9 @@ uint find_shortest_key(TABLE *table, const key_map *usable_keys); /* functions from opt_sum.cc */ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds); +/* from sql_delete.cc, used by opt_range.cc */ +extern "C" int refposcmp2(void* arg, const void *a,const void *b); + /* class to copying an field/item to a key struct */ class store_key :public Sql_alloc diff --git a/sql/sql_union.cc b/sql/sql_union.cc index 8900d48ee4f7aa26e692ae41516fb7d4953fc624..8e4503f888306a52d90c104cb651c8eb7e4ad424 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -192,7 +192,7 @@ int st_select_lex_unit::prepare(THD *thd, select_result *sel_result, union_result->not_describe=1; union_result->tmp_table_param=tmp_table_param; - for (;sl; sl= sl->next_select()) + for (sl= select_cursor; sl; sl= sl->next_select()) { JOIN *join= new JOIN(thd, sl->item_list, sl->options | thd->options | SELECT_NO_UNLOCK,