33
#include <drizzled/drizzled.h>
24
#include <drizzled/server_includes.h>
34
25
#include <drizzled/sql_sort.h>
35
#include <drizzled/filesort.h>
36
26
#include <drizzled/error.h>
37
27
#include <drizzled/probes.h>
38
28
#include <drizzled/session.h>
39
29
#include <drizzled/table.h>
40
30
#include <drizzled/table_list.h>
41
#include <drizzled/optimizer/range.h>
42
#include <drizzled/records.h>
43
#include <drizzled/internal/iocache.h>
44
#include <drizzled/internal/my_sys.h>
45
#include <plugin/myisam/myisam.h>
46
#include <drizzled/plugin/transactional_storage_engine.h>
47
#include <drizzled/atomics.h>
48
#include <drizzled/global_buffer.h>
50
#include <drizzled/sort_field.h>
53
35
using namespace std;
58
/* Defines used by filesort and uniques */
62
class BufferCompareContext
65
qsort_cmp2 key_compare;
66
void *key_compare_arg;
68
BufferCompareContext() :
77
uint32_t rec_length; /* Length of sorted records */
78
uint32_t sort_length; /* Length of sorted columns */
79
uint32_t ref_length; /* Length of record ref. */
80
uint32_t addon_length; /* Length of added packed fields */
81
uint32_t res_length; /* Length of records in final sorted file/buffer */
82
uint32_t keys; /* Max keys / buffer */
83
ha_rows max_rows,examined_rows;
84
Table *sort_form; /* For quicker make_sortkey */
85
SortField *local_sortorder;
87
sort_addon_field *addon_field; /* Descriptors for companion fields */
88
unsigned char *unique_buff;
91
/* The fields below are used only by Unique class */
93
BufferCompareContext cmp_context;
121
int write_keys(unsigned char * *sort_keys,
123
internal::IO_CACHE *buffer_file,
124
internal::IO_CACHE *tempfile);
126
void make_sortkey(unsigned char *to,
127
unsigned char *ref_pos);
128
void register_used_fields();
129
bool save_index(unsigned char **sort_keys,
131
filesort_info *table_sort);
135
37
/* functions defined in this file */
137
static char **make_char_array(char **old_pos, uint32_t fields,
39
static char **make_char_array(char **old_pos, register uint32_t fields,
140
static unsigned char *read_buffpek_from_file(internal::IO_CACHE *buffer_file,
41
static unsigned char *read_buffpek_from_file(IO_CACHE *buffer_file, uint32_t count,
43
static ha_rows find_all_keys(SORTPARAM *param,SQL_SELECT *select,
44
unsigned char * *sort_keys, IO_CACHE *buffer_file,
45
IO_CACHE *tempfile,IO_CACHE *indexfile);
46
static int write_keys(SORTPARAM *param,unsigned char * *sort_keys,
47
uint32_t count, IO_CACHE *buffer_file, IO_CACHE *tempfile);
48
static void make_sortkey(SORTPARAM *param,unsigned char *to, unsigned char *ref_pos);
49
static void register_used_fields(SORTPARAM *param);
50
static int merge_index(SORTPARAM *param,unsigned char *sort_buffer,
52
uint32_t maxbuffer,IO_CACHE *tempfile,
54
static bool save_index(SORTPARAM *param,unsigned char **sort_keys, uint32_t count,
55
filesort_info_st *table_sort);
144
56
static uint32_t suffix_length(uint32_t string_length);
145
static void unpack_addon_fields(sort_addon_field *addon_field,
57
static uint32_t sortlength(Session *session, SORT_FIELD *sortorder, uint32_t s_length,
58
bool *multi_byte_charset);
59
static SORT_ADDON_FIELD *get_addon_fields(Session *session, Field **ptabfield,
60
uint32_t sortlength, uint32_t *plength);
61
static void unpack_addon_fields(struct st_sort_addon_field *addon_field,
146
62
unsigned char *buff);
148
FileSort::FileSort(Session &arg) :
155
65
Creates a set of pointers that can be used to read the rows
185
96
examined_rows will be set to number of examined rows
188
ha_rows FileSort::run(Table *table, SortField *sortorder, uint32_t s_length,
189
optimizer::SqlSelect *select, ha_rows max_rows,
190
bool sort_positions, ha_rows &examined_rows)
99
ha_rows filesort(Session *session, Table *table, SORT_FIELD *sortorder, uint32_t s_length,
100
SQL_SELECT *select, ha_rows max_rows,
101
bool sort_positions, ha_rows *examined_rows)
193
uint32_t memavl= 0, min_sort_memory;
104
uint32_t memavl, min_sort_memory;
194
105
uint32_t maxbuffer;
195
size_t allocated_sort_memory= 0;
196
buffpek *buffpek_inst= 0;
197
107
ha_rows records= HA_POS_ERROR;
198
108
unsigned char **sort_keys= 0;
199
internal::IO_CACHE tempfile;
200
internal::IO_CACHE buffpek_pointers;
201
internal::IO_CACHE *selected_records_file;
202
internal::IO_CACHE *outfile;
109
IO_CACHE tempfile, buffpek_pointers, *selected_records_file, *outfile;
204
111
bool multi_byte_charset;
207
Don't use table->sort in filesort as it is also used by
208
QuickIndexMergeSelect. Work with a copy and put it back at the end
209
when index_merge select has finished with it.
211
filesort_info table_sort(table->sort);
212
table->sort.io_cache= NULL;
113
filesort_info_st table_sort;
214
114
TableList *tab= table->pos_in_table_list;
215
115
Item_subselect *subselect= tab ? tab->containing_subselect() : 0;
217
DRIZZLE_FILESORT_START(table->getShare()->getSchemaName(), table->getShare()->getTableName());
117
DRIZZLE_FILESORT_START();
220
120
Release InnoDB's adaptive hash index latch (if holding) before
223
plugin::TransactionalStorageEngine::releaseTemporaryLatches(&getSession());
123
ha_release_temporary_latches(session);
126
Don't use table->sort in filesort as it is also used by
127
QUICK_INDEX_MERGE_SELECT. Work with a copy and put it back at the end
128
when index_merge select has finished with it.
130
memcpy(&table_sort, &table->sort, sizeof(filesort_info_st));
131
table->sort.io_cache= NULL;
226
133
outfile= table_sort.io_cache;
227
assert(tempfile.buffer == 0);
228
assert(buffpek_pointers.buffer == 0);
230
param.sort_length= sortlength(sortorder, s_length, &multi_byte_charset);
231
param.ref_length= table->cursor->ref_length;
233
if (!(table->cursor->getEngine()->check_flag(HTON_BIT_FAST_KEY_READ)) && !sort_positions)
134
my_b_clear(&tempfile);
135
my_b_clear(&buffpek_pointers);
138
memset(¶m, 0, sizeof(param));
139
param.sort_length= sortlength(session, sortorder, s_length, &multi_byte_charset);
140
param.ref_length= table->file->ref_length;
141
param.addon_field= 0;
142
param.addon_length= 0;
143
if (!(table->file->ha_table_flags() & HA_FAST_KEY_READ) && !sort_positions)
236
146
Get the descriptors of all fields whose values are appended
237
147
to sorted fields and get its total length in param.spack_length.
239
param.addon_field= get_addon_fields(table->getFields(),
149
param.addon_field= get_addon_fields(session, table->field,
240
150
param.sort_length,
241
151
¶m.addon_length);
293
201
selected_records_file= 0;
296
if (multi_byte_charset && !(param.tmp_buffer= (char*) malloc(param.sort_length)))
204
if (multi_byte_charset &&
205
!(param.tmp_buffer= (char*) malloc(param.sort_length)))
301
memavl= getSession().variables.sortbuff_size;
208
memavl= session->variables.sortbuff_size;
302
209
min_sort_memory= max((uint32_t)MIN_SORT_MEMORY, param.sort_length*MERGEBUFF2);
303
210
while (memavl >= min_sort_memory)
305
212
uint32_t old_memavl;
306
213
uint32_t keys= memavl/(param.rec_length+sizeof(char*));
307
214
param.keys= (uint32_t) min(records+1, (ha_rows)keys);
309
allocated_sort_memory= param.keys * param.rec_length;
310
if (not global_sort_buffer.add(allocated_sort_memory))
312
my_error(ER_OUT_OF_GLOBAL_SORTMEMORY, MYF(ME_ERROR+ME_WAITTANG));
316
215
if ((table_sort.sort_keys=
317
216
(unsigned char **) make_char_array((char **) table_sort.sort_keys,
318
217
param.keys, param.rec_length)))
321
global_sort_buffer.sub(allocated_sort_memory);
322
219
old_memavl= memavl;
323
220
if ((memavl= memavl/4*3) < min_sort_memory && old_memavl > min_sort_memory)
324
221
memavl= min_sort_memory;
329
226
my_error(ER_OUT_OF_SORTMEMORY,MYF(ME_ERROR+ME_WAITTANG));
333
if (buffpek_pointers.open_cached_file(drizzle_tmpdir.c_str(),TEMP_PREFIX, DISK_BUFFER_SIZE, MYF(MY_WME)))
229
if (open_cached_file(&buffpek_pointers,drizzle_tmpdir,TEMP_PREFIX,
230
DISK_BUFFER_SIZE, MYF(MY_WME)))
338
233
param.keys--; /* TODO: check why we do this */
339
234
param.sort_form= table;
340
235
param.end=(param.local_sortorder=sortorder)+s_length;
341
if ((records= find_all_keys(¶m,select,sort_keys, &buffpek_pointers,
342
&tempfile, selected_records_file)) == HA_POS_ERROR)
236
if ((records=find_all_keys(¶m,select,sort_keys, &buffpek_pointers,
237
&tempfile, selected_records_file)) ==
346
maxbuffer= (uint32_t) (my_b_tell(&buffpek_pointers)/sizeof(*buffpek_inst));
240
maxbuffer= (uint32_t) (my_b_tell(&buffpek_pointers)/sizeof(*buffpek));
348
242
if (maxbuffer == 0) // The whole set is in memory
350
if (param.save_index(sort_keys,(uint32_t) records, &table_sort))
244
if (save_index(¶m,sort_keys,(uint32_t) records, &table_sort))
359
251
if (table_sort.buffpek)
360
252
free(table_sort.buffpek);
361
table_sort.buffpek = 0;
253
table_sort.buffpek= 0;
363
255
if (!(table_sort.buffpek=
364
(unsigned char *) read_buffpek_from_file(&buffpek_pointers, maxbuffer, table_sort.buffpek)))
256
(unsigned char *) read_buffpek_from_file(&buffpek_pointers, maxbuffer,
257
table_sort.buffpek)))
368
buffpek_inst= (buffpek *) table_sort.buffpek;
259
buffpek= (BUFFPEK *) table_sort.buffpek;
369
260
table_sort.buffpek_len= maxbuffer;
370
buffpek_pointers.close_cached_file();
261
close_cached_file(&buffpek_pointers);
371
262
/* Open cached file if it isn't open */
372
if (! my_b_inited(outfile) && outfile->open_cached_file(drizzle_tmpdir.c_str(),TEMP_PREFIX,READ_RECORD_BUFFER, MYF(MY_WME)))
377
if (outfile->reinit_io_cache(internal::WRITE_CACHE,0L,0,0))
263
if (! my_b_inited(outfile) &&
264
open_cached_file(outfile,drizzle_tmpdir,TEMP_PREFIX,READ_RECORD_BUFFER,
267
if (reinit_io_cache(outfile,WRITE_CACHE,0L,0,0))
383
271
Use also the space previously used by string pointers in sort_buffer
384
272
for temporary key storage.
386
param.keys=((param.keys*(param.rec_length+sizeof(char*))) / param.rec_length-1);
274
param.keys=((param.keys*(param.rec_length+sizeof(char*))) /
388
276
maxbuffer--; // Offset from 0
389
if (merge_many_buff(¶m,(unsigned char*) sort_keys,buffpek_inst,&maxbuffer, &tempfile))
394
if (flush_io_cache(&tempfile) || tempfile.reinit_io_cache(internal::READ_CACHE,0L,0,0))
399
if (merge_index(¶m,(unsigned char*) sort_keys,buffpek_inst,maxbuffer,&tempfile, outfile))
277
if (merge_many_buff(¶m,(unsigned char*) sort_keys,buffpek,&maxbuffer,
280
if (flush_io_cache(&tempfile) ||
281
reinit_io_cache(&tempfile,READ_CACHE,0L,0,0))
283
if (merge_index(¶m,(unsigned char*) sort_keys,buffpek,maxbuffer,&tempfile,
405
287
if (records > param.max_rows)
407
records= param.max_rows;
288
records=param.max_rows;
412
if (not subselect || not subselect->is_uncacheable())
292
if (param.tmp_buffer)
293
if (param.tmp_buffer)
294
free(param.tmp_buffer);
295
if (!subselect || !subselect->is_uncacheable())
297
if ((unsigned char*) sort_keys)
298
free((unsigned char*) sort_keys);
415
299
table_sort.sort_keys= 0;
300
if ((unsigned char*) buffpek)
301
free((unsigned char*) buffpek);
417
302
table_sort.buffpek= 0;
418
303
table_sort.buffpek_len= 0;
421
tempfile.close_cached_file();
422
buffpek_pointers.close_cached_file();
305
close_cached_file(&tempfile);
306
close_cached_file(&buffpek_pointers);
424
307
if (my_b_inited(outfile))
426
309
if (flush_io_cache(outfile))
431
internal::my_off_t save_pos= outfile->pos_in_file;
312
my_off_t save_pos=outfile->pos_in_file;
432
313
/* For following reads */
433
if (outfile->reinit_io_cache(internal::READ_CACHE,0L,0,0))
314
if (reinit_io_cache(outfile,READ_CACHE,0L,0,0))
437
316
outfile->end_of_file=save_pos;
443
320
my_message(ER_FILSORT_ABORT, ER(ER_FILSORT_ABORT),
444
321
MYF(ME_ERROR+ME_WAITTANG));
448
getSession().status_var.filesort_rows+= (uint32_t) records;
450
examined_rows= param.examined_rows;
451
global_sort_buffer.sub(allocated_sort_memory);
452
table->sort= table_sort;
453
DRIZZLE_FILESORT_DONE(error, records);
454
return (error ? HA_POS_ERROR : records);
323
statistic_add(session->status_var.filesort_rows,
324
(uint32_t) records, &LOCK_status);
325
*examined_rows= param.examined_rows;
326
memcpy(&table->sort, &table_sort, sizeof(filesort_info_st));
327
DRIZZLE_FILESORT_END();
328
return(error ? HA_POS_ERROR : records);
332
void Table::filesort_free_buffers(bool full)
334
if (sort.record_pointers)
336
free((unsigned char*) sort.record_pointers);
337
sort.record_pointers=0;
343
if ((unsigned char*) sort.sort_keys)
344
free((unsigned char*) sort.sort_keys);
349
if ((unsigned char*) sort.buffpek)
350
free((unsigned char*) sort.buffpek);
357
free((char *) sort.addon_buf);
358
free((char *) sort.addon_field);
457
364
/** Make a array of string pointers. */
459
static char **make_char_array(char **old_pos, uint32_t fields,
366
static char **make_char_array(char **old_pos, register uint32_t fields,
476
383
/** Read 'count' number of buffer pointers into memory. */
478
static unsigned char *read_buffpek_from_file(internal::IO_CACHE *buffpek_pointers, uint32_t count,
385
static unsigned char *read_buffpek_from_file(IO_CACHE *buffpek_pointers, uint32_t count,
479
386
unsigned char *buf)
481
uint32_t length= sizeof(buffpek)*count;
388
uint32_t length= sizeof(BUFFPEK)*count;
482
389
unsigned char *tmp= buf;
483
if (count > UINT_MAX/sizeof(buffpek))
484
return 0; /* sizeof(buffpek)*count will overflow */
390
if (count > UINT_MAX/sizeof(BUFFPEK))
391
return 0; /* sizeof(BUFFPEK)*count will overflow */
486
393
tmp= (unsigned char *)malloc(length);
489
if (buffpek_pointers->reinit_io_cache(internal::READ_CACHE,0L,0,0) ||
396
if (reinit_io_cache(buffpek_pointers,READ_CACHE,0L,0,0) ||
490
397
my_b_read(buffpek_pointers, (unsigned char*) tmp, length))
492
399
free((char*) tmp);
534
441
HA_POS_ERROR on error.
537
ha_rows FileSort::find_all_keys(SortParam *param,
538
optimizer::SqlSelect *select,
539
unsigned char **sort_keys,
540
internal::IO_CACHE *buffpek_pointers,
541
internal::IO_CACHE *tempfile, internal::IO_CACHE *indexfile)
444
static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select,
445
unsigned char **sort_keys,
446
IO_CACHE *buffpek_pointers,
447
IO_CACHE *tempfile, IO_CACHE *indexfile)
543
449
int error,flag,quick_select;
544
450
uint32_t idx,indexpos,ref_length;
545
451
unsigned char *ref_pos,*next_pos,ref_buff[MAX_REFLENGTH];
546
internal::my_off_t record;
547
453
Table *sort_form;
548
volatile Session::killed_state_t *killed= getSession().getKilledPtr();
550
boost::dynamic_bitset<> *save_read_set= NULL;
551
boost::dynamic_bitset<> *save_write_set= NULL;
454
Session *session= current_session;
455
volatile Session::killed_state *killed= &session->killed;
457
MY_BITMAP *save_read_set, *save_write_set;
554
460
error=quick_select=0;
555
461
sort_form=param->sort_form;
556
file= sort_form->cursor;
462
file=sort_form->file;
557
463
ref_length=param->ref_length;
558
464
ref_pos= ref_buff;
559
465
quick_select=select && select->quick;
561
flag= ((!indexfile && ! file->isOrdered())
467
flag= ((!indexfile && file->ha_table_flags() & HA_REC_NOT_IN_SEQ)
562
468
|| quick_select);
563
469
if (indexfile || flag)
564
470
ref_pos= &file->ref[0];
566
472
if (! indexfile && ! quick_select)
568
474
next_pos=(unsigned char*) 0; /* Find records in sequence */
569
if (file->startTableScan(1))
570
return(HA_POS_ERROR);
571
file->extra_opt(HA_EXTRA_CACHE, getSession().variables.read_buff_size);
475
file->ha_rnd_init(1);
476
file->extra_opt(HA_EXTRA_CACHE,
477
current_session->variables.read_buff_size);
574
ReadRecord read_record_info;
480
READ_RECORD read_record_info;
575
481
if (quick_select)
577
483
if (select->quick->reset())
578
484
return(HA_POS_ERROR);
580
if (read_record_info.init_read_record(&getSession(), select->quick->head, select, 1, 1))
581
return(HA_POS_ERROR);
485
init_read_record(&read_record_info, current_session, select->quick->head,
584
489
/* Remember original bitmaps */
585
490
save_read_set= sort_form->read_set;
586
491
save_write_set= sort_form->write_set;
587
492
/* Set up temporary column read map for columns used by sort */
588
sort_form->tmp_set.reset();
493
bitmap_clear_all(&sort_form->tmp_set);
589
494
/* Temporary set for register_used_fields and register_field_in_read_map */
590
495
sort_form->read_set= &sort_form->tmp_set;
591
param->register_used_fields();
496
register_used_fields(param);
592
497
if (select && select->cond)
593
498
select->cond->walk(&Item::register_field_in_read_map, 1,
594
499
(unsigned char*) sort_form);
595
sort_form->column_bitmaps_set(sort_form->tmp_set, sort_form->tmp_set);
500
sort_form->column_bitmaps_set(&sort_form->tmp_set, &sort_form->tmp_set);
603
508
error= HA_ERR_END_OF_FILE;
606
file->position(sort_form->getInsertRecord());
511
file->position(sort_form->record[0]);
608
513
else /* Not quick-select */
612
if (my_b_read(indexfile,(unsigned char*) ref_pos,ref_length))
517
if (my_b_read(indexfile,(unsigned char*) ref_pos,ref_length)) /* purecov: deadcode */
614
error= errno ? errno : -1; /* Abort */
519
error= my_errno ? my_errno : -1; /* Abort */
617
error=file->rnd_pos(sort_form->getInsertRecord(),next_pos);
522
error=file->rnd_pos(sort_form->record[0],next_pos);
621
error=file->rnd_next(sort_form->getInsertRecord());
526
error=file->rnd_next(sort_form->record[0]);
625
internal::my_store_ptr(ref_pos,ref_length,record); // Position to row
626
record+= sort_form->getShare()->db_record_offset;
530
my_store_ptr(ref_pos,ref_length,record); // Position to row
531
record+= sort_form->s->db_record_offset;
629
file->position(sort_form->getInsertRecord());
534
file->position(sort_form->record[0]);
631
536
if (error && error != HA_ERR_RECORD_DELETED)
669
571
index_merge quick select uses table->sort when retrieving rows, so free
670
572
resoures it has allocated.
672
read_record_info.end_read_record();
574
end_read_record(&read_record_info);
676
578
(void) file->extra(HA_EXTRA_NO_CACHE); /* End cacheing of records */
678
file->endTableScan();
681
if (getSession().is_error())
583
if (session->is_error())
682
584
return(HA_POS_ERROR);
684
586
/* Signal we should use orignal column read and write maps */
685
sort_form->column_bitmaps_set(*save_read_set, *save_write_set);
587
sort_form->column_bitmaps_set(save_read_set, save_write_set);
687
589
if (error != HA_ERR_END_OF_FILE)
689
sort_form->print_error(error,MYF(ME_ERROR | ME_WAITTANG));
690
return(HA_POS_ERROR);
693
if (indexpos && idx && param->write_keys(sort_keys,idx,buffpek_pointers,tempfile))
695
return(HA_POS_ERROR);
591
file->print_error(error,MYF(ME_ERROR | ME_WAITTANG)); /* purecov: inspected */
592
return(HA_POS_ERROR); /* purecov: inspected */
594
if (indexpos && idx &&
595
write_keys(param,sort_keys,idx,buffpek_pointers,tempfile))
596
return(HA_POS_ERROR); /* purecov: inspected */
698
597
return(my_b_inited(tempfile) ?
699
598
(ha_rows) (my_b_tell(tempfile)/param->rec_length) :
726
int SortParam::write_keys(unsigned char **sort_keys, uint32_t count,
727
internal::IO_CACHE *buffpek_pointers, internal::IO_CACHE *tempfile)
626
write_keys(SORTPARAM *param, register unsigned char **sort_keys, uint32_t count,
627
IO_CACHE *buffpek_pointers, IO_CACHE *tempfile)
629
size_t sort_length, rec_length;
731
internal::my_string_ptr_sort((unsigned char*) sort_keys, (uint32_t) count, sort_length);
633
sort_length= param->sort_length;
634
rec_length= param->rec_length;
635
my_string_ptr_sort((unsigned char*) sort_keys, (uint32_t) count, sort_length);
732
636
if (!my_b_inited(tempfile) &&
733
tempfile->open_cached_file(drizzle_tmpdir.c_str(), TEMP_PREFIX, DISK_BUFFER_SIZE, MYF(MY_WME)))
637
open_cached_file(tempfile, drizzle_tmpdir, TEMP_PREFIX, DISK_BUFFER_SIZE,
639
goto err; /* purecov: inspected */
737
640
/* check we won't have more buffpeks than we can possibly keep in memory */
738
if (my_b_tell(buffpek_pointers) + sizeof(buffpek) > (uint64_t)UINT_MAX)
641
if (my_b_tell(buffpek_pointers) + sizeof(BUFFPEK) > (uint64_t)UINT_MAX)
743
643
buffpek.file_pos= my_b_tell(tempfile);
744
if ((ha_rows) count > max_rows)
745
count=(uint32_t) max_rows;
644
if ((ha_rows) count > param->max_rows)
645
count=(uint32_t) param->max_rows; /* purecov: inspected */
747
646
buffpek.count=(ha_rows) count;
749
for (unsigned char **ptr= sort_keys + count ; sort_keys != ptr ; sort_keys++)
647
for (end=sort_keys+count ; sort_keys != end ; sort_keys++)
751
648
if (my_b_write(tempfile, (unsigned char*) *sort_keys, (uint32_t) rec_length))
757
650
if (my_b_write(buffpek_pointers, (unsigned char*) &buffpek, sizeof(buffpek)))
763
656
} /* write_keys */
822
716
Item *item=sort_field->item;
823
717
maybe_null= item->maybe_null;
825
718
switch (sort_field->result_type) {
826
719
case STRING_RESULT:
828
const CHARSET_INFO * const cs=item->collation.collation;
829
char fill_char= ((cs->state & MY_CS_BINSORT) ? (char) 0 : ' ');
831
uint32_t sort_field_length;
721
const CHARSET_INFO * const cs=item->collation.collation;
722
char fill_char= ((cs->state & MY_CS_BINSORT) ? (char) 0 : ' ');
724
uint32_t sort_field_length;
728
/* All item->str() to use some extra byte for end null.. */
729
String tmp((char*) to,sort_field->length+4,cs);
730
String *res= item->str_result(&tmp);
835
/* All item->str() to use some extra byte for end null.. */
836
String tmp((char*) to,sort_field->length+4,cs);
837
String *res= item->str_result(&tmp);
841
memset(to-1, 0, sort_field->length+1);
845
This should only happen during extreme conditions if we run out
846
of memory or have an item marked not null when it can be null.
847
This code is here mainly to avoid a hard crash in this case.
850
memset(to, 0, sort_field->length); // Avoid crash
854
length= res->length();
855
sort_field_length= sort_field->length - sort_field->suffix_length;
856
diff=(int) (sort_field_length - length);
860
length= sort_field_length;
862
if (sort_field->suffix_length)
864
/* Store length last in result_string */
865
store_length(to + sort_field_length, length,
866
sort_field->suffix_length);
868
if (sort_field->need_strxnfrm)
870
char *from=(char*) res->ptr();
872
if ((unsigned char*) from == to)
874
set_if_smaller(length,sort_field->length);
875
memcpy(tmp_buffer,from,length);
878
tmp_length= my_strnxfrm(cs,to,sort_field->length,
879
(unsigned char*) from, length);
880
assert(tmp_length == sort_field->length);
734
memset(to-1, 0, sort_field->length+1);
884
my_strnxfrm(cs,(unsigned char*)to,length,(const unsigned char*)res->ptr(),length);
885
cs->cset->fill(cs, (char *)to+length,diff,fill_char);
737
/* purecov: begin deadcode */
739
This should only happen during extreme conditions if we run out
740
of memory or have an item marked not null when it can be null.
741
This code is here mainly to avoid a hard crash in this case.
744
memset(to, 0, sort_field->length); // Avoid crash
749
length= res->length();
750
sort_field_length= sort_field->length - sort_field->suffix_length;
751
diff=(int) (sort_field_length - length);
755
length= sort_field_length;
757
if (sort_field->suffix_length)
759
/* Store length last in result_string */
760
store_length(to + sort_field_length, length,
761
sort_field->suffix_length);
763
if (sort_field->need_strxnfrm)
765
char *from=(char*) res->ptr();
767
if ((unsigned char*) from == to)
769
set_if_smaller(length,sort_field->length);
770
memcpy(param->tmp_buffer,from,length);
771
from=param->tmp_buffer;
773
tmp_length= my_strnxfrm(cs,to,sort_field->length,
774
(unsigned char*) from, length);
775
assert(tmp_length == sort_field->length);
779
my_strnxfrm(cs,(unsigned char*)to,length,(const unsigned char*)res->ptr(),length);
780
cs->cset->fill(cs, (char *)to+length,diff,fill_char);
891
786
int64_t value= item->val_int_result();
789
*to++=1; /* purecov: inspected */
895
790
if (item->null_value)
906
to[7]= (unsigned char) value;
907
to[6]= (unsigned char) (value >> 8);
908
to[5]= (unsigned char) (value >> 16);
909
to[4]= (unsigned char) (value >> 24);
910
to[3]= (unsigned char) (value >> 32);
911
to[2]= (unsigned char) (value >> 40);
912
to[1]= (unsigned char) (value >> 48);
801
to[7]= (unsigned char) value;
802
to[6]= (unsigned char) (value >> 8);
803
to[5]= (unsigned char) (value >> 16);
804
to[4]= (unsigned char) (value >> 24);
805
to[3]= (unsigned char) (value >> 32);
806
to[2]= (unsigned char) (value >> 40);
807
to[1]= (unsigned char) (value >> 48);
913
808
if (item->unsigned_flag) /* Fix sign */
914
809
to[0]= (unsigned char) (value >> 56);
916
811
to[0]= (unsigned char) (value >> 56) ^ 128; /* Reverse signbit */
919
814
case DECIMAL_RESULT:
921
type::Decimal dec_buf, *dec_val= item->val_decimal_result(&dec_buf);
816
my_decimal dec_buf, *dec_val= item->val_decimal_result(&dec_buf);
924
819
if (item->null_value)
1017
909
/* Save filepos last */
1018
memcpy(to, ref_pos, (size_t) ref_length);
910
memcpy(to, ref_pos, (size_t) param->ref_length);
1024
fields used by sorting in the sorted table's read set
917
Register fields used by sorting in the sorted table's read set
1027
void SortParam::register_used_fields()
920
static void register_used_fields(SORTPARAM *param)
1029
SortField *sort_field;
1030
Table *table= sort_form;
922
register SORT_FIELD *sort_field;
923
Table *table=param->sort_form;
1032
for (sort_field= local_sortorder ;
925
for (sort_field= param->local_sortorder ;
926
sort_field != param->end ;
1037
930
if ((field= sort_field->field))
1039
if (field->getTable() == table)
1040
table->setReadSet(field->position());
932
if (field->table == table)
933
table->setReadSet(field->field_index);
1064
bool SortParam::save_index(unsigned char **sort_keys, uint32_t count, filesort_info *table_sort)
957
static bool save_index(SORTPARAM *param, unsigned char **sort_keys, uint32_t count,
958
filesort_info_st *table_sort)
960
uint32_t offset,res_length;
1067
961
unsigned char *to;
1069
internal::my_string_ptr_sort((unsigned char*) sort_keys, (uint32_t) count, sort_length);
1070
offset= rec_length - res_length;
1072
if ((ha_rows) count > max_rows)
1073
count=(uint32_t) max_rows;
1075
if (!(to= table_sort->record_pointers= (unsigned char*) malloc(res_length*count)))
1078
for (unsigned char **end_ptr= sort_keys+count ; sort_keys != end_ptr ; sort_keys++)
963
my_string_ptr_sort((unsigned char*) sort_keys, (uint32_t) count, param->sort_length);
964
res_length= param->res_length;
965
offset= param->rec_length-res_length;
966
if ((ha_rows) count > param->max_rows)
967
count=(uint32_t) param->max_rows;
968
if (!(to= table_sort->record_pointers=
969
(unsigned char*) malloc(res_length*count)))
970
return(1); /* purecov: inspected */
971
for (unsigned char **end= sort_keys+count ; sort_keys != end ; sort_keys++)
1080
973
memcpy(to, *sort_keys+offset, res_length);
1081
974
to+= res_length;
1088
980
/** Merge buffers to make < MERGEBUFF2 buffers. */
1090
int FileSort::merge_many_buff(SortParam *param, unsigned char *sort_buffer,
1091
buffpek *buffpek_inst, uint32_t *maxbuffer, internal::IO_CACHE *t_file)
982
int merge_many_buff(SORTPARAM *param, unsigned char *sort_buffer,
983
BUFFPEK *buffpek, uint32_t *maxbuffer, IO_CACHE *t_file)
1093
internal::IO_CACHE t_file2,*from_file,*to_file,*temp;
986
IO_CACHE t_file2,*from_file,*to_file,*temp;
1096
989
if (*maxbuffer < MERGEBUFF2)
990
return(0); /* purecov: inspected */
1098
991
if (flush_io_cache(t_file) ||
1099
t_file2.open_cached_file(drizzle_tmpdir.c_str(),TEMP_PREFIX,DISK_BUFFER_SIZE, MYF(MY_WME)))
992
open_cached_file(&t_file2,drizzle_tmpdir,TEMP_PREFIX,DISK_BUFFER_SIZE,
994
return(1); /* purecov: inspected */
1104
996
from_file= t_file ; to_file= &t_file2;
1105
997
while (*maxbuffer >= MERGEBUFF2)
1109
if (from_file->reinit_io_cache(internal::READ_CACHE,0L,0,0))
1114
if (to_file->reinit_io_cache(internal::WRITE_CACHE,0L,0,0))
1119
lastbuff=buffpek_inst;
999
if (reinit_io_cache(from_file,READ_CACHE,0L,0,0))
1001
if (reinit_io_cache(to_file,WRITE_CACHE,0L,0,0))
1120
1004
for (i=0 ; i <= *maxbuffer-MERGEBUFF*3/2 ; i+=MERGEBUFF)
1122
1006
if (merge_buffers(param,from_file,to_file,sort_buffer,lastbuff++,
1123
buffpek_inst+i,buffpek_inst+i+MERGEBUFF-1,0))
1007
buffpek+i,buffpek+i+MERGEBUFF-1,0))
1129
1010
if (merge_buffers(param,from_file,to_file,sort_buffer,lastbuff++,
1130
buffpek_inst+i,buffpek_inst+ *maxbuffer,0))
1011
buffpek+i,buffpek+ *maxbuffer,0))
1012
break; /* purecov: inspected */
1135
1013
if (flush_io_cache(to_file))
1014
break; /* purecov: inspected */
1140
1015
temp=from_file; from_file=to_file; to_file=temp;
1141
from_file->setup_io_cache();
1142
to_file->setup_io_cache();
1143
*maxbuffer= (uint32_t) (lastbuff-buffpek_inst)-1;
1016
setup_io_cache(from_file);
1017
setup_io_cache(to_file);
1018
*maxbuffer= (uint32_t) (lastbuff-buffpek)-1;
1147
to_file->close_cached_file(); // This holds old result
1021
close_cached_file(to_file); // This holds old result
1148
1022
if (to_file == t_file)
1150
1024
*t_file=t_file2; // Copy result file
1151
t_file->setup_io_cache();
1025
setup_io_cache(t_file);
1154
1028
return(*maxbuffer >= MERGEBUFF2); /* Return 1 if interrupted */
1162
1036
(uint32_t)-1 if something goes wrong
1165
uint32_t FileSort::read_to_buffer(internal::IO_CACHE *fromfile, buffpek *buffpek_inst, uint32_t rec_length)
1039
uint32_t read_to_buffer(IO_CACHE *fromfile, BUFFPEK *buffpek,
1040
uint32_t rec_length)
1042
register uint32_t count;
1168
1043
uint32_t length;
1170
if ((count= (uint32_t) min((ha_rows) buffpek_inst->max_keys,buffpek_inst->count)))
1045
if ((count= (uint32_t) min((ha_rows) buffpek->max_keys,buffpek->count)))
1172
if (pread(fromfile->file,(unsigned char*) buffpek_inst->base, (length= rec_length*count),buffpek_inst->file_pos) == 0)
1173
return((uint32_t) -1);
1047
if (pread(fromfile->file,(unsigned char*) buffpek->base, (length= rec_length*count),buffpek->file_pos) == 0)
1048
return((uint32_t) -1); /* purecov: inspected */
1175
buffpek_inst->key= buffpek_inst->base;
1176
buffpek_inst->file_pos+= length; /* New filepos */
1177
buffpek_inst->count-= count;
1178
buffpek_inst->mem_count= count;
1050
buffpek->key= buffpek->base;
1051
buffpek->file_pos+= length; /* New filepos */
1052
buffpek->count-= count;
1053
buffpek->mem_count= count;
1180
1055
return (count*rec_length);
1181
1056
} /* read_to_buffer */
1222
int FileSort::merge_buffers(SortParam *param, internal::IO_CACHE *from_file,
1223
internal::IO_CACHE *to_file, unsigned char *sort_buffer,
1224
buffpek *lastbuff, buffpek *Fb, buffpek *Tb,
1093
int merge_buffers(SORTPARAM *param, IO_CACHE *from_file,
1094
IO_CACHE *to_file, unsigned char *sort_buffer,
1095
BUFFPEK *lastbuff, BUFFPEK *Fb, BUFFPEK *Tb,
1228
1099
uint32_t rec_length,res_length,offset;
1229
1100
size_t sort_length;
1230
1101
uint32_t maxcount;
1231
1102
ha_rows max_rows,org_max_rows;
1232
internal::my_off_t to_start_filepos;
1103
my_off_t to_start_filepos;
1233
1104
unsigned char *strpos;
1234
buffpek *buffpek_inst;
1235
1106
qsort2_cmp cmp;
1236
1107
void *first_cmp_arg;
1237
volatile Session::killed_state_t *killed= getSession().getKilledPtr();
1238
Session::killed_state_t not_killable;
1108
volatile Session::killed_state *killed= ¤t_session->killed;
1109
Session::killed_state not_killable;
1240
getSession().status_var.filesort_merge_passes++;
1111
status_var_increment(current_session->status_var.filesort_merge_passes);
1241
1112
if (param->not_killable)
1243
1114
killed= ¬_killable;
1267
cmp= internal::get_ptr_compare(sort_length);
1138
cmp= get_ptr_compare(sort_length);
1268
1139
first_cmp_arg= (void*) &sort_length;
1270
priority_queue<buffpek *, vector<buffpek *>, compare_functor >
1141
priority_queue<BUFFPEK *, vector<BUFFPEK *>, compare_functor >
1271
1142
queue(compare_functor(cmp, first_cmp_arg));
1272
for (buffpek_inst= Fb ; buffpek_inst <= Tb ; buffpek_inst++)
1143
for (buffpek= Fb ; buffpek <= Tb ; buffpek++)
1274
buffpek_inst->base= strpos;
1275
buffpek_inst->max_keys= maxcount;
1276
strpos+= (uint32_t) (error= (int) read_to_buffer(from_file, buffpek_inst,
1145
buffpek->base= strpos;
1146
buffpek->max_keys= maxcount;
1147
strpos+= (uint32_t) (error= (int) read_to_buffer(from_file, buffpek,
1278
1149
if (error == -1)
1281
buffpek_inst->max_keys= buffpek_inst->mem_count; // If less data in buffers than expected
1282
queue.push(buffpek_inst);
1150
goto err; /* purecov: inspected */
1151
buffpek->max_keys= buffpek->mem_count; // If less data in buffers than expected
1152
queue.push(buffpek);
1285
1155
if (param->unique_buff)
1292
1162
This is safe as we know that there is always more than one element
1293
1163
in each block to merge (This is guaranteed by the Unique:: algorithm
1295
buffpek_inst= queue.top();
1296
memcpy(param->unique_buff, buffpek_inst->key, rec_length);
1297
if (my_b_write(to_file, (unsigned char*) buffpek_inst->key, rec_length))
1165
buffpek= queue.top();
1166
memcpy(param->unique_buff, buffpek->key, rec_length);
1167
if (my_b_write(to_file, (unsigned char*) buffpek->key, rec_length))
1169
error=1; goto err; /* purecov: inspected */
1301
buffpek_inst->key+= rec_length;
1302
buffpek_inst->mem_count--;
1171
buffpek->key+= rec_length;
1172
buffpek->mem_count--;
1303
1173
if (!--max_rows)
1175
error= 0; /* purecov: inspected */
1176
goto end; /* purecov: inspected */
1308
1178
/* Top element has been used */
1310
queue.push(buffpek_inst);
1180
queue.push(buffpek);
1314
1183
cmp= 0; // Not unique
1317
1185
while (queue.size() > 1)
1189
error= 1; goto err; /* purecov: inspected */
1325
buffpek_inst= queue.top();
1193
buffpek= queue.top();
1326
1194
if (cmp) // Remove duplicates
1328
1196
if (!(*cmp)(first_cmp_arg, &(param->unique_buff),
1329
(unsigned char**) &buffpek_inst->key))
1197
(unsigned char**) &buffpek->key))
1330
1198
goto skip_duplicate;
1331
memcpy(param->unique_buff, buffpek_inst->key, rec_length);
1199
memcpy(param->unique_buff, buffpek->key, rec_length);
1335
if (my_b_write(to_file,(unsigned char*) buffpek_inst->key, rec_length))
1203
if (my_b_write(to_file,(unsigned char*) buffpek->key, rec_length))
1205
error=1; goto err; /* purecov: inspected */
1342
if (my_b_write(to_file, (unsigned char*) buffpek_inst->key+offset, res_length))
1210
if (my_b_write(to_file, (unsigned char*) buffpek->key+offset, res_length))
1212
error=1; goto err; /* purecov: inspected */
1347
1215
if (!--max_rows)
1217
error= 0; /* purecov: inspected */
1218
goto end; /* purecov: inspected */
1353
1221
skip_duplicate:
1354
buffpek_inst->key+= rec_length;
1355
if (! --buffpek_inst->mem_count)
1222
buffpek->key+= rec_length;
1223
if (! --buffpek->mem_count)
1357
if (!(error= (int) read_to_buffer(from_file,buffpek_inst,
1225
if (!(error= (int) read_to_buffer(from_file,buffpek,
1361
1229
break; /* One buffer have been removed */
1363
1231
else if (error == -1)
1232
goto err; /* purecov: inspected */
1368
1234
/* Top element has been replaced */
1370
queue.push(buffpek_inst);
1236
queue.push(buffpek);
1373
buffpek_inst= queue.top();
1374
buffpek_inst->base= sort_buffer;
1375
buffpek_inst->max_keys= param->keys;
1239
buffpek= queue.top();
1240
buffpek->base= sort_buffer;
1241
buffpek->max_keys= param->keys;
1378
1244
As we know all entries in the buffer are unique, we only have to
1383
if (!(*cmp)(first_cmp_arg, &(param->unique_buff), (unsigned char**) &buffpek_inst->key))
1249
if (!(*cmp)(first_cmp_arg, &(param->unique_buff), (unsigned char**) &buffpek->key))
1385
buffpek_inst->key+= rec_length; // Remove duplicate
1386
--buffpek_inst->mem_count;
1251
buffpek->key+= rec_length; // Remove duplicate
1252
--buffpek->mem_count;
1392
if ((ha_rows) buffpek_inst->mem_count > max_rows)
1258
if ((ha_rows) buffpek->mem_count > max_rows)
1393
1259
{ /* Don't write too many records */
1394
buffpek_inst->mem_count= (uint32_t) max_rows;
1395
buffpek_inst->count= 0; /* Don't read more */
1260
buffpek->mem_count= (uint32_t) max_rows;
1261
buffpek->count= 0; /* Don't read more */
1397
max_rows-= buffpek_inst->mem_count;
1263
max_rows-= buffpek->mem_count;
1400
if (my_b_write(to_file,(unsigned char*) buffpek_inst->key,
1401
(rec_length*buffpek_inst->mem_count)))
1266
if (my_b_write(to_file,(unsigned char*) buffpek->key,
1267
(rec_length*buffpek->mem_count)))
1269
error= 1; goto err; /* purecov: inspected */
1409
strpos= buffpek_inst->key+offset;
1410
for (end= strpos+buffpek_inst->mem_count*rec_length ;
1274
register unsigned char *end;
1275
strpos= buffpek->key+offset;
1276
for (end= strpos+buffpek->mem_count*rec_length ;
1411
1277
strpos != end ;
1412
1278
strpos+= rec_length)
1414
1280
if (my_b_write(to_file, (unsigned char *) strpos, res_length))
1422
while ((error=(int) read_to_buffer(from_file,buffpek_inst, rec_length))
1287
while ((error=(int) read_to_buffer(from_file,buffpek, rec_length))
1423
1288
!= -1 && error != 0);
1426
1291
lastbuff->count= min(org_max_rows-max_rows, param->max_rows);
1427
1292
lastbuff->file_pos= to_start_filepos;
1430
1295
} /* merge_buffers */
1433
1298
/* Do a merge to output-file (save only positions) */
1435
int FileSort::merge_index(SortParam *param, unsigned char *sort_buffer,
1436
buffpek *buffpek_inst, uint32_t maxbuffer,
1437
internal::IO_CACHE *tempfile, internal::IO_CACHE *outfile)
1300
static int merge_index(SORTPARAM *param, unsigned char *sort_buffer,
1301
BUFFPEK *buffpek, uint32_t maxbuffer,
1302
IO_CACHE *tempfile, IO_CACHE *outfile)
1439
if (merge_buffers(param,tempfile,outfile,sort_buffer,buffpek_inst,buffpek_inst,
1440
buffpek_inst+maxbuffer,1))
1304
if (merge_buffers(param,tempfile,outfile,sort_buffer,buffpek,buffpek,
1305
buffpek+maxbuffer,1))
1306
return(1); /* purecov: inspected */
1444
1308
} /* merge_index */
1504
1371
sortorder->result_type= sortorder->item->result_type();
1505
1372
if (sortorder->item->result_as_int64_t())
1506
1373
sortorder->result_type= INT_RESULT;
1508
1374
switch (sortorder->result_type) {
1509
1375
case STRING_RESULT:
1510
sortorder->length=sortorder->item->max_length;
1376
sortorder->length=sortorder->item->max_length;
1511
1377
set_if_smaller(sortorder->length,
1512
getSession().variables.max_sort_length);
1513
if (use_strnxfrm((cs=sortorder->item->collation.collation)))
1378
session->variables.max_sort_length);
1379
if (use_strnxfrm((cs=sortorder->item->collation.collation)))
1515
1381
sortorder->length= cs->coll->strnxfrmlen(cs, sortorder->length);
1516
sortorder->need_strxnfrm= 1;
1517
*multi_byte_charset= 1;
1382
sortorder->need_strxnfrm= 1;
1383
*multi_byte_charset= 1;
1519
1385
else if (cs == &my_charset_bin)
1521
1387
/* Store length last to be able to sort blob/varbinary */
1522
1388
sortorder->suffix_length= suffix_length(sortorder->length);
1523
1389
sortorder->length+= sortorder->suffix_length;
1526
1392
case INT_RESULT:
1527
sortorder->length=8; // Size of intern int64_t
1393
sortorder->length=8; // Size of intern int64_t
1529
1395
case DECIMAL_RESULT:
1530
1396
sortorder->length=
1531
class_decimal_get_binary_size(sortorder->item->max_length -
1397
my_decimal_get_binary_size(sortorder->item->max_length -
1532
1398
(sortorder->item->decimals ? 1 : 0),
1533
1399
sortorder->item->decimals);
1535
1401
case REAL_RESULT:
1536
sortorder->length=sizeof(double);
1402
sortorder->length=sizeof(double);
1538
1404
case ROW_RESULT:
1539
// This case should never be choosen
1406
// This case should never be choosen
1543
1410
if (sortorder->item->maybe_null)
1544
length++; // Place for NULL marker
1411
length++; // Place for NULL marker
1546
set_if_smaller(sortorder->length, (size_t)getSession().variables.max_sort_length);
1413
set_if_smaller(sortorder->length,
1414
(size_t)session->variables.max_sort_length);
1547
1415
length+=sortorder->length;
1549
1417
sortorder->field= (Field*) 0; // end marker