summaryrefslogtreecommitdiff
path: root/sql/filesort.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/filesort.cc')
-rw-r--r--sql/filesort.cc150
1 files changed, 86 insertions, 64 deletions
diff --git a/sql/filesort.cc b/sql/filesort.cc
index a80e4a0fa54..b6a5d844eac 100644
--- a/sql/filesort.cc
+++ b/sql/filesort.cc
@@ -30,19 +30,20 @@
/* How to write record_ref. */
#define WRITE_REF(file,from) \
-if (my_b_write((file),(byte*) (from),param->ref_length)) \
+if (my_b_write((file),(uchar*) (from),param->ref_length)) \
DBUG_RETURN(1);
/* functions defined in this file */
-static char **make_char_array(register uint fields, uint length, myf my_flag);
+static char **make_char_array(char **old_pos, register uint fields,
+ uint length, myf my_flag);
static BUFFPEK *read_buffpek_from_file(IO_CACHE *buffer_file, uint count);
static ha_rows find_all_keys(SORTPARAM *param,SQL_SELECT *select,
uchar * *sort_keys, IO_CACHE *buffer_file,
IO_CACHE *tempfile,IO_CACHE *indexfile);
static int write_keys(SORTPARAM *param,uchar * *sort_keys,
uint count, IO_CACHE *buffer_file, IO_CACHE *tempfile);
-static void make_sortkey(SORTPARAM *param,uchar *to, byte *ref_pos);
+static void make_sortkey(SORTPARAM *param,uchar *to, uchar *ref_pos);
static void register_used_fields(SORTPARAM *param);
static int merge_index(SORTPARAM *param,uchar *sort_buffer,
BUFFPEK *buffpek,
@@ -56,7 +57,7 @@ static uint sortlength(THD *thd, SORT_FIELD *sortorder, uint s_length,
static SORT_ADDON_FIELD *get_addon_fields(THD *thd, Field **ptabfield,
uint sortlength, uint *plength);
static void unpack_addon_fields(struct st_sort_addon_field *addon_field,
- byte *buff);
+ uchar *buff);
/*
Sort a table
@@ -153,7 +154,7 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length,
if (param.addon_field)
{
param.res_length= param.addon_length;
- if (!(table_sort.addon_buf= (byte *) my_malloc(param.addon_length,
+ if (!(table_sort.addon_buf= (uchar *) my_malloc(param.addon_length,
MYF(MY_WME))))
goto err;
}
@@ -171,11 +172,11 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length,
if (select && select->quick)
{
- statistic_increment(thd->status_var.filesort_range_count, &LOCK_status);
+ status_var_increment(thd->status_var.filesort_range_count);
}
else
{
- statistic_increment(thd->status_var.filesort_scan_count, &LOCK_status);
+ status_var_increment(thd->status_var.filesort_scan_count);
}
#ifdef CAN_TRUST_RANGE
if (select && select->quick && select->quick->records > 0L)
@@ -198,7 +199,7 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length,
}
if (multi_byte_charset &&
- !(param.tmp_buffer=my_malloc(param.sort_length,MYF(MY_WME))))
+ !(param.tmp_buffer= (char*) my_malloc(param.sort_length,MYF(MY_WME))))
goto err;
memavl= thd->variables.sortbuff_size;
@@ -208,9 +209,9 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length,
ulong old_memavl;
ulong keys= memavl/(param.rec_length+sizeof(char*));
param.keys=(uint) min(records+1, keys);
- if (table_sort.sort_keys ||
- (table_sort.sort_keys= (uchar **) make_char_array(param.keys, param.rec_length,
- MYF(0))))
+ if ((table_sort.sort_keys=
+ (uchar **) make_char_array((char **) table_sort.sort_keys,
+ param.keys, param.rec_length, MYF(0))))
break;
old_memavl=memavl;
if ((memavl=memavl/4*3) < min_sort_memory && old_memavl > min_sort_memory)
@@ -245,7 +246,7 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length,
{
if (!table_sort.buffpek && table_sort.buffpek_len < maxbuffer &&
!(table_sort.buffpek=
- (byte *) read_buffpek_from_file(&buffpek_pointers, maxbuffer)))
+ (uchar *) read_buffpek_from_file(&buffpek_pointers, maxbuffer)))
goto err;
buffpek= (BUFFPEK *) table_sort.buffpek;
table_sort.buffpek_len= maxbuffer;
@@ -255,7 +256,8 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length,
open_cached_file(outfile,mysql_tmpdir,TEMP_PREFIX,READ_RECORD_BUFFER,
MYF(MY_WME)))
goto err;
- reinit_io_cache(outfile,WRITE_CACHE,0L,0,0);
+ if (reinit_io_cache(outfile,WRITE_CACHE,0L,0,0))
+ goto err;
/*
Use also the space previously used by string pointers in sort_buffer
@@ -283,9 +285,9 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length,
x_free(param.tmp_buffer);
if (!subselect || !subselect->is_uncacheable())
{
- x_free((gptr) sort_keys);
+ x_free((uchar*) sort_keys);
table_sort.sort_keys= 0;
- x_free((gptr) buffpek);
+ x_free((uchar*) buffpek);
table_sort.buffpek= 0;
table_sort.buffpek_len= 0;
}
@@ -323,19 +325,19 @@ void filesort_free_buffers(TABLE *table, bool full)
{
if (table->sort.record_pointers)
{
- my_free((gptr) table->sort.record_pointers,MYF(0));
+ my_free((uchar*) table->sort.record_pointers,MYF(0));
table->sort.record_pointers=0;
}
if (full)
{
if (table->sort.sort_keys )
{
- x_free((gptr) table->sort.sort_keys);
+ x_free((uchar*) table->sort.sort_keys);
table->sort.sort_keys= 0;
}
if (table->sort.buffpek)
{
- x_free((gptr) table->sort.buffpek);
+ x_free((uchar*) table->sort.buffpek);
table->sort.buffpek= 0;
table->sort.buffpek_len= 0;
}
@@ -351,14 +353,16 @@ void filesort_free_buffers(TABLE *table, bool full)
/* Make a array of string pointers */
-static char **make_char_array(register uint fields, uint length, myf my_flag)
+static char **make_char_array(char **old_pos, register uint fields,
+ uint length, myf my_flag)
{
register char **pos;
- char **old_pos,*char_pos;
+ char *char_pos;
DBUG_ENTER("make_char_array");
- if ((old_pos= (char**) my_malloc((uint) fields*(length+sizeof(char*)),
- my_flag)))
+ if (old_pos ||
+ (old_pos= (char**) my_malloc((uint) fields*(length+sizeof(char*)),
+ my_flag)))
{
pos=old_pos; char_pos=((char*) (pos+fields)) -length;
while (fields--) *(pos++) = (char_pos+= length);
@@ -375,11 +379,13 @@ static BUFFPEK *read_buffpek_from_file(IO_CACHE *buffpek_pointers, uint count)
ulong length;
BUFFPEK *tmp;
DBUG_ENTER("read_buffpek_from_file");
+ if (count > UINT_MAX/sizeof(BUFFPEK))
+ return 0; /* sizeof(BUFFPEK)*count will overflow */
tmp=(BUFFPEK*) my_malloc(length=sizeof(BUFFPEK)*count, MYF(MY_WME));
if (tmp)
{
if (reinit_io_cache(buffpek_pointers,READ_CACHE,0L,0,0) ||
- my_b_read(buffpek_pointers, (byte*) tmp, length))
+ my_b_read(buffpek_pointers, (uchar*) tmp, length))
{
my_free((char*) tmp, MYF(0));
tmp=0;
@@ -431,7 +437,7 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select,
{
int error,flag,quick_select;
uint idx,indexpos,ref_length;
- byte *ref_pos,*next_pos,ref_buff[MAX_REFLENGTH];
+ uchar *ref_pos,*next_pos,ref_buff[MAX_REFLENGTH];
my_off_t record;
TABLE *sort_form;
THD *thd= current_thd;
@@ -458,7 +464,7 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select,
next_pos=ref_pos;
if (! indexfile && ! quick_select)
{
- next_pos=(byte*) 0; /* Find records in sequence */
+ next_pos=(uchar*) 0; /* Find records in sequence */
file->ha_rnd_init(1);
file->extra_opt(HA_EXTRA_CACHE,
current_thd->variables.read_buff_size);
@@ -483,7 +489,7 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select,
register_used_fields(param);
if (select && select->cond)
select->cond->walk(&Item::register_field_in_read_map, 1,
- (byte*) sort_form);
+ (uchar*) sort_form);
sort_form->column_bitmaps_set(&sort_form->tmp_set, &sort_form->tmp_set);
for (;;)
@@ -501,7 +507,7 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select,
{
if (indexfile)
{
- if (my_b_read(indexfile,(byte*) ref_pos,ref_length)) /* purecov: deadcode */
+ if (my_b_read(indexfile,(uchar*) ref_pos,ref_length)) /* purecov: deadcode */
{
error= my_errno ? my_errno : -1; /* Abort */
break;
@@ -609,7 +615,7 @@ static int
write_keys(SORTPARAM *param, register uchar **sort_keys, uint count,
IO_CACHE *buffpek_pointers, IO_CACHE *tempfile)
{
- uint sort_length, rec_length;
+ size_t sort_length, rec_length;
uchar **end;
BUFFPEK buffpek;
DBUG_ENTER("write_keys");
@@ -619,20 +625,23 @@ write_keys(SORTPARAM *param, register uchar **sort_keys, uint count,
#ifdef MC68000
quicksort(sort_keys,count,sort_length);
#else
- my_string_ptr_sort((gptr) sort_keys, (uint) count, sort_length);
+ my_string_ptr_sort((uchar*) sort_keys, (uint) count, sort_length);
#endif
if (!my_b_inited(tempfile) &&
open_cached_file(tempfile, mysql_tmpdir, TEMP_PREFIX, DISK_BUFFER_SIZE,
MYF(MY_WME)))
goto err; /* purecov: inspected */
+ /* check we won't have more buffpeks than we can possibly keep in memory */
+ if (my_b_tell(buffpek_pointers) + sizeof(BUFFPEK) > (ulonglong)UINT_MAX)
+ goto err;
buffpek.file_pos= my_b_tell(tempfile);
if ((ha_rows) count > param->max_rows)
count=(uint) param->max_rows; /* purecov: inspected */
buffpek.count=(ha_rows) count;
for (end=sort_keys+count ; sort_keys != end ; sort_keys++)
- if (my_b_write(tempfile, (byte*) *sort_keys, (uint) rec_length))
+ if (my_b_write(tempfile, (uchar*) *sort_keys, (uint) rec_length))
goto err;
- if (my_b_write(buffpek_pointers, (byte*) &buffpek, sizeof(buffpek)))
+ if (my_b_write(buffpek_pointers, (uchar*) &buffpek, sizeof(buffpek)))
goto err;
DBUG_RETURN(0);
@@ -667,7 +676,7 @@ static inline void store_length(uchar *to, uint length, uint pack_length)
/* makes a sort-key from record */
static void make_sortkey(register SORTPARAM *param,
- register uchar *to, byte *ref_pos)
+ register uchar *to, uchar *ref_pos)
{
reg3 Field *field;
reg1 SORT_FIELD *sort_field;
@@ -694,7 +703,7 @@ static void make_sortkey(register SORTPARAM *param,
else
*to++=1;
}
- field->sort_string((char*) to,sort_field->length);
+ field->sort_string(to, sort_field->length);
}
else
{ // Item
@@ -823,7 +832,7 @@ static void make_sortkey(register SORTPARAM *param,
}
*to++=1;
}
- my_decimal2binary(E_DEC_FATAL_ERROR, dec_val, (char*)to,
+ my_decimal2binary(E_DEC_FATAL_ERROR, dec_val, to,
item->max_length - (item->decimals ? 1:0),
item->decimals);
break;
@@ -841,7 +850,7 @@ static void make_sortkey(register SORTPARAM *param,
}
*to++=1;
}
- change_double_for_sort(value,(byte*) to);
+ change_double_for_sort(value,(uchar*) to);
break;
}
case ROW_RESULT:
@@ -891,13 +900,13 @@ static void make_sortkey(register SORTPARAM *param,
else
{
#ifdef HAVE_purify
- uchar *end= (uchar*) field->pack((char *) to, field->ptr);
+ uchar *end= field->pack(to, field->ptr);
uint length= (uint) ((to + addonf->length) - end);
DBUG_ASSERT((int) length >= 0);
if (length)
bzero(end, length);
#else
- (void) field->pack((char *) to, field->ptr);
+ (void) field->pack(to, field->ptr);
#endif
}
to+= addonf->length;
@@ -906,7 +915,7 @@ static void make_sortkey(register SORTPARAM *param,
else
{
/* Save filepos last */
- memcpy((byte*) to, ref_pos, (size_s) param->ref_length);
+ memcpy((uchar*) to, ref_pos, (size_t) param->ref_length);
}
return;
}
@@ -935,7 +944,7 @@ static void register_used_fields(SORTPARAM *param)
else
{ // Item
sort_field->item->walk(&Item::register_field_in_read_map, 1,
- (byte *) table);
+ (uchar *) table);
}
}
@@ -958,16 +967,16 @@ static bool save_index(SORTPARAM *param, uchar **sort_keys, uint count,
FILESORT_INFO *table_sort)
{
uint offset,res_length;
- byte *to;
+ uchar *to;
DBUG_ENTER("save_index");
- my_string_ptr_sort((gptr) sort_keys, (uint) count, param->sort_length);
+ my_string_ptr_sort((uchar*) sort_keys, (uint) count, param->sort_length);
res_length= param->res_length;
offset= param->rec_length-res_length;
if ((ha_rows) count > param->max_rows)
count=(uint) param->max_rows;
if (!(to= table_sort->record_pointers=
- (byte*) my_malloc(res_length*count, MYF(MY_WME))))
+ (uchar*) my_malloc(res_length*count, MYF(MY_WME))))
DBUG_RETURN(1); /* purecov: inspected */
for (uchar **end= sort_keys+count ; sort_keys != end ; sort_keys++)
{
@@ -983,7 +992,7 @@ static bool save_index(SORTPARAM *param, uchar **sort_keys, uint count,
int merge_many_buff(SORTPARAM *param, uchar *sort_buffer,
BUFFPEK *buffpek, uint *maxbuffer, IO_CACHE *t_file)
{
- register int i;
+ register uint i;
IO_CACHE t_file2,*from_file,*to_file,*temp;
BUFFPEK *lastbuff;
DBUG_ENTER("merge_many_buff");
@@ -998,14 +1007,16 @@ int merge_many_buff(SORTPARAM *param, uchar *sort_buffer,
from_file= t_file ; to_file= &t_file2;
while (*maxbuffer >= MERGEBUFF2)
{
- reinit_io_cache(from_file,READ_CACHE,0L,0,0);
- reinit_io_cache(to_file,WRITE_CACHE,0L,0,0);
+ if (reinit_io_cache(from_file,READ_CACHE,0L,0,0))
+ goto cleanup;
+ if (reinit_io_cache(to_file,WRITE_CACHE,0L,0,0))
+ goto cleanup;
lastbuff=buffpek;
- for (i=0 ; i <= (int) *maxbuffer-MERGEBUFF*3/2 ; i+=MERGEBUFF)
+ for (i=0 ; i <= *maxbuffer-MERGEBUFF*3/2 ; i+=MERGEBUFF)
{
if (merge_buffers(param,from_file,to_file,sort_buffer,lastbuff++,
buffpek+i,buffpek+i+MERGEBUFF-1,0))
- break; /* purecov: inspected */
+ goto cleanup;
}
if (merge_buffers(param,from_file,to_file,sort_buffer,lastbuff++,
buffpek+i,buffpek+ *maxbuffer,0))
@@ -1017,6 +1028,7 @@ int merge_many_buff(SORTPARAM *param, uchar *sort_buffer,
setup_io_cache(to_file);
*maxbuffer= (uint) (lastbuff-buffpek)-1;
}
+cleanup:
close_cached_file(to_file); // This holds old result
if (to_file == t_file)
{
@@ -1039,7 +1051,7 @@ uint read_to_buffer(IO_CACHE *fromfile, BUFFPEK *buffpek,
if ((count=(uint) min((ha_rows) buffpek->max_keys,buffpek->count)))
{
- if (my_pread(fromfile->file,(byte*) buffpek->base,
+ if (my_pread(fromfile->file,(uchar*) buffpek->base,
(length= rec_length*count),buffpek->file_pos,MYF_RW))
return((uint) -1); /* purecov: inspected */
buffpek->key=buffpek->base;
@@ -1108,7 +1120,8 @@ int merge_buffers(SORTPARAM *param, IO_CACHE *from_file,
int flag)
{
int error;
- uint rec_length,sort_length,res_length,offset;
+ uint rec_length,res_length,offset;
+ size_t sort_length;
ulong maxcount;
ha_rows max_rows,org_max_rows;
my_off_t to_start_filepos;
@@ -1116,12 +1129,12 @@ int merge_buffers(SORTPARAM *param, IO_CACHE *from_file,
BUFFPEK *buffpek;
QUEUE queue;
qsort2_cmp cmp;
+ void *first_cmp_arg;
volatile THD::killed_state *killed= &current_thd->killed;
THD::killed_state not_killable;
DBUG_ENTER("merge_buffers");
- statistic_increment(current_thd->status_var.filesort_merge_passes,
- &LOCK_status);
+ status_var_increment(current_thd->status_var.filesort_merge_passes);
if (param->not_killable)
{
killed= &not_killable;
@@ -1141,9 +1154,18 @@ int merge_buffers(SORTPARAM *param, IO_CACHE *from_file,
/* The following will fire if there is not enough space in sort_buffer */
DBUG_ASSERT(maxcount!=0);
+ if (param->unique_buff)
+ {
+ cmp= param->compare;
+ first_cmp_arg= (void *) &param->cmp_context;
+ }
+ else
+ {
+ cmp= get_ptr_compare(sort_length);
+ first_cmp_arg= (void*) &sort_length;
+ }
if (init_queue(&queue, (uint) (Tb-Fb)+1, offsetof(BUFFPEK,key), 0,
- (queue_compare) (cmp= get_ptr_compare(sort_length)),
- (void*) &sort_length))
+ (queue_compare) cmp, first_cmp_arg))
DBUG_RETURN(1); /* purecov: inspected */
for (buffpek= Fb ; buffpek <= Tb ; buffpek++)
{
@@ -1154,7 +1176,7 @@ int merge_buffers(SORTPARAM *param, IO_CACHE *from_file,
if (error == -1)
goto err; /* purecov: inspected */
buffpek->max_keys= buffpek->mem_count; // If less data in buffers than expected
- queue_insert(&queue, (byte*) buffpek);
+ queue_insert(&queue, (uchar*) buffpek);
}
if (param->unique_buff)
@@ -1169,7 +1191,7 @@ int merge_buffers(SORTPARAM *param, IO_CACHE *from_file,
*/
buffpek= (BUFFPEK*) queue_top(&queue);
memcpy(param->unique_buff, buffpek->key, rec_length);
- if (my_b_write(to_file, (byte*) buffpek->key, rec_length))
+ if (my_b_write(to_file, (uchar*) buffpek->key, rec_length))
{
error=1; goto err; /* purecov: inspected */
}
@@ -1196,21 +1218,21 @@ int merge_buffers(SORTPARAM *param, IO_CACHE *from_file,
buffpek= (BUFFPEK*) queue_top(&queue);
if (cmp) // Remove duplicates
{
- if (!(*cmp)(&sort_length, &(param->unique_buff),
+ if (!(*cmp)(first_cmp_arg, &(param->unique_buff),
(uchar**) &buffpek->key))
goto skip_duplicate;
memcpy(param->unique_buff, (uchar*) buffpek->key, rec_length);
}
if (flag == 0)
{
- if (my_b_write(to_file,(byte*) buffpek->key, rec_length))
+ if (my_b_write(to_file,(uchar*) buffpek->key, rec_length))
{
error=1; goto err; /* purecov: inspected */
}
}
else
{
- if (my_b_write(to_file, (byte*) buffpek->key+offset, res_length))
+ if (my_b_write(to_file, (uchar*) buffpek->key+offset, res_length))
{
error=1; goto err; /* purecov: inspected */
}
@@ -1248,7 +1270,7 @@ int merge_buffers(SORTPARAM *param, IO_CACHE *from_file,
*/
if (cmp)
{
- if (!(*cmp)(&sort_length, &(param->unique_buff), (uchar**) &buffpek->key))
+ if (!(*cmp)(first_cmp_arg, &(param->unique_buff), (uchar**) &buffpek->key))
{
buffpek->key+= rec_length; // Remove duplicate
--buffpek->mem_count;
@@ -1265,7 +1287,7 @@ int merge_buffers(SORTPARAM *param, IO_CACHE *from_file,
max_rows-= buffpek->mem_count;
if (flag == 0)
{
- if (my_b_write(to_file,(byte*) buffpek->key,
+ if (my_b_write(to_file,(uchar*) buffpek->key,
(rec_length*buffpek->mem_count)))
{
error= 1; goto err; /* purecov: inspected */
@@ -1279,7 +1301,7 @@ int merge_buffers(SORTPARAM *param, IO_CACHE *from_file,
strpos != end ;
strpos+= rec_length)
{
- if (my_b_write(to_file, (byte *) strpos, res_length))
+ if (my_b_write(to_file, (uchar *) strpos, res_length))
{
error=1; goto err;
}
@@ -1548,7 +1570,7 @@ get_addon_fields(THD *thd, Field **ptabfield, uint sortlength, uint *plength)
*/
static void
-unpack_addon_fields(struct st_sort_addon_field *addon_field, byte *buff)
+unpack_addon_fields(struct st_sort_addon_field *addon_field, uchar *buff)
{
Field *field;
SORT_ADDON_FIELD *addonf= addon_field;
@@ -1561,7 +1583,7 @@ unpack_addon_fields(struct st_sort_addon_field *addon_field, byte *buff)
continue;
}
field->set_notnull();
- field->unpack(field->ptr, (char *) buff+addonf->offset);
+ field->unpack(field->ptr, buff + addonf->offset);
}
}
@@ -1572,7 +1594,7 @@ unpack_addon_fields(struct st_sort_addon_field *addon_field, byte *buff)
#define DBL_EXP_DIG (sizeof(double)*8-DBL_MANT_DIG)
-void change_double_for_sort(double nr,byte *to)
+void change_double_for_sort(double nr,uchar *to)
{
uchar *tmp=(uchar*) to;
if (nr == 0.0)