mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +03:00
WL#2126 - Multi_read_range.
Added the required structures and functions for handing over multiple key ranges to the table handler.
This commit is contained in:
@ -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
|
|||||||
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
|
||||||
|
125
sql/handler.cc
125
sql/handler.cc
@ -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 @@
|
|||||||
#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
|
|||||||
} 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 @@ public:
|
|||||||
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 @@ public:
|
|||||||
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
|
|||||||
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.",
|
|||||||
"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,
|
||||||
|
241
sql/opt_range.cc
241
sql/opt_range.cc
@ -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,
|
|||||||
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,
|
|||||||
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()
|
|||||||
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()
|
|||||||
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);
|
||||||
|
}
|
||||||
|
KEY_MULTI_RANGE *mrange_slot, *mrange_end;
|
||||||
|
for (mrange_slot= multi_range, mrange_end= mrange_slot+count;
|
||||||
|
mrange_slot < mrange_end;
|
||||||
|
mrange_slot++)
|
||||||
|
{
|
||||||
|
start_key= &mrange_slot->start_key;
|
||||||
|
end_key= &mrange_slot->end_key;
|
||||||
|
range= *(cur_range++);
|
||||||
|
|
||||||
if (!range)
|
start_key->key= (const byte*) range->min_key;
|
||||||
DBUG_RETURN(HA_ERR_END_OF_FILE); // All ranges used
|
start_key->length= range->min_length;
|
||||||
|
start_key->flag= ((range->flag & NEAR_MIN) ? HA_READ_AFTER_KEY :
|
||||||
|
(range->flag & EQ_RANGE) ?
|
||||||
|
HA_READ_KEY_EXACT : HA_READ_KEY_OR_NEXT);
|
||||||
|
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);
|
||||||
|
|
||||||
start_key.key= (const byte*) range->min_key;
|
mrange_slot->range_flag= range->flag;
|
||||||
start_key.length= range->min_length;
|
}
|
||||||
start_key.flag= ((range->flag & NEAR_MIN) ? HA_READ_AFTER_KEY :
|
|
||||||
(range->flag & EQ_RANGE) ?
|
|
||||||
HA_READ_KEY_EXACT : HA_READ_KEY_OR_NEXT);
|
|
||||||
end_key.key= (const byte*) range->max_key;
|
|
||||||
end_key.length= range->max_length;
|
|
||||||
/*
|
|
||||||
We use 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,
|
|
||||||
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)
|
|||||||
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()
|
|||||||
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 @@
|
|||||||
#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 @@ public:
|
|||||||
*/
|
*/
|
||||||
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 @@ protected:
|
|||||||
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 @@ public:
|
|||||||
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 @@ public:
|
|||||||
#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,
|
|||||||
}
|
}
|
||||||
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",
|
|||||||
&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
|
|||||||
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;
|
||||||
|
Reference in New Issue
Block a user