Commit a1e9e67e authored by unknown's avatar unknown

index_merge implementation using Unique class, to be merged into 5.0


sql/filesort.cc:
  index_merge implementation using Unique class
sql/opt_ft.cc:
  index_merge implementation using Unique class
sql/opt_ft.h:
  index_merge implementation using Unique class
sql/opt_range.cc:
  index_merge implementation using Unique class
sql/opt_range.h:
  index_merge implementation using Unique class
sql/records.cc:
  index_merge implementation using Unique class
sql/sql_class.cc:
  index_merge implementation using Unique class
sql/sql_list.h:
  index_merge implementation using Unique class
sql/sql_select.cc:
  index_merge implementation using Unique class
sql/sql_select.h:
  index_merge implementation using Unique class
sql/sql_test.cc:
  index_merge implementation using Unique class
sql/sql_union.cc:
  index_merge implementation using Unique class
sql/sql_update.cc:
  index_merge implementation using Unique class
BitKeeper/etc/logging_ok:
  Logging to logging@openlogging.org accepted
parent e515e4dc
...@@ -110,6 +110,7 @@ serg@serg.mylan ...@@ -110,6 +110,7 @@ serg@serg.mylan
serg@serg.mysql.com serg@serg.mysql.com
serg@sergbook.mylan serg@sergbook.mylan
serg@sergbook.mysql.com serg@sergbook.mysql.com
sergefp@mysql.com
sinisa@rhols221.adsl.netsonic.fi sinisa@rhols221.adsl.netsonic.fi
tfr@beta.frontier86.ee tfr@beta.frontier86.ee
tfr@indrek.tfr.cafe.ee tfr@indrek.tfr.cafe.ee
......
...@@ -49,7 +49,8 @@ static int merge_index(SORTPARAM *param,uchar *sort_buffer, ...@@ -49,7 +49,8 @@ static int merge_index(SORTPARAM *param,uchar *sort_buffer,
BUFFPEK *buffpek, BUFFPEK *buffpek,
uint maxbuffer,IO_CACHE *tempfile, uint maxbuffer,IO_CACHE *tempfile,
IO_CACHE *outfile); 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, static uint sortlength(SORT_FIELD *sortorder, uint s_length,
bool *multi_byte_charset); bool *multi_byte_charset);
static SORT_ADDON_FIELD *get_addon_fields(THD *thd, Field **ptabfield, static SORT_ADDON_FIELD *get_addon_fields(THD *thd, Field **ptabfield,
...@@ -86,7 +87,9 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length, ...@@ -86,7 +87,9 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length,
#ifdef SKIP_DBUG_IN_FILESORT #ifdef SKIP_DBUG_IN_FILESORT
DBUG_PUSH(""); /* No DBUG here */ DBUG_PUSH(""); /* No DBUG here */
#endif #endif
FILESORT_INFO table_sort;
bzero(&table_sort, sizeof(FILESORT_INFO));
outfile= table->sort.io_cache; outfile= table->sort.io_cache;
my_b_clear(&tempfile); my_b_clear(&tempfile);
my_b_clear(&buffpek_pointers); my_b_clear(&buffpek_pointers);
...@@ -108,14 +111,15 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length, ...@@ -108,14 +111,15 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length,
param.sort_length, param.sort_length,
&param.addon_length); &param.addon_length);
} }
table->sort.addon_buf= 0;
table->sort.addon_length= param.addon_length; table_sort.addon_buf= 0;
table->sort.addon_field= param.addon_field; table_sort.addon_length= param.addon_length;
table->sort.unpack= unpack_addon_fields; table_sort.addon_field= param.addon_field;
table_sort.unpack= unpack_addon_fields;
if (param.addon_field) if (param.addon_field)
{ {
param.res_length= param.addon_length; 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)))) MYF(MY_WME))))
goto err; goto err;
} }
...@@ -194,7 +198,7 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length, ...@@ -194,7 +198,7 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length,
if (maxbuffer == 0) // The whole set is in memory if (maxbuffer == 0) // The whole set is in memory
{ {
if (save_index(&param,sort_keys,(uint) records)) if (save_index(&param,sort_keys,(uint) records, &table_sort))
goto err; goto err;
} }
else else
...@@ -257,6 +261,8 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length, ...@@ -257,6 +261,8 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length,
#ifdef SKIP_DBUG_IN_FILESORT #ifdef SKIP_DBUG_IN_FILESORT
DBUG_POP(); /* Ok to DBUG */ DBUG_POP(); /* Ok to DBUG */
#endif #endif
memcpy(&table->sort, &table_sort, sizeof(FILESORT_INFO));
table->sort.io_cache= outfile;
DBUG_PRINT("exit",("records: %ld",records)); DBUG_PRINT("exit",("records: %ld",records));
DBUG_RETURN(error ? HA_POS_ERROR : records); DBUG_RETURN(error ? HA_POS_ERROR : records);
} /* filesort */ } /* filesort */
...@@ -360,12 +366,24 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select, ...@@ -360,12 +366,24 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select,
current_thd->variables.read_buff_size); 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 (;;) for (;;)
{ {
if (quick_select) if (quick_select)
{ {
if ((error=select->quick->get_next())) if ((error= read_record_info.read_record(&read_record_info)))
break; {
error= HA_ERR_END_OF_FILE;
break;
}
file->position(sort_form->record[0]); file->position(sort_form->record[0]);
} }
else /* Not quick-select */ else /* Not quick-select */
...@@ -393,6 +411,7 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select, ...@@ -393,6 +411,7 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select,
if (error && error != HA_ERR_RECORD_DELETED) if (error && error != HA_ERR_RECORD_DELETED)
break; break;
} }
if (*killed) if (*killed)
{ {
DBUG_PRINT("info",("Sort killed by user")); DBUG_PRINT("info",("Sort killed by user"));
...@@ -426,8 +445,14 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select, ...@@ -426,8 +445,14 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select,
else else
file->unlock_row(); file->unlock_row();
} }
(void) file->extra(HA_EXTRA_NO_CACHE); /* End cacheing of records */ if (quick_select)
file->rnd_end(); 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)); DBUG_PRINT("test",("error: %d indexpos: %d",error,indexpos));
if (error != HA_ERR_END_OF_FILE) if (error != HA_ERR_END_OF_FILE)
{ {
...@@ -665,8 +690,8 @@ static void make_sortkey(register SORTPARAM *param, ...@@ -665,8 +690,8 @@ static void make_sortkey(register SORTPARAM *param,
return; 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; uint offset,res_length;
byte *to; byte *to;
...@@ -677,7 +702,7 @@ static bool save_index(SORTPARAM *param, uchar **sort_keys, uint count) ...@@ -677,7 +702,7 @@ static bool save_index(SORTPARAM *param, uchar **sort_keys, uint count)
offset= param->rec_length-res_length; offset= param->rec_length-res_length;
if ((ha_rows) count > param->max_rows) if ((ha_rows) count > param->max_rows)
count=(uint) 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)))) (byte*) my_malloc(res_length*count, MYF(MY_WME))))
DBUG_RETURN(1); /* purecov: inspected */ DBUG_RETURN(1); /* purecov: inspected */
for (uchar **end= sort_keys+count ; sort_keys != end ; sort_keys++) for (uchar **end= sort_keys+count ; sort_keys != end ; sort_keys++)
......
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
** Create a FT or QUICK RANGE based on a key ** Create a FT or QUICK RANGE based on a key
****************************************************************************/ ****************************************************************************/
QUICK_SELECT *get_ft_or_quick_select_for_ref(TABLE *table, JOIN_TAB *tab) QUICK_RANGE_SELECT *get_ft_or_quick_select_for_ref(TABLE *table, JOIN_TAB *tab)
{ {
if (tab->type == JT_FT) if (tab->type == JT_FT)
return new FT_SELECT(table, &tab->ref); return new FT_SELECT(table, &tab->ref);
......
...@@ -24,17 +24,18 @@ ...@@ -24,17 +24,18 @@
#pragma interface /* gcc class implementation */ #pragma interface /* gcc class implementation */
#endif #endif
class FT_SELECT: public QUICK_SELECT { class FT_SELECT: public QUICK_RANGE_SELECT {
public: public:
TABLE_REF *ref; TABLE_REF *ref;
FT_SELECT(TABLE *table, TABLE_REF *tref) : FT_SELECT(TABLE *table, TABLE_REF *tref) :
QUICK_SELECT (table,tref->key,1), ref(tref) { init(); } QUICK_RANGE_SELECT (table,tref->key,1), ref(tref) { init(); }
int init() { return error=file->ft_init(); } int init() { QUICK_RANGE_SELECT::init(); return (error=file->ft_init()); }
int get_next() { return error=file->ft_read(record); } int get_next() { return error=file->ft_read(record); }
int get_type() { return QS_TYPE_FULLTEXT; }
}; };
QUICK_SELECT *get_ft_or_quick_select_for_ref(TABLE *table, JOIN_TAB *tab); QUICK_RANGE_SELECT *get_ft_or_quick_select_for_ref(TABLE *table, JOIN_TAB *tab);
#endif #endif
This diff is collapsed.
...@@ -65,48 +65,142 @@ class QUICK_RANGE :public Sql_alloc { ...@@ -65,48 +65,142 @@ class QUICK_RANGE :public Sql_alloc {
} }
}; };
//class INDEX_MERGE;
class QUICK_SELECT { /*
Quick select interface.
This class is parent for all QUICK_*_SELECT and FT_SELECT classes.
*/
class QUICK_SELECT_I
{
public: public:
ha_rows records; /* estimate of # of records to be retrieved */
double read_time; /* time to perform this retrieval */
TABLE *head;
/*
the only index this quick select uses, or MAX_KEY for
QUICK_INDEX_MERGE_SELECT
*/
uint index;
uint max_used_key_length, used_key_parts;
QUICK_SELECT_I();
virtual ~QUICK_SELECT_I(){};
virtual int init() = 0;
virtual int reset(void) = 0;
virtual int get_next() = 0; /* get next record to retrieve */
virtual bool reverse_sorted() = 0;
virtual bool unique_key_range() { return false; }
enum {
QS_TYPE_RANGE = 0,
QS_TYPE_INDEX_MERGE = 1,
QS_TYPE_RANGE_DESC = 2,
QS_TYPE_FULLTEXT = 3
};
/* Get type of this quick select - one of the QS_* values */
virtual int get_type() = 0;
};
struct st_qsel_param;
class SEL_ARG;
class QUICK_RANGE_SELECT : public QUICK_SELECT_I
{
protected:
bool next,dont_free; bool next,dont_free;
public:
int error; int error;
uint index, max_used_key_length, used_key_parts;
TABLE *head;
handler *file; handler *file;
byte *record; byte *record;
protected:
friend void print_quick_sel_range(QUICK_RANGE_SELECT *quick,
key_map needed_reg);
friend QUICK_RANGE_SELECT *get_quick_select_for_ref(TABLE *table,
struct st_table_ref *ref);
friend bool get_quick_keys(struct st_qsel_param *param,
QUICK_RANGE_SELECT *quick,KEY_PART *key,
SEL_ARG *key_tree,char *min_key,uint min_key_flag,
char *max_key, uint max_key_flag);
friend QUICK_RANGE_SELECT *get_quick_select(struct st_qsel_param*,uint idx,
SEL_ARG *key_tree,
MEM_ROOT *alloc);
friend class QUICK_SELECT_DESC;
List<QUICK_RANGE> ranges; List<QUICK_RANGE> ranges;
List_iterator<QUICK_RANGE> it; List_iterator<QUICK_RANGE> it;
QUICK_RANGE *range; QUICK_RANGE *range;
MEM_ROOT alloc; MEM_ROOT alloc;
KEY_PART *key_parts; KEY_PART *key_parts;
ha_rows records;
double read_time;
QUICK_SELECT(TABLE *table,uint index_arg,bool no_alloc=0);
virtual ~QUICK_SELECT();
void reset(void) { next=0; it.rewind(); }
int init() { return error=file->index_init(index); }
virtual int get_next();
virtual bool reverse_sorted() { return 0; }
int cmp_next(QUICK_RANGE *range); int cmp_next(QUICK_RANGE *range);
public:
QUICK_RANGE_SELECT(TABLE *table,uint index_arg,bool no_alloc=0,
MEM_ROOT *parent_alloc=NULL);
~QUICK_RANGE_SELECT();
int reset(void) { next=0; it.rewind(); return 0; }
int init();
int get_next();
bool reverse_sorted() { return 0; }
bool unique_key_range(); bool unique_key_range();
int get_type() { return QS_TYPE_RANGE; }
}; };
/*
Index merge quick select.
It is implemented as a container for several QUICK_RANGE_SELECTs.
*/
class QUICK_INDEX_MERGE_SELECT : public QUICK_SELECT_I
{
public:
QUICK_INDEX_MERGE_SELECT(THD *thd, TABLE *table);
~QUICK_INDEX_MERGE_SELECT();
int init();
int reset(void);
int get_next();
bool reverse_sorted() { return false; }
bool unique_key_range() { return false; }
int get_type() { return QS_TYPE_INDEX_MERGE; }
bool push_quick_back(QUICK_RANGE_SELECT *quick_sel_range);
/* range quick selects this index_merge read consists of */
List<QUICK_RANGE_SELECT> quick_selects;
/* quick select which is currently used for rows retrieval */
List_iterator_fast<QUICK_RANGE_SELECT> cur_quick_it;
QUICK_RANGE_SELECT* cur_quick_select;
/* last element in quick_selects list. */
QUICK_RANGE_SELECT* last_quick_select;
Unique *unique;
MEM_ROOT alloc;
THD *thd;
int prepare_unique();
bool reset_called;
};
class QUICK_SELECT_DESC: public QUICK_SELECT class QUICK_SELECT_DESC: public QUICK_RANGE_SELECT
{ {
public: public:
QUICK_SELECT_DESC(QUICK_SELECT *q, uint used_key_parts); QUICK_SELECT_DESC(QUICK_RANGE_SELECT *q, uint used_key_parts);
int get_next(); int get_next();
bool reverse_sorted() { return 1; } bool reverse_sorted() { return 1; }
int get_type() { return QS_TYPE_RANGE_DESC; }
private: private:
int cmp_prev(QUICK_RANGE *range); int cmp_prev(QUICK_RANGE *range);
bool range_reads_after_key(QUICK_RANGE *range); bool range_reads_after_key(QUICK_RANGE *range);
#ifdef NOT_USED #ifdef NOT_USED
bool test_if_null_range(QUICK_RANGE *range, uint used_key_parts); bool test_if_null_range(QUICK_RANGE *range, uint used_key_parts);
#endif #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<QUICK_RANGE> rev_ranges;
List_iterator<QUICK_RANGE> rev_it; List_iterator<QUICK_RANGE> rev_it;
}; };
...@@ -114,7 +208,7 @@ class QUICK_SELECT_DESC: public QUICK_SELECT ...@@ -114,7 +208,7 @@ class QUICK_SELECT_DESC: public QUICK_SELECT
class SQL_SELECT :public Sql_alloc { class SQL_SELECT :public Sql_alloc {
public: public:
QUICK_SELECT *quick; // If quick-select used QUICK_SELECT_I *quick; // If quick-select used
COND *cond; // where condition COND *cond; // where condition
TABLE *head; TABLE *head;
IO_CACHE file; // Positions to used records IO_CACHE file; // Positions to used records
...@@ -134,6 +228,6 @@ class SQL_SELECT :public Sql_alloc { ...@@ -134,6 +228,6 @@ class SQL_SELECT :public Sql_alloc {
bool force_quick_range=0); bool force_quick_range=0);
}; };
QUICK_SELECT *get_quick_select_for_ref(TABLE *table, struct st_table_ref *ref); QUICK_RANGE_SELECT *get_quick_select_for_ref(TABLE *table, struct st_table_ref *ref);
#endif #endif
...@@ -98,7 +98,8 @@ void init_read_record(READ_RECORD *info,THD *thd, TABLE *table, ...@@ -98,7 +98,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")); DBUG_PRINT("info",("using rr_quick"));
info->read_record=rr_quick; info->read_record=rr_quick;
......
...@@ -537,8 +537,8 @@ int THD::send_explain_fields(select_result *result) ...@@ -537,8 +537,8 @@ int THD::send_explain_fields(select_result *result)
item->maybe_null=1; item->maybe_null=1;
field_list.push_back(item=new Item_empty_string("key",NAME_LEN)); field_list.push_back(item=new Item_empty_string("key",NAME_LEN));
item->maybe_null=1; item->maybe_null=1;
field_list.push_back(item=new Item_return_int("key_len",3, field_list.push_back(item=new Item_empty_string("key_len",
MYSQL_TYPE_LONGLONG)); NAME_LEN*MAX_KEY));
item->maybe_null=1; item->maybe_null=1;
field_list.push_back(item=new Item_empty_string("ref", field_list.push_back(item=new Item_empty_string("ref",
NAME_LEN*MAX_REF_PARTS)); NAME_LEN*MAX_REF_PARTS));
......
...@@ -135,6 +135,12 @@ class base_list :public Sql_alloc ...@@ -135,6 +135,12 @@ class base_list :public Sql_alloc
last= &first; last= &first;
return tmp->info; return tmp->info;
} }
inline void concat(base_list *list)
{
*last= list->first;
last= list->last;
elements+= list->elements;
}
inline list_node* last_node() { return *last; } inline list_node* last_node() { return *last; }
inline list_node* first_node() { return first;} inline list_node* first_node() { return first;}
inline void *head() { return first->info; } inline void *head() { return first->info; }
...@@ -255,6 +261,7 @@ template <class T> class List :public base_list ...@@ -255,6 +261,7 @@ template <class T> class List :public base_list
} }
empty(); empty();
} }
inline void concat(List<T> *list) { base_list::concat(list); }
}; };
......
...@@ -32,7 +32,8 @@ ...@@ -32,7 +32,8 @@
const char *join_type_str[]={ "UNKNOWN","system","const","eq_ref","ref", const char *join_type_str[]={ "UNKNOWN","system","const","eq_ref","ref",
"MAYBE_REF","ALL","range","index","fulltext", "MAYBE_REF","ALL","range","index","fulltext",
"ref_or_null","simple_in","index_in" "ref_or_null","simple_in","index_in",
"index_merge"
}; };
static void optimize_keyuse(JOIN *join, DYNAMIC_ARRAY *keyuse_array); static void optimize_keyuse(JOIN *join, DYNAMIC_ARRAY *keyuse_array);
...@@ -114,7 +115,6 @@ static int join_read_next_same_or_null(READ_RECORD *info); ...@@ -114,7 +115,6 @@ static int join_read_next_same_or_null(READ_RECORD *info);
static COND *make_cond_for_table(COND *cond,table_map table, static COND *make_cond_for_table(COND *cond,table_map table,
table_map used_table); table_map used_table);
static Item* part_of_refkey(TABLE *form,Field *field); static Item* part_of_refkey(TABLE *form,Field *field);
static uint find_shortest_key(TABLE *table, key_map usable_keys);
static bool test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order, static bool test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,
ha_rows select_limit, bool no_changes); ha_rows select_limit, bool no_changes);
static int create_sort_index(THD *thd, JOIN *join, ORDER *order, static int create_sort_index(THD *thd, JOIN *join, ORDER *order,
...@@ -3285,7 +3285,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) ...@@ -3285,7 +3285,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
with key reading */ with key reading */
if (tab->needed_reg == 0 && tab->type != JT_EQ_REF if (tab->needed_reg == 0 && tab->type != JT_EQ_REF
&& tab->type != JT_FT && (tab->type != JT_REF || && tab->type != JT_FT && (tab->type != JT_REF ||
(uint) tab->ref.key == tab->quick->index)) (uint) tab->ref.key == tab->quick->index))
{ {
sel->quick=tab->quick; // Use value from get_quick_... sel->quick=tab->quick; // Use value from get_quick_...
sel->quick_keys=0; sel->quick_keys=0;
...@@ -5725,8 +5725,8 @@ test_if_quick_select(JOIN_TAB *tab) ...@@ -5725,8 +5725,8 @@ test_if_quick_select(JOIN_TAB *tab)
static int static int
join_init_read_record(JOIN_TAB *tab) join_init_read_record(JOIN_TAB *tab)
{ {
if (tab->select && tab->select->quick) if (tab->select && tab->select->quick && tab->select->quick->reset())
tab->select->quick->reset(); return 1;
init_read_record(&tab->read_record, tab->join->thd, tab->table, init_read_record(&tab->read_record, tab->join->thd, tab->table,
tab->select,1,1); tab->select,1,1);
return (*tab->read_record.read_record)(&tab->read_record); return (*tab->read_record.read_record)(&tab->read_record);
...@@ -6473,7 +6473,7 @@ static int test_if_order_by_key(ORDER *order, TABLE *table, uint idx, ...@@ -6473,7 +6473,7 @@ static int test_if_order_by_key(ORDER *order, TABLE *table, uint idx,
return reverse; return reverse;
} }
static uint find_shortest_key(TABLE *table, key_map usable_keys) uint find_shortest_key(TABLE *table, key_map usable_keys)
{ {
uint min_length= (uint) ~0; uint min_length= (uint) ~0;
uint best= MAX_KEY; uint best= MAX_KEY;
...@@ -6601,6 +6601,9 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, ...@@ -6601,6 +6601,9 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
} }
else if (select && select->quick) // Range found by opt_range else if (select && select->quick) // Range found by opt_range
{ {
/* assume results are not ordered when index merge is used */
if (select->quick->get_type() == QUICK_SELECT_I::QS_TYPE_INDEX_MERGE)
DBUG_RETURN(0);
ref_key= select->quick->index; ref_key= select->quick->index;
ref_key_parts= select->quick->used_key_parts; ref_key_parts= select->quick->used_key_parts;
} }
...@@ -6635,6 +6638,10 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, ...@@ -6635,6 +6638,10 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
} }
else else
{ {
/*
We have verified above that select->quick is not
index_merge quick select.
*/
select->quick->index= new_ref_key; select->quick->index= new_ref_key;
select->quick->init(); select->quick->init();
} }
...@@ -6656,10 +6663,13 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, ...@@ -6656,10 +6663,13 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
*/ */
if (!select->quick->reverse_sorted()) if (!select->quick->reverse_sorted())
{ {
if (table->file->index_flags(ref_key) & HA_NOT_READ_PREFIX_LAST) if (table->file->index_flags(ref_key) & HA_NOT_READ_PREFIX_LAST ||
(select->quick->get_type() ==
QUICK_SELECT_I::QS_TYPE_INDEX_MERGE))
DBUG_RETURN(0); // Use filesort DBUG_RETURN(0); // Use filesort
// ORDER BY range_key DESC
QUICK_SELECT_DESC *tmp=new QUICK_SELECT_DESC(select->quick, // ORDER BY range_key DESC
QUICK_SELECT_DESC *tmp=new QUICK_SELECT_DESC((QUICK_RANGE_SELECT*)(select->quick),
used_key_parts); used_key_parts);
if (!tmp || tmp->error) if (!tmp || tmp->error)
{ {
...@@ -6794,8 +6804,11 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order, ...@@ -6794,8 +6804,11 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order,
{ {
select->quick=tab->quick; select->quick=tab->quick;
tab->quick=0; tab->quick=0;
/* We can only use 'Only index' if quick key is same as ref_key */ /*
if (table->key_read && (uint) tab->ref.key != select->quick->index) We can only use 'Only index' if quick key is same as ref_key
and in index_merge 'Only index' cannot be used
*/
if (table->key_read && ((uint) tab->ref.key != select->quick->index))
{ {
table->key_read=0; table->key_read=0;
table->file->extra(HA_EXTRA_NO_KEYREAD); table->file->extra(HA_EXTRA_NO_KEYREAD);
...@@ -8598,12 +8611,15 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, ...@@ -8598,12 +8611,15 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
JOIN_TAB *tab=join->join_tab+i; JOIN_TAB *tab=join->join_tab+i;
TABLE *table=tab->table; TABLE *table=tab->table;
char buff[512],*buff_ptr=buff; char buff[512],*buff_ptr=buff;
char buff1[512], buff2[512]; char buff1[512], buff2[512], buff3[512];
char keylen_str_buf[64];
char derived_name[64]; char derived_name[64];
String tmp1(buff1,sizeof(buff1),cs); String tmp1(buff1,sizeof(buff1),cs);
String tmp2(buff2,sizeof(buff2),cs); String tmp2(buff2,sizeof(buff2),cs);
String tmp3(buff3,sizeof(buff3),cs);
tmp1.length(0); tmp1.length(0);
tmp2.length(0); tmp2.length(0);
tmp3.length(0);
item_list.empty(); item_list.empty();
item_list.push_back(new Item_int((int32) item_list.push_back(new Item_int((int32)
...@@ -8612,7 +8628,13 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, ...@@ -8612,7 +8628,13 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
strlen(join->select_lex->type), strlen(join->select_lex->type),
cs)); cs));
if (tab->type == JT_ALL && tab->select && tab->select->quick) if (tab->type == JT_ALL && tab->select && tab->select->quick)
tab->type= JT_RANGE; {
if (tab->select->quick->get_type() ==
QUICK_SELECT_I::QS_TYPE_INDEX_MERGE)
tab->type = JT_INDEX_MERGE;
else
tab->type = JT_RANGE;
}
if (table->derived_select_number) if (table->derived_select_number)
{ {
/* Derived table name generation */ /* Derived table name generation */
...@@ -8646,10 +8668,14 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, ...@@ -8646,10 +8668,14 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
if (tab->ref.key_parts) if (tab->ref.key_parts)
{ {
KEY *key_info=table->key_info+ tab->ref.key; KEY *key_info=table->key_info+ tab->ref.key;
register uint length;
item_list.push_back(new Item_string(key_info->name, item_list.push_back(new Item_string(key_info->name,
strlen(key_info->name), strlen(key_info->name),
system_charset_info)); system_charset_info));
item_list.push_back(new Item_int((int32) tab->ref.key_length)); length= longlong2str(tab->ref.key_length, keylen_str_buf, 10) -
keylen_str_buf;
item_list.push_back(new Item_string(keylen_str_buf, length,
system_charset_info));
for (store_key **ref=tab->ref.key_copy ; *ref ; ref++) for (store_key **ref=tab->ref.key_copy ; *ref ; ref++)
{ {
if (tmp2.length()) if (tmp2.length())
...@@ -8661,18 +8687,60 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, ...@@ -8661,18 +8687,60 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
else if (tab->type == JT_NEXT) else if (tab->type == JT_NEXT)
{ {
KEY *key_info=table->key_info+ tab->index; KEY *key_info=table->key_info+ tab->index;
register uint length;
item_list.push_back(new Item_string(key_info->name, item_list.push_back(new Item_string(key_info->name,
strlen(key_info->name),cs)); strlen(key_info->name),cs));
item_list.push_back(new Item_int((int32) key_info->key_length)); length= longlong2str(key_info->key_length, keylen_str_buf, 10) -
keylen_str_buf;
item_list.push_back(new Item_string(keylen_str_buf,
length,
system_charset_info));
item_list.push_back(item_null); item_list.push_back(item_null);
} }
else if (tab->select && tab->select->quick) else if (tab->select && tab->select->quick)
{ {
KEY *key_info=table->key_info+ tab->select->quick->index; if (tab->select->quick->get_type() ==
item_list.push_back(new Item_string(key_info->name, QUICK_SELECT_I::QS_TYPE_INDEX_MERGE)
strlen(key_info->name),cs)); {
item_list.push_back(new Item_int((int32) tab->select->quick-> QUICK_INDEX_MERGE_SELECT *quick_imerge=
max_used_key_length)); (QUICK_INDEX_MERGE_SELECT*)tab->select->quick;
QUICK_RANGE_SELECT *quick;
List_iterator_fast<QUICK_RANGE_SELECT> it(quick_imerge->
quick_selects);
while ((quick= it++))
{
KEY *key_info= table->key_info + quick->index;
register uint length;
if (tmp3.length())
tmp3.append(',');
tmp3.append(key_info->name);
if (tmp2.length())
tmp2.append(',');
length= longlong2str(quick->max_used_key_length, keylen_str_buf,
10) -
keylen_str_buf;
tmp2.append(keylen_str_buf, length);
}
}
else
{
KEY *key_info= table->key_info + tab->select->quick->index;
register uint length;
tmp3.append(key_info->name);
length= longlong2str(tab->select->quick->max_used_key_length,
keylen_str_buf, 10) -
keylen_str_buf;
tmp2.append(keylen_str_buf, length);
}
item_list.push_back(new Item_string(tmp3.ptr(),tmp3.length(),cs));
item_list.push_back(new Item_string(tmp2.ptr(),tmp2.length(),cs));
item_list.push_back(item_null); item_list.push_back(item_null);
} }
else else
......
...@@ -76,7 +76,7 @@ typedef struct st_join_cache { ...@@ -76,7 +76,7 @@ typedef struct st_join_cache {
enum join_type { JT_UNKNOWN,JT_SYSTEM,JT_CONST,JT_EQ_REF,JT_REF,JT_MAYBE_REF, enum join_type { JT_UNKNOWN,JT_SYSTEM,JT_CONST,JT_EQ_REF,JT_REF,JT_MAYBE_REF,
JT_ALL, JT_RANGE, JT_NEXT, JT_FT, JT_REF_OR_NULL, JT_ALL, JT_RANGE, JT_NEXT, JT_FT, JT_REF_OR_NULL,
JT_SIMPLE_IN, JT_INDEX_IN}; JT_SIMPLE_IN, JT_INDEX_IN, JT_INDEX_MERGE};
class JOIN; class JOIN;
...@@ -85,7 +85,7 @@ typedef struct st_join_table { ...@@ -85,7 +85,7 @@ typedef struct st_join_table {
KEYUSE *keyuse; /* pointer to first used key */ KEYUSE *keyuse; /* pointer to first used key */
SQL_SELECT *select; SQL_SELECT *select;
COND *select_cond; COND *select_cond;
QUICK_SELECT *quick; QUICK_SELECT_I *quick;
Item *on_expr; Item *on_expr;
const char *info; const char *info;
byte *null_ref_key; byte *null_ref_key;
...@@ -307,10 +307,14 @@ void copy_fields(TMP_TABLE_PARAM *param); ...@@ -307,10 +307,14 @@ void copy_fields(TMP_TABLE_PARAM *param);
void copy_funcs(Item **func_ptr); void copy_funcs(Item **func_ptr);
bool create_myisam_from_heap(THD *thd, TABLE *table, TMP_TABLE_PARAM *param, bool create_myisam_from_heap(THD *thd, TABLE *table, TMP_TABLE_PARAM *param,
int error, bool ignore_last_dupp_error); int error, bool ignore_last_dupp_error);
uint find_shortest_key(TABLE *table, key_map usable_keys);
/* functions from opt_sum.cc */ /* functions from opt_sum.cc */
int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds); 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 to copying an field/item to a key struct */
class store_key :public Sql_alloc class store_key :public Sql_alloc
......
...@@ -179,9 +179,39 @@ TEST_join(JOIN *join) ...@@ -179,9 +179,39 @@ TEST_join(JOIN *join)
" quick select checked for each record (keys: %d)\n", " quick select checked for each record (keys: %d)\n",
(int) tab->select->quick_keys); (int) tab->select->quick_keys);
else if (tab->select->quick) else if (tab->select->quick)
fprintf(DBUG_FILE," quick select used on key %s, length: %d\n", {
int quick_type= tab->select->quick->get_type();
if ((quick_type == QUICK_SELECT_I::QS_TYPE_RANGE) ||
(quick_type == QUICK_SELECT_I::QS_TYPE_RANGE_DESC))
{
fprintf(DBUG_FILE,
" quick select used on key %s, length: %d\n",
form->key_info[tab->select->quick->index].name, form->key_info[tab->select->quick->index].name,
tab->select->quick->max_used_key_length); tab->select->quick->max_used_key_length);
}
else if (quick_type == QUICK_SELECT_I::QS_TYPE_INDEX_MERGE)
{
QUICK_INDEX_MERGE_SELECT *quick_imerge=
(QUICK_INDEX_MERGE_SELECT*)tab->select->quick;
QUICK_RANGE_SELECT *quick;
fprintf(DBUG_FILE,
" index_merge quick select used\n");
List_iterator_fast<QUICK_RANGE_SELECT> it(quick_imerge->quick_selects);
while ((quick = it++))
{
fprintf(DBUG_FILE,
" range quick select: key %s, length: %d\n",
form->key_info[quick->index].name,
quick->max_used_key_length);
}
}
else
{
fprintf(DBUG_FILE,
" quick select of unknown nature used\n");
}
}
else else
VOID(fputs(" select used\n",DBUG_FILE)); VOID(fputs(" select used\n",DBUG_FILE));
} }
......
...@@ -117,7 +117,8 @@ int st_select_lex_unit::prepare(THD *thd, select_result *sel_result, ...@@ -117,7 +117,8 @@ int st_select_lex_unit::prepare(THD *thd, select_result *sel_result,
{ {
SELECT_LEX *lex_select_save= thd->lex.current_select; SELECT_LEX *lex_select_save= thd->lex.current_select;
SELECT_LEX *select_cursor; SELECT_LEX *select_cursor;
DBUG_ENTER("st_select_lex_unit::prepare"); SELECT_LEX *sl;
DBUG_ENTER("st_select_lex_unit::prepare");
if (prepared) if (prepared)
DBUG_RETURN(0); DBUG_RETURN(0);
...@@ -185,7 +186,7 @@ int st_select_lex_unit::prepare(THD *thd, select_result *sel_result, ...@@ -185,7 +186,7 @@ int st_select_lex_unit::prepare(THD *thd, select_result *sel_result,
union_result->not_describe=1; union_result->not_describe=1;
union_result->tmp_table_param=tmp_table_param; union_result->tmp_table_param=tmp_table_param;
for (SELECT_LEX *sl= select_cursor; sl; sl= sl->next_select()) for (sl= select_cursor; sl; sl= sl->next_select())
{ {
JOIN *join= new JOIN(thd, sl->item_list, JOIN *join= new JOIN(thd, sl->item_list,
sl->options | thd->options | SELECT_NO_UNLOCK, sl->options | thd->options | SELECT_NO_UNLOCK,
......
...@@ -171,10 +171,18 @@ int mysql_update(THD *thd, ...@@ -171,10 +171,18 @@ int mysql_update(THD *thd,
init_ftfuncs(thd, &thd->lex.select_lex, 1); init_ftfuncs(thd, &thd->lex.select_lex, 1);
/* Check if we are modifying a key that we are used to search with */ /* Check if we are modifying a key that we are used to search with */
if (select && select->quick) if (select && select->quick)
used_key_is_modified= (!select->quick->unique_key_range() && {
check_if_key_used(table, if (select->quick->get_type() != QUICK_SELECT_I::QS_TYPE_INDEX_MERGE)
(used_index=select->quick->index), {
fields)); used_index= select->quick->index;
used_key_is_modified= (!select->quick->unique_key_range() &&
check_if_key_used(table,used_index,fields));
}
else
{
used_key_is_modified= true;
}
}
else if ((used_index=table->file->key_used_on_scan) < MAX_KEY) else if ((used_index=table->file->key_used_on_scan) < MAX_KEY)
used_key_is_modified=check_if_key_used(table, used_index, fields); used_key_is_modified=check_if_key_used(table, used_index, fields);
else else
...@@ -688,8 +696,26 @@ static bool safe_update_on_fly(JOIN_TAB *join_tab, List<Item> *fields) ...@@ -688,8 +696,26 @@ static bool safe_update_on_fly(JOIN_TAB *join_tab, List<Item> *fields)
case JT_ALL: case JT_ALL:
/* If range search on index */ /* If range search on index */
if (join_tab->quick) if (join_tab->quick)
return !check_if_key_used(table, join_tab->quick->index, {
*fields); if (join_tab->quick->get_type() != QUICK_SELECT_I::QS_TYPE_INDEX_MERGE)
{
return !check_if_key_used(table,join_tab->quick->index,*fields);
}
else
{
QUICK_INDEX_MERGE_SELECT *qsel_imerge=
(QUICK_INDEX_MERGE_SELECT*)(join_tab->quick);
List_iterator_fast<QUICK_RANGE_SELECT> it(qsel_imerge->quick_selects);
QUICK_RANGE_SELECT *quick;
while ((quick= it++))
{
if (check_if_key_used(table, quick->index, *fields))
return 0;
}
return 1;
}
}
/* If scanning in clustered key */ /* If scanning in clustered key */
if ((table->file->table_flags() & HA_PRIMARY_KEY_IN_READ_INDEX) && if ((table->file->table_flags() & HA_PRIMARY_KEY_IN_READ_INDEX) &&
table->primary_key < MAX_KEY) table->primary_key < MAX_KEY)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment