32
#include "drizzled/sql_sort.h"
33
#include "drizzled/error.h"
34
#include "drizzled/probes.h"
35
#include "drizzled/session.h"
36
#include "drizzled/table.h"
37
#include "drizzled/table_list.h"
38
#include "drizzled/optimizer/range.h"
39
#include "drizzled/records.h"
40
#include "drizzled/internal/iocache.h"
41
#include "drizzled/internal/my_sys.h"
42
#include "plugin/myisam/myisam.h"
43
#include "drizzled/plugin/transactional_storage_engine.h"
24
#include <drizzled/server_includes.h>
26
#include <drizzled/error.h>
27
#include <drizzled/probes.h>
50
29
/* functions defined in this file */
52
31
static char **make_char_array(char **old_pos, register uint32_t fields,
55
static unsigned char *read_buffpek_from_file(internal::IO_CACHE *buffer_file,
59
static ha_rows find_all_keys(SORTPARAM *param,
60
optimizer::SqlSelect *select,
61
unsigned char * *sort_keys,
62
internal::IO_CACHE *buffer_file,
63
internal::IO_CACHE *tempfile,
64
internal::IO_CACHE *indexfile);
66
static int write_keys(SORTPARAM *param,
67
unsigned char * *sort_keys,
69
internal::IO_CACHE *buffer_file,
70
internal::IO_CACHE *tempfile);
72
static void make_sortkey(SORTPARAM *param,
74
unsigned char *ref_pos);
32
uint32_t length, myf my_flag);
33
static unsigned char *read_buffpek_from_file(IO_CACHE *buffer_file, uint32_t count,
35
static ha_rows find_all_keys(SORTPARAM *param,SQL_SELECT *select,
36
unsigned char * *sort_keys, IO_CACHE *buffer_file,
37
IO_CACHE *tempfile,IO_CACHE *indexfile);
38
static int write_keys(SORTPARAM *param,unsigned char * *sort_keys,
39
uint32_t count, IO_CACHE *buffer_file, IO_CACHE *tempfile);
40
static void make_sortkey(SORTPARAM *param,unsigned char *to, unsigned char *ref_pos);
75
41
static void register_used_fields(SORTPARAM *param);
76
static int merge_index(SORTPARAM *param,
77
unsigned char *sort_buffer,
42
static int merge_index(SORTPARAM *param,unsigned char *sort_buffer,
80
internal::IO_CACHE *tempfile,
81
internal::IO_CACHE *outfile);
82
static bool save_index(SORTPARAM *param,
83
unsigned char **sort_keys,
44
uint32_t maxbuffer,IO_CACHE *tempfile,
46
static bool save_index(SORTPARAM *param,unsigned char **sort_keys, uint32_t count,
85
47
filesort_info_st *table_sort);
86
48
static uint32_t suffix_length(uint32_t string_length);
87
static uint32_t sortlength(Session *session,
88
SORT_FIELD *sortorder,
90
bool *multi_byte_charset);
91
static SORT_ADDON_FIELD *get_addon_fields(Session *session,
49
static uint32_t sortlength(Session *session, SORT_FIELD *sortorder, uint32_t s_length,
50
bool *multi_byte_charset);
51
static SORT_ADDON_FIELD *get_addon_fields(Session *session, Field **ptabfield,
52
uint32_t sortlength, uint32_t *plength);
95
53
static void unpack_addon_fields(struct st_sort_addon_field *addon_field,
96
54
unsigned char *buff);
148
106
TableList *tab= table->pos_in_table_list;
149
107
Item_subselect *subselect= tab ? tab->containing_subselect() : 0;
151
DRIZZLE_FILESORT_START(table->s->getSchemaName(), table->s->getTableName());
109
DRIZZLE_FILESORT_START();
154
112
Release InnoDB's adaptive hash index latch (if holding) before
157
plugin::TransactionalStorageEngine::releaseTemporaryLatches(session);
115
ha_release_temporary_latches(session);
160
Don't use table->sort in filesort as it is also used by
161
QuickIndexMergeSelect. Work with a copy and put it back at the end
118
Don't use table->sort in filesort as it is also used by
119
QUICK_INDEX_MERGE_SELECT. Work with a copy and put it back at the end
162
120
when index_merge select has finished with it.
164
122
memcpy(&table_sort, &table->sort, sizeof(filesort_info_st));
165
123
table->sort.io_cache= NULL;
167
125
outfile= table_sort.io_cache;
168
126
my_b_clear(&tempfile);
169
127
my_b_clear(&buffpek_pointers);
172
130
memset(¶m, 0, sizeof(param));
173
131
param.sort_length= sortlength(session, sortorder, s_length, &multi_byte_charset);
174
param.ref_length= table->cursor->ref_length;
132
param.ref_length= table->file->ref_length;
175
133
param.addon_field= 0;
176
134
param.addon_length= 0;
177
if (!(table->cursor->getEngine()->check_flag(HTON_BIT_FAST_KEY_READ)) && !sort_positions)
135
if (!(table->file->ha_table_flags() & HA_FAST_KEY_READ) && !sort_positions)
180
Get the descriptors of all fields whose values are appended
138
Get the descriptors of all fields whose values are appended
181
139
to sorted fields and get its total length in param.spack_length.
183
param.addon_field= get_addon_fields(session, table->field,
141
param.addon_field= get_addon_fields(session, table->field,
184
142
param.sort_length,
185
143
¶m.addon_length);
218
177
#ifdef CAN_TRUST_RANGE
219
178
if (select && select->quick && select->quick->records > 0L)
221
records= min((ha_rows) (select->quick->records*2+EXTRA_RECORDS*2),
222
table->cursor->stats.records)+EXTRA_RECORDS;
180
records=cmin((ha_rows) (select->quick->records*2+EXTRA_RECORDS*2),
181
table->file->stats.records)+EXTRA_RECORDS;
223
182
selected_records_file=0;
228
records= table->cursor->estimate_rows_upper_bound();
187
records= table->file->estimate_rows_upper_bound();
230
If number of records is not known, use as much of sort buffer
189
If number of records is not known, use as much of sort buffer
233
192
if (records == HA_POS_ERROR)
234
193
records--; // we use 'records+1' below.
238
197
if (multi_byte_charset &&
239
!(param.tmp_buffer= (char*) malloc(param.sort_length)))
198
!(param.tmp_buffer= (char*) my_malloc(param.sort_length,MYF(MY_WME))))
242
201
memavl= session->variables.sortbuff_size;
243
min_sort_memory= max((uint32_t)MIN_SORT_MEMORY, param.sort_length*MERGEBUFF2);
202
min_sort_memory= cmax((uint32_t)MIN_SORT_MEMORY, param.sort_length*MERGEBUFF2);
244
203
while (memavl >= min_sort_memory)
246
205
uint32_t old_memavl;
247
206
uint32_t keys= memavl/(param.rec_length+sizeof(char*));
248
param.keys= (uint32_t) min(records+1, (ha_rows)keys);
207
param.keys=(uint32_t) cmin(records+1, keys);
249
208
if ((table_sort.sort_keys=
250
209
(unsigned char **) make_char_array((char **) table_sort.sort_keys,
251
param.keys, param.rec_length)))
210
param.keys, param.rec_length, MYF(0))))
254
if ((memavl= memavl/4*3) < min_sort_memory && old_memavl > min_sort_memory)
213
if ((memavl=memavl/4*3) < min_sort_memory && old_memavl > min_sort_memory)
255
214
memavl= min_sort_memory;
257
216
sort_keys= table_sort.sort_keys;
358
317
(uint32_t) records, &LOCK_status);
359
318
*examined_rows= param.examined_rows;
360
319
memcpy(&table->sort, &table_sort, sizeof(filesort_info_st));
361
DRIZZLE_FILESORT_DONE(error, records);
362
return (error ? HA_POS_ERROR : records);
320
DRIZZLE_FILESORT_END();
321
return(error ? HA_POS_ERROR : records);
366
void Table::filesort_free_buffers(bool full)
325
void filesort_free_buffers(Table *table, bool full)
368
if (sort.record_pointers)
327
if (table->sort.record_pointers)
370
free((unsigned char*) sort.record_pointers);
371
sort.record_pointers=0;
329
free((unsigned char*) table->sort.record_pointers);
330
table->sort.record_pointers=0;
334
if (table->sort.sort_keys )
377
if ((unsigned char*) sort.sort_keys)
378
free((unsigned char*) sort.sort_keys);
336
if ((unsigned char*) table->sort.sort_keys)
337
free((unsigned char*) table->sort.sort_keys);
338
table->sort.sort_keys= 0;
340
if (table->sort.buffpek)
383
if ((unsigned char*) sort.buffpek)
384
free((unsigned char*) sort.buffpek);
342
if ((unsigned char*) table->sort.buffpek)
343
free((unsigned char*) table->sort.buffpek);
344
table->sort.buffpek= 0;
345
table->sort.buffpek_len= 0;
348
if (table->sort.addon_buf)
391
free((char *) sort.addon_buf);
392
free((char *) sort.addon_field);
350
free((char *) table->sort.addon_buf);
351
free((char *) table->sort.addon_field);
352
table->sort.addon_buf=0;
353
table->sort.addon_field=0;
398
357
/** Make a array of string pointers. */
400
359
static char **make_char_array(char **old_pos, register uint32_t fields,
360
uint32_t length, myf my_flag)
403
362
register char **pos;
407
(old_pos= (char**) malloc((uint32_t) fields*(length+sizeof(char*)))))
366
(old_pos= (char**) my_malloc((uint32_t) fields*(length+sizeof(char*)),
409
369
pos=old_pos; char_pos=((char*) (pos+fields)) -length;
410
370
while (fields--) *(pos++) = (char_pos+= length);
475
435
HA_POS_ERROR on error.
478
static ha_rows find_all_keys(SORTPARAM *param,
479
optimizer::SqlSelect *select,
438
static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select,
480
439
unsigned char **sort_keys,
481
internal::IO_CACHE *buffpek_pointers,
482
internal::IO_CACHE *tempfile, internal::IO_CACHE *indexfile)
440
IO_CACHE *buffpek_pointers,
441
IO_CACHE *tempfile, IO_CACHE *indexfile)
484
443
int error,flag,quick_select;
485
444
uint32_t idx,indexpos,ref_length;
486
445
unsigned char *ref_pos,*next_pos,ref_buff[MAX_REFLENGTH];
487
internal::my_off_t record;
488
447
Table *sort_form;
489
448
Session *session= current_session;
490
449
volatile Session::killed_state *killed= &session->killed;
492
MyBitmap *save_read_set, *save_write_set;
451
MY_BITMAP *save_read_set, *save_write_set;
495
454
error=quick_select=0;
496
455
sort_form=param->sort_form;
497
file= sort_form->cursor;
456
file=sort_form->file;
498
457
ref_length=param->ref_length;
499
458
ref_pos= ref_buff;
500
459
quick_select=select && select->quick;
502
flag= ((!indexfile && ! file->isOrdered())
461
flag= ((!indexfile && file->ha_table_flags() & HA_REC_NOT_IN_SEQ)
503
462
|| quick_select);
504
463
if (indexfile || flag)
505
464
ref_pos= &file->ref[0];
618
579
if (session->is_error())
619
580
return(HA_POS_ERROR);
621
582
/* Signal we should use orignal column read and write maps */
622
583
sort_form->column_bitmaps_set(save_read_set, save_write_set);
624
585
if (error != HA_ERR_END_OF_FILE)
626
sort_form->print_error(error,MYF(ME_ERROR | ME_WAITTANG));
627
return(HA_POS_ERROR);
587
file->print_error(error,MYF(ME_ERROR | ME_WAITTANG)); /* purecov: inspected */
588
return(HA_POS_ERROR); /* purecov: inspected */
629
590
if (indexpos && idx &&
630
591
write_keys(param,sort_keys,idx,buffpek_pointers,tempfile))
631
return(HA_POS_ERROR);
592
return(HA_POS_ERROR); /* purecov: inspected */
632
593
return(my_b_inited(tempfile) ?
633
594
(ha_rows) (my_b_tell(tempfile)/param->rec_length) :
668
629
sort_length= param->sort_length;
669
630
rec_length= param->rec_length;
670
internal::my_string_ptr_sort((unsigned char*) sort_keys, (uint32_t) count, sort_length);
631
my_string_ptr_sort((unsigned char*) sort_keys, (uint32_t) count, sort_length);
671
632
if (!my_b_inited(tempfile) &&
672
633
open_cached_file(tempfile, drizzle_tmpdir, TEMP_PREFIX, DISK_BUFFER_SIZE,
635
goto err; /* purecov: inspected */
675
636
/* check we won't have more buffpeks than we can possibly keep in memory */
676
637
if (my_b_tell(buffpek_pointers) + sizeof(BUFFPEK) > (uint64_t)UINT_MAX)
678
639
buffpek.file_pos= my_b_tell(tempfile);
679
640
if ((ha_rows) count > param->max_rows)
680
count=(uint32_t) param->max_rows;
641
count=(uint32_t) param->max_rows; /* purecov: inspected */
681
642
buffpek.count=(ha_rows) count;
682
643
for (end=sort_keys+count ; sort_keys != end ; sort_keys++)
683
644
if (my_b_write(tempfile, (unsigned char*) *sort_keys, (uint32_t) rec_length))
990
static bool save_index(SORTPARAM *param, unsigned char **sort_keys, uint32_t count,
954
static bool save_index(SORTPARAM *param, unsigned char **sort_keys, uint32_t count,
991
955
filesort_info_st *table_sort)
993
957
uint32_t offset,res_length;
994
958
unsigned char *to;
996
internal::my_string_ptr_sort((unsigned char*) sort_keys, (uint32_t) count, param->sort_length);
960
my_string_ptr_sort((unsigned char*) sort_keys, (uint32_t) count, param->sort_length);
997
961
res_length= param->res_length;
998
962
offset= param->rec_length-res_length;
999
963
if ((ha_rows) count > param->max_rows)
1000
964
count=(uint32_t) param->max_rows;
1001
if (!(to= table_sort->record_pointers=
1002
(unsigned char*) malloc(res_length*count)))
965
if (!(to= table_sort->record_pointers=
966
(unsigned char*) my_malloc(res_length*count, MYF(MY_WME))))
967
return(1); /* purecov: inspected */
1004
968
for (unsigned char **end= sort_keys+count ; sort_keys != end ; sort_keys++)
1006
970
memcpy(to, *sort_keys+offset, res_length);
1013
977
/** Merge buffers to make < MERGEBUFF2 buffers. */
1015
979
int merge_many_buff(SORTPARAM *param, unsigned char *sort_buffer,
1016
BUFFPEK *buffpek, uint32_t *maxbuffer, internal::IO_CACHE *t_file)
980
BUFFPEK *buffpek, uint32_t *maxbuffer, IO_CACHE *t_file)
1018
982
register uint32_t i;
1019
internal::IO_CACHE t_file2,*from_file,*to_file,*temp;
983
IO_CACHE t_file2,*from_file,*to_file,*temp;
1020
984
BUFFPEK *lastbuff;
1022
986
if (*maxbuffer < MERGEBUFF2)
987
return(0); /* purecov: inspected */
1024
988
if (flush_io_cache(t_file) ||
1025
989
open_cached_file(&t_file2,drizzle_tmpdir,TEMP_PREFIX,DISK_BUFFER_SIZE,
991
return(1); /* purecov: inspected */
1029
993
from_file= t_file ; to_file= &t_file2;
1030
994
while (*maxbuffer >= MERGEBUFF2)
1032
if (reinit_io_cache(from_file,internal::READ_CACHE,0L,0,0))
996
if (reinit_io_cache(from_file,READ_CACHE,0L,0,0))
1034
if (reinit_io_cache(to_file,internal::WRITE_CACHE,0L,0,0))
998
if (reinit_io_cache(to_file,WRITE_CACHE,0L,0,0))
1036
1000
lastbuff=buffpek;
1037
1001
for (i=0 ; i <= *maxbuffer-MERGEBUFF*3/2 ; i+=MERGEBUFF)
1069
1033
(uint32_t)-1 if something goes wrong
1072
uint32_t read_to_buffer(internal::IO_CACHE *fromfile, BUFFPEK *buffpek,
1073
uint32_t rec_length)
1036
uint32_t read_to_buffer(IO_CACHE *fromfile, BUFFPEK *buffpek,
1037
uint32_t rec_length)
1075
1039
register uint32_t count;
1076
1040
uint32_t length;
1078
if ((count= (uint32_t) min((ha_rows) buffpek->max_keys,buffpek->count)))
1042
if ((count=(uint32_t) cmin((ha_rows) buffpek->max_keys,buffpek->count)))
1080
1044
if (pread(fromfile->file,(unsigned char*) buffpek->base, (length= rec_length*count),buffpek->file_pos) == 0)
1081
return((uint32_t) -1);
1083
buffpek->key= buffpek->base;
1045
return((uint32_t) -1); /* purecov: inspected */
1046
buffpek->key=buffpek->base;
1084
1047
buffpek->file_pos+= length; /* New filepos */
1085
buffpek->count-= count;
1048
buffpek->count-= count;
1086
1049
buffpek->mem_count= count;
1088
1051
return (count*rec_length);
1089
1052
} /* read_to_buffer */
1092
class compare_functor
1056
Put all room used by freed buffer to use in adjacent buffer.
1058
Note, that we can't simply distribute memory evenly between all buffers,
1059
because new areas must not overlap with old ones.
1061
@param[in] queue list of non-empty buffers, without freed buffer
1062
@param[in] reuse empty buffer
1063
@param[in] key_length key length
1066
void reuse_freed_buff(QUEUE *queue, BUFFPEK *reuse, uint32_t key_length)
1094
qsort2_cmp key_compare;
1095
void *key_compare_arg;
1097
compare_functor(qsort2_cmp in_key_compare, void *in_compare_arg)
1098
: key_compare(in_key_compare), key_compare_arg(in_compare_arg) { }
1099
inline bool operator()(const BUFFPEK *i, const BUFFPEK *j) const
1068
unsigned char *reuse_end= reuse->base + reuse->max_keys * key_length;
1069
for (uint32_t i= 0; i < queue->elements; ++i)
1101
int val= key_compare(key_compare_arg,
1071
BUFFPEK *bp= (BUFFPEK *) queue_element(queue, i);
1072
if (bp->base + bp->max_keys * key_length == reuse->base)
1074
bp->max_keys+= reuse->max_keys;
1077
else if (bp->base == reuse_end)
1079
bp->base= reuse->base;
1080
bp->max_keys+= reuse->max_keys;
1171
cmp= internal::get_ptr_compare(sort_length);
1152
cmp= get_ptr_compare(sort_length);
1172
1153
first_cmp_arg= (void*) &sort_length;
1174
priority_queue<BUFFPEK *, vector<BUFFPEK *>, compare_functor >
1175
queue(compare_functor(cmp, first_cmp_arg));
1155
if (init_queue(&queue, (uint32_t) (Tb-Fb)+1, offsetof(BUFFPEK,key), 0,
1156
(queue_compare) cmp, first_cmp_arg))
1157
return(1); /* purecov: inspected */
1176
1158
for (buffpek= Fb ; buffpek <= Tb ; buffpek++)
1178
1160
buffpek->base= strpos;
1195
1177
This is safe as we know that there is always more than one element
1196
1178
in each block to merge (This is guaranteed by the Unique:: algorithm
1198
buffpek= queue.top();
1180
buffpek= (BUFFPEK*) queue_top(&queue);
1199
1181
memcpy(param->unique_buff, buffpek->key, rec_length);
1200
1182
if (my_b_write(to_file, (unsigned char*) buffpek->key, rec_length))
1184
error=1; goto err; /* purecov: inspected */
1204
1186
buffpek->key+= rec_length;
1205
1187
buffpek->mem_count--;
1206
1188
if (!--max_rows)
1190
error= 0; /* purecov: inspected */
1191
goto end; /* purecov: inspected */
1211
/* Top element has been used */
1213
queue.push(buffpek);
1193
queue_replaced(&queue); // Top element has been used
1216
1196
cmp= 0; // Not unique
1218
while (queue.size() > 1)
1198
while (queue.elements > 1)
1202
error= 1; goto err; /* purecov: inspected */
1226
buffpek= queue.top();
1206
buffpek= (BUFFPEK*) queue_top(&queue);
1227
1207
if (cmp) // Remove duplicates
1229
1209
if (!(*cmp)(first_cmp_arg, &(param->unique_buff),