diff options
Diffstat (limited to 'sql/sql_select.cc')
-rw-r--r-- | sql/sql_select.cc | 223 |
1 files changed, 125 insertions, 98 deletions
diff --git a/sql/sql_select.cc b/sql/sql_select.cc index e28ee52c00f..05676f9058a 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -148,14 +148,15 @@ static int remove_duplicates(JOIN *join,TABLE *entry,List<Item> &fields, Item *having); static int remove_dup_with_compare(THD *thd, TABLE *entry, Field **field, ulong offset,Item *having); -static int remove_dup_with_hash_index(THD *thd, TABLE *table, +static int remove_dup_with_hash_index(THD *thd,TABLE *table, uint field_count, Field **first_field, ulong key_length,Item *having); static int join_init_cache(THD *thd,JOIN_TAB *tables,uint table_count); static ulong used_blob_length(CACHE_FIELD **ptr); static bool store_record_in_cache(JOIN_CACHE *cache); -static void reset_cache(JOIN_CACHE *cache); +static void reset_cache_read(JOIN_CACHE *cache); +static void reset_cache_write(JOIN_CACHE *cache); static void read_cached_record(JOIN_TAB *tab); static bool cmp_buffer_with_ref(JOIN_TAB *tab); static bool setup_new_fields(THD *thd,TABLE_LIST *tables,List<Item> &fields, @@ -643,7 +644,6 @@ JOIN::optimize() { zero_result_cause= "no matching row in const table"; DBUG_PRINT("error",("Error: %s", zero_result_cause)); - select_options= 0; //TODO why option in return_zero_rows was droped error= 0; DBUG_RETURN(0); } @@ -657,22 +657,8 @@ JOIN::optimize() } if (const_tables && !thd->locked_tables && !(select_options & SELECT_NO_UNLOCK)) - { - TABLE **curr_table, **end; - for (curr_table= table, end=curr_table + const_tables ; - curr_table != end; - curr_table++) - { - /* BDB tables require that we call index_end() before doing an unlock */ - if ((*curr_table)->key_read) - { - (*curr_table)->key_read=0; - (*curr_table)->file->extra(HA_EXTRA_NO_KEYREAD); - } - (*curr_table)->file->index_end(); - } mysql_unlock_some_tables(thd, table, const_tables); - } + if (!conds && outer_join) { /* Handle the case where we have an OUTER JOIN without a WHERE */ @@ -977,7 +963,7 @@ JOIN::optimize() If having is not handled here, it will be checked before the row is sent to the client. */ - if (having && + if (tmp_having && (sort_and_group || (exec_tmp_table1->distinct && !group_list))) having= tmp_having; @@ -1127,12 +1113,14 @@ JOIN::exec() DBUG_ENTER("JOIN::exec"); error= 0; - thd->limit_found_rows= thd->examined_row_count= 0; if (procedure) { if (procedure->change_columns(fields_list) || result->prepare(fields_list, unit)) + { + thd->limit_found_rows= thd->examined_row_count= 0; DBUG_VOID_RETURN; + } } if (!tables_list) @@ -1158,8 +1146,10 @@ JOIN::exec() else error=(int) result->send_eof(); } + thd->limit_found_rows= thd->examined_row_count= 0; DBUG_VOID_RETURN; } + thd->limit_found_rows= thd->examined_row_count= 0; if (zero_result_cause) { @@ -1578,6 +1568,7 @@ JOIN::cleanup() } } tmp_join->tmp_join= 0; + tmp_table_param.copy_field=0; DBUG_RETURN(tmp_join->cleanup()); } @@ -2332,12 +2323,13 @@ add_key_fields(JOIN_TAB *stat,KEY_FIELD **key_fields,uint *and_level, case Item_func::OPTIMIZE_NONE: break; case Item_func::OPTIMIZE_KEY: - // BETWEEN or IN + // BETWEEN, IN, NOT if (cond_func->key_item()->real_item()->type() == Item::FIELD_ITEM && !(cond_func->used_tables() & OUTER_REF_TABLE_BIT)) add_key_field(key_fields,*and_level,cond_func, - ((Item_field*) (cond_func->key_item()->real_item()))-> - field, 0, + ((Item_field*)(cond_func->key_item()->real_item()))->field, + cond_func->argument_count() == 2 && + cond_func->functype() == Item_func::IN_FUNC, cond_func->arguments()+1, cond_func->argument_count()-1, usable_tables); break; @@ -4848,7 +4840,6 @@ make_join_readinfo(JOIN *join, uint options) } delete tab->quick; tab->quick=0; - table->file->index_init(tab->ref.key); tab->read_first_record= join_read_key; tab->read_record.read_record= join_no_more_records; if (table->used_keys.is_set(tab->ref.key) && @@ -4868,7 +4859,6 @@ make_join_readinfo(JOIN *join, uint options) } delete tab->quick; tab->quick=0; - table->file->index_init(tab->ref.key); if (table->used_keys.is_set(tab->ref.key) && !table->no_keyread) { @@ -4888,7 +4878,6 @@ make_join_readinfo(JOIN *join, uint options) break; case JT_FT: table->status=STATUS_NO_RECORD; - table->file->index_init(tab->ref.key); tab->read_first_record= join_ft_read_first; tab->read_record.read_record= join_ft_read_next; break; @@ -4958,7 +4947,6 @@ make_join_readinfo(JOIN *join, uint options) !(tab->select && tab->select->quick)) { // Only read index tree tab->index=find_shortest_key(table, & table->used_keys); - tab->table->file->index_init(tab->index); tab->read_first_record= join_read_first; tab->type=JT_NEXT; // Read with index_first / index_next } @@ -5032,9 +5020,7 @@ void JOIN_TAB::cleanup() 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(); + table->file->ha_index_or_rnd_end(); /* We need to reset this for next select (Tested in part_of_refkey) @@ -5060,7 +5046,9 @@ void JOIN::join_free(bool full) { JOIN_TAB *tab,*end; - DBUG_ENTER("join_free"); + DBUG_ENTER("JOIN::join_free"); + + full= full || !select_lex->uncacheable; if (table) { @@ -5073,36 +5061,49 @@ JOIN::join_free(bool full) free_io_cache(table[const_tables]); filesort_free_buffers(table[const_tables]); } - if (!full && select_lex->uncacheable) + + for (SELECT_LEX_UNIT *unit= select_lex->first_inner_unit(); unit; + unit= unit->next_unit()) { - for (tab= join_tab, end= tab+tables; tab != end; tab++) - { - if (tab->table) - { - /* Don't free index if we are using read_record */ - if (!tab->read_record.table) - tab->table->file->index_end(); - } - } + JOIN *join; + for (SELECT_LEX *sl= unit->first_select_in_union(); sl; + sl= sl->next_select()) + if ((join= sl->join)) + join->join_free(full); } - else + + if (full) { for (tab= join_tab, end= tab+tables; tab != end; tab++) tab->cleanup(); table= 0; } + else + { + for (tab= join_tab, end= tab+tables; tab != end; tab++) + { + if (tab->table) + tab->table->file->ha_index_or_rnd_end(); + } + } } + /* We are not using tables anymore Unlock all tables. We may be in an INSERT .... SELECT statement. */ - if ((full || !select_lex->uncacheable) && - lock && thd->lock && - !(select_options & SELECT_NO_UNLOCK)) + if (full && lock && thd->lock && !(select_options & SELECT_NO_UNLOCK) && + !select_lex->subquery_in_having) { - mysql_unlock_read_tables(thd, lock);// Don't free join->lock - lock=0; + // TODO: unlock tables even if the join isn't top level select in the tree + if (select_lex == (thd->lex->unit.fake_select_lex ? + thd->lex->unit.fake_select_lex : &thd->lex->select_lex)) + { + mysql_unlock_read_tables(thd, lock); // Don't free join->lock + lock=0; + } } + if (full) { group_fields.delete_elements(); @@ -5324,6 +5325,8 @@ return_zero_rows(JOIN *join, select_result *result,TABLE_LIST *tables, DBUG_RETURN(0); } + join->join_free(0); + if (send_row) { for (TABLE_LIST *table=tables; table ; table=table->next) @@ -5341,12 +5344,6 @@ return_zero_rows(JOIN *join, select_result *result,TABLE_LIST *tables, item->no_rows_in_result(); result->send_data(fields); } - if (tables) // Not from do_select() - { - /* Close open cursors */ - for (TABLE_LIST *table=tables; table ; table=table->next) - table->table->file->index_end(); - } result->send_eof(); // Should be safe } /* Update results for FOUND_ROWS */ @@ -6419,6 +6416,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, table->db_low_byte_first=1; // True for HEAP and MyISAM table->temp_pool_slot = temp_pool_slot; table->copy_blobs= 1; + table->in_use= thd; table->keys_for_keyread.init(); table->keys_in_use.init(); table->read_only_keys.init(); @@ -6581,6 +6579,10 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, recinfo->length=null_pack_length; recinfo++; bfill(null_flags,null_pack_length,255); // Set null fields + + table->null_flags= (uchar*) table->record[0]; + table->null_fields= null_count+ hidden_null_count; + table->null_bytes= null_pack_length; } null_count= (blob_count == 0) ? 1 : 0; hidden_field_count=param->hidden_field_count; @@ -6644,7 +6646,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, param->copy_field_end=copy; param->recinfo=recinfo; - store_record(table,default_values); // Make empty default record + store_record(table,default_values); // Make empty default record if (thd->variables.tmp_table_size == ~(ulong) 0) // No limit table->max_rows= ~(ha_rows) 0; @@ -6996,8 +6998,8 @@ bool create_myisam_from_heap(THD *thd, TABLE *table, TMP_TABLE_PARAM *param, goto err1; if (table->file->indexes_are_disabled()) new_table.file->disable_indexes(HA_KEY_SWITCH_ALL); - table->file->index_end(); - table->file->rnd_init(); + table->file->ha_index_or_rnd_end(); + table->file->ha_rnd_init(1); if (table->no_rows) { new_table.file->extra(HA_EXTRA_NO_ROWS); @@ -7019,7 +7021,7 @@ bool create_myisam_from_heap(THD *thd, TABLE *table, TMP_TABLE_PARAM *param, } /* remove heap table and change to use myisam table */ - (void) table->file->rnd_end(); + (void) table->file->ha_rnd_end(); (void) table->file->close(); (void) table->file->delete_table(table->real_name); delete table->file; @@ -7033,7 +7035,7 @@ bool create_myisam_from_heap(THD *thd, TABLE *table, TMP_TABLE_PARAM *param, err: DBUG_PRINT("error",("Got error: %d",write_err)); table->file->print_error(error,MYF(0)); // Give table is full error - (void) table->file->rnd_end(); + (void) table->file->ha_rnd_end(); (void) new_table.file->close(); err1: new_table.file->delete_table(new_table.real_name); @@ -7082,7 +7084,8 @@ do_select(JOIN *join,List<Item> *fields,TABLE *table,Procedure *procedure) { DBUG_PRINT("info",("Using end_update")); end_select=end_update; - table->file->index_init(0); + if (!table->file->inited) + table->file->ha_index_init(0); } else { @@ -7160,9 +7163,9 @@ do_select(JOIN *join,List<Item> *fields,TABLE *table,Procedure *procedure) my_errno= tmp; error= -1; } - if ((tmp=table->file->index_end())) + if ((tmp=table->file->ha_index_or_rnd_end())) { - DBUG_PRINT("error",("index_end() failed")); + DBUG_PRINT("error",("ha_index_or_rnd_end() failed")); my_errno= tmp; error= -1; } @@ -7541,8 +7544,7 @@ flush_cached_records(JOIN *join,JOIN_TAB *join_tab,bool skip_last) /* read through all records */ if ((error=join_init_read_record(join_tab))) { - reset_cache(&join_tab->cache); - join_tab->cache.records=0; join_tab->cache.ptr_record= (uint) ~0; + reset_cache_write(&join_tab->cache); return -error; /* No records or error */ } @@ -7565,21 +7567,23 @@ flush_cached_records(JOIN *join,JOIN_TAB *join_tab,bool skip_last) !join_tab->cache.select->skip_record())) { uint i; - reset_cache(&join_tab->cache); + reset_cache_read(&join_tab->cache); for (i=(join_tab->cache.records- (skip_last ? 1 : 0)) ; i-- > 0 ;) { read_cached_record(join_tab); if (!select || !select->skip_record()) if ((error=(join_tab->next_select)(join,join_tab+1,0)) < 0) + { + reset_cache_write(&join_tab->cache); return error; /* purecov: inspected */ + } } } } while (!(error=info->read_record(info))); 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; + reset_cache_write(&join_tab->cache); if (error > 0) // Fatal error return -1; /* purecov: inspected */ for (JOIN_TAB *tmp2=join->join_tab; tmp2 != join_tab ; tmp2++) @@ -7650,7 +7654,8 @@ join_read_const_table(JOIN_TAB *tab, POSITION *pos) else { if (!table->key_read && table->used_keys.is_set(tab->ref.key) && - !table->no_keyread) + !table->no_keyread && + (int) table->reginfo.lock_type <= (int) TL_READ_HIGH_PRIORITY) { table->key_read=1; table->file->extra(HA_EXTRA_KEYREAD); @@ -7663,6 +7668,11 @@ join_read_const_table(JOIN_TAB *tab, POSITION *pos) if (!table->outer_join || error > 0) DBUG_RETURN(error); } + if (table->key_read) + { + table->key_read=0; + table->file->extra(HA_EXTRA_NO_KEYREAD); + } } if (tab->on_expr && !table->null_row) { @@ -7741,6 +7751,8 @@ join_read_key(JOIN_TAB *tab) int error; TABLE *table= tab->table; + if (!table->file->inited) + table->file->ha_index_init(tab->ref.key); if (cmp_buffer_with_ref(tab) || (table->status & (STATUS_GARBAGE | STATUS_NO_PARENT | STATUS_NULL_ROW))) { @@ -7766,6 +7778,8 @@ join_read_always_key(JOIN_TAB *tab) int error; TABLE *table= tab->table; + if (!table->file->inited) + table->file->ha_index_init(tab->ref.key); if (cp_buffer_from_ref(&tab->ref)) return -1; if ((error=table->file->index_read(table->record[0], @@ -7791,6 +7805,8 @@ join_read_last_key(JOIN_TAB *tab) int error; TABLE *table= tab->table; + if (!table->file->inited) + table->file->ha_index_init(tab->ref.key); if (cp_buffer_from_ref(&tab->ref)) return -1; if ((error=table->file->index_read_last(table->record[0], @@ -7899,6 +7915,8 @@ join_read_first(JOIN_TAB *tab) tab->read_record.file=table->file; tab->read_record.index=tab->index; tab->read_record.record=table->record[0]; + if (!table->file->inited) + table->file->ha_index_init(tab->index); if ((error=tab->table->file->index_first(tab->table->record[0]))) { if (error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE) @@ -7936,6 +7954,8 @@ join_read_last(JOIN_TAB *tab) tab->read_record.file=table->file; tab->read_record.index=tab->index; tab->read_record.record=table->record[0]; + if (!table->file->inited) + table->file->ha_index_init(tab->index); if ((error= tab->table->file->index_last(tab->table->record[0]))) return report_error(table, error); return 0; @@ -7958,6 +7978,8 @@ join_ft_read_first(JOIN_TAB *tab) int error; TABLE *table= tab->table; + if (!table->file->inited) + table->file->ha_index_init(tab->ref.key); #if NOT_USED_YET if (cp_buffer_from_ref(&tab->ref)) // as ft-key doesn't use store_key's return -1; // see also FT_SELECT::init() @@ -8048,7 +8070,8 @@ end_send(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), if ((join->tables == 1) && !join->tmp_table && !join->sort_and_group && !join->send_group_parts && !join->having && !jt->select_cond && !(jt->select && jt->select->quick) && - !(jt->table->file->table_flags() & HA_NOT_EXACT_COUNT)) + !(jt->table->file->table_flags() & HA_NOT_EXACT_COUNT) && + (jt->ref.key < 0)) { /* Join over all rows in table; Return number of found rows */ TABLE *table=jt->table; @@ -8274,7 +8297,6 @@ end_update(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), if (item->maybe_null) group->buff[-1]=item->null_value ? 1 : 0; } - // table->file->index_init(0); if (!table->file->index_read(table->record[1], join->tmp_table_param.group_buff,0, HA_READ_KEY_EXACT)) @@ -8305,7 +8327,7 @@ end_update(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), error, 0)) DBUG_RETURN(-1); // Not a table_is_full error /* Change method to update rows */ - table->file->index_init(0); + table->file->ha_index_init(0); join->join_tab[join->tables-1].next_select=end_unique_update; } join->send_records++; @@ -8814,10 +8836,10 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, if (tab->ref.key >= 0) { tab->ref.key= new_ref_key; - table->file->index_init(new_ref_key); } else { + select->quick->file->ha_index_end(); /* We have verified above that select->quick is not index_merge quick select. @@ -8844,7 +8866,7 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, if (!select->quick->reverse_sorted()) { int quick_type= select->quick->get_type(); - if (table->file->index_flags(ref_key) & HA_NOT_READ_PREFIX_LAST || + if (!(table->file->index_flags(ref_key) & HA_READ_PREV) || quick_type == QUICK_SELECT_I::QS_TYPE_INDEX_MERGE || quick_type == QUICK_SELECT_I::QS_TYPE_ROR_INTERSECT || quick_type == QUICK_SELECT_I::QS_TYPE_ROR_UNION) @@ -8870,7 +8892,7 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, Use a traversal function that starts by reading the last row with key part (A) and then traverse the index backwards. */ - if (table->file->index_flags(ref_key) & HA_NOT_READ_PREFIX_LAST) + if (!(table->file->index_flags(ref_key) & HA_READ_PREV)) DBUG_RETURN(0); // Use filesort tab->read_first_record= join_read_last_key; tab->read_record.read_record= join_read_prev_same; @@ -8924,7 +8946,6 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, tab->index=nr; tab->read_first_record= (flag > 0 ? join_read_first: join_read_last); - table->file->index_init(nr); tab->type=JT_NEXT; // Read with index_first(), index_next() if (table->used_keys.is_set(nr)) { @@ -9190,7 +9211,7 @@ static int remove_dup_with_compare(THD *thd, TABLE *table, Field **first_field, org_record=(char*) (record=table->record[0])+offset; new_record=(char*) table->record[1]+offset; - file->rnd_init(); + file->ha_rnd_init(1); error=file->rnd_next(record); for (;;) { @@ -9302,7 +9323,7 @@ static int remove_dup_with_hash_index(THD *thd, TABLE *table, (*field_length++)= (*ptr)->pack_length(); } - file->rnd_init(); + file->ha_rnd_init(1); key_pos=key_buffer; for (;;) { @@ -9348,14 +9369,14 @@ static int remove_dup_with_hash_index(THD *thd, TABLE *table, my_free((char*) key_buffer,MYF(0)); hash_free(&hash); file->extra(HA_EXTRA_NO_CACHE); - (void) file->rnd_end(); + (void) file->ha_rnd_end(); DBUG_RETURN(0); err: my_free((char*) key_buffer,MYF(0)); hash_free(&hash); file->extra(HA_EXTRA_NO_CACHE); - (void) file->rnd_end(); + (void) file->ha_rnd_end(); if (error) file->print_error(error,MYF(0)); DBUG_RETURN(1); @@ -9482,7 +9503,6 @@ join_init_cache(THD *thd,JOIN_TAB *tables,uint table_count) } } - cache->records=0; cache->ptr_record= (uint) ~0; cache->length=length+blobs*sizeof(char*); cache->blobs=blobs; *blob_ptr=0; /* End sequentel */ @@ -9490,7 +9510,7 @@ join_init_cache(THD *thd,JOIN_TAB *tables,uint table_count) if (!(cache->buff=(uchar*) my_malloc(size,MYF(0)))) DBUG_RETURN(1); /* Don't use cache */ /* purecov: inspected */ cache->end=cache->buff+size; - reset_cache(cache); + reset_cache_write(cache); DBUG_RETURN(0); } @@ -9574,13 +9594,21 @@ store_record_in_cache(JOIN_CACHE *cache) static void -reset_cache(JOIN_CACHE *cache) +reset_cache_read(JOIN_CACHE *cache) { cache->record_nr=0; cache->pos=cache->buff; } +static void reset_cache_write(JOIN_CACHE *cache) +{ + reset_cache_read(cache); + cache->records= 0; + cache->ptr_record= (uint) ~0; +} + + static void read_cached_record(JOIN_TAB *tab) { @@ -10029,10 +10057,11 @@ calc_group_buffer(JOIN *join,ORDER *group) join->tmp_table_param.group_null_parts=null_parts; } + /* - alloc group fields or take prepared (chached) + allocate group fields or take prepared (cached) - SYNOPSYS + SYNOPSIS make_group_fields() main_join - join of current select curr_join - current join (join of current select or temporary copy of it) @@ -10045,22 +10074,21 @@ calc_group_buffer(JOIN *join,ORDER *group) static bool make_group_fields(JOIN *main_join, JOIN *curr_join) { - if (main_join->group_fields_cache.elements) - { - curr_join->group_fields= main_join->group_fields_cache; - curr_join->sort_and_group= 1; - } - else - { - if (alloc_group_fields(curr_join, curr_join->group_list)) - { - return (1); - } - main_join->group_fields_cache= curr_join->group_fields; - } - return (0); + if (main_join->group_fields_cache.elements) + { + curr_join->group_fields= main_join->group_fields_cache; + curr_join->sort_and_group= 1; + } + else + { + if (alloc_group_fields(curr_join, curr_join->group_list)) + return (1); + main_join->group_fields_cache= curr_join->group_fields; + } + return (0); } + /* Get a list of buffers for saveing last group Groups are saved in reverse order for easyer check loop @@ -10101,7 +10129,6 @@ test_if_group_changed(List<Item_buff> &list) } - /* Setup copy_fields to save fields at start of new group |