56
/* Defines used by filesort and uniques */
60
class BufferCompareContext
63
qsort_cmp2 key_compare;
64
void *key_compare_arg;
66
BufferCompareContext() :
75
uint32_t rec_length; /* Length of sorted records */
76
uint32_t sort_length; /* Length of sorted columns */
77
uint32_t ref_length; /* Length of record ref. */
78
uint32_t addon_length; /* Length of added packed fields */
79
uint32_t res_length; /* Length of records in final sorted file/buffer */
80
uint32_t keys; /* Max keys / buffer */
81
ha_rows max_rows,examined_rows;
82
Table *sort_form; /* For quicker make_sortkey */
83
SortField *local_sortorder;
85
sort_addon_field *addon_field; /* Descriptors for companion fields */
86
unsigned char *unique_buff;
89
/* The fields below are used only by Unique class */
91
BufferCompareContext cmp_context;
119
int write_keys(unsigned char * *sort_keys,
121
internal::IO_CACHE *buffer_file,
122
internal::IO_CACHE *tempfile);
124
void make_sortkey(unsigned char *to,
125
unsigned char *ref_pos);
126
void register_used_fields();
127
bool save_index(unsigned char **sort_keys,
129
filesort_info *table_sort);
55
133
/* functions defined in this file */
57
135
static char **make_char_array(char **old_pos, register uint32_t fields,
62
140
unsigned char *buf);
64
static int write_keys(SORTPARAM *param,
65
unsigned char * *sort_keys,
67
internal::IO_CACHE *buffer_file,
68
internal::IO_CACHE *tempfile);
70
static void make_sortkey(SORTPARAM *param,
72
unsigned char *ref_pos);
73
static void register_used_fields(SORTPARAM *param);
74
static bool save_index(SORTPARAM *param,
75
unsigned char **sort_keys,
77
filesort_info *table_sort);
78
142
static uint32_t suffix_length(uint32_t string_length);
79
143
static void unpack_addon_fields(sort_addon_field *addon_field,
80
144
unsigned char *buff);
122
186
ha_rows FileSort::run(Table *table, SortField *sortorder, uint32_t s_length,
123
187
optimizer::SqlSelect *select, ha_rows max_rows,
124
bool sort_positions, ha_rows *examined_rows)
188
bool sort_positions, ha_rows &examined_rows)
127
191
uint32_t memavl= 0, min_sort_memory;
128
192
uint32_t maxbuffer;
129
193
size_t allocated_sort_memory= 0;
130
buffpek *buffpek_inst;
194
buffpek *buffpek_inst= 0;
131
195
ha_rows records= HA_POS_ERROR;
132
196
unsigned char **sort_keys= 0;
133
internal::IO_CACHE tempfile, buffpek_pointers, *selected_records_file, *outfile;
197
internal::IO_CACHE tempfile;
198
internal::IO_CACHE buffpek_pointers;
199
internal::IO_CACHE *selected_records_file;
200
internal::IO_CACHE *outfile;
135
202
bool multi_byte_charset;
137
filesort_info table_sort;
205
Don't use table->sort in filesort as it is also used by
206
QuickIndexMergeSelect. Work with a copy and put it back at the end
207
when index_merge select has finished with it.
209
filesort_info table_sort(table->sort);
210
table->sort.io_cache= NULL;
138
212
TableList *tab= table->pos_in_table_list;
139
213
Item_subselect *subselect= tab ? tab->containing_subselect() : 0;
147
221
plugin::TransactionalStorageEngine::releaseTemporaryLatches(&getSession());
150
Don't use table->sort in filesort as it is also used by
151
QuickIndexMergeSelect. Work with a copy and put it back at the end
152
when index_merge select has finished with it.
154
memcpy(&table_sort, &table->sort, sizeof(filesort_info));
155
table->sort.io_cache= NULL;
157
224
outfile= table_sort.io_cache;
158
my_b_clear(&tempfile);
159
my_b_clear(&buffpek_pointers);
162
memset(¶m, 0, sizeof(param));
225
assert(tempfile.buffer == 0);
226
assert(buffpek_pointers.buffer == 0);
163
228
param.sort_length= sortlength(sortorder, s_length, &multi_byte_charset);
164
229
param.ref_length= table->cursor->ref_length;
165
param.addon_field= 0;
166
param.addon_length= 0;
167
231
if (!(table->cursor->getEngine()->check_flag(HTON_BIT_FAST_KEY_READ)) && !sort_positions)
225
291
selected_records_file= 0;
228
if (multi_byte_charset &&
229
!(param.tmp_buffer= (char*) malloc(param.sort_length)))
294
if (multi_byte_charset && !(param.tmp_buffer= (char*) malloc(param.sort_length)))
232
299
memavl= getSession().variables.sortbuff_size;
233
300
min_sort_memory= max((uint32_t)MIN_SORT_MEMORY, param.sort_length*MERGEBUFF2);
264
if (open_cached_file(&buffpek_pointers,drizzle_tmpdir.c_str(),TEMP_PREFIX,
265
DISK_BUFFER_SIZE, MYF(MY_WME)))
331
if (open_cached_file(&buffpek_pointers,drizzle_tmpdir.c_str(),TEMP_PREFIX, DISK_BUFFER_SIZE, MYF(MY_WME)))
268
336
param.keys--; /* TODO: check why we do this */
269
337
param.sort_form= table;
278
346
if (maxbuffer == 0) // The whole set is in memory
280
if (save_index(¶m,sort_keys,(uint32_t) records, &table_sort))
348
if (param.save_index(sort_keys,(uint32_t) records, &table_sort))
289
359
table_sort.buffpek = 0;
291
361
if (!(table_sort.buffpek=
292
(unsigned char *) read_buffpek_from_file(&buffpek_pointers, maxbuffer,
293
table_sort.buffpek)))
362
(unsigned char *) read_buffpek_from_file(&buffpek_pointers, maxbuffer, table_sort.buffpek)))
295
366
buffpek_inst= (buffpek *) table_sort.buffpek;
296
367
table_sort.buffpek_len= maxbuffer;
297
368
close_cached_file(&buffpek_pointers);
298
369
/* Open cached file if it isn't open */
299
if (! my_b_inited(outfile) &&
300
open_cached_file(outfile,drizzle_tmpdir.c_str(),TEMP_PREFIX,READ_RECORD_BUFFER, MYF(MY_WME)))
370
if (! my_b_inited(outfile) && open_cached_file(outfile,drizzle_tmpdir.c_str(),TEMP_PREFIX,READ_RECORD_BUFFER, MYF(MY_WME)))
302
375
if (reinit_io_cache(outfile,internal::WRITE_CACHE,0L,0,0))
306
381
Use also the space previously used by string pointers in sort_buffer
310
385
param.rec_length-1);
311
386
maxbuffer--; // Offset from 0
312
387
if (merge_many_buff(¶m,(unsigned char*) sort_keys,buffpek_inst,&maxbuffer, &tempfile))
314
if (flush_io_cache(&tempfile) ||
315
reinit_io_cache(&tempfile,internal::READ_CACHE,0L,0,0))
392
if (flush_io_cache(&tempfile) || reinit_io_cache(&tempfile,internal::READ_CACHE,0L,0,0))
317
397
if (merge_index(¶m,(unsigned char*) sort_keys,buffpek_inst,maxbuffer,&tempfile, outfile))
320
403
if (records > param.max_rows)
321
records=param.max_rows;
405
records= param.max_rows;
325
if (param.tmp_buffer)
326
if (param.tmp_buffer)
327
free(param.tmp_buffer);
328
if (!subselect || !subselect->is_uncacheable())
410
if (not subselect || not subselect->is_uncacheable())
331
413
table_sort.sort_keys= 0;
333
415
table_sort.buffpek= 0;
334
416
table_sort.buffpek_len= 0;
336
419
close_cached_file(&tempfile);
337
420
close_cached_file(&buffpek_pointers);
338
421
if (my_b_inited(outfile))
340
423
if (flush_io_cache(outfile))
343
428
internal::my_off_t save_pos=outfile->pos_in_file;
344
429
/* For following reads */
345
430
if (reinit_io_cache(outfile,internal::READ_CACHE,0L,0,0))
347
434
outfile->end_of_file=save_pos;
357
444
getSession().status_var.filesort_rows+= (uint32_t) records;
359
*examined_rows= param.examined_rows;
446
examined_rows= param.examined_rows;
360
447
global_sort_buffer.sub(allocated_sort_memory);
361
memcpy(&table->sort, &table_sort, sizeof(filesort_info));
448
table->sort= table_sort;
362
449
DRIZZLE_FILESORT_DONE(error, records);
363
450
return (error ? HA_POS_ERROR : records);
367
void Table::filesort_free_buffers(bool full)
369
if (sort.record_pointers)
371
free((unsigned char*) sort.record_pointers);
372
sort.record_pointers=0;
378
if ((unsigned char*) sort.sort_keys)
379
free((unsigned char*) sort.sort_keys);
384
if ((unsigned char*) sort.buffpek)
385
free((unsigned char*) sort.buffpek);
393
free((char *) sort.addon_buf);
394
free((char *) sort.addon_field);
400
453
/** Make a array of string pointers. */
402
455
static char **make_char_array(char **old_pos, register uint32_t fields,
477
530
HA_POS_ERROR on error.
480
ha_rows FileSort::find_all_keys(SORTPARAM *param,
533
ha_rows FileSort::find_all_keys(SortParam *param,
481
534
optimizer::SqlSelect *select,
482
535
unsigned char **sort_keys,
483
536
internal::IO_CACHE *buffpek_pointers,
529
582
sort_form->tmp_set.reset();
530
583
/* Temporary set for register_used_fields and register_field_in_read_map */
531
584
sort_form->read_set= &sort_form->tmp_set;
532
register_used_fields(param);
585
param->register_used_fields();
533
586
if (select && select->cond)
534
587
select->cond->walk(&Item::register_field_in_read_map, 1,
535
588
(unsigned char*) sort_form);
589
642
if (idx == param->keys)
591
if (write_keys(param,sort_keys,idx,buffpek_pointers,tempfile))
644
if (param->write_keys(sort_keys, idx, buffpek_pointers, tempfile))
592
645
return(HA_POS_ERROR);
596
make_sortkey(param,sort_keys[idx++],ref_pos);
649
param->make_sortkey(sort_keys[idx++], ref_pos);
599
653
file->unlock_row();
600
656
/* It does not make sense to read more keys in case of a fatal error */
601
657
if (getSession().is_error())
628
684
return(HA_POS_ERROR);
630
686
if (indexpos && idx &&
631
write_keys(param,sort_keys,idx,buffpek_pointers,tempfile))
687
param->write_keys(sort_keys,idx,buffpek_pointers,tempfile))
632
688
return(HA_POS_ERROR);
633
689
return(my_b_inited(tempfile) ?
634
690
(ha_rows) (my_b_tell(tempfile)/param->rec_length) :
662
write_keys(SORTPARAM *param, register unsigned char **sort_keys, uint32_t count,
663
internal::IO_CACHE *buffpek_pointers, internal::IO_CACHE *tempfile)
717
int SortParam::write_keys(register unsigned char **sort_keys, uint32_t count,
718
internal::IO_CACHE *buffpek_pointers, internal::IO_CACHE *tempfile)
665
size_t sort_length, rec_length;
669
sort_length= param->sort_length;
670
rec_length= param->rec_length;
671
722
internal::my_string_ptr_sort((unsigned char*) sort_keys, (uint32_t) count, sort_length);
672
723
if (!my_b_inited(tempfile) &&
673
open_cached_file(tempfile, drizzle_tmpdir.c_str(), TEMP_PREFIX, DISK_BUFFER_SIZE,
724
open_cached_file(tempfile, drizzle_tmpdir.c_str(), TEMP_PREFIX, DISK_BUFFER_SIZE, MYF(MY_WME)))
684
734
buffpek.file_pos= my_b_tell(tempfile);
685
if ((ha_rows) count > param->max_rows)
686
count=(uint32_t) param->max_rows;
735
if ((ha_rows) count > max_rows)
736
count=(uint32_t) max_rows;
687
738
buffpek.count=(ha_rows) count;
688
for (end=sort_keys+count ; sort_keys != end ; sort_keys++)
740
for (unsigned char **ptr= sort_keys + count ; sort_keys != ptr ; sort_keys++)
690
742
if (my_b_write(tempfile, (unsigned char*) *sort_keys, (uint32_t) rec_length))
728
780
/** Make a sort-key from record. */
730
static void make_sortkey(register SORTPARAM *param,
731
register unsigned char *to, unsigned char *ref_pos)
782
void SortParam::make_sortkey(register unsigned char *to, unsigned char *ref_pos)
734
785
SortField *sort_field;
737
for (sort_field=param->local_sortorder ;
738
sort_field != param->end ;
788
for (sort_field= local_sortorder ;
741
792
bool maybe_null=0;
811
862
if ((unsigned char*) from == to)
813
864
set_if_smaller(length,sort_field->length);
814
memcpy(param->tmp_buffer,from,length);
815
from=param->tmp_buffer;
865
memcpy(tmp_buffer,from,length);
817
868
tmp_length= my_strnxfrm(cs,to,sort_field->length,
818
869
(unsigned char*) from, length);
919
970
In this implementation we use fixed layout for field values -
920
971
the same for all records.
922
sort_addon_field *addonf= param->addon_field;
973
sort_addon_field *addonf= addon_field;
923
974
unsigned char *nulls= to;
924
975
assert(addonf != 0);
925
976
memset(nulls, 0, addonf->offset);
961
1011
Register fields used by sorting in the sorted table's read set
964
static void register_used_fields(SORTPARAM *param)
1014
void SortParam::register_used_fields()
966
1016
SortField *sort_field;
967
Table *table=param->sort_form;
1017
Table *table= sort_form;
969
for (sort_field= param->local_sortorder ;
970
sort_field != param->end ;
1019
for (sort_field= local_sortorder ;
1001
static bool save_index(SORTPARAM *param, unsigned char **sort_keys, uint32_t count,
1002
filesort_info *table_sort)
1051
bool SortParam::save_index(unsigned char **sort_keys, uint32_t count,
1052
filesort_info *table_sort)
1004
uint32_t offset,res_length;
1005
1055
unsigned char *to;
1007
internal::my_string_ptr_sort((unsigned char*) sort_keys, (uint32_t) count, param->sort_length);
1008
res_length= param->res_length;
1009
offset= param->rec_length-res_length;
1010
if ((ha_rows) count > param->max_rows)
1011
count=(uint32_t) param->max_rows;
1057
internal::my_string_ptr_sort((unsigned char*) sort_keys, (uint32_t) count, sort_length);
1058
offset= rec_length - res_length;
1059
if ((ha_rows) count > max_rows)
1060
count=(uint32_t) max_rows;
1012
1061
if (!(to= table_sort->record_pointers=
1013
1062
(unsigned char*) malloc(res_length*count)))
1015
for (unsigned char **end= sort_keys+count ; sort_keys != end ; sort_keys++)
1065
for (unsigned char **end_ptr= sort_keys+count ; sort_keys != end_ptr ; sort_keys++)
1017
1067
memcpy(to, *sort_keys+offset, res_length);
1018
1068
to+= res_length;
1024
1074
/** Merge buffers to make < MERGEBUFF2 buffers. */
1026
int FileSort::merge_many_buff(SORTPARAM *param, unsigned char *sort_buffer,
1076
int FileSort::merge_many_buff(SortParam *param, unsigned char *sort_buffer,
1027
1077
buffpek *buffpek_inst, uint32_t *maxbuffer, internal::IO_CACHE *t_file)
1029
1079
internal::IO_CACHE t_file2,*from_file,*to_file,*temp;
1154
int FileSort::merge_buffers(SORTPARAM *param, internal::IO_CACHE *from_file,
1204
int FileSort::merge_buffers(SortParam *param, internal::IO_CACHE *from_file,
1155
1205
internal::IO_CACHE *to_file, unsigned char *sort_buffer,
1156
1206
buffpek *lastbuff, buffpek *Fb, buffpek *Tb,
1365
1415
/* Do a merge to output-file (save only positions) */
1367
int FileSort::merge_index(SORTPARAM *param, unsigned char *sort_buffer,
1417
int FileSort::merge_index(SortParam *param, unsigned char *sort_buffer,
1368
1418
buffpek *buffpek_inst, uint32_t maxbuffer,
1369
1419
internal::IO_CACHE *tempfile, internal::IO_CACHE *outfile)