Commit 8d11c01c authored by unknown's avatar unknown

WL#2126 - Multi_read_range.

Added the required structures and functions for
handing over multiple key ranges to the table handler.


include/my_base.h:
  WL#2126 - Multi_read_range.
  Moved key range flags from sql/opt_range.h to here.
  Added the multi-range structure.
sql/handler.cc:
  WL#2126 - Multi_read_range.
  Added the new table handler methods.
sql/handler.h:
  WL#2126 - Multi_read_range.
  Added a new table flag.
  Added a declaration for the handler buffer.
  Added new elements to class handler.
  Added new function declarations.
sql/mysqld.cc:
  WL#2126 - Multi_read_range.
  Added an option to set new system variable 'multi_range_count'.
sql/opt_range.cc:
  WL#2126 - Multi_read_range.
  Added initialization for the new class members.
  Added initialization for the extended get_next().
  Added de-initialization for the allocated buffers.
  Added a buffer allocation method.
  Added an inner loop to collect multiple ranges.
  Adapted range collection loops to the new initialization.
sql/opt_range.h:
  WL#2126 - Multi_read_range.
  Moved key range flags from here to include/my_base.h.
  Added new elements to class QUICK_RANGE_SELECT.
  Added a copy constructor.
sql/records.cc:
  WL#2126 - Multi_read_range.
  Added a call of the allocation method.
sql/set_var.cc:
  WL#2126 - Multi_read_range.
  Added the new system variable 'multi_range_count'.
sql/sql_class.h:
  WL#2126 - Multi_read_range.
  Added the new system variable 'multi_range_count'.
parent dd6981f4
...@@ -370,6 +370,15 @@ enum data_file_type { ...@@ -370,6 +370,15 @@ enum data_file_type {
/* For key ranges */ /* For key ranges */
#define NO_MIN_RANGE 1
#define NO_MAX_RANGE 2
#define NEAR_MIN 4
#define NEAR_MAX 8
#define UNIQUE_RANGE 16
#define EQ_RANGE 32
#define NULL_RANGE 64
#define GEOM_FLAG 128
typedef struct st_key_range typedef struct st_key_range
{ {
const byte *key; const byte *key;
...@@ -377,6 +386,14 @@ typedef struct st_key_range ...@@ -377,6 +386,14 @@ typedef struct st_key_range
enum ha_rkey_function flag; enum ha_rkey_function flag;
} key_range; } key_range;
typedef struct st_key_multi_range
{
key_range start_key;
key_range end_key;
char *ptr; /* Free to use by caller (ptr to row etc) */
uint range_flag; /* key range flags see above */
} KEY_MULTI_RANGE;
/* For number of records */ /* For number of records */
#ifdef BIG_TABLES #ifdef BIG_TABLES
......
...@@ -1685,6 +1685,131 @@ int ha_table_exists(THD* thd, const char* db, const char* name) ...@@ -1685,6 +1685,131 @@ int ha_table_exists(THD* thd, const char* db, const char* name)
#endif #endif
/*
Read the first row of a multi-range set.
SYNOPSIS
read_multi_range_first()
found_range_p Returns a pointer to the element in 'ranges' that
corresponds to the returned row.
ranges An array of KEY_MULTI_RANGE range descriptions.
range_count Number of ranges in 'ranges'.
sorted If result should be sorted per key.
buffer A HANDLER_BUFFER for internal handler usage.
NOTES
Record is read into table->record[0].
*found_range_p returns a valid value only if read_multi_range_first()
returns 0.
Sorting is done within each range. If you want an overall sort, enter
'ranges' with sorted ranges.
RETURN
0 OK, found a row
HA_ERR_END_OF_FILE No rows in range
# Error code
*/
int handler::read_multi_range_first(KEY_MULTI_RANGE **found_range_p,
KEY_MULTI_RANGE *ranges, uint range_count,
bool sorted, HANDLER_BUFFER *buffer)
{
int result= HA_ERR_END_OF_FILE;
DBUG_ENTER("handler::read_multi_range_first");
multi_range_sorted= sorted;
multi_range_buffer= buffer;
for (multi_range_curr= ranges, multi_range_end= ranges + range_count;
multi_range_curr < multi_range_end;
multi_range_curr++)
{
result= read_range_first(multi_range_curr->start_key.length ?
&multi_range_curr->start_key : 0,
multi_range_curr->end_key.length ?
&multi_range_curr->end_key : 0,
test(multi_range_curr->range_flag & EQ_RANGE),
multi_range_sorted);
if (result != HA_ERR_END_OF_FILE)
break;
}
*found_range_p= multi_range_curr;
DBUG_PRINT("exit",("result %d", result));
DBUG_RETURN(result);
}
/*
Read the next row of a multi-range set.
SYNOPSIS
read_multi_range_next()
found_range_p Returns a pointer to the element in 'ranges' that
corresponds to the returned row.
NOTES
Record is read into table->record[0].
*found_range_p returns a valid value only if read_multi_range_next()
returns 0.
RETURN
0 OK, found a row
HA_ERR_END_OF_FILE No (more) rows in range
# Error code
*/
int handler::read_multi_range_next(KEY_MULTI_RANGE **found_range_p)
{
int result;
DBUG_ENTER("handler::read_multi_range_next");
/* We should not be called after the last call returned EOF. */
DBUG_ASSERT(multi_range_curr < multi_range_end);
do
{
/* Save a call if there can be only one row in range. */
if (multi_range_curr->range_flag != (UNIQUE_RANGE | EQ_RANGE))
{
result= read_range_next();
/* On success or non-EOF errors jump to the end. */
if (result != HA_ERR_END_OF_FILE)
break;
}
else
{
/*
We need to set this for the last range only, but checking this
condition is more expensive than just setting the result code.
*/
result= HA_ERR_END_OF_FILE;
}
/* Try the next range(s) until one matches a record. */
for (multi_range_curr++;
multi_range_curr < multi_range_end;
multi_range_curr++)
{
result= read_range_first(multi_range_curr->start_key.length ?
&multi_range_curr->start_key : 0,
multi_range_curr->end_key.length ?
&multi_range_curr->end_key : 0,
test(multi_range_curr->range_flag & EQ_RANGE),
multi_range_sorted);
if (result != HA_ERR_END_OF_FILE)
break;
}
}
while ((result == HA_ERR_END_OF_FILE) &&
(multi_range_curr < multi_range_end));
*found_range_p= multi_range_curr;
DBUG_PRINT("exit",("handler::read_multi_range_next: result %d", result));
DBUG_RETURN(result);
}
/* /*
Read first row between two ranges. Read first row between two ranges.
Store ranges for future calls to read_range_next Store ranges for future calls to read_range_next
......
...@@ -76,6 +76,7 @@ ...@@ -76,6 +76,7 @@
#define HA_FILE_BASED (1 << 26) #define HA_FILE_BASED (1 << 26)
#define HA_NO_VARCHAR (1 << 27) #define HA_NO_VARCHAR (1 << 27)
#define HA_CAN_BIT_FIELD (1 << 28) /* supports bit fields */ #define HA_CAN_BIT_FIELD (1 << 28) /* supports bit fields */
#define HA_NEED_READ_RANGE_BUFFER (1 << 29) /* for read_multi_range */
/* bits in index_flags(index_number) for what you can do with index */ /* bits in index_flags(index_number) for what you can do with index */
...@@ -276,6 +277,21 @@ typedef struct st_ha_check_opt ...@@ -276,6 +277,21 @@ typedef struct st_ha_check_opt
} HA_CHECK_OPT; } HA_CHECK_OPT;
/*
This is a buffer area that the handler can use to store rows.
'end_of_used_area' should be kept updated after calls to
read-functions so that other parts of the code can use the
remaining area (until next read calls is issued).
*/
typedef struct st_handler_buffer
{
const byte *buffer; /* Buffer one can start using */
const byte *buffer_end; /* End of buffer */
byte *end_of_used_area; /* End of area that was used by handler */
} HANDLER_BUFFER;
class handler :public Sql_alloc class handler :public Sql_alloc
{ {
protected: protected:
...@@ -310,6 +326,12 @@ class handler :public Sql_alloc ...@@ -310,6 +326,12 @@ class handler :public Sql_alloc
time_t check_time; time_t check_time;
time_t update_time; time_t update_time;
/* The following are for read_multi_range */
bool multi_range_sorted;
KEY_MULTI_RANGE *multi_range_curr;
KEY_MULTI_RANGE *multi_range_end;
HANDLER_BUFFER *multi_range_buffer;
/* The following are for read_range() */ /* The following are for read_range() */
key_range save_end_range, *end_range; key_range save_end_range, *end_range;
KEY_PART_INFO *range_key_part; KEY_PART_INFO *range_key_part;
...@@ -421,6 +443,10 @@ class handler :public Sql_alloc ...@@ -421,6 +443,10 @@ class handler :public Sql_alloc
virtual int index_next_same(byte *buf, const byte *key, uint keylen); virtual int index_next_same(byte *buf, const byte *key, uint keylen);
virtual int index_read_last(byte * buf, const byte * key, uint key_len) virtual int index_read_last(byte * buf, const byte * key, uint key_len)
{ return (my_errno=HA_ERR_WRONG_COMMAND); } { return (my_errno=HA_ERR_WRONG_COMMAND); }
virtual int read_multi_range_first(KEY_MULTI_RANGE **found_range_p,
KEY_MULTI_RANGE *ranges, uint range_count,
bool sorted, HANDLER_BUFFER *buffer);
virtual int read_multi_range_next(KEY_MULTI_RANGE **found_range_p);
virtual int read_range_first(const key_range *start_key, virtual int read_range_first(const key_range *start_key,
const key_range *end_key, const key_range *end_key,
bool eq_range, bool sorted); bool eq_range, bool sorted);
......
...@@ -4141,7 +4141,7 @@ enum options_mysqld ...@@ -4141,7 +4141,7 @@ enum options_mysqld
OPT_MAX_SEEKS_FOR_KEY, OPT_MAX_TMP_TABLES, OPT_MAX_USER_CONNECTIONS, OPT_MAX_SEEKS_FOR_KEY, OPT_MAX_TMP_TABLES, OPT_MAX_USER_CONNECTIONS,
OPT_MAX_LENGTH_FOR_SORT_DATA, OPT_MAX_LENGTH_FOR_SORT_DATA,
OPT_MAX_WRITE_LOCK_COUNT, OPT_BULK_INSERT_BUFFER_SIZE, OPT_MAX_WRITE_LOCK_COUNT, OPT_BULK_INSERT_BUFFER_SIZE,
OPT_MAX_ERROR_COUNT, OPT_MYISAM_DATA_POINTER_SIZE, OPT_MAX_ERROR_COUNT, OPT_MULTI_RANGE_COUNT, OPT_MYISAM_DATA_POINTER_SIZE,
OPT_MYISAM_BLOCK_SIZE, OPT_MYISAM_MAX_EXTRA_SORT_FILE_SIZE, OPT_MYISAM_BLOCK_SIZE, OPT_MYISAM_MAX_EXTRA_SORT_FILE_SIZE,
OPT_MYISAM_MAX_SORT_FILE_SIZE, OPT_MYISAM_SORT_BUFFER_SIZE, OPT_MYISAM_MAX_SORT_FILE_SIZE, OPT_MYISAM_SORT_BUFFER_SIZE,
OPT_NET_BUFFER_LENGTH, OPT_NET_RETRY_COUNT, OPT_NET_BUFFER_LENGTH, OPT_NET_RETRY_COUNT,
...@@ -5137,6 +5137,11 @@ The minimum value for this variable is 4096.", ...@@ -5137,6 +5137,11 @@ The minimum value for this variable is 4096.",
"After this many write locks, allow some read locks to run in between.", "After this many write locks, allow some read locks to run in between.",
(gptr*) &max_write_lock_count, (gptr*) &max_write_lock_count, 0, GET_ULONG, (gptr*) &max_write_lock_count, (gptr*) &max_write_lock_count, 0, GET_ULONG,
REQUIRED_ARG, ~0L, 1, ~0L, 0, 1, 0}, REQUIRED_ARG, ~0L, 1, ~0L, 0, 1, 0},
{"multi_range_count", OPT_MULTI_RANGE_COUNT,
"Number of key ranges to request at once.",
(gptr*) &global_system_variables.multi_range_count,
(gptr*) &max_system_variables.multi_range_count, 0,
GET_ULONG, REQUIRED_ARG, 256, 1, ~0L, 0, 1, 0},
{"myisam_block_size", OPT_MYISAM_BLOCK_SIZE, {"myisam_block_size", OPT_MYISAM_BLOCK_SIZE,
"Block size to be used for MyISAM index pages.", "Block size to be used for MyISAM index pages.",
(gptr*) &opt_myisam_block_size, (gptr*) &opt_myisam_block_size,
......
...@@ -712,7 +712,7 @@ QUICK_SELECT_I::QUICK_SELECT_I() ...@@ -712,7 +712,7 @@ QUICK_SELECT_I::QUICK_SELECT_I()
QUICK_RANGE_SELECT::QUICK_RANGE_SELECT(THD *thd, TABLE *table, uint key_nr, QUICK_RANGE_SELECT::QUICK_RANGE_SELECT(THD *thd, TABLE *table, uint key_nr,
bool no_alloc, MEM_ROOT *parent_alloc) bool no_alloc, MEM_ROOT *parent_alloc)
:dont_free(0),error(0),free_file(0),cur_range(NULL),range(0) :dont_free(0),error(0),free_file(0),cur_range(NULL),range(0),in_range(0)
{ {
sorted= 0; sorted= 0;
index= key_nr; index= key_nr;
...@@ -720,6 +720,13 @@ QUICK_RANGE_SELECT::QUICK_RANGE_SELECT(THD *thd, TABLE *table, uint key_nr, ...@@ -720,6 +720,13 @@ QUICK_RANGE_SELECT::QUICK_RANGE_SELECT(THD *thd, TABLE *table, uint key_nr,
key_part_info= head->key_info[index].key_part; key_part_info= head->key_info[index].key_part;
my_init_dynamic_array(&ranges, sizeof(QUICK_RANGE*), 16, 16); my_init_dynamic_array(&ranges, sizeof(QUICK_RANGE*), 16, 16);
/* 'thd' is not accessible in QUICK_RANGE_SELECT::get_next_init(). */
multi_range_bufsiz= thd->variables.read_rnd_buff_size;
multi_range_count= thd->variables.multi_range_count;
multi_range_length= 0;
multi_range= NULL;
multi_range_buff= NULL;
if (!no_alloc && !parent_alloc) if (!no_alloc && !parent_alloc)
{ {
// Allocates everything through the internal memroot // Allocates everything through the internal memroot
...@@ -736,6 +743,10 @@ QUICK_RANGE_SELECT::QUICK_RANGE_SELECT(THD *thd, TABLE *table, uint key_nr, ...@@ -736,6 +743,10 @@ QUICK_RANGE_SELECT::QUICK_RANGE_SELECT(THD *thd, TABLE *table, uint key_nr,
int QUICK_RANGE_SELECT::init() int QUICK_RANGE_SELECT::init()
{ {
DBUG_ENTER("QUICK_RANGE_SELECT::init"); DBUG_ENTER("QUICK_RANGE_SELECT::init");
if ((error= get_next_init()))
DBUG_RETURN(error);
if (file->inited == handler::NONE) if (file->inited == handler::NONE)
DBUG_RETURN(error= file->ha_index_init(index)); DBUG_RETURN(error= file->ha_index_init(index));
error= 0; error= 0;
...@@ -771,6 +782,10 @@ QUICK_RANGE_SELECT::~QUICK_RANGE_SELECT() ...@@ -771,6 +782,10 @@ QUICK_RANGE_SELECT::~QUICK_RANGE_SELECT()
delete_dynamic(&ranges); /* ranges are allocated in alloc */ delete_dynamic(&ranges); /* ranges are allocated in alloc */
free_root(&alloc,MYF(0)); free_root(&alloc,MYF(0));
} }
if (multi_range)
my_free((char*) multi_range, MYF(0));
if (multi_range_buff)
my_free((char*) multi_range_buff, MYF(0));
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
...@@ -5872,58 +5887,178 @@ int QUICK_ROR_UNION_SELECT::get_next() ...@@ -5872,58 +5887,178 @@ int QUICK_ROR_UNION_SELECT::get_next()
DBUG_RETURN(error); DBUG_RETURN(error);
} }
/* get next possible record using quick-struct */
/*
Initialize data structures needed by get_next().
SYNOPSIS
QUICK_RANGE_SELECT::get_next_init()
DESCRIPTION
This is called from get_next() at its first call for an object.
It allocates memory buffers and sets size variables.
RETURN
0 OK.
!= 0 Error.
*/
int QUICK_RANGE_SELECT::get_next_init(void)
{
uint mrange_bufsiz;
byte *mrange_buff;
DBUG_ENTER("QUICK_RANGE_SELECT::get_next_init");
/* Do not allocate the buffers twice. */
if (multi_range_length)
{
DBUG_ASSERT(multi_range_length == min(multi_range_count, ranges.elements));
DBUG_RETURN(0);
}
/* If the ranges are not yet initialized, wait for the next call. */
if (! ranges.elements)
{
DBUG_RETURN(0);
}
/*
Allocate the ranges array.
*/
multi_range_length= min(multi_range_count, ranges.elements);
DBUG_ASSERT(multi_range_length > 0);
while (multi_range_length && ! (multi_range= (KEY_MULTI_RANGE*)
my_malloc(multi_range_length *
sizeof(KEY_MULTI_RANGE),
MYF(MY_WME))))
{
/* Try to shrink the buffers until it is 0. */
multi_range_length/= 2;
}
if (! multi_range)
{
multi_range_length= 0;
DBUG_RETURN(HA_ERR_OUT_OF_MEM);
}
/*
Allocate the handler buffer if necessary.
*/
if (file->table_flags() & HA_NEED_READ_RANGE_BUFFER)
{
mrange_bufsiz= min(multi_range_bufsiz,
QUICK_SELECT_I::records * head->reclength);
while (mrange_bufsiz &&
! my_multi_malloc(MYF(MY_WME),
&multi_range_buff, sizeof(*multi_range_buff),
&mrange_buff, mrange_bufsiz,
NullS))
{
/* Try to shrink the buffers until both are 0. */
mrange_bufsiz/= 2;
}
if (! multi_range_buff)
{
my_free((char*) multi_range, MYF(0));
multi_range= NULL;
multi_range_length= 0;
DBUG_RETURN(HA_ERR_OUT_OF_MEM);
}
/* Initialize the handler buffer. */
multi_range_buff->buffer= mrange_buff;
multi_range_buff->buffer_end= mrange_buff + mrange_bufsiz;
multi_range_buff->end_of_used_area= mrange_buff;
}
/* Initialize the current QUICK_RANGE pointer. */
cur_range= (QUICK_RANGE**) ranges.buffer;
DBUG_RETURN(0);
}
/*
Get next possible record using quick-struct.
SYNOPSIS
QUICK_RANGE_SELECT::get_next()
NOTES
Record is read into table->record[0]
RETURN
0 Found row
HA_ERR_END_OF_FILE No (more) rows in range
# Error code
*/
int QUICK_RANGE_SELECT::get_next() int QUICK_RANGE_SELECT::get_next()
{ {
int result;
KEY_MULTI_RANGE *mrange;
key_range *start_key;
key_range *end_key;
DBUG_ENTER("QUICK_RANGE_SELECT::get_next"); DBUG_ENTER("QUICK_RANGE_SELECT::get_next");
DBUG_ASSERT(multi_range_length && multi_range &&
(cur_range >= (QUICK_RANGE**) ranges.buffer) &&
(cur_range <= (QUICK_RANGE**) ranges.buffer + ranges.elements));
for (;;) for (;;)
{ {
int result; if (in_range)
key_range start_key, end_key;
if (range)
{ {
// Already read through key /* We did already start to read this key. */
result= file->read_range_next(); result= file->read_multi_range_next(&mrange);
if (result != HA_ERR_END_OF_FILE) if (result != HA_ERR_END_OF_FILE)
{
in_range= ! result;
DBUG_RETURN(result); DBUG_RETURN(result);
}
} }
if (!cur_range) uint count= min(multi_range_length, ranges.elements -
range= *(cur_range= (QUICK_RANGE**) ranges.buffer); (cur_range - (QUICK_RANGE**) ranges.buffer));
else if (count == 0)
range= {
(cur_range == ((QUICK_RANGE**) ranges.buffer + ranges.elements - 1)) ? /* Ranges have already been used up before. None is left for read. */
(QUICK_RANGE*) 0 : *(++cur_range); in_range= FALSE;
DBUG_RETURN(HA_ERR_END_OF_FILE);
if (!range) }
DBUG_RETURN(HA_ERR_END_OF_FILE); // All ranges used KEY_MULTI_RANGE *mrange_slot, *mrange_end;
for (mrange_slot= multi_range, mrange_end= mrange_slot+count;
start_key.key= (const byte*) range->min_key; mrange_slot < mrange_end;
start_key.length= range->min_length; mrange_slot++)
start_key.flag= ((range->flag & NEAR_MIN) ? HA_READ_AFTER_KEY : {
(range->flag & EQ_RANGE) ? start_key= &mrange_slot->start_key;
HA_READ_KEY_EXACT : HA_READ_KEY_OR_NEXT); end_key= &mrange_slot->end_key;
end_key.key= (const byte*) range->max_key; range= *(cur_range++);
end_key.length= range->max_length;
/* start_key->key= (const byte*) range->min_key;
We use READ_AFTER_KEY here because if we are reading on a key start_key->length= range->min_length;
prefix we want to find all keys with this prefix start_key->flag= ((range->flag & NEAR_MIN) ? HA_READ_AFTER_KEY :
*/ (range->flag & EQ_RANGE) ?
end_key.flag= (range->flag & NEAR_MAX ? HA_READ_BEFORE_KEY : HA_READ_KEY_EXACT : HA_READ_KEY_OR_NEXT);
HA_READ_AFTER_KEY); end_key->key= (const byte*) range->max_key;
end_key->length= range->max_length;
/*
We use HA_READ_AFTER_KEY here because if we are reading on a key
prefix. We want to find all keys with this prefix.
*/
end_key->flag= (range->flag & NEAR_MAX ? HA_READ_BEFORE_KEY :
HA_READ_AFTER_KEY);
result= file->read_range_first(range->min_length ? &start_key : 0, mrange_slot->range_flag= range->flag;
range->max_length ? &end_key : 0, }
test(range->flag & EQ_RANGE),
sorted);
if (range->flag == (UNIQUE_RANGE | EQ_RANGE))
range=0; // Stop searching
result= file->read_multi_range_first(&mrange, multi_range, count,
sorted, multi_range_buff);
if (result != HA_ERR_END_OF_FILE) if (result != HA_ERR_END_OF_FILE)
{
in_range= ! result;
DBUG_RETURN(result); DBUG_RETURN(result);
range=0; // No matching rows; go to next range }
in_range= FALSE; /* No matching rows; go to next set of ranges. */
} }
} }
...@@ -5974,15 +6109,14 @@ int QUICK_RANGE_SELECT::get_next_prefix(uint prefix_length, byte *cur_prefix) ...@@ -5974,15 +6109,14 @@ int QUICK_RANGE_SELECT::get_next_prefix(uint prefix_length, byte *cur_prefix)
DBUG_RETURN(result); DBUG_RETURN(result);
} }
if (!cur_range) uint count= ranges.elements - (cur_range - (QUICK_RANGE**) ranges.buffer);
range= *(cur_range= (QUICK_RANGE**) ranges.buffer); /* First range. */ if (count == 0)
else {
range= /* Ranges have already been used up before. None is left for read. */
(cur_range == ((QUICK_RANGE**) ranges.buffer + ranges.elements - 1)) ? range= 0;
(QUICK_RANGE*) 0 : *(++cur_range); /* Next range. */ DBUG_RETURN(HA_ERR_END_OF_FILE);
}
if (!range) range= *(cur_range++);
DBUG_RETURN(HA_ERR_END_OF_FILE); // All ranges used
start_key.key= (const byte*) range->min_key; start_key.key= (const byte*) range->min_key;
start_key.length= min(range->min_length, prefix_length); start_key.length= min(range->min_length, prefix_length);
...@@ -6030,15 +6164,14 @@ int QUICK_RANGE_SELECT_GEOM::get_next() ...@@ -6030,15 +6164,14 @@ int QUICK_RANGE_SELECT_GEOM::get_next()
DBUG_RETURN(result); DBUG_RETURN(result);
} }
if (!cur_range) uint count= ranges.elements - (cur_range - (QUICK_RANGE**) ranges.buffer);
range= *(cur_range= (QUICK_RANGE**) ranges.buffer); if (count == 0)
else {
range= /* Ranges have already been used up before. None is left for read. */
(cur_range == ((QUICK_RANGE**) ranges.buffer + ranges.elements - 1)) ? range= 0;
(QUICK_RANGE*) 0 : *(++cur_range); DBUG_RETURN(HA_ERR_END_OF_FILE);
}
if (!range) range= *(cur_range++);
DBUG_RETURN(HA_ERR_END_OF_FILE); // All ranges used
result= file->index_read(record, result= file->index_read(record,
(byte*) range->min_key, (byte*) range->min_key,
......
...@@ -24,16 +24,6 @@ ...@@ -24,16 +24,6 @@
#pragma interface /* gcc class implementation */ #pragma interface /* gcc class implementation */
#endif #endif
#define NO_MIN_RANGE 1
#define NO_MAX_RANGE 2
#define NEAR_MIN 4
#define NEAR_MAX 8
#define UNIQUE_RANGE 16
#define EQ_RANGE 32
#define NULL_RANGE 64
#define GEOM_FLAG 128
typedef struct st_key_part { typedef struct st_key_part {
uint16 key,part, store_length, length; uint16 key,part, store_length, length;
uint8 null_bit; uint8 null_bit;
...@@ -135,9 +125,24 @@ class QUICK_SELECT_I ...@@ -135,9 +125,24 @@ class QUICK_SELECT_I
*/ */
virtual int reset(void) = 0; virtual int reset(void) = 0;
/*
Initialize get_next() for row retrieval.
SYNOPSIS
get_next_init()
get_next_init() must be called before the first get_next().
If get_next_init() call fails get_next() must not be called.
RETURN
0 OK
other Error code
*/
virtual int get_next_init() { return false; }
virtual int get_next() = 0; /* get next record to retrieve */
/* Range end should be called when we have looped over the whole index */ /* Range end should be called when we have looped over the whole index */
virtual void range_end() {} virtual void range_end() {}
virtual int get_next() = 0; /* get next record to retrieve */
virtual bool reverse_sorted() = 0; virtual bool reverse_sorted() = 0;
virtual bool unique_key_range() { return false; } virtual bool unique_key_range() { return false; }
...@@ -236,6 +241,14 @@ class QUICK_RANGE_SELECT : public QUICK_SELECT_I ...@@ -236,6 +241,14 @@ class QUICK_RANGE_SELECT : public QUICK_SELECT_I
closed no later then this quick select is deleted. closed no later then this quick select is deleted.
*/ */
bool free_file; bool free_file;
bool in_range;
uint multi_range_count; /* copy from thd->variables.multi_range_count */
uint multi_range_length; /* the allocated length for the array */
uint multi_range_bufsiz; /* copy from thd->variables.read_rnd_buff_size */
KEY_MULTI_RANGE *multi_range; /* the multi-range array (allocated and
freed by QUICK_RANGE_SELECT) */
HANDLER_BUFFER *multi_range_buff; /* the handler buffer (allocated and
freed by QUICK_RANGE_SELECT) */
protected: protected:
friend class TRP_ROR_INTERSECT; friend class TRP_ROR_INTERSECT;
...@@ -270,18 +283,19 @@ class QUICK_RANGE_SELECT : public QUICK_SELECT_I ...@@ -270,18 +283,19 @@ class QUICK_RANGE_SELECT : public QUICK_SELECT_I
MEM_ROOT *parent_alloc=NULL); MEM_ROOT *parent_alloc=NULL);
~QUICK_RANGE_SELECT(); ~QUICK_RANGE_SELECT();
int init();
int reset(void) int reset(void)
{ {
next=0; next=0;
range= NULL; range= NULL;
cur_range= NULL; cur_range= (QUICK_RANGE**) ranges.buffer;
/* /*
Note: in opt_range.cc there are places where it is assumed that this Note: in opt_range.cc there are places where it is assumed that this
function always succeeds function always succeeds
*/ */
return 0; return 0;
} }
int init(); int get_next_init(void);
int get_next(); int get_next();
void range_end(); void range_end();
int get_next_prefix(uint prefix_length, byte *cur_prefix); int get_next_prefix(uint prefix_length, byte *cur_prefix);
...@@ -296,6 +310,13 @@ class QUICK_RANGE_SELECT : public QUICK_SELECT_I ...@@ -296,6 +310,13 @@ class QUICK_RANGE_SELECT : public QUICK_SELECT_I
#ifndef DBUG_OFF #ifndef DBUG_OFF
void dbug_dump(int indent, bool verbose); void dbug_dump(int indent, bool verbose);
#endif #endif
QUICK_RANGE_SELECT(const QUICK_RANGE_SELECT& org) : QUICK_SELECT_I()
{
bcopy(&org, this, sizeof(*this));
multi_range_length= 0;
multi_range= NULL;
multi_range_buff= NULL;
}
}; };
......
...@@ -100,11 +100,19 @@ void init_read_record(READ_RECORD *info,THD *thd, TABLE *table, ...@@ -100,11 +100,19 @@ void init_read_record(READ_RECORD *info,THD *thd, TABLE *table,
} }
else if (select && select->quick) else if (select && select->quick)
{ {
int error;
DBUG_PRINT("info",("using rr_quick")); DBUG_PRINT("info",("using rr_quick"));
if (!table->file->inited) if (!table->file->inited)
table->file->ha_index_init(select->quick->index); table->file->ha_index_init(select->quick->index);
info->read_record=rr_quick; info->read_record=rr_quick;
if ((error= select->quick->get_next_init()))
{
/* Cannot return error code here. Instead print to error log. */
table->file->print_error(error,MYF(ME_NOREFRESH));
thd->fatal_error();
}
} }
else if (table->sort.record_pointers) else if (table->sort.record_pointers)
{ {
......
...@@ -259,6 +259,8 @@ sys_var_thd_ulong sys_max_tmp_tables("max_tmp_tables", ...@@ -259,6 +259,8 @@ sys_var_thd_ulong sys_max_tmp_tables("max_tmp_tables",
&SV::max_tmp_tables); &SV::max_tmp_tables);
sys_var_long_ptr sys_max_write_lock_count("max_write_lock_count", sys_var_long_ptr sys_max_write_lock_count("max_write_lock_count",
&max_write_lock_count); &max_write_lock_count);
sys_var_thd_ulong sys_multi_range_count("multi_range_count",
&SV::multi_range_count);
sys_var_long_ptr sys_myisam_data_pointer_size("myisam_data_pointer_size", sys_var_long_ptr sys_myisam_data_pointer_size("myisam_data_pointer_size",
&myisam_data_pointer_size); &myisam_data_pointer_size);
sys_var_thd_ulonglong sys_myisam_max_extra_sort_file_size("myisam_max_extra_sort_file_size", &SV::myisam_max_extra_sort_file_size, fix_myisam_max_extra_sort_file_size, 1); sys_var_thd_ulonglong sys_myisam_max_extra_sort_file_size("myisam_max_extra_sort_file_size", &SV::myisam_max_extra_sort_file_size, fix_myisam_max_extra_sort_file_size, 1);
......
...@@ -388,6 +388,7 @@ struct system_variables ...@@ -388,6 +388,7 @@ struct system_variables
ulong max_sort_length; ulong max_sort_length;
ulong max_tmp_tables; ulong max_tmp_tables;
ulong max_insert_delayed_threads; ulong max_insert_delayed_threads;
ulong multi_range_count;
ulong myisam_repair_threads; ulong myisam_repair_threads;
ulong myisam_sort_buff_size; ulong myisam_sort_buff_size;
ulong net_buffer_length; ulong net_buffer_length;
......
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