diff options
Diffstat (limited to 'sql/sql_select.cc')
-rw-r--r-- | sql/sql_select.cc | 221 |
1 files changed, 122 insertions, 99 deletions
diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 63718dc9d55..41c0b07bc49 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1,5 +1,5 @@ /* Copyright (c) 2000, 2012 Oracle and/or its affiliates. - Copyright (c) 2009, 2012, Monty Program Ab + Copyright (c) 2009, 2013 Monty Program Ab. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -228,7 +228,7 @@ static int create_sort_index(THD *thd, JOIN *join, ORDER *order, 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); + Item *having); static int remove_dup_with_hash_index(THD *thd,TABLE *table, uint field_count, Field **first_field, ulong key_length,Item *having); @@ -383,7 +383,7 @@ bool handle_select(THD *thd, LEX *lex, select_result *result, ER(ER_QUERY_EXCEEDED_ROWS_EXAMINED_LIMIT), thd->accessed_rows_and_keys, thd->lex->limit_rows_examined->val_uint()); - thd->killed= NOT_KILLED; + thd->reset_killed(); } /* Disable LIMIT ROWS EXAMINED after query execution. */ thd->lex->limit_rows_examined_cnt= ULONGLONG_MAX; @@ -2077,6 +2077,8 @@ bool JOIN::setup_subquery_caches() */ void JOIN::restore_tmp() { + DBUG_PRINT("info", ("restore_tmp this %p tmp_join %p", this, tmp_join)); + DBUG_ASSERT(tmp_join != this); memcpy(tmp_join, this, (size_t) sizeof(JOIN)); } @@ -7750,8 +7752,9 @@ get_best_combination(JOIN *join) if ( !(keyuse= join->best_positions[tablenr].key)) { j->type=JT_ALL; - if (tablenr != join->const_tables) - join->full_join=1; + if (join->best_positions[tablenr].use_join_buffer && + tablenr != join->const_tables) + join->full_join= 1; } /*if (join->best_positions[tablenr].sj_strategy == SJ_OPT_LOOSE_SCAN) @@ -8744,7 +8747,9 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) We will use join cache here : prevent sorting of the first table only and sort at the end. */ - if (i != join->const_tables && join->table_count > join->const_tables + 1) + if (i != join->const_tables && + join->table_count > join->const_tables + 1 && + join->best_positions[i].use_join_buffer) join->full_join= 1; } @@ -10769,7 +10774,6 @@ void JOIN::cleanup(bool full) filesort_free_buffers(first_tab->table, full); } } - if (full) { JOIN_TAB *sort_tab= first_linear_tab(this, WITHOUT_CONST_TABLES); @@ -10804,21 +10808,19 @@ void JOIN::cleanup(bool full) } } } - /* - We are not using tables anymore - Unlock all tables. We may be in an INSERT .... SELECT statement. - */ if (full) { - if (tmp_join) - tmp_table_param.copy_field= 0; - group_fields.delete_elements(); /* - Ensure that the above delete_elements() would not be called + Ensure that the following delete_elements() would not be called twice for the same list. */ - if (tmp_join && tmp_join != this) - tmp_join->group_fields= group_fields; + if (tmp_join && tmp_join != this && + tmp_join->group_fields == this->group_fields) + tmp_join->group_fields.empty(); + + // Run Cached_item DTORs! + group_fields.delete_elements(); + /* We can't call delete_elements() on copy_funcs as this will cause problems in free_elements() as some of the elements are then deleted. @@ -14330,10 +14332,20 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields, if (group) { + ORDER **prev= &group; if (!param->quick_group) group=0; // Can't use group key else for (ORDER *tmp=group ; tmp ; tmp=tmp->next) { + /* Exclude found constant from the list */ + if ((*tmp->item)->const_item()) + { + *prev= tmp->next; + param->group_parts--; + continue; + } + else + prev= &(tmp->next); /* marker == 4 means two things: - store NULLs in the key, and @@ -14341,7 +14353,7 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields, can't index BIT fields. */ (*tmp->item)->marker=4; // Store null in key - if ((*tmp->item)->max_length >= CONVERT_IF_BIGGER_TO_BLOB) + if ((*tmp->item)->too_big_for_varchar()) using_unique_constraint=1; } if (param->group_length >= MAX_BLOB_WIDTH) @@ -15880,11 +15892,11 @@ do_select(JOIN *join,List<Item> *fields,TABLE *table,Procedure *procedure) if (table->group && join->tmp_table_param.sum_func_count && table->s->keys && !table->file->inited) { - int tmp_error; - if ((tmp_error= table->file->ha_index_init(0, 0))) + rc= table->file->ha_index_init(0, 0); + if (rc) { - table->file->print_error(tmp_error, MYF(0)); /* purecov: inspected */ - DBUG_RETURN(-1); /* purecov: inspected */ + table->file->print_error(rc, MYF(0)); + DBUG_RETURN(-1); } } } @@ -16918,7 +16930,12 @@ int join_read_key2(THD *thd, JOIN_TAB *tab, TABLE *table, TABLE_REF *table_ref) int error; if (!table->file->inited) { - table->file->ha_index_init(table_ref->key, (tab ? tab->sorted : TRUE)); + error= table->file->ha_index_init(table_ref->key, tab ? tab->sorted : TRUE); + if (error) + { + (void) report_error(table, error); + return 1; + } } /* TODO: Why don't we do "Late NULLs Filtering" here? */ @@ -17009,8 +17026,8 @@ join_read_always_key(JOIN_TAB *tab) { if ((error= table->file->ha_index_init(tab->ref.key, tab->sorted))) { - table->file->print_error(error, MYF(0));/* purecov: inspected */ - return(1); /* purecov: inspected */ + (void) report_error(table, error); + return 1; } } @@ -17040,14 +17057,13 @@ join_read_last_key(JOIN_TAB *tab) int error; TABLE *table= tab->table; - if (!table->file->inited) + if (!table->file->inited && + (error= table->file->ha_index_init(tab->ref.key, tab->sorted))) { - if ((error= table->file->ha_index_init(tab->ref.key, tab->sorted))) - { - table->file->print_error(error, MYF(0));/* purecov: inspected */ - return(1); /* purecov: inspected */ - } + (void) report_error(table, error); + return 1; } + if (cp_buffer_from_ref(tab->join->thd, table, &tab->ref)) return -1; if ((error= table->file->ha_index_read_map(table->record[0], @@ -17266,9 +17282,10 @@ join_ft_read_first(JOIN_TAB *tab) if (!table->file->inited && (error= table->file->ha_index_init(tab->ref.key, 1))) { - table->file->print_error(error, MYF(0)); /* purecov: inspected */ - return(1); /* purecov: inspected */ + (void) report_error(table, error); + return 1; } + table->file->ft_init(); if ((error= table->file->ha_ft_read(table->record[0]))) @@ -17691,9 +17708,10 @@ end_update(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), /* Change method to update rows */ if ((error= table->file->ha_index_init(0, 0))) { - table->file->print_error(error, MYF(0));/* purecov: inspected */ - DBUG_RETURN(NESTED_LOOP_ERROR); /* purecov: inspected */ + table->file->print_error(error, MYF(0)); + DBUG_RETURN(NESTED_LOOP_ERROR); } + join->join_tab[join->top_join_tab_count-1].next_select=end_unique_update; } join->send_records++; @@ -18335,18 +18353,36 @@ static int test_if_order_by_key(ORDER *order, TABLE *table, uint idx, table->s->primary_key != MAX_KEY && table->s->primary_key != idx) { + KEY_PART_INFO *start,*end; + uint pk_part_idx= 0; on_pk_suffix= TRUE; - key_part= table->key_info[table->s->primary_key].key_part; - key_part_end=key_part+table->key_info[table->s->primary_key].key_parts; + start= key_part= table->key_info[table->s->primary_key].key_part; const_key_parts=table->const_key_parts[table->s->primary_key]; - for (; const_key_parts & 1 ; const_key_parts>>= 1) - key_part++; /* - The primary and secondary key parts were all const (i.e. there's - one row). The sorting doesn't matter. + Calculate true key_part_end and const_key_parts + (we have to stop as first not continous primary key part) */ - if (key_part == key_part_end && reverse == 0) + for (key_part_end= key_part, + end= key_part+table->key_info[table->s->primary_key].key_parts; + key_part_end < end; key_part_end++, pk_part_idx++) + { + /* Found hole in the pk_parts; Abort */ + if (!(table->key_info[idx].ext_key_part_map & + (((key_part_map) 1) << pk_part_idx))) + break; + } + /* Adjust const_key_parts */ + const_key_parts&= (((key_part_map) 1) << pk_part_idx) -1; + + for (; const_key_parts & 1 ; const_key_parts>>= 1) + key_part++; + /* + Test if the primary key parts were all const (i.e. there's one row). + The sorting doesn't matter. + */ + if (key_part == start+table->key_info[table->s->primary_key].key_parts && + reverse == 0) { key_parts= 0; reverse= 1; @@ -18366,7 +18402,8 @@ static int test_if_order_by_key(ORDER *order, TABLE *table, uint idx, if (reverse && flag != reverse) DBUG_RETURN(0); reverse=flag; // Remember if reverse - key_part++; + if (key_part < key_part_end) + key_part++; } if (on_pk_suffix) { @@ -19269,19 +19306,24 @@ void JOIN::clean_pre_sort_join_tab() } -/***************************************************************************** - Remove duplicates from tmp table - This should be recoded to add a unique index to the table and remove - duplicates - Table is a locked single thread table - fields is the number of fields to check (from the end) -*****************************************************************************/ +/** + Compare fields from table->record[0] and table->record[1], + possibly skipping few first fields. + + @param table + @param ptr field to start the comparison from, + somewhere in the table->field[] array + @retval 1 different + @retval 0 identical +*/ static bool compare_record(TABLE *table, Field **ptr) { for (; *ptr ; ptr++) { - if ((*ptr)->cmp_offset(table->s->rec_buff_length)) + Field *f= *ptr; + if (f->is_null() != f->is_null(table->s->rec_buff_length) || + (!f->is_null() && f->cmp_offset(table->s->rec_buff_length))) return 1; } return 0; @@ -19309,16 +19351,16 @@ static void free_blobs(Field **ptr) static int -remove_duplicates(JOIN *join, TABLE *entry,List<Item> &fields, Item *having) +remove_duplicates(JOIN *join, TABLE *table, List<Item> &fields, Item *having) { int error; - ulong reclength,offset; + ulong keylength= 0; uint field_count; THD *thd= join->thd; DBUG_ENTER("remove_duplicates"); - entry->reginfo.lock_type=TL_WRITE; + table->reginfo.lock_type=TL_WRITE; /* Calculate how many saved fields there is in list */ field_count=0; @@ -19335,11 +19377,10 @@ remove_duplicates(JOIN *join, TABLE *entry,List<Item> &fields, Item *having) join->unit->select_limit_cnt= 1; // Only send first row DBUG_RETURN(0); } - Field **first_field=entry->field+entry->s->fields - field_count; - offset= (field_count ? - entry->field[entry->s->fields - field_count]-> - offset(entry->record[0]) : 0); - reclength=entry->s->reclength-offset; + + Field **first_field=table->field+table->s->fields - field_count; + for (Field **ptr=first_field; *ptr; ptr++) + keylength+= (*ptr)->sort_length() + (*ptr)->maybe_null(); /* Disable LIMIT ROWS EXAMINED in order to avoid interrupting prematurely @@ -19347,19 +19388,18 @@ remove_duplicates(JOIN *join, TABLE *entry,List<Item> &fields, Item *having) */ thd->lex->limit_rows_examined_cnt= ULONGLONG_MAX; if (thd->killed == ABORT_QUERY) - thd->killed= NOT_KILLED; - free_io_cache(entry); // Safety - entry->file->info(HA_STATUS_VARIABLE); - if (entry->s->db_type() == heap_hton || - (!entry->s->blob_fields && - ((ALIGN_SIZE(reclength) + HASH_OVERHEAD) * entry->file->stats.records < + thd->reset_killed(); + + free_io_cache(table); // Safety + table->file->info(HA_STATUS_VARIABLE); + if (table->s->db_type() == heap_hton || + (!table->s->blob_fields && + ((ALIGN_SIZE(keylength) + HASH_OVERHEAD) * table->file->stats.records < thd->variables.sortbuff_size))) - error=remove_dup_with_hash_index(join->thd, entry, - field_count, first_field, - reclength, having); + error=remove_dup_with_hash_index(join->thd, table, field_count, first_field, + keylength, having); else - error=remove_dup_with_compare(join->thd, entry, first_field, offset, - having); + error=remove_dup_with_compare(join->thd, table, first_field, having); if (join->select_lex != join->select_lex->master_unit()->fake_select_lex) thd->lex->set_limit_rows_examined(); @@ -19369,18 +19409,13 @@ remove_duplicates(JOIN *join, TABLE *entry,List<Item> &fields, Item *having) static int remove_dup_with_compare(THD *thd, TABLE *table, Field **first_field, - ulong offset, Item *having) + Item *having) { handler *file=table->file; - char *org_record,*new_record; - uchar *record; + uchar *record=table->record[0]; int error; - ulong reclength= table->s->reclength-offset; DBUG_ENTER("remove_dup_with_compare"); - org_record=(char*) (record=table->record[0])+offset; - new_record=(char*) table->record[1]+offset; - if (file->ha_rnd_init_with_error(1)) DBUG_RETURN(1); @@ -19417,7 +19452,7 @@ static int remove_dup_with_compare(THD *thd, TABLE *table, Field **first_field, error=0; goto err; } - memcpy(new_record,org_record,reclength); + store_record(table,record[1]); /* Read through rest of file and mark duplicated rows deleted */ bool found=0; @@ -19476,8 +19511,9 @@ static int remove_dup_with_hash_index(THD *thd, TABLE *table, int error; handler *file= table->file; ulong extra_length= ALIGN_SIZE(key_length)-key_length; - uint *field_lengths,*field_length; + uint *field_lengths, *field_length; HASH hash; + Field **ptr; DBUG_ENTER("remove_dup_with_hash_index"); if (!my_multi_malloc(MYF(MY_WME), @@ -19489,21 +19525,8 @@ static int remove_dup_with_hash_index(THD *thd, TABLE *table, NullS)) DBUG_RETURN(1); - { - Field **ptr; - ulong total_length= 0; - for (ptr= first_field, field_length=field_lengths ; *ptr ; ptr++) - { - uint length= (*ptr)->sort_length(); - (*field_length++)= length; - total_length+= length; - } - DBUG_PRINT("info",("field_count: %u key_length: %lu total_length: %lu", - field_count, key_length, total_length)); - DBUG_ASSERT(total_length <= key_length); - key_length= total_length; - extra_length= ALIGN_SIZE(key_length)-key_length; - } + for (ptr= first_field, field_length=field_lengths ; *ptr ; ptr++) + (*field_length++)= (*ptr)->sort_length(); if (my_hash_init(&hash, &my_charset_bin, (uint) file->stats.records, 0, key_length, (my_hash_get_key) 0, 0, 0)) @@ -19543,10 +19566,10 @@ static int remove_dup_with_hash_index(THD *thd, TABLE *table, /* copy fields to key buffer */ org_key_pos= key_pos; field_length=field_lengths; - for (Field **ptr= first_field ; *ptr ; ptr++) + for (ptr= first_field ; *ptr ; ptr++) { - (*ptr)->sort_string(key_pos,*field_length); - key_pos+= *field_length++; + (*ptr)->make_sort_key(key_pos, *field_length); + key_pos+= (*ptr)->maybe_null() + *field_length++; } /* Check if it exists before */ if (my_hash_search(&hash, org_key_pos, key_length)) @@ -23168,7 +23191,7 @@ test_if_cheaper_ordering(const JOIN_TAB *tab, ORDER *order, TABLE *table, { int direction; ha_rows select_limit= select_limit_arg; - uint used_key_parts; + uint used_key_parts= 0; if (keys.is_set(nr) && (direction= test_if_order_by_key(order, table, nr, &used_key_parts))) @@ -23236,7 +23259,7 @@ test_if_cheaper_ordering(const JOIN_TAB *tab, ORDER *order, TABLE *table, to be adjusted accordingly if some components of the secondary key are included in the primary key. */ - for(uint i= 0; i < used_pk_parts; i++) + for(uint i= 1; i < used_pk_parts; i++) { if (pkinfo->key_part[i].field->key_start.is_set(nr)) { |