33
#include "drizzled/drizzled.h"
34
#include "drizzled/sql_sort.h"
35
#include "drizzled/filesort.h"
36
#include "drizzled/error.h"
37
#include "drizzled/probes.h"
38
#include "drizzled/session.h"
39
#include "drizzled/table.h"
40
#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"
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);
133
/* functions defined in this file */
135
static char **make_char_array(char **old_pos, register uint32_t fields,
138
static unsigned char *read_buffpek_from_file(internal::IO_CACHE *buffer_file,
142
static uint32_t suffix_length(uint32_t string_length);
143
static void unpack_addon_fields(sort_addon_field *addon_field,
144
unsigned char *buff);
146
FileSort::FileSort(Session &arg) :
24
#include "mysql_priv.h"
26
#include <stddef.h> /* for macro offsetof */
32
#define SKIP_DBUG_IN_FILESORT
35
/// How to write record_ref.
36
#define WRITE_REF(file,from) \
37
if (my_b_write((file),(uchar*) (from),param->ref_length)) \
40
/* functions defined in this file */
42
static char **make_char_array(char **old_pos, register uint fields,
43
uint length, myf my_flag);
44
static uchar *read_buffpek_from_file(IO_CACHE *buffer_file, uint count,
46
static ha_rows find_all_keys(SORTPARAM *param,SQL_SELECT *select,
47
uchar * *sort_keys, IO_CACHE *buffer_file,
48
IO_CACHE *tempfile,IO_CACHE *indexfile);
49
static int write_keys(SORTPARAM *param,uchar * *sort_keys,
50
uint count, IO_CACHE *buffer_file, IO_CACHE *tempfile);
51
static void make_sortkey(SORTPARAM *param,uchar *to, uchar *ref_pos);
52
static void register_used_fields(SORTPARAM *param);
53
static int merge_index(SORTPARAM *param,uchar *sort_buffer,
55
uint maxbuffer,IO_CACHE *tempfile,
57
static bool save_index(SORTPARAM *param,uchar **sort_keys, uint count,
58
FILESORT_INFO *table_sort);
59
static uint suffix_length(ulong string_length);
60
static uint sortlength(THD *thd, SORT_FIELD *sortorder, uint s_length,
61
bool *multi_byte_charset);
62
static SORT_ADDON_FIELD *get_addon_fields(THD *thd, Field **ptabfield,
63
uint sortlength, uint *plength);
64
static void unpack_addon_fields(struct st_sort_addon_field *addon_field,
153
68
Creates a set of pointers that can be used to read the rows
183
99
examined_rows will be set to number of examined rows
186
ha_rows FileSort::run(Table *table, SortField *sortorder, uint32_t s_length,
187
optimizer::SqlSelect *select, ha_rows max_rows,
188
bool sort_positions, ha_rows &examined_rows)
102
ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length,
103
SQL_SELECT *select, ha_rows max_rows,
104
bool sort_positions, ha_rows *examined_rows)
191
uint32_t memavl= 0, min_sort_memory;
193
size_t allocated_sort_memory= 0;
194
buffpek *buffpek_inst= 0;
107
ulong memavl, min_sort_memory;
195
110
ha_rows records= HA_POS_ERROR;
196
unsigned char **sort_keys= 0;
197
internal::IO_CACHE tempfile;
198
internal::IO_CACHE buffpek_pointers;
199
internal::IO_CACHE *selected_records_file;
200
internal::IO_CACHE *outfile;
111
uchar **sort_keys= 0;
112
IO_CACHE tempfile, buffpek_pointers, *selected_records_file, *outfile;
202
114
bool multi_byte_charset;
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;
212
TableList *tab= table->pos_in_table_list;
115
DBUG_ENTER("filesort");
116
DBUG_EXECUTE("info",TEST_filesort(sortorder,s_length););
117
#ifdef SKIP_DBUG_IN_FILESORT
118
DBUG_PUSH(""); /* No DBUG here */
120
FILESORT_INFO table_sort;
121
TABLE_LIST *tab= table->pos_in_table_list;
213
122
Item_subselect *subselect= tab ? tab->containing_subselect() : 0;
215
DRIZZLE_FILESORT_START(table->getShare()->getSchemaName(), table->getShare()->getTableName());
124
MYSQL_FILESORT_START();
218
127
Release InnoDB's adaptive hash index latch (if holding) before
221
plugin::TransactionalStorageEngine::releaseTemporaryLatches(&getSession());
130
ha_release_temporary_latches(thd);
133
Don't use table->sort in filesort as it is also used by
134
QUICK_INDEX_MERGE_SELECT. Work with a copy and put it back at the end
135
when index_merge select has finished with it.
137
memcpy(&table_sort, &table->sort, sizeof(FILESORT_INFO));
138
table->sort.io_cache= NULL;
224
140
outfile= table_sort.io_cache;
225
assert(tempfile.buffer == 0);
226
assert(buffpek_pointers.buffer == 0);
228
param.sort_length= sortlength(sortorder, s_length, &multi_byte_charset);
229
param.ref_length= table->cursor->ref_length;
231
if (!(table->cursor->getEngine()->check_flag(HTON_BIT_FAST_KEY_READ)) && !sort_positions)
141
my_b_clear(&tempfile);
142
my_b_clear(&buffpek_pointers);
145
bzero((char*) ¶m,sizeof(param));
146
param.sort_length= sortlength(thd, sortorder, s_length, &multi_byte_charset);
147
param.ref_length= table->file->ref_length;
148
param.addon_field= 0;
149
param.addon_length= 0;
150
if (!(table->file->ha_table_flags() & HA_FAST_KEY_READ) &&
151
!table->fulltext_searched && !sort_positions)
234
Get the descriptors of all fields whose values are appended
154
Get the descriptors of all fields whose values are appended
235
155
to sorted fields and get its total length in param.spack_length.
237
param.addon_field= get_addon_fields(table->getFields(),
157
param.addon_field= get_addon_fields(thd, table->field,
238
158
param.sort_length,
239
159
¶m.addon_length);
266
185
if (select && select->quick)
268
getSession().status_var.filesort_range_count++;
187
status_var_increment(thd->status_var.filesort_range_count);
272
getSession().status_var.filesort_scan_count++;
191
status_var_increment(thd->status_var.filesort_scan_count);
274
193
#ifdef CAN_TRUST_RANGE
275
194
if (select && select->quick && select->quick->records > 0L)
277
records= min((ha_rows) (select->quick->records*2+EXTRA_RECORDS*2),
278
table->cursor->stats.records)+EXTRA_RECORDS;
196
records=min((ha_rows) (select->quick->records*2+EXTRA_RECORDS*2),
197
table->file->stats.records)+EXTRA_RECORDS;
279
198
selected_records_file=0;
284
records= table->cursor->estimate_rows_upper_bound();
203
records= table->file->estimate_rows_upper_bound();
286
If number of records is not known, use as much of sort buffer
205
If number of records is not known, use as much of sort buffer
289
208
if (records == HA_POS_ERROR)
290
209
records--; // we use 'records+1' below.
291
210
selected_records_file= 0;
294
if (multi_byte_charset && !(param.tmp_buffer= (char*) malloc(param.sort_length)))
213
if (multi_byte_charset &&
214
!(param.tmp_buffer= (char*) my_malloc(param.sort_length,MYF(MY_WME))))
299
memavl= getSession().variables.sortbuff_size;
300
min_sort_memory= max((uint32_t)MIN_SORT_MEMORY, param.sort_length*MERGEBUFF2);
217
memavl= thd->variables.sortbuff_size;
218
min_sort_memory= max(MIN_SORT_MEMORY, param.sort_length*MERGEBUFF2);
301
219
while (memavl >= min_sort_memory)
304
uint32_t keys= memavl/(param.rec_length+sizeof(char*));
305
param.keys= (uint32_t) min(records+1, (ha_rows)keys);
307
allocated_sort_memory= param.keys * param.rec_length;
308
if (not global_sort_buffer.add(allocated_sort_memory))
310
my_error(ER_OUT_OF_GLOBAL_SORTMEMORY, MYF(ME_ERROR+ME_WAITTANG));
222
ulong keys= memavl/(param.rec_length+sizeof(char*));
223
param.keys=(uint) min(records+1, keys);
314
224
if ((table_sort.sort_keys=
315
(unsigned char **) make_char_array((char **) table_sort.sort_keys,
316
param.keys, param.rec_length)))
225
(uchar **) make_char_array((char **) table_sort.sort_keys,
226
param.keys, param.rec_length, MYF(0))))
319
global_sort_buffer.sub(allocated_sort_memory);
321
if ((memavl= memavl/4*3) < min_sort_memory && old_memavl > min_sort_memory)
229
if ((memavl=memavl/4*3) < min_sort_memory && old_memavl > min_sort_memory)
322
230
memavl= min_sort_memory;
324
232
sort_keys= table_sort.sort_keys;
327
235
my_error(ER_OUT_OF_SORTMEMORY,MYF(ME_ERROR+ME_WAITTANG));
331
if (buffpek_pointers.open_cached_file(drizzle_tmpdir.c_str(),TEMP_PREFIX, DISK_BUFFER_SIZE, MYF(MY_WME)))
238
if (open_cached_file(&buffpek_pointers,mysql_tmpdir,TEMP_PREFIX,
239
DISK_BUFFER_SIZE, MYF(MY_WME)))
336
242
param.keys--; /* TODO: check why we do this */
337
243
param.sort_form= table;
338
244
param.end=(param.local_sortorder=sortorder)+s_length;
339
if ((records= find_all_keys(¶m,select,sort_keys, &buffpek_pointers,
340
&tempfile, selected_records_file)) == HA_POS_ERROR)
245
if ((records=find_all_keys(¶m,select,sort_keys, &buffpek_pointers,
246
&tempfile, selected_records_file)) ==
344
maxbuffer= (uint32_t) (my_b_tell(&buffpek_pointers)/sizeof(*buffpek_inst));
249
maxbuffer= (uint) (my_b_tell(&buffpek_pointers)/sizeof(*buffpek));
346
251
if (maxbuffer == 0) // The whole set is in memory
348
if (param.save_index(sort_keys,(uint32_t) records, &table_sort))
253
if (save_index(¶m,sort_keys,(uint) records, &table_sort))
355
258
if (table_sort.buffpek && table_sort.buffpek_len < maxbuffer)
357
if (table_sort.buffpek)
358
free(table_sort.buffpek);
359
table_sort.buffpek = 0;
260
x_free(table_sort.buffpek);
261
table_sort.buffpek= 0;
361
263
if (!(table_sort.buffpek=
362
(unsigned char *) read_buffpek_from_file(&buffpek_pointers, maxbuffer, table_sort.buffpek)))
264
(uchar *) read_buffpek_from_file(&buffpek_pointers, maxbuffer,
265
table_sort.buffpek)))
366
buffpek_inst= (buffpek *) table_sort.buffpek;
267
buffpek= (BUFFPEK *) table_sort.buffpek;
367
268
table_sort.buffpek_len= maxbuffer;
368
buffpek_pointers.close_cached_file();
269
close_cached_file(&buffpek_pointers);
369
270
/* Open cached file if it isn't open */
370
if (! my_b_inited(outfile) && outfile->open_cached_file(drizzle_tmpdir.c_str(),TEMP_PREFIX,READ_RECORD_BUFFER, MYF(MY_WME)))
375
if (outfile->reinit_io_cache(internal::WRITE_CACHE,0L,0,0))
271
if (! my_b_inited(outfile) &&
272
open_cached_file(outfile,mysql_tmpdir,TEMP_PREFIX,READ_RECORD_BUFFER,
275
if (reinit_io_cache(outfile,WRITE_CACHE,0L,0,0))
381
279
Use also the space previously used by string pointers in sort_buffer
382
280
for temporary key storage.
384
param.keys=((param.keys*(param.rec_length+sizeof(char*))) / param.rec_length-1);
282
param.keys=((param.keys*(param.rec_length+sizeof(char*))) /
386
284
maxbuffer--; // Offset from 0
387
if (merge_many_buff(¶m,(unsigned char*) sort_keys,buffpek_inst,&maxbuffer, &tempfile))
392
if (flush_io_cache(&tempfile) || tempfile.reinit_io_cache(internal::READ_CACHE,0L,0,0))
397
if (merge_index(¶m,(unsigned char*) sort_keys,buffpek_inst,maxbuffer,&tempfile, outfile))
285
if (merge_many_buff(¶m,(uchar*) sort_keys,buffpek,&maxbuffer,
288
if (flush_io_cache(&tempfile) ||
289
reinit_io_cache(&tempfile,READ_CACHE,0L,0,0))
291
if (merge_index(¶m,(uchar*) sort_keys,buffpek,maxbuffer,&tempfile,
403
295
if (records > param.max_rows)
405
records= param.max_rows;
296
records=param.max_rows;
410
if (not subselect || not subselect->is_uncacheable())
300
if (param.tmp_buffer)
301
x_free(param.tmp_buffer);
302
if (!subselect || !subselect->is_uncacheable())
304
x_free((uchar*) sort_keys);
413
305
table_sort.sort_keys= 0;
306
x_free((uchar*) buffpek);
415
307
table_sort.buffpek= 0;
416
308
table_sort.buffpek_len= 0;
419
tempfile.close_cached_file();
420
buffpek_pointers.close_cached_file();
310
close_cached_file(&tempfile);
311
close_cached_file(&buffpek_pointers);
422
312
if (my_b_inited(outfile))
424
314
if (flush_io_cache(outfile))
429
internal::my_off_t save_pos= outfile->pos_in_file;
317
my_off_t save_pos=outfile->pos_in_file;
430
318
/* For following reads */
431
if (outfile->reinit_io_cache(internal::READ_CACHE,0L,0,0))
319
if (reinit_io_cache(outfile,READ_CACHE,0L,0,0))
435
321
outfile->end_of_file=save_pos;
441
325
my_message(ER_FILSORT_ABORT, ER(ER_FILSORT_ABORT),
442
326
MYF(ME_ERROR+ME_WAITTANG));
446
getSession().status_var.filesort_rows+= (uint32_t) records;
448
examined_rows= param.examined_rows;
449
global_sort_buffer.sub(allocated_sort_memory);
450
table->sort= table_sort;
451
DRIZZLE_FILESORT_DONE(error, records);
452
return (error ? HA_POS_ERROR : records);
328
statistic_add(thd->status_var.filesort_rows,
329
(ulong) records, &LOCK_status);
330
*examined_rows= param.examined_rows;
331
#ifdef SKIP_DBUG_IN_FILESORT
332
DBUG_POP(); /* Ok to DBUG */
334
memcpy(&table->sort, &table_sort, sizeof(FILESORT_INFO));
335
DBUG_PRINT("exit",("records: %ld", (long) records));
336
MYSQL_FILESORT_END();
337
DBUG_RETURN(error ? HA_POS_ERROR : records);
341
void filesort_free_buffers(TABLE *table, bool full)
343
if (table->sort.record_pointers)
345
my_free((uchar*) table->sort.record_pointers,MYF(0));
346
table->sort.record_pointers=0;
350
if (table->sort.sort_keys )
352
x_free((uchar*) table->sort.sort_keys);
353
table->sort.sort_keys= 0;
355
if (table->sort.buffpek)
357
x_free((uchar*) table->sort.buffpek);
358
table->sort.buffpek= 0;
359
table->sort.buffpek_len= 0;
362
if (table->sort.addon_buf)
364
my_free((char *) table->sort.addon_buf, MYF(0));
365
my_free((char *) table->sort.addon_field, MYF(MY_ALLOW_ZERO_PTR));
366
table->sort.addon_buf=0;
367
table->sort.addon_field=0;
455
371
/** Make a array of string pointers. */
457
static char **make_char_array(char **old_pos, register uint32_t fields,
373
static char **make_char_array(char **old_pos, register uint fields,
374
uint length, myf my_flag)
460
376
register char **pos;
378
DBUG_ENTER("make_char_array");
464
(old_pos= (char**) malloc((uint32_t) fields*(length+sizeof(char*)))))
381
(old_pos= (char**) my_malloc((uint) fields*(length+sizeof(char*)),
466
384
pos=old_pos; char_pos=((char*) (pos+fields)) -length;
467
385
while (fields--) *(pos++) = (char_pos+= length);
388
DBUG_RETURN(old_pos);
471
389
} /* make_char_array */
474
392
/** Read 'count' number of buffer pointers into memory. */
476
static unsigned char *read_buffpek_from_file(internal::IO_CACHE *buffpek_pointers, uint32_t count,
394
static uchar *read_buffpek_from_file(IO_CACHE *buffpek_pointers, uint count,
479
uint32_t length= sizeof(buffpek)*count;
480
unsigned char *tmp= buf;
481
if (count > UINT_MAX/sizeof(buffpek))
482
return 0; /* sizeof(buffpek)*count will overflow */
397
ulong length= sizeof(BUFFPEK)*count;
399
DBUG_ENTER("read_buffpek_from_file");
400
if (count > UINT_MAX/sizeof(BUFFPEK))
401
return 0; /* sizeof(BUFFPEK)*count will overflow */
484
tmp= (unsigned char *)malloc(length);
403
tmp= (uchar *)my_malloc(length, MYF(MY_WME));
487
if (buffpek_pointers->reinit_io_cache(internal::READ_CACHE,0L,0,0) ||
488
my_b_read(buffpek_pointers, (unsigned char*) tmp, length))
406
if (reinit_io_cache(buffpek_pointers,READ_CACHE,0L,0,0) ||
407
my_b_read(buffpek_pointers, (uchar*) tmp, length))
409
my_free((char*) tmp, MYF(0));
532
451
HA_POS_ERROR on error.
535
ha_rows FileSort::find_all_keys(SortParam *param,
536
optimizer::SqlSelect *select,
537
unsigned char **sort_keys,
538
internal::IO_CACHE *buffpek_pointers,
539
internal::IO_CACHE *tempfile, internal::IO_CACHE *indexfile)
454
static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select,
456
IO_CACHE *buffpek_pointers,
457
IO_CACHE *tempfile, IO_CACHE *indexfile)
541
459
int error,flag,quick_select;
542
uint32_t idx,indexpos,ref_length;
543
unsigned char *ref_pos,*next_pos,ref_buff[MAX_REFLENGTH];
544
internal::my_off_t record;
546
volatile Session::killed_state_t *killed= getSession().getKilledPtr();
548
boost::dynamic_bitset<> *save_read_set= NULL;
549
boost::dynamic_bitset<> *save_write_set= NULL;
460
uint idx,indexpos,ref_length;
461
uchar *ref_pos,*next_pos,ref_buff[MAX_REFLENGTH];
464
THD *thd= current_thd;
465
volatile THD::killed_state *killed= &thd->killed;
467
MY_BITMAP *save_read_set, *save_write_set;
468
DBUG_ENTER("find_all_keys");
469
DBUG_PRINT("info",("using: %s",
470
(select ? select->quick ? "ranges" : "where":
552
474
error=quick_select=0;
553
475
sort_form=param->sort_form;
554
file= sort_form->cursor;
476
file=sort_form->file;
555
477
ref_length=param->ref_length;
556
478
ref_pos= ref_buff;
557
479
quick_select=select && select->quick;
559
flag= ((!indexfile && ! file->isOrdered())
481
flag= ((!indexfile && file->ha_table_flags() & HA_REC_NOT_IN_SEQ)
560
482
|| quick_select);
561
483
if (indexfile || flag)
562
484
ref_pos= &file->ref[0];
563
485
next_pos=ref_pos;
564
486
if (! indexfile && ! quick_select)
566
next_pos=(unsigned char*) 0; /* Find records in sequence */
567
file->startTableScan(1);
568
file->extra_opt(HA_EXTRA_CACHE, getSession().variables.read_buff_size);
488
next_pos=(uchar*) 0; /* Find records in sequence */
489
file->ha_rnd_init(1);
490
file->extra_opt(HA_EXTRA_CACHE,
491
current_thd->variables.read_buff_size);
571
ReadRecord read_record_info;
494
READ_RECORD read_record_info;
572
495
if (quick_select)
574
497
if (select->quick->reset())
575
return(HA_POS_ERROR);
577
read_record_info.init_read_record(&getSession(), select->quick->head, select, 1, 1);
498
DBUG_RETURN(HA_POS_ERROR);
499
init_read_record(&read_record_info, current_thd, select->quick->head,
580
503
/* Remember original bitmaps */
581
504
save_read_set= sort_form->read_set;
582
505
save_write_set= sort_form->write_set;
583
506
/* Set up temporary column read map for columns used by sort */
584
sort_form->tmp_set.reset();
507
bitmap_clear_all(&sort_form->tmp_set);
585
508
/* Temporary set for register_used_fields and register_field_in_read_map */
586
509
sort_form->read_set= &sort_form->tmp_set;
587
param->register_used_fields();
510
register_used_fields(param);
588
511
if (select && select->cond)
589
512
select->cond->walk(&Item::register_field_in_read_map, 1,
590
(unsigned char*) sort_form);
591
sort_form->column_bitmaps_set(sort_form->tmp_set, sort_form->tmp_set);
514
sort_form->column_bitmaps_set(&sort_form->tmp_set, &sort_form->tmp_set);
722
int SortParam::write_keys(register unsigned char **sort_keys, uint32_t count,
723
internal::IO_CACHE *buffpek_pointers, internal::IO_CACHE *tempfile)
641
write_keys(SORTPARAM *param, register uchar **sort_keys, uint count,
642
IO_CACHE *buffpek_pointers, IO_CACHE *tempfile)
644
size_t sort_length, rec_length;
647
DBUG_ENTER("write_keys");
727
internal::my_string_ptr_sort((unsigned char*) sort_keys, (uint32_t) count, sort_length);
649
sort_length= param->sort_length;
650
rec_length= param->rec_length;
652
quicksort(sort_keys,count,sort_length);
654
my_string_ptr_sort((uchar*) sort_keys, (uint) count, sort_length);
728
656
if (!my_b_inited(tempfile) &&
729
tempfile->open_cached_file(drizzle_tmpdir.c_str(), TEMP_PREFIX, DISK_BUFFER_SIZE, MYF(MY_WME)))
657
open_cached_file(tempfile, mysql_tmpdir, TEMP_PREFIX, DISK_BUFFER_SIZE,
659
goto err; /* purecov: inspected */
733
660
/* check we won't have more buffpeks than we can possibly keep in memory */
734
if (my_b_tell(buffpek_pointers) + sizeof(buffpek) > (uint64_t)UINT_MAX)
661
if (my_b_tell(buffpek_pointers) + sizeof(BUFFPEK) > (ulonglong)UINT_MAX)
739
663
buffpek.file_pos= my_b_tell(tempfile);
740
if ((ha_rows) count > max_rows)
741
count=(uint32_t) max_rows;
664
if ((ha_rows) count > param->max_rows)
665
count=(uint) param->max_rows; /* purecov: inspected */
743
666
buffpek.count=(ha_rows) count;
745
for (unsigned char **ptr= sort_keys + count ; sort_keys != ptr ; sort_keys++)
747
if (my_b_write(tempfile, (unsigned char*) *sort_keys, (uint32_t) rec_length))
753
if (my_b_write(buffpek_pointers, (unsigned char*) &buffpek, sizeof(buffpek)))
667
for (end=sort_keys+count ; sort_keys != end ; sort_keys++)
668
if (my_b_write(tempfile, (uchar*) *sort_keys, (uint) rec_length))
670
if (my_b_write(buffpek_pointers, (uchar*) &buffpek, sizeof(buffpek)))
759
676
} /* write_keys */
818
736
Item *item=sort_field->item;
819
737
maybe_null= item->maybe_null;
821
738
switch (sort_field->result_type) {
822
739
case STRING_RESULT:
824
const CHARSET_INFO * const cs=item->collation.collation;
825
char fill_char= ((cs->state & MY_CS_BINSORT) ? (char) 0 : ' ');
827
uint32_t sort_field_length;
741
CHARSET_INFO *cs=item->collation.collation;
742
char fill_char= ((cs->state & MY_CS_BINSORT) ? (char) 0 : ' ');
744
uint sort_field_length;
748
/* All item->str() to use some extra byte for end null.. */
749
String tmp((char*) to,sort_field->length+4,cs);
750
String *res= item->str_result(&tmp);
831
/* All item->str() to use some extra byte for end null.. */
832
String tmp((char*) to,sort_field->length+4,cs);
833
String *res= item->str_result(&tmp);
837
memset(to-1, 0, sort_field->length+1);
841
This should only happen during extreme conditions if we run out
842
of memory or have an item marked not null when it can be null.
843
This code is here mainly to avoid a hard crash in this case.
846
memset(to, 0, sort_field->length); // Avoid crash
850
length= res->length();
851
sort_field_length= sort_field->length - sort_field->suffix_length;
852
diff=(int) (sort_field_length - length);
856
length= sort_field_length;
858
if (sort_field->suffix_length)
860
/* Store length last in result_string */
861
store_length(to + sort_field_length, length,
862
sort_field->suffix_length);
864
if (sort_field->need_strxnfrm)
866
char *from=(char*) res->ptr();
868
if ((unsigned char*) from == to)
870
set_if_smaller(length,sort_field->length);
871
memcpy(tmp_buffer,from,length);
874
tmp_length= my_strnxfrm(cs,to,sort_field->length,
875
(unsigned char*) from, length);
876
assert(tmp_length == sort_field->length);
754
bzero((char*) to-1,sort_field->length+1);
880
my_strnxfrm(cs,(unsigned char*)to,length,(const unsigned char*)res->ptr(),length);
881
cs->cset->fill(cs, (char *)to+length,diff,fill_char);
757
/* purecov: begin deadcode */
759
This should only happen during extreme conditions if we run out
760
of memory or have an item marked not null when it can be null.
761
This code is here mainly to avoid a hard crash in this case.
764
DBUG_PRINT("warning",
765
("Got null on something that shouldn't be null"));
766
bzero((char*) to,sort_field->length); // Avoid crash
771
length= res->length();
772
sort_field_length= sort_field->length - sort_field->suffix_length;
773
diff=(int) (sort_field_length - length);
777
length= sort_field_length;
779
if (sort_field->suffix_length)
781
/* Store length last in result_string */
782
store_length(to + sort_field_length, length,
783
sort_field->suffix_length);
785
if (sort_field->need_strxnfrm)
787
char *from=(char*) res->ptr();
789
if ((uchar*) from == to)
791
set_if_smaller(length,sort_field->length);
792
memcpy(param->tmp_buffer,from,length);
793
from=param->tmp_buffer;
795
tmp_length= my_strnxfrm(cs,to,sort_field->length,
796
(uchar*) from, length);
797
DBUG_ASSERT(tmp_length == sort_field->length);
801
my_strnxfrm(cs,(uchar*)to,length,(const uchar*)res->ptr(),length);
802
cs->cset->fill(cs, (char *)to+length,diff,fill_char);
887
int64_t value= item->val_int_result();
808
longlong value= item->val_int_result();
811
*to++=1; /* purecov: inspected */
891
812
if (item->null_value)
894
memset(to-1, 0, sort_field->length+1);
815
bzero((char*) to-1,sort_field->length+1);
897
memset(to, 0, sort_field->length);
818
DBUG_PRINT("warning",
819
("Got null on something that shouldn't be null"));
820
bzero((char*) to,sort_field->length);
902
to[7]= (unsigned char) value;
903
to[6]= (unsigned char) (value >> 8);
904
to[5]= (unsigned char) (value >> 16);
905
to[4]= (unsigned char) (value >> 24);
906
to[3]= (unsigned char) (value >> 32);
907
to[2]= (unsigned char) (value >> 40);
908
to[1]= (unsigned char) (value >> 48);
909
if (item->unsigned_flag) /* Fix sign */
910
to[0]= (unsigned char) (value >> 56);
912
to[0]= (unsigned char) (value >> 56) ^ 128; /* Reverse signbit */
825
#if SIZEOF_LONG_LONG > 4
826
to[7]= (uchar) value;
827
to[6]= (uchar) (value >> 8);
828
to[5]= (uchar) (value >> 16);
829
to[4]= (uchar) (value >> 24);
830
to[3]= (uchar) (value >> 32);
831
to[2]= (uchar) (value >> 40);
832
to[1]= (uchar) (value >> 48);
833
if (item->unsigned_flag) /* Fix sign */
834
to[0]= (uchar) (value >> 56);
836
to[0]= (uchar) (value >> 56) ^ 128; /* Reverse signbit */
838
to[3]= (uchar) value;
839
to[2]= (uchar) (value >> 8);
840
to[1]= (uchar) (value >> 16);
841
if (item->unsigned_flag) /* Fix sign */
842
to[0]= (uchar) (value >> 24);
844
to[0]= (uchar) (value >> 24) ^ 128; /* Reverse signbit */
915
848
case DECIMAL_RESULT:
917
850
my_decimal dec_buf, *dec_val= item->val_decimal_result(&dec_buf);
920
853
if (item->null_value)
922
memset(to, 0, sort_field->length+1);
855
bzero((char*)to, sort_field->length+1);
1060
bool SortParam::save_index(unsigned char **sort_keys, uint32_t count, filesort_info *table_sort)
992
static bool save_index(SORTPARAM *param, uchar **sort_keys, uint count,
993
FILESORT_INFO *table_sort)
1065
internal::my_string_ptr_sort((unsigned char*) sort_keys, (uint32_t) count, sort_length);
1066
offset= rec_length - res_length;
1068
if ((ha_rows) count > max_rows)
1069
count=(uint32_t) max_rows;
1071
if (!(to= table_sort->record_pointers= (unsigned char*) malloc(res_length*count)))
1074
for (unsigned char **end_ptr= sort_keys+count ; sort_keys != end_ptr ; sort_keys++)
995
uint offset,res_length;
997
DBUG_ENTER("save_index");
999
my_string_ptr_sort((uchar*) sort_keys, (uint) count, param->sort_length);
1000
res_length= param->res_length;
1001
offset= param->rec_length-res_length;
1002
if ((ha_rows) count > param->max_rows)
1003
count=(uint) param->max_rows;
1004
if (!(to= table_sort->record_pointers=
1005
(uchar*) my_malloc(res_length*count, MYF(MY_WME))))
1006
DBUG_RETURN(1); /* purecov: inspected */
1007
for (uchar **end= sort_keys+count ; sort_keys != end ; sort_keys++)
1076
1009
memcpy(to, *sort_keys+offset, res_length);
1077
1010
to+= res_length;
1084
1016
/** Merge buffers to make < MERGEBUFF2 buffers. */
1086
int FileSort::merge_many_buff(SortParam *param, unsigned char *sort_buffer,
1087
buffpek *buffpek_inst, uint32_t *maxbuffer, internal::IO_CACHE *t_file)
1018
int merge_many_buff(SORTPARAM *param, uchar *sort_buffer,
1019
BUFFPEK *buffpek, uint *maxbuffer, IO_CACHE *t_file)
1089
internal::IO_CACHE t_file2,*from_file,*to_file,*temp;
1022
IO_CACHE t_file2,*from_file,*to_file,*temp;
1024
DBUG_ENTER("merge_many_buff");
1092
1026
if (*maxbuffer < MERGEBUFF2)
1027
DBUG_RETURN(0); /* purecov: inspected */
1094
1028
if (flush_io_cache(t_file) ||
1095
t_file2.open_cached_file(drizzle_tmpdir.c_str(),TEMP_PREFIX,DISK_BUFFER_SIZE, MYF(MY_WME)))
1029
open_cached_file(&t_file2,mysql_tmpdir,TEMP_PREFIX,DISK_BUFFER_SIZE,
1031
DBUG_RETURN(1); /* purecov: inspected */
1100
1033
from_file= t_file ; to_file= &t_file2;
1101
1034
while (*maxbuffer >= MERGEBUFF2)
1103
register uint32_t i;
1105
if (from_file->reinit_io_cache(internal::READ_CACHE,0L,0,0))
1110
if (to_file->reinit_io_cache(internal::WRITE_CACHE,0L,0,0))
1115
lastbuff=buffpek_inst;
1036
if (reinit_io_cache(from_file,READ_CACHE,0L,0,0))
1038
if (reinit_io_cache(to_file,WRITE_CACHE,0L,0,0))
1116
1041
for (i=0 ; i <= *maxbuffer-MERGEBUFF*3/2 ; i+=MERGEBUFF)
1118
1043
if (merge_buffers(param,from_file,to_file,sort_buffer,lastbuff++,
1119
buffpek_inst+i,buffpek_inst+i+MERGEBUFF-1,0))
1044
buffpek+i,buffpek+i+MERGEBUFF-1,0))
1125
1047
if (merge_buffers(param,from_file,to_file,sort_buffer,lastbuff++,
1126
buffpek_inst+i,buffpek_inst+ *maxbuffer,0))
1048
buffpek+i,buffpek+ *maxbuffer,0))
1049
break; /* purecov: inspected */
1131
1050
if (flush_io_cache(to_file))
1051
break; /* purecov: inspected */
1136
1052
temp=from_file; from_file=to_file; to_file=temp;
1137
from_file->setup_io_cache();
1138
to_file->setup_io_cache();
1139
*maxbuffer= (uint32_t) (lastbuff-buffpek_inst)-1;
1053
setup_io_cache(from_file);
1054
setup_io_cache(to_file);
1055
*maxbuffer= (uint) (lastbuff-buffpek)-1;
1143
to_file->close_cached_file(); // This holds old result
1058
close_cached_file(to_file); // This holds old result
1144
1059
if (to_file == t_file)
1146
1061
*t_file=t_file2; // Copy result file
1147
t_file->setup_io_cache();
1062
setup_io_cache(t_file);
1150
return(*maxbuffer >= MERGEBUFF2); /* Return 1 if interrupted */
1065
DBUG_RETURN(*maxbuffer >= MERGEBUFF2); /* Return 1 if interrupted */
1151
1066
} /* merge_many_buff */
1155
1070
Read data to buffer.
1158
(uint32_t)-1 if something goes wrong
1073
(uint)-1 if something goes wrong
1161
uint32_t FileSort::read_to_buffer(internal::IO_CACHE *fromfile, buffpek *buffpek_inst, uint32_t rec_length)
1076
uint read_to_buffer(IO_CACHE *fromfile, BUFFPEK *buffpek,
1163
register uint32_t count;
1079
register uint count;
1166
if ((count= (uint32_t) min((ha_rows) buffpek_inst->max_keys,buffpek_inst->count)))
1082
if ((count=(uint) min((ha_rows) buffpek->max_keys,buffpek->count)))
1168
if (pread(fromfile->file,(unsigned char*) buffpek_inst->base, (length= rec_length*count),buffpek_inst->file_pos) == 0)
1169
return((uint32_t) -1);
1171
buffpek_inst->key= buffpek_inst->base;
1172
buffpek_inst->file_pos+= length; /* New filepos */
1173
buffpek_inst->count-= count;
1174
buffpek_inst->mem_count= count;
1084
if (my_pread(fromfile->file,(uchar*) buffpek->base,
1085
(length= rec_length*count),buffpek->file_pos,MYF_RW))
1086
return((uint) -1); /* purecov: inspected */
1087
buffpek->key=buffpek->base;
1088
buffpek->file_pos+= length; /* New filepos */
1089
buffpek->count-= count;
1090
buffpek->mem_count= count;
1176
1092
return (count*rec_length);
1177
1093
} /* read_to_buffer */
1180
class compare_functor
1097
Put all room used by freed buffer to use in adjacent buffer.
1099
Note, that we can't simply distribute memory evenly between all buffers,
1100
because new areas must not overlap with old ones.
1102
@param[in] queue list of non-empty buffers, without freed buffer
1103
@param[in] reuse empty buffer
1104
@param[in] key_length key length
1107
void reuse_freed_buff(QUEUE *queue, BUFFPEK *reuse, uint key_length)
1182
qsort2_cmp key_compare;
1183
void *key_compare_arg;
1186
compare_functor(qsort2_cmp in_key_compare, void *in_compare_arg) :
1187
key_compare(in_key_compare),
1188
key_compare_arg(in_compare_arg)
1191
inline bool operator()(const buffpek *i, const buffpek *j) const
1109
uchar *reuse_end= reuse->base + reuse->max_keys * key_length;
1110
for (uint i= 0; i < queue->elements; ++i)
1193
int val= key_compare(key_compare_arg, &i->key, &j->key);
1112
BUFFPEK *bp= (BUFFPEK *) queue_element(queue, i);
1113
if (bp->base + bp->max_keys * key_length == reuse->base)
1115
bp->max_keys+= reuse->max_keys;
1118
else if (bp->base == reuse_end)
1120
bp->base= reuse->base;
1121
bp->max_keys+= reuse->max_keys;
1201
1130
Merge buffers to one buffer.
1203
1132
@param param Sort parameter
1204
@param from_file File with source data (buffpeks point to this file)
1133
@param from_file File with source data (BUFFPEKs point to this file)
1205
1134
@param to_file File to write the sorted result data.
1206
1135
@param sort_buffer Buffer for data to store up to MERGEBUFF2 sort keys.
1207
@param lastbuff OUT Store here buffpek describing data written to to_file
1208
@param Fb First element in source buffpeks array
1209
@param Tb Last element in source buffpeks array
1136
@param lastbuff OUT Store here BUFFPEK describing data written to to_file
1137
@param Fb First element in source BUFFPEKs array
1138
@param Tb Last element in source BUFFPEKs array
1288
1219
This is safe as we know that there is always more than one element
1289
1220
in each block to merge (This is guaranteed by the Unique:: algorithm
1291
buffpek_inst= queue.top();
1292
memcpy(param->unique_buff, buffpek_inst->key, rec_length);
1293
if (my_b_write(to_file, (unsigned char*) buffpek_inst->key, rec_length))
1222
buffpek= (BUFFPEK*) queue_top(&queue);
1223
memcpy(param->unique_buff, buffpek->key, rec_length);
1224
if (my_b_write(to_file, (uchar*) buffpek->key, rec_length))
1226
error=1; goto err; /* purecov: inspected */
1297
buffpek_inst->key+= rec_length;
1298
buffpek_inst->mem_count--;
1228
buffpek->key+= rec_length;
1229
buffpek->mem_count--;
1299
1230
if (!--max_rows)
1232
error= 0; /* purecov: inspected */
1233
goto end; /* purecov: inspected */
1304
/* Top element has been used */
1306
queue.push(buffpek_inst);
1235
queue_replaced(&queue); // Top element has been used
1310
1238
cmp= 0; // Not unique
1313
while (queue.size() > 1)
1240
while (queue.elements > 1)
1244
error= 1; goto err; /* purecov: inspected */
1321
buffpek_inst= queue.top();
1248
buffpek= (BUFFPEK*) queue_top(&queue);
1322
1249
if (cmp) // Remove duplicates
1324
1251
if (!(*cmp)(first_cmp_arg, &(param->unique_buff),
1325
(unsigned char**) &buffpek_inst->key))
1252
(uchar**) &buffpek->key))
1326
1253
goto skip_duplicate;
1327
memcpy(param->unique_buff, buffpek_inst->key, rec_length);
1254
memcpy(param->unique_buff, (uchar*) buffpek->key, rec_length);
1331
if (my_b_write(to_file,(unsigned char*) buffpek_inst->key, rec_length))
1258
if (my_b_write(to_file,(uchar*) buffpek->key, rec_length))
1260
error=1; goto err; /* purecov: inspected */
1338
if (my_b_write(to_file, (unsigned char*) buffpek_inst->key+offset, res_length))
1265
if (my_b_write(to_file, (uchar*) buffpek->key+offset, res_length))
1267
error=1; goto err; /* purecov: inspected */
1343
1270
if (!--max_rows)
1272
error= 0; /* purecov: inspected */
1273
goto end; /* purecov: inspected */
1349
1276
skip_duplicate:
1350
buffpek_inst->key+= rec_length;
1351
if (! --buffpek_inst->mem_count)
1277
buffpek->key+= rec_length;
1278
if (! --buffpek->mem_count)
1353
if (!(error= (int) read_to_buffer(from_file,buffpek_inst,
1280
if (!(error= (int) read_to_buffer(from_file,buffpek,
1283
VOID(queue_remove(&queue,0));
1284
reuse_freed_buff(&queue, buffpek, rec_length);
1357
1285
break; /* One buffer have been removed */
1359
1287
else if (error == -1)
1288
goto err; /* purecov: inspected */
1364
/* Top element has been replaced */
1366
queue.push(buffpek_inst);
1290
queue_replaced(&queue); /* Top element has been replaced */
1369
buffpek_inst= queue.top();
1370
buffpek_inst->base= sort_buffer;
1371
buffpek_inst->max_keys= param->keys;
1293
buffpek= (BUFFPEK*) queue_top(&queue);
1294
buffpek->base= sort_buffer;
1295
buffpek->max_keys= param->keys;
1374
1298
As we know all entries in the buffer are unique, we only have to
1379
if (!(*cmp)(first_cmp_arg, &(param->unique_buff), (unsigned char**) &buffpek_inst->key))
1303
if (!(*cmp)(first_cmp_arg, &(param->unique_buff), (uchar**) &buffpek->key))
1381
buffpek_inst->key+= rec_length; // Remove duplicate
1382
--buffpek_inst->mem_count;
1305
buffpek->key+= rec_length; // Remove duplicate
1306
--buffpek->mem_count;
1388
if ((ha_rows) buffpek_inst->mem_count > max_rows)
1312
if ((ha_rows) buffpek->mem_count > max_rows)
1389
1313
{ /* Don't write too many records */
1390
buffpek_inst->mem_count= (uint32_t) max_rows;
1391
buffpek_inst->count= 0; /* Don't read more */
1314
buffpek->mem_count= (uint) max_rows;
1315
buffpek->count= 0; /* Don't read more */
1393
max_rows-= buffpek_inst->mem_count;
1317
max_rows-= buffpek->mem_count;
1396
if (my_b_write(to_file,(unsigned char*) buffpek_inst->key,
1397
(rec_length*buffpek_inst->mem_count)))
1320
if (my_b_write(to_file,(uchar*) buffpek->key,
1321
(rec_length*buffpek->mem_count)))
1323
error= 1; goto err; /* purecov: inspected */
1404
register unsigned char *end;
1405
strpos= buffpek_inst->key+offset;
1406
for (end= strpos+buffpek_inst->mem_count*rec_length ;
1328
register uchar *end;
1329
strpos= buffpek->key+offset;
1330
for (end= strpos+buffpek->mem_count*rec_length ;
1407
1331
strpos != end ;
1408
1332
strpos+= rec_length)
1410
if (my_b_write(to_file, (unsigned char *) strpos, res_length))
1334
if (my_b_write(to_file, (uchar *) strpos, res_length))
1418
while ((error=(int) read_to_buffer(from_file,buffpek_inst, rec_length))
1341
while ((error=(int) read_to_buffer(from_file,buffpek, rec_length))
1419
1342
!= -1 && error != 0);
1422
1345
lastbuff->count= min(org_max_rows-max_rows, param->max_rows);
1423
1346
lastbuff->file_pos= to_start_filepos;
1348
delete_queue(&queue);
1426
1350
} /* merge_buffers */
1429
1353
/* Do a merge to output-file (save only positions) */
1431
int FileSort::merge_index(SortParam *param, unsigned char *sort_buffer,
1432
buffpek *buffpek_inst, uint32_t maxbuffer,
1433
internal::IO_CACHE *tempfile, internal::IO_CACHE *outfile)
1355
static int merge_index(SORTPARAM *param, uchar *sort_buffer,
1356
BUFFPEK *buffpek, uint maxbuffer,
1357
IO_CACHE *tempfile, IO_CACHE *outfile)
1435
if (merge_buffers(param,tempfile,outfile,sort_buffer,buffpek_inst,buffpek_inst,
1436
buffpek_inst+maxbuffer,1))
1359
DBUG_ENTER("merge_index");
1360
if (merge_buffers(param,tempfile,outfile,sort_buffer,buffpek,buffpek,
1361
buffpek+maxbuffer,1))
1362
DBUG_RETURN(1); /* purecov: inspected */
1440
1364
} /* merge_index */
1443
static uint32_t suffix_length(uint32_t string_length)
1367
static uint suffix_length(ulong string_length)
1445
1369
if (string_length < 256)
1500
1427
sortorder->result_type= sortorder->item->result_type();
1501
if (sortorder->item->result_as_int64_t())
1428
if (sortorder->item->result_as_longlong())
1502
1429
sortorder->result_type= INT_RESULT;
1504
1430
switch (sortorder->result_type) {
1505
1431
case STRING_RESULT:
1506
sortorder->length=sortorder->item->max_length;
1507
set_if_smaller(sortorder->length,
1508
getSession().variables.max_sort_length);
1509
if (use_strnxfrm((cs=sortorder->item->collation.collation)))
1432
sortorder->length=sortorder->item->max_length;
1433
set_if_smaller(sortorder->length, thd->variables.max_sort_length);
1434
if (use_strnxfrm((cs=sortorder->item->collation.collation)))
1511
1436
sortorder->length= cs->coll->strnxfrmlen(cs, sortorder->length);
1512
sortorder->need_strxnfrm= 1;
1513
*multi_byte_charset= 1;
1437
sortorder->need_strxnfrm= 1;
1438
*multi_byte_charset= 1;
1515
1440
else if (cs == &my_charset_bin)
1517
1442
/* Store length last to be able to sort blob/varbinary */
1518
1443
sortorder->suffix_length= suffix_length(sortorder->length);
1519
1444
sortorder->length+= sortorder->suffix_length;
1522
1447
case INT_RESULT:
1523
sortorder->length=8; // Size of intern int64_t
1448
#if SIZEOF_LONG_LONG > 4
1449
sortorder->length=8; // Size of intern longlong
1451
sortorder->length=4;
1525
1454
case DECIMAL_RESULT:
1526
1455
sortorder->length=
1527
my_decimal_get_binary_size(sortorder->item->max_length -
1456
my_decimal_get_binary_size(sortorder->item->max_length -
1528
1457
(sortorder->item->decimals ? 1 : 0),
1529
1458
sortorder->item->decimals);
1531
1460
case REAL_RESULT:
1532
sortorder->length=sizeof(double);
1461
sortorder->length=sizeof(double);
1534
1463
case ROW_RESULT:
1535
// This case should never be choosen
1465
// This case should never be choosen
1539
1469
if (sortorder->item->maybe_null)
1540
length++; // Place for NULL marker
1470
length++; // Place for NULL marker
1542
set_if_smaller(sortorder->length, (size_t)getSession().variables.max_sort_length);
1472
set_if_smaller(sortorder->length, thd->variables.max_sort_length);
1543
1473
length+=sortorder->length;
1545
1475
sortorder->field= (Field*) 0; // end marker
1476
DBUG_PRINT("info",("sort_length: %d",length));