~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/filesort.cc

  • Committer: Monty Taylor
  • Date: 2009-08-12 06:25:19 UTC
  • mto: (1114.1.1 innodb-plugin-merge)
  • mto: This revision was merged to the branch mainline in revision 1183.
  • Revision ID: mordred@inaugust.com-20090812062519-cij02mrrunvnxblt
Tags: innodb-plugin-1.0.4
InnoDB Plugin 1.0.4

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* Copyright (C) 2000-2006 MySQL AB
 
1
/* Copyright (C) 2000-2006 MySQL AB  
2
2
 
3
3
   This program is free software; you can redistribute it and/or modify
4
4
   it under the terms of the GNU General Public License as published by
11
11
 
12
12
   You should have received a copy of the GNU General Public License
13
13
   along with this program; if not, write to the Free Software
14
 
   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */
 
14
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
15
15
 
16
16
 
17
17
/**
21
21
  Sorts a database
22
22
*/
23
23
 
24
 
#include "config.h"
25
 
 
26
 
#include <float.h>
27
 
#include <limits.h>
28
 
 
29
 
#include <queue>
30
 
#include <algorithm>
31
 
#include <iostream>
32
 
 
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"
49
 
 
50
 
 
51
 
using namespace std;
52
 
 
53
 
namespace drizzled
54
 
{
55
 
 
56
 
/* Defines used by filesort and uniques */
57
 
#define MERGEBUFF               7
58
 
#define MERGEBUFF2              15
59
 
 
60
 
class BufferCompareContext
61
 
{
62
 
public:
63
 
  qsort_cmp2 key_compare;
64
 
  void *key_compare_arg;
65
 
 
66
 
  BufferCompareContext() :
67
 
    key_compare(0),
68
 
    key_compare_arg(0)
69
 
  { }
70
 
 
71
 
};
72
 
 
73
 
class SortParam {
74
 
public:
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;
84
 
  SortField *end;
85
 
  sort_addon_field *addon_field; /* Descriptors for companion fields */
86
 
  unsigned char *unique_buff;
87
 
  bool not_killable;
88
 
  char *tmp_buffer;
89
 
  /* The fields below are used only by Unique class */
90
 
  qsort2_cmp compare;
91
 
  BufferCompareContext cmp_context;
92
 
 
93
 
  SortParam() :
94
 
    rec_length(0),
95
 
    sort_length(0),
96
 
    ref_length(0),
97
 
    addon_length(0),
98
 
    res_length(0),
99
 
    keys(0),
100
 
    max_rows(0),
101
 
    examined_rows(0),
102
 
    sort_form(0),
103
 
    local_sortorder(0),
104
 
    end(0),
105
 
    addon_field(0),
106
 
    unique_buff(0),
107
 
    not_killable(0),
108
 
    tmp_buffer(0),
109
 
    compare(0)
110
 
  {
111
 
  }
112
 
 
113
 
  ~SortParam()
114
 
  {
115
 
    if (tmp_buffer)
116
 
      free(tmp_buffer);
117
 
  }
118
 
 
119
 
  int write_keys(unsigned char * *sort_keys,
120
 
                 uint32_t count,
121
 
                 internal::IO_CACHE *buffer_file,
122
 
                 internal::IO_CACHE *tempfile);
123
 
 
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,
128
 
                  uint32_t count,
129
 
                  filesort_info *table_sort);
130
 
 
131
 
};
 
24
#include <drizzled/server_includes.h>
 
25
#include <drizzled/sql_sort.h>
 
26
#include <drizzled/error.h>
 
27
#include <drizzled/probes.h>
 
28
#include <drizzled/session.h>
 
29
#include <drizzled/table.h>
 
30
#include <drizzled/table_list.h>
132
31
 
133
32
/* functions defined in this file */
134
33
 
135
34
static char **make_char_array(char **old_pos, register uint32_t fields,
136
 
                              uint32_t length);
137
 
 
138
 
static unsigned char *read_buffpek_from_file(internal::IO_CACHE *buffer_file,
139
 
                                             uint32_t count,
140
 
                                             unsigned char *buf);
141
 
 
 
35
                              uint32_t length, myf my_flag);
 
36
static unsigned char *read_buffpek_from_file(IO_CACHE *buffer_file, uint32_t count,
 
37
                                     unsigned char *buf);
 
38
static ha_rows find_all_keys(SORTPARAM *param,SQL_SELECT *select,
 
39
                             unsigned char * *sort_keys, IO_CACHE *buffer_file,
 
40
                             IO_CACHE *tempfile,IO_CACHE *indexfile);
 
41
static int write_keys(SORTPARAM *param,unsigned char * *sort_keys,
 
42
                      uint32_t count, IO_CACHE *buffer_file, IO_CACHE *tempfile);
 
43
static void make_sortkey(SORTPARAM *param,unsigned char *to, unsigned char *ref_pos);
 
44
static void register_used_fields(SORTPARAM *param);
 
45
static int merge_index(SORTPARAM *param,unsigned char *sort_buffer,
 
46
                       BUFFPEK *buffpek,
 
47
                       uint32_t maxbuffer,IO_CACHE *tempfile,
 
48
                       IO_CACHE *outfile);
 
49
static bool save_index(SORTPARAM *param,unsigned char **sort_keys, uint32_t count, 
 
50
                       filesort_info_st *table_sort);
142
51
static uint32_t suffix_length(uint32_t string_length);
143
 
static void unpack_addon_fields(sort_addon_field *addon_field,
 
52
static uint32_t sortlength(Session *session, SORT_FIELD *sortorder, uint32_t s_length,
 
53
                       bool *multi_byte_charset);
 
54
static SORT_ADDON_FIELD *get_addon_fields(Session *session, Field **ptabfield,
 
55
                                          uint32_t sortlength, uint32_t *plength);
 
56
static void unpack_addon_fields(struct st_sort_addon_field *addon_field,
144
57
                                unsigned char *buff);
145
 
 
146
 
FileSort::FileSort(Session &arg) :
147
 
  _session(arg)
148
 
149
 
}
150
 
 
151
58
/**
152
59
  Sort a table.
153
60
  Creates a set of pointers that can be used to read the rows
160
67
  The result set is stored in table->io_cache or
161
68
  table->record_pointers.
162
69
 
 
70
  @param session           Current thread
163
71
  @param table          Table to sort
164
72
  @param sortorder      How to sort the table
165
73
  @param s_length       Number of elements in sortorder
183
91
    examined_rows       will be set to number of examined rows
184
92
*/
185
93
 
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)
 
94
ha_rows filesort(Session *session, Table *table, SORT_FIELD *sortorder, uint32_t s_length,
 
95
                 SQL_SELECT *select, ha_rows max_rows,
 
96
                 bool sort_positions, ha_rows *examined_rows)
189
97
{
190
 
  int error= 1;
191
 
  uint32_t memavl= 0, min_sort_memory;
 
98
  int error;
 
99
  uint32_t memavl, min_sort_memory;
192
100
  uint32_t maxbuffer;
193
 
  size_t allocated_sort_memory= 0;
194
 
  buffpek *buffpek_inst= 0;
 
101
  BUFFPEK *buffpek;
195
102
  ha_rows records= HA_POS_ERROR;
196
103
  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;
201
 
  SortParam param;
 
104
  IO_CACHE tempfile, buffpek_pointers, *selected_records_file, *outfile; 
 
105
  SORTPARAM param;
202
106
  bool multi_byte_charset;
203
107
 
204
 
  /*
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.
208
 
  */
209
 
  filesort_info table_sort(table->sort);
210
 
  table->sort.io_cache= NULL;
211
 
 
 
108
  filesort_info_st table_sort;
212
109
  TableList *tab= table->pos_in_table_list;
213
110
  Item_subselect *subselect= tab ? tab->containing_subselect() : 0;
214
111
 
215
 
  DRIZZLE_FILESORT_START(table->getShare()->getSchemaName(), table->getShare()->getTableName());
 
112
  DRIZZLE_FILESORT_START();
216
113
 
217
114
  /*
218
115
   Release InnoDB's adaptive hash index latch (if holding) before
219
116
   running a sort.
220
117
  */
221
 
  plugin::TransactionalStorageEngine::releaseTemporaryLatches(&getSession());
222
 
 
223
 
 
 
118
  ha_release_temporary_latches(session);
 
119
 
 
120
  /* 
 
121
    Don't use table->sort in filesort as it is also used by 
 
122
    QUICK_INDEX_MERGE_SELECT. Work with a copy and put it back at the end 
 
123
    when index_merge select has finished with it.
 
124
  */
 
125
  memcpy(&table_sort, &table->sort, sizeof(filesort_info_st));
 
126
  table->sort.io_cache= NULL;
 
127
  
224
128
  outfile= table_sort.io_cache;
225
 
  assert(tempfile.buffer == 0);
226
 
  assert(buffpek_pointers.buffer == 0);
227
 
 
228
 
  param.sort_length= sortlength(sortorder, s_length, &multi_byte_charset);
229
 
  param.ref_length= table->cursor->ref_length;
230
 
 
231
 
  if (!(table->cursor->getEngine()->check_flag(HTON_BIT_FAST_KEY_READ)) && !sort_positions)
 
129
  my_b_clear(&tempfile);
 
130
  my_b_clear(&buffpek_pointers);
 
131
  buffpek=0;
 
132
  error= 1;
 
133
  memset(&param, 0, sizeof(param));
 
134
  param.sort_length= sortlength(session, sortorder, s_length, &multi_byte_charset);
 
135
  param.ref_length= table->file->ref_length;
 
136
  param.addon_field= 0;
 
137
  param.addon_length= 0;
 
138
  if (!(table->file->ha_table_flags() & HA_FAST_KEY_READ) && !sort_positions)
232
139
  {
233
 
    /*
234
 
      Get the descriptors of all fields whose values are appended
 
140
    /* 
 
141
      Get the descriptors of all fields whose values are appended 
235
142
      to sorted fields and get its total length in param.spack_length.
236
143
    */
237
 
    param.addon_field= get_addon_fields(table->getFields(),
 
144
    param.addon_field= get_addon_fields(session, table->field, 
238
145
                                        param.sort_length,
239
146
                                        &param.addon_length);
240
147
  }
246
153
  if (param.addon_field)
247
154
  {
248
155
    param.res_length= param.addon_length;
249
 
    if (!(table_sort.addon_buf= (unsigned char *) malloc(param.addon_length)))
250
 
    {
 
156
    if (!(table_sort.addon_buf= (unsigned char *) my_malloc(param.addon_length,
 
157
                                                    MYF(MY_WME))))
251
158
      goto err;
252
 
    }
253
159
  }
254
160
  else
255
161
  {
256
162
    param.res_length= param.ref_length;
257
 
    /*
258
 
      The reference to the record is considered
 
163
    /* 
 
164
      The reference to the record is considered 
259
165
      as an additional sorted field
260
166
    */
261
167
    param.sort_length+= param.ref_length;
265
171
 
266
172
  if (select && select->quick)
267
173
  {
268
 
    getSession().status_var.filesort_range_count++;
 
174
    status_var_increment(session->status_var.filesort_range_count);
269
175
  }
270
176
  else
271
177
  {
272
 
    getSession().status_var.filesort_scan_count++;
 
178
    status_var_increment(session->status_var.filesort_scan_count);
273
179
  }
274
180
#ifdef CAN_TRUST_RANGE
275
181
  if (select && select->quick && select->quick->records > 0L)
276
182
  {
277
 
    records= min((ha_rows) (select->quick->records*2+EXTRA_RECORDS*2),
278
 
                 table->cursor->stats.records)+EXTRA_RECORDS;
 
183
    records=cmin((ha_rows) (select->quick->records*2+EXTRA_RECORDS*2),
 
184
                table->file->stats.records)+EXTRA_RECORDS;
279
185
    selected_records_file=0;
280
186
  }
281
187
  else
282
188
#endif
283
189
  {
284
 
    records= table->cursor->estimate_rows_upper_bound();
 
190
    records= table->file->estimate_rows_upper_bound();
285
191
    /*
286
 
      If number of records is not known, use as much of sort buffer
287
 
      as possible.
 
192
      If number of records is not known, use as much of sort buffer 
 
193
      as possible. 
288
194
    */
289
195
    if (records == HA_POS_ERROR)
290
196
      records--;  // we use 'records+1' below.
291
197
    selected_records_file= 0;
292
198
  }
293
199
 
294
 
  if (multi_byte_charset && !(param.tmp_buffer= (char*) malloc(param.sort_length)))
295
 
  {
 
200
  if (multi_byte_charset &&
 
201
      !(param.tmp_buffer= (char*) my_malloc(param.sort_length,MYF(MY_WME))))
296
202
    goto err;
297
 
  }
298
203
 
299
 
  memavl= getSession().variables.sortbuff_size;
300
 
  min_sort_memory= max((uint32_t)MIN_SORT_MEMORY, param.sort_length*MERGEBUFF2);
 
204
  memavl= session->variables.sortbuff_size;
 
205
  min_sort_memory= cmax((uint32_t)MIN_SORT_MEMORY, param.sort_length*MERGEBUFF2);
301
206
  while (memavl >= min_sort_memory)
302
207
  {
303
208
    uint32_t old_memavl;
304
209
    uint32_t keys= memavl/(param.rec_length+sizeof(char*));
305
 
    param.keys= (uint32_t) min(records+1, (ha_rows)keys);
306
 
 
307
 
    allocated_sort_memory= param.keys * param.rec_length;
308
 
    if (not global_sort_buffer.add(allocated_sort_memory))
309
 
    {
310
 
      my_error(ER_OUT_OF_GLOBAL_SORTMEMORY, MYF(ME_ERROR+ME_WAITTANG));
311
 
      goto err;
312
 
    }
313
 
 
 
210
    param.keys=(uint32_t) cmin(records+1, keys);
314
211
    if ((table_sort.sort_keys=
315
212
         (unsigned char **) make_char_array((char **) table_sort.sort_keys,
316
 
                                            param.keys, param.rec_length)))
 
213
                                    param.keys, param.rec_length, MYF(0))))
317
214
      break;
318
 
 
319
 
    global_sort_buffer.sub(allocated_sort_memory);
320
 
    old_memavl= memavl;
321
 
    if ((memavl= memavl/4*3) < min_sort_memory && old_memavl > min_sort_memory)
 
215
    old_memavl=memavl;
 
216
    if ((memavl=memavl/4*3) < min_sort_memory && old_memavl > min_sort_memory)
322
217
      memavl= min_sort_memory;
323
218
  }
324
219
  sort_keys= table_sort.sort_keys;
327
222
    my_error(ER_OUT_OF_SORTMEMORY,MYF(ME_ERROR+ME_WAITTANG));
328
223
    goto err;
329
224
  }
330
 
 
331
 
  if (buffpek_pointers.open_cached_file(drizzle_tmpdir.c_str(),TEMP_PREFIX, DISK_BUFFER_SIZE, MYF(MY_WME)))
332
 
  {
 
225
  if (open_cached_file(&buffpek_pointers,drizzle_tmpdir,TEMP_PREFIX,
 
226
                       DISK_BUFFER_SIZE, MYF(MY_WME)))
333
227
    goto err;
334
 
  }
335
228
 
336
229
  param.keys--;                         /* TODO: check why we do this */
337
230
  param.sort_form= table;
338
231
  param.end=(param.local_sortorder=sortorder)+s_length;
339
 
  if ((records= find_all_keys(&param,select,sort_keys, &buffpek_pointers,
340
 
                              &tempfile, selected_records_file)) == HA_POS_ERROR)
341
 
  {
 
232
  if ((records=find_all_keys(&param,select,sort_keys, &buffpek_pointers,
 
233
                             &tempfile, selected_records_file)) ==
 
234
      HA_POS_ERROR)
342
235
    goto err;
343
 
  }
344
 
  maxbuffer= (uint32_t) (my_b_tell(&buffpek_pointers)/sizeof(*buffpek_inst));
 
236
  maxbuffer= (uint32_t) (my_b_tell(&buffpek_pointers)/sizeof(*buffpek));
345
237
 
346
238
  if (maxbuffer == 0)                   // The whole set is in memory
347
239
  {
348
 
    if (param.save_index(sort_keys,(uint32_t) records, &table_sort))
349
 
    {
 
240
    if (save_index(&param,sort_keys,(uint32_t) records, &table_sort))
350
241
      goto err;
351
 
    }
352
242
  }
353
243
  else
354
244
  {
356
246
    {
357
247
      if (table_sort.buffpek)
358
248
        free(table_sort.buffpek);
359
 
      table_sort.buffpek = 0;
 
249
      table_sort.buffpek= 0;
360
250
    }
361
251
    if (!(table_sort.buffpek=
362
 
          (unsigned char *) read_buffpek_from_file(&buffpek_pointers, maxbuffer, table_sort.buffpek)))
363
 
    {
 
252
          (unsigned char *) read_buffpek_from_file(&buffpek_pointers, maxbuffer,
 
253
                                 table_sort.buffpek)))
364
254
      goto err;
365
 
    }
366
 
    buffpek_inst= (buffpek *) table_sort.buffpek;
 
255
    buffpek= (BUFFPEK *) table_sort.buffpek;
367
256
    table_sort.buffpek_len= maxbuffer;
368
 
    buffpek_pointers.close_cached_file();
 
257
    close_cached_file(&buffpek_pointers);
369
258
        /* 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)))
371
 
    {
372
 
      goto err;
373
 
    }
374
 
 
375
 
    if (outfile->reinit_io_cache(internal::WRITE_CACHE,0L,0,0))
376
 
    {
377
 
      goto err;
378
 
    }
 
259
    if (! my_b_inited(outfile) &&
 
260
        open_cached_file(outfile,drizzle_tmpdir,TEMP_PREFIX,READ_RECORD_BUFFER,
 
261
                          MYF(MY_WME)))
 
262
      goto err;
 
263
    if (reinit_io_cache(outfile,WRITE_CACHE,0L,0,0))
 
264
      goto err;
379
265
 
380
266
    /*
381
267
      Use also the space previously used by string pointers in sort_buffer
382
268
      for temporary key storage.
383
269
    */
384
 
    param.keys=((param.keys*(param.rec_length+sizeof(char*))) / param.rec_length-1);
385
 
 
 
270
    param.keys=((param.keys*(param.rec_length+sizeof(char*))) /
 
271
                param.rec_length-1);
386
272
    maxbuffer--;                                // Offset from 0
387
 
    if (merge_many_buff(&param,(unsigned char*) sort_keys,buffpek_inst,&maxbuffer, &tempfile))
388
 
    {
389
 
      goto err;
390
 
    }
391
 
 
392
 
    if (flush_io_cache(&tempfile) || tempfile.reinit_io_cache(internal::READ_CACHE,0L,0,0))
393
 
    {
394
 
      goto err;
395
 
    }
396
 
 
397
 
    if (merge_index(&param,(unsigned char*) sort_keys,buffpek_inst,maxbuffer,&tempfile, outfile))
398
 
    {
399
 
      goto err;
400
 
    }
 
273
    if (merge_many_buff(&param,(unsigned char*) sort_keys,buffpek,&maxbuffer,
 
274
                        &tempfile))
 
275
      goto err;
 
276
    if (flush_io_cache(&tempfile) ||
 
277
        reinit_io_cache(&tempfile,READ_CACHE,0L,0,0))
 
278
      goto err;
 
279
    if (merge_index(&param,(unsigned char*) sort_keys,buffpek,maxbuffer,&tempfile,
 
280
                    outfile))
 
281
      goto err;
401
282
  }
402
 
 
403
283
  if (records > param.max_rows)
404
 
  {
405
 
    records= param.max_rows;
406
 
  }
 
284
    records=param.max_rows;
407
285
  error =0;
408
286
 
409
287
 err:
410
 
  if (not subselect || not subselect->is_uncacheable())
 
288
  if (param.tmp_buffer)
 
289
    if (param.tmp_buffer)
 
290
      free(param.tmp_buffer);
 
291
  if (!subselect || !subselect->is_uncacheable())
411
292
  {
412
 
    free(sort_keys);
 
293
    if ((unsigned char*) sort_keys)
 
294
      free((unsigned char*) sort_keys);
413
295
    table_sort.sort_keys= 0;
414
 
    free(buffpek_inst);
 
296
    if ((unsigned char*) buffpek)
 
297
      free((unsigned char*) buffpek);
415
298
    table_sort.buffpek= 0;
416
299
    table_sort.buffpek_len= 0;
417
300
  }
418
 
 
419
 
  tempfile.close_cached_file();
420
 
  buffpek_pointers.close_cached_file();
421
 
 
 
301
  close_cached_file(&tempfile);
 
302
  close_cached_file(&buffpek_pointers);
422
303
  if (my_b_inited(outfile))
423
304
  {
424
305
    if (flush_io_cache(outfile))
425
 
    {
426
306
      error=1;
427
 
    }
428
307
    {
429
 
      internal::my_off_t save_pos= outfile->pos_in_file;
 
308
      my_off_t save_pos=outfile->pos_in_file;
430
309
      /* For following reads */
431
 
      if (outfile->reinit_io_cache(internal::READ_CACHE,0L,0,0))
432
 
      {
 
310
      if (reinit_io_cache(outfile,READ_CACHE,0L,0,0))
433
311
        error=1;
434
 
      }
435
312
      outfile->end_of_file=save_pos;
436
313
    }
437
314
  }
438
 
 
439
315
  if (error)
440
 
  {
441
316
    my_message(ER_FILSORT_ABORT, ER(ER_FILSORT_ABORT),
442
317
               MYF(ME_ERROR+ME_WAITTANG));
443
 
  }
444
318
  else
445
 
  {
446
 
    getSession().status_var.filesort_rows+= (uint32_t) records;
447
 
  }
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);
 
319
    statistic_add(session->status_var.filesort_rows,
 
320
                  (uint32_t) records, &LOCK_status);
 
321
  *examined_rows= param.examined_rows;
 
322
  memcpy(&table->sort, &table_sort, sizeof(filesort_info_st));
 
323
  DRIZZLE_FILESORT_END();
 
324
  return(error ? HA_POS_ERROR : records);
453
325
} /* filesort */
454
326
 
 
327
 
 
328
void filesort_free_buffers(Table *table, bool full)
 
329
{
 
330
  if (table->sort.record_pointers)
 
331
  {
 
332
    free((unsigned char*) table->sort.record_pointers);
 
333
    table->sort.record_pointers=0;
 
334
  }
 
335
  if (full)
 
336
  {
 
337
    if (table->sort.sort_keys )
 
338
    {
 
339
      if ((unsigned char*) table->sort.sort_keys)
 
340
        free((unsigned char*) table->sort.sort_keys);
 
341
      table->sort.sort_keys= 0;
 
342
    }
 
343
    if (table->sort.buffpek)
 
344
    {
 
345
      if ((unsigned char*) table->sort.buffpek)
 
346
        free((unsigned char*) table->sort.buffpek);
 
347
      table->sort.buffpek= 0;
 
348
      table->sort.buffpek_len= 0;
 
349
    }
 
350
  }
 
351
  if (table->sort.addon_buf)
 
352
  {
 
353
    free((char *) table->sort.addon_buf);
 
354
    free((char *) table->sort.addon_field);
 
355
    table->sort.addon_buf=0;
 
356
    table->sort.addon_field=0;
 
357
  }
 
358
}
 
359
 
455
360
/** Make a array of string pointers. */
456
361
 
457
362
static char **make_char_array(char **old_pos, register uint32_t fields,
458
 
                              uint32_t length)
 
363
                              uint32_t length, myf my_flag)
459
364
{
460
365
  register char **pos;
461
366
  char *char_pos;
462
367
 
463
368
  if (old_pos ||
464
 
      (old_pos= (char**) malloc((uint32_t) fields*(length+sizeof(char*)))))
 
369
      (old_pos= (char**) my_malloc((uint32_t) fields*(length+sizeof(char*)),
 
370
                                   my_flag)))
465
371
  {
466
372
    pos=old_pos; char_pos=((char*) (pos+fields)) -length;
467
373
    while (fields--) *(pos++) = (char_pos+= length);
473
379
 
474
380
/** Read 'count' number of buffer pointers into memory. */
475
381
 
476
 
static unsigned char *read_buffpek_from_file(internal::IO_CACHE *buffpek_pointers, uint32_t count,
 
382
static unsigned char *read_buffpek_from_file(IO_CACHE *buffpek_pointers, uint32_t count,
477
383
                                     unsigned char *buf)
478
384
{
479
 
  uint32_t length= sizeof(buffpek)*count;
 
385
  uint32_t length= sizeof(BUFFPEK)*count;
480
386
  unsigned char *tmp= buf;
481
 
  if (count > UINT_MAX/sizeof(buffpek))
482
 
    return 0; /* sizeof(buffpek)*count will overflow */
 
387
  if (count > UINT_MAX/sizeof(BUFFPEK))
 
388
    return 0; /* sizeof(BUFFPEK)*count will overflow */
483
389
  if (!tmp)
484
 
    tmp= (unsigned char *)malloc(length);
 
390
    tmp= (unsigned char *)my_malloc(length, MYF(MY_WME));
485
391
  if (tmp)
486
392
  {
487
 
    if (buffpek_pointers->reinit_io_cache(internal::READ_CACHE,0L,0,0) ||
 
393
    if (reinit_io_cache(buffpek_pointers,READ_CACHE,0L,0,0) ||
488
394
        my_b_read(buffpek_pointers, (unsigned char*) tmp, length))
489
395
    {
490
396
      free((char*) tmp);
502
408
  @param param             Sorting parameter
503
409
  @param select            Use this to get source data
504
410
  @param sort_keys         Array of pointers to sort key + addon buffers.
505
 
  @param buffpek_pointers  File to write buffpeks describing sorted segments
 
411
  @param buffpek_pointers  File to write BUFFPEKs describing sorted segments
506
412
                           in tempfile.
507
413
  @param tempfile          File to write sorted sequences of sortkeys to.
508
414
  @param indexfile         If !NULL, use it for source data (contains rowids)
516
422
       {
517
423
         sort sort_keys buffer;
518
424
         dump sorted sequence to 'tempfile';
519
 
         dump buffpek describing sequence location into 'buffpek_pointers';
 
425
         dump BUFFPEK describing sequence location into 'buffpek_pointers';
520
426
       }
521
427
       put sort key into 'sort_keys';
522
428
     }
532
438
    HA_POS_ERROR on error.
533
439
*/
534
440
 
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)
 
441
static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select,
 
442
                             unsigned char **sort_keys,
 
443
                             IO_CACHE *buffpek_pointers,
 
444
                             IO_CACHE *tempfile, IO_CACHE *indexfile)
540
445
{
541
446
  int error,flag,quick_select;
542
447
  uint32_t idx,indexpos,ref_length;
543
448
  unsigned char *ref_pos,*next_pos,ref_buff[MAX_REFLENGTH];
544
 
  internal::my_off_t record;
 
449
  my_off_t record;
545
450
  Table *sort_form;
546
 
  volatile Session::killed_state_t *killed= getSession().getKilledPtr();
547
 
  Cursor *file;
548
 
  boost::dynamic_bitset<> *save_read_set= NULL;
549
 
  boost::dynamic_bitset<> *save_write_set= NULL;
 
451
  Session *session= current_session;
 
452
  volatile Session::killed_state *killed= &session->killed;
 
453
  handler *file;
 
454
  MY_BITMAP *save_read_set, *save_write_set;
550
455
 
551
456
  idx=indexpos=0;
552
457
  error=quick_select=0;
553
458
  sort_form=param->sort_form;
554
 
  file= sort_form->cursor;
 
459
  file=sort_form->file;
555
460
  ref_length=param->ref_length;
556
461
  ref_pos= ref_buff;
557
462
  quick_select=select && select->quick;
558
463
  record=0;
559
 
  flag= ((!indexfile && ! file->isOrdered())
 
464
  flag= ((!indexfile && file->ha_table_flags() & HA_REC_NOT_IN_SEQ)
560
465
         || quick_select);
561
466
  if (indexfile || flag)
562
467
    ref_pos= &file->ref[0];
564
469
  if (! indexfile && ! quick_select)
565
470
  {
566
471
    next_pos=(unsigned char*) 0;                        /* Find records in sequence */
567
 
    if (file->startTableScan(1))
568
 
      return(HA_POS_ERROR);
569
 
    file->extra_opt(HA_EXTRA_CACHE, getSession().variables.read_buff_size);
 
472
    file->ha_rnd_init(1);
 
473
    file->extra_opt(HA_EXTRA_CACHE,
 
474
                    current_session->variables.read_buff_size);
570
475
  }
571
476
 
572
 
  ReadRecord read_record_info;
 
477
  READ_RECORD read_record_info;
573
478
  if (quick_select)
574
479
  {
575
480
    if (select->quick->reset())
576
481
      return(HA_POS_ERROR);
577
 
 
578
 
    if (read_record_info.init_read_record(&getSession(), select->quick->head, select, 1, 1))
579
 
      return(HA_POS_ERROR);
 
482
    init_read_record(&read_record_info, current_session, select->quick->head,
 
483
                     select, 1, 1);
580
484
  }
581
485
 
582
486
  /* Remember original bitmaps */
583
487
  save_read_set=  sort_form->read_set;
584
488
  save_write_set= sort_form->write_set;
585
489
  /* Set up temporary column read map for columns used by sort */
586
 
  sort_form->tmp_set.reset();
 
490
  bitmap_clear_all(&sort_form->tmp_set);
587
491
  /* Temporary set for register_used_fields and register_field_in_read_map */
588
492
  sort_form->read_set= &sort_form->tmp_set;
589
 
  param->register_used_fields();
 
493
  register_used_fields(param);
590
494
  if (select && select->cond)
591
495
    select->cond->walk(&Item::register_field_in_read_map, 1,
592
496
                       (unsigned char*) sort_form);
593
 
  sort_form->column_bitmaps_set(sort_form->tmp_set, sort_form->tmp_set);
 
497
  sort_form->column_bitmaps_set(&sort_form->tmp_set, &sort_form->tmp_set);
594
498
 
595
499
  for (;;)
596
500
  {
601
505
        error= HA_ERR_END_OF_FILE;
602
506
        break;
603
507
      }
604
 
      file->position(sort_form->getInsertRecord());
 
508
      file->position(sort_form->record[0]);
605
509
    }
606
510
    else                                        /* Not quick-select */
607
511
    {
608
512
      if (indexfile)
609
513
      {
610
 
        if (my_b_read(indexfile,(unsigned char*) ref_pos,ref_length))
 
514
        if (my_b_read(indexfile,(unsigned char*) ref_pos,ref_length)) /* purecov: deadcode */
611
515
        {
612
 
          error= errno ? errno : -1;            /* Abort */
 
516
          error= my_errno ? my_errno : -1;              /* Abort */
613
517
          break;
614
518
        }
615
 
        error=file->rnd_pos(sort_form->getInsertRecord(),next_pos);
 
519
        error=file->rnd_pos(sort_form->record[0],next_pos);
616
520
      }
617
521
      else
618
522
      {
619
 
        error=file->rnd_next(sort_form->getInsertRecord());
 
523
        error=file->rnd_next(sort_form->record[0]);
 
524
        if (!error)
 
525
          update_virtual_fields_marked_for_write(sort_form);
620
526
 
621
527
        if (!flag)
622
528
        {
623
 
          internal::my_store_ptr(ref_pos,ref_length,record); // Position to row
624
 
          record+= sort_form->getShare()->db_record_offset;
 
529
          my_store_ptr(ref_pos,ref_length,record); // Position to row
 
530
          record+= sort_form->s->db_record_offset;
625
531
        }
626
532
        else if (!error)
627
 
          file->position(sort_form->getInsertRecord());
 
533
          file->position(sort_form->record[0]);
628
534
      }
629
535
      if (error && error != HA_ERR_RECORD_DELETED)
630
536
        break;
635
541
      if (!indexfile && !quick_select)
636
542
      {
637
543
        (void) file->extra(HA_EXTRA_NO_CACHE);
638
 
        file->endTableScan();
 
544
        file->ha_rnd_end();
639
545
      }
640
 
      return(HA_POS_ERROR);
 
546
      return(HA_POS_ERROR);             /* purecov: inspected */
641
547
    }
642
548
    if (error == 0)
643
549
      param->examined_rows++;
645
551
    {
646
552
      if (idx == param->keys)
647
553
      {
648
 
        if (param->write_keys(sort_keys, idx, buffpek_pointers, tempfile))
 
554
        if (write_keys(param,sort_keys,idx,buffpek_pointers,tempfile))
649
555
          return(HA_POS_ERROR);
650
556
        idx=0;
651
557
        indexpos++;
652
558
      }
653
 
      param->make_sortkey(sort_keys[idx++], ref_pos);
 
559
      make_sortkey(param,sort_keys[idx++],ref_pos);
654
560
    }
655
561
    else
656
 
    {
657
562
      file->unlock_row();
658
 
    }
659
 
 
660
563
    /* It does not make sense to read more keys in case of a fatal error */
661
 
    if (getSession().is_error())
 
564
    if (session->is_error())
662
565
      break;
663
566
  }
664
567
  if (quick_select)
667
570
      index_merge quick select uses table->sort when retrieving rows, so free
668
571
      resoures it has allocated.
669
572
    */
670
 
    read_record_info.end_read_record();
 
573
    end_read_record(&read_record_info);
671
574
  }
672
575
  else
673
576
  {
674
577
    (void) file->extra(HA_EXTRA_NO_CACHE);      /* End cacheing of records */
675
578
    if (!next_pos)
676
 
      file->endTableScan();
 
579
      file->ha_rnd_end();
677
580
  }
678
581
 
679
 
  if (getSession().is_error())
 
582
  if (session->is_error())
680
583
    return(HA_POS_ERROR);
681
 
 
 
584
  
682
585
  /* Signal we should use orignal column read and write maps */
683
 
  sort_form->column_bitmaps_set(*save_read_set, *save_write_set);
 
586
  sort_form->column_bitmaps_set(save_read_set, save_write_set);
684
587
 
685
588
  if (error != HA_ERR_END_OF_FILE)
686
589
  {
687
 
    sort_form->print_error(error,MYF(ME_ERROR | ME_WAITTANG));
688
 
    return(HA_POS_ERROR);
689
 
  }
690
 
 
691
 
  if (indexpos && idx && param->write_keys(sort_keys,idx,buffpek_pointers,tempfile))
692
 
  {
693
 
    return(HA_POS_ERROR);
694
 
  }
695
 
 
 
590
    file->print_error(error,MYF(ME_ERROR | ME_WAITTANG)); /* purecov: inspected */
 
591
    return(HA_POS_ERROR);                       /* purecov: inspected */
 
592
  }
 
593
  if (indexpos && idx &&
 
594
      write_keys(param,sort_keys,idx,buffpek_pointers,tempfile))
 
595
    return(HA_POS_ERROR);                       /* purecov: inspected */
696
596
  return(my_b_inited(tempfile) ?
697
597
              (ha_rows) (my_b_tell(tempfile)/param->rec_length) :
698
598
              idx);
703
603
  @details
704
604
  Sort the buffer and write:
705
605
  -# the sorted sequence to tempfile
706
 
  -# a buffpek describing the sorted sequence position to buffpek_pointers
 
606
  -# a BUFFPEK describing the sorted sequence position to buffpek_pointers
707
607
 
708
608
    (was: Skriver en buffert med nycklar till filen)
709
609
 
710
610
  @param param             Sort parameters
711
611
  @param sort_keys         Array of pointers to keys to sort
712
612
  @param count             Number of elements in sort_keys array
713
 
  @param buffpek_pointers  One 'buffpek' struct will be written into this file.
714
 
                           The buffpek::{file_pos, count} will indicate where
 
613
  @param buffpek_pointers  One 'BUFFPEK' struct will be written into this file.
 
614
                           The BUFFPEK::{file_pos, count} will indicate where
715
615
                           the sorted data was stored.
716
616
  @param tempfile          The sorted sequence will be written into this file.
717
617
 
721
621
    1 Error
722
622
*/
723
623
 
724
 
int SortParam::write_keys(register unsigned char **sort_keys, uint32_t count,
725
 
                          internal::IO_CACHE *buffpek_pointers, internal::IO_CACHE *tempfile)
 
624
static int
 
625
write_keys(SORTPARAM *param, register unsigned char **sort_keys, uint32_t count,
 
626
           IO_CACHE *buffpek_pointers, IO_CACHE *tempfile)
726
627
{
727
 
  buffpek buffpek;
 
628
  size_t sort_length, rec_length;
 
629
  unsigned char **end;
 
630
  BUFFPEK buffpek;
728
631
 
729
 
  internal::my_string_ptr_sort((unsigned char*) sort_keys, (uint32_t) count, sort_length);
 
632
  sort_length= param->sort_length;
 
633
  rec_length= param->rec_length;
 
634
  my_string_ptr_sort((unsigned char*) sort_keys, (uint32_t) count, sort_length);
730
635
  if (!my_b_inited(tempfile) &&
731
 
      tempfile->open_cached_file(drizzle_tmpdir.c_str(), TEMP_PREFIX, DISK_BUFFER_SIZE, MYF(MY_WME)))
732
 
  {
733
 
    return 1;
734
 
  }
 
636
      open_cached_file(tempfile, drizzle_tmpdir, TEMP_PREFIX, DISK_BUFFER_SIZE,
 
637
                       MYF(MY_WME)))
 
638
    goto err;                                   /* purecov: inspected */
735
639
  /* check we won't have more buffpeks than we can possibly keep in memory */
736
 
  if (my_b_tell(buffpek_pointers) + sizeof(buffpek) > (uint64_t)UINT_MAX)
737
 
  {
738
 
    return 1;
739
 
  }
740
 
 
 
640
  if (my_b_tell(buffpek_pointers) + sizeof(BUFFPEK) > (uint64_t)UINT_MAX)
 
641
    goto err;
741
642
  buffpek.file_pos= my_b_tell(tempfile);
742
 
  if ((ha_rows) count > max_rows)
743
 
    count=(uint32_t) max_rows;
744
 
 
 
643
  if ((ha_rows) count > param->max_rows)
 
644
    count=(uint32_t) param->max_rows;               /* purecov: inspected */
745
645
  buffpek.count=(ha_rows) count;
746
 
 
747
 
  for (unsigned char **ptr= sort_keys + count ; sort_keys != ptr ; sort_keys++)
748
 
  {
 
646
  for (end=sort_keys+count ; sort_keys != end ; sort_keys++)
749
647
    if (my_b_write(tempfile, (unsigned char*) *sort_keys, (uint32_t) rec_length))
750
 
    {
751
 
      return 1;
752
 
    }
753
 
  }
754
 
 
 
648
      goto err;
755
649
  if (my_b_write(buffpek_pointers, (unsigned char*) &buffpek, sizeof(buffpek)))
756
 
  {
757
 
    return 1;
758
 
  }
 
650
    goto err;
 
651
  return(0);
759
652
 
760
 
  return 0;
 
653
err:
 
654
  return(1);
761
655
} /* write_keys */
762
656
 
763
657
 
786
680
 
787
681
/** Make a sort-key from record. */
788
682
 
789
 
void SortParam::make_sortkey(register unsigned char *to, unsigned char *ref_pos)
 
683
static void make_sortkey(register SORTPARAM *param,
 
684
                         register unsigned char *to, unsigned char *ref_pos)
790
685
{
791
 
  Field *field;
792
 
  SortField *sort_field;
793
 
  size_t length;
 
686
  register Field *field;
 
687
  register SORT_FIELD *sort_field;
 
688
  register uint32_t length;
794
689
 
795
 
  for (sort_field= local_sortorder ;
796
 
       sort_field != end ;
 
690
  for (sort_field=param->local_sortorder ;
 
691
       sort_field != param->end ;
797
692
       sort_field++)
798
693
  {
799
694
    bool maybe_null=0;
819
714
    {                                           // Item
820
715
      Item *item=sort_field->item;
821
716
      maybe_null= item->maybe_null;
822
 
 
823
717
      switch (sort_field->result_type) {
824
718
      case STRING_RESULT:
825
 
        {
826
 
          const CHARSET_INFO * const cs=item->collation.collation;
827
 
          char fill_char= ((cs->state & MY_CS_BINSORT) ? (char) 0 : ' ');
828
 
          int diff;
829
 
          uint32_t sort_field_length;
 
719
      {
 
720
        const CHARSET_INFO * const cs=item->collation.collation;
 
721
        char fill_char= ((cs->state & MY_CS_BINSORT) ? (char) 0 : ' ');
 
722
        int diff;
 
723
        uint32_t sort_field_length;
830
724
 
 
725
        if (maybe_null)
 
726
          *to++=1;
 
727
        /* All item->str() to use some extra byte for end null.. */
 
728
        String tmp((char*) to,sort_field->length+4,cs);
 
729
        String *res= item->str_result(&tmp);
 
730
        if (!res)
 
731
        {
831
732
          if (maybe_null)
832
 
            *to++=1;
833
 
          /* All item->str() to use some extra byte for end null.. */
834
 
          String tmp((char*) to,sort_field->length+4,cs);
835
 
          String *res= item->str_result(&tmp);
836
 
          if (!res)
837
 
          {
838
 
            if (maybe_null)
839
 
              memset(to-1, 0, sort_field->length+1);
840
 
            else
841
 
            {
842
 
              /*
843
 
                This should only happen during extreme conditions if we run out
844
 
                of memory or have an item marked not null when it can be null.
845
 
                This code is here mainly to avoid a hard crash in this case.
846
 
              */
847
 
              assert(0);
848
 
              memset(to, 0, sort_field->length);        // Avoid crash
849
 
            }
850
 
            break;
851
 
          }
852
 
          length= res->length();
853
 
          sort_field_length= sort_field->length - sort_field->suffix_length;
854
 
          diff=(int) (sort_field_length - length);
855
 
          if (diff < 0)
856
 
          {
857
 
            diff=0;
858
 
            length= sort_field_length;
859
 
          }
860
 
          if (sort_field->suffix_length)
861
 
          {
862
 
            /* Store length last in result_string */
863
 
            store_length(to + sort_field_length, length,
864
 
                         sort_field->suffix_length);
865
 
          }
866
 
          if (sort_field->need_strxnfrm)
867
 
          {
868
 
            char *from=(char*) res->ptr();
869
 
            uint32_t tmp_length;
870
 
            if ((unsigned char*) from == to)
871
 
            {
872
 
              set_if_smaller(length,sort_field->length);
873
 
              memcpy(tmp_buffer,from,length);
874
 
              from= tmp_buffer;
875
 
            }
876
 
            tmp_length= my_strnxfrm(cs,to,sort_field->length,
877
 
                                    (unsigned char*) from, length);
878
 
            assert(tmp_length == sort_field->length);
879
 
          }
 
733
            memset(to-1, 0, sort_field->length+1);
880
734
          else
881
735
          {
882
 
            my_strnxfrm(cs,(unsigned char*)to,length,(const unsigned char*)res->ptr(),length);
883
 
            cs->cset->fill(cs, (char *)to+length,diff,fill_char);
 
736
            /* purecov: begin deadcode */
 
737
            /*
 
738
              This should only happen during extreme conditions if we run out
 
739
              of memory or have an item marked not null when it can be null.
 
740
              This code is here mainly to avoid a hard crash in this case.
 
741
            */
 
742
            assert(0);
 
743
            memset(to, 0, sort_field->length);  // Avoid crash
 
744
            /* purecov: end */
884
745
          }
885
746
          break;
886
747
        }
 
748
        length= res->length();
 
749
        sort_field_length= sort_field->length - sort_field->suffix_length;
 
750
        diff=(int) (sort_field_length - length);
 
751
        if (diff < 0)
 
752
        {
 
753
          diff=0;
 
754
          length= sort_field_length;
 
755
        }
 
756
        if (sort_field->suffix_length)
 
757
        {
 
758
          /* Store length last in result_string */
 
759
          store_length(to + sort_field_length, length,
 
760
                       sort_field->suffix_length);
 
761
        }
 
762
        if (sort_field->need_strxnfrm)
 
763
        {
 
764
          char *from=(char*) res->ptr();
 
765
          uint32_t tmp_length;
 
766
          if ((unsigned char*) from == to)
 
767
          {
 
768
            set_if_smaller(length,sort_field->length);
 
769
            memcpy(param->tmp_buffer,from,length);
 
770
            from=param->tmp_buffer;
 
771
          }
 
772
          tmp_length= my_strnxfrm(cs,to,sort_field->length,
 
773
                                  (unsigned char*) from, length);
 
774
          assert(tmp_length == sort_field->length);
 
775
        }
 
776
        else
 
777
        {
 
778
          my_strnxfrm(cs,(unsigned char*)to,length,(const unsigned char*)res->ptr(),length);
 
779
          cs->cset->fill(cs, (char *)to+length,diff,fill_char);
 
780
        }
 
781
        break;
 
782
      }
887
783
      case INT_RESULT:
888
 
        {
 
784
        {
889
785
          int64_t value= item->val_int_result();
890
786
          if (maybe_null)
891
787
          {
892
 
            *to++=1;
 
788
            *to++=1;                            /* purecov: inspected */
893
789
            if (item->null_value)
894
790
            {
895
791
              if (maybe_null)
901
797
              break;
902
798
            }
903
799
          }
904
 
          to[7]= (unsigned char) value;
905
 
          to[6]= (unsigned char) (value >> 8);
906
 
          to[5]= (unsigned char) (value >> 16);
907
 
          to[4]= (unsigned char) (value >> 24);
908
 
          to[3]= (unsigned char) (value >> 32);
909
 
          to[2]= (unsigned char) (value >> 40);
910
 
          to[1]= (unsigned char) (value >> 48);
 
800
          to[7]= (unsigned char) value;
 
801
          to[6]= (unsigned char) (value >> 8);
 
802
          to[5]= (unsigned char) (value >> 16);
 
803
          to[4]= (unsigned char) (value >> 24);
 
804
          to[3]= (unsigned char) (value >> 32);
 
805
          to[2]= (unsigned char) (value >> 40);
 
806
          to[1]= (unsigned char) (value >> 48);
911
807
          if (item->unsigned_flag)                    /* Fix sign */
912
808
            to[0]= (unsigned char) (value >> 56);
913
809
          else
914
810
            to[0]= (unsigned char) (value >> 56) ^ 128; /* Reverse signbit */
915
 
          break;
916
 
        }
 
811
          break;
 
812
        }
917
813
      case DECIMAL_RESULT:
918
814
        {
919
 
          type::Decimal dec_buf, *dec_val= item->val_decimal_result(&dec_buf);
 
815
          my_decimal dec_buf, *dec_val= item->val_decimal_result(&dec_buf);
920
816
          if (maybe_null)
921
817
          {
922
818
            if (item->null_value)
923
 
            {
 
819
            { 
924
820
              memset(to, 0, sort_field->length+1);
925
821
              to++;
926
822
              break;
927
823
            }
928
824
            *to++=1;
929
825
          }
930
 
          dec_val->val_binary(E_DEC_FATAL_ERROR, to,
931
 
                              item->max_length - (item->decimals ? 1:0),
932
 
                              item->decimals);
933
 
          break;
 
826
          my_decimal2binary(E_DEC_FATAL_ERROR, dec_val, to,
 
827
                            item->max_length - (item->decimals ? 1:0),
 
828
                            item->decimals);
 
829
         break;
934
830
        }
935
831
      case REAL_RESULT:
936
 
        {
 
832
        {
937
833
          double value= item->val_result();
938
 
          if (maybe_null)
 
834
          if (maybe_null)
939
835
          {
940
836
            if (item->null_value)
941
837
            {
943
839
              to++;
944
840
              break;
945
841
            }
946
 
            *to++=1;
 
842
            *to++=1;
947
843
          }
948
 
          change_double_for_sort(value,(unsigned char*) to);
949
 
          break;
950
 
        }
 
844
          change_double_for_sort(value,(unsigned char*) to);
 
845
          break;
 
846
        }
951
847
      case ROW_RESULT:
952
 
      default:
953
 
        // This case should never be choosen
954
 
        assert(0);
955
 
        break;
 
848
      default: 
 
849
        // This case should never be choosen
 
850
        assert(0);
 
851
        break;
956
852
      }
957
853
    }
958
 
 
959
854
    if (sort_field->reverse)
960
855
    {                                                   /* Revers key */
961
856
      if (maybe_null)
968
863
      }
969
864
    }
970
865
    else
971
 
    {
972
866
      to+= sort_field->length;
973
 
    }
974
867
  }
975
868
 
976
 
  if (addon_field)
 
869
  if (param->addon_field)
977
870
  {
978
 
    /*
 
871
    /* 
979
872
      Save field values appended to sorted fields.
980
873
      First null bit indicators are appended then field values follow.
981
874
      In this implementation we use fixed layout for field values -
982
875
      the same for all records.
983
876
    */
984
 
    sort_addon_field *addonf= addon_field;
 
877
    SORT_ADDON_FIELD *addonf= param->addon_field;
985
878
    unsigned char *nulls= to;
986
879
    assert(addonf != 0);
987
880
    memset(nulls, 0, addonf->offset);
991
884
      if (addonf->null_bit && field->is_null())
992
885
      {
993
886
        nulls[addonf->null_offset]|= addonf->null_bit;
994
 
#ifdef HAVE_VALGRIND
 
887
#ifdef HAVE_purify
995
888
        memset(to, 0, addonf->length);
996
889
#endif
997
890
      }
998
891
      else
999
892
      {
1000
 
#ifdef HAVE_VALGRIND
 
893
#ifdef HAVE_purify
1001
894
        unsigned char *end= field->pack(to, field->ptr);
1002
 
        uint32_t local_length= (uint32_t) ((to + addonf->length) - end);
1003
 
        assert((int) local_length >= 0);
1004
 
        if (local_length)
1005
 
          memset(end, 0, local_length);
 
895
        uint32_t length= (uint32_t) ((to + addonf->length) - end);
 
896
        assert((int) length >= 0);
 
897
        if (length)
 
898
          memset(end, 0, length);
1006
899
#else
1007
900
        (void) field->pack(to, field->ptr);
1008
901
#endif
1013
906
  else
1014
907
  {
1015
908
    /* Save filepos last */
1016
 
    memcpy(to, ref_pos, (size_t) ref_length);
 
909
    memcpy(to, ref_pos, (size_t) param->ref_length);
1017
910
  }
 
911
  return;
1018
912
}
1019
913
 
1020
914
 
1022
916
  Register fields used by sorting in the sorted table's read set
1023
917
*/
1024
918
 
1025
 
void SortParam::register_used_fields()
 
919
static void register_used_fields(SORTPARAM *param)
1026
920
{
1027
 
  SortField *sort_field;
1028
 
  Table *table= sort_form;
 
921
  register SORT_FIELD *sort_field;
 
922
  Table *table=param->sort_form;
 
923
  MY_BITMAP *bitmap= table->read_set;
1029
924
 
1030
 
  for (sort_field= local_sortorder ;
1031
 
       sort_field != end ;
 
925
  for (sort_field= param->local_sortorder ;
 
926
       sort_field != param->end ;
1032
927
       sort_field++)
1033
928
  {
1034
929
    Field *field;
1035
930
    if ((field= sort_field->field))
1036
931
    {
1037
 
      if (field->getTable() == table)
1038
 
        table->setReadSet(field->position());
 
932
      if (field->table == table)
 
933
      bitmap_set_bit(bitmap, field->field_index);
1039
934
    }
1040
935
    else
1041
936
    {                                           // Item
1044
939
    }
1045
940
  }
1046
941
 
1047
 
  if (addon_field)
 
942
  if (param->addon_field)
1048
943
  {
1049
 
    sort_addon_field *addonf= addon_field;
 
944
    SORT_ADDON_FIELD *addonf= param->addon_field;
1050
945
    Field *field;
1051
946
    for ( ; (field= addonf->field) ; addonf++)
1052
 
      table->setReadSet(field->position());
 
947
      bitmap_set_bit(bitmap, field->field_index);
1053
948
  }
1054
949
  else
1055
950
  {
1059
954
}
1060
955
 
1061
956
 
1062
 
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)
1063
959
{
1064
 
  uint32_t offset;
 
960
  uint32_t offset,res_length;
1065
961
  unsigned char *to;
1066
962
 
1067
 
  internal::my_string_ptr_sort((unsigned char*) sort_keys, (uint32_t) count, sort_length);
1068
 
  offset= rec_length - res_length;
1069
 
 
1070
 
  if ((ha_rows) count > max_rows)
1071
 
    count=(uint32_t) max_rows;
1072
 
 
1073
 
  if (!(to= table_sort->record_pointers= (unsigned char*) malloc(res_length*count)))
1074
 
    return true;
1075
 
 
1076
 
  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*) my_malloc(res_length*count, MYF(MY_WME))))
 
970
    return(1);                 /* purecov: inspected */
 
971
  for (unsigned char **end= sort_keys+count ; sort_keys != end ; sort_keys++)
1077
972
  {
1078
973
    memcpy(to, *sort_keys+offset, res_length);
1079
974
    to+= res_length;
1080
975
  }
1081
 
 
1082
 
  return false;
 
976
  return(0);
1083
977
}
1084
978
 
1085
979
 
1086
980
/** Merge buffers to make < MERGEBUFF2 buffers. */
1087
981
 
1088
 
int FileSort::merge_many_buff(SortParam *param, unsigned char *sort_buffer,
1089
 
                              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)
1090
984
{
1091
 
  internal::IO_CACHE t_file2,*from_file,*to_file,*temp;
1092
 
  buffpek *lastbuff;
 
985
  register uint32_t i;
 
986
  IO_CACHE t_file2,*from_file,*to_file,*temp;
 
987
  BUFFPEK *lastbuff;
1093
988
 
1094
989
  if (*maxbuffer < MERGEBUFF2)
1095
 
    return 0;
 
990
    return(0);                          /* purecov: inspected */
1096
991
  if (flush_io_cache(t_file) ||
1097
 
      t_file2.open_cached_file(drizzle_tmpdir.c_str(),TEMP_PREFIX,DISK_BUFFER_SIZE, MYF(MY_WME)))
1098
 
  {
1099
 
    return 1;
1100
 
  }
 
992
      open_cached_file(&t_file2,drizzle_tmpdir,TEMP_PREFIX,DISK_BUFFER_SIZE,
 
993
                        MYF(MY_WME)))
 
994
    return(1);                          /* purecov: inspected */
1101
995
 
1102
996
  from_file= t_file ; to_file= &t_file2;
1103
997
  while (*maxbuffer >= MERGEBUFF2)
1104
998
  {
1105
 
    register uint32_t i;
1106
 
 
1107
 
    if (from_file->reinit_io_cache(internal::READ_CACHE,0L,0,0))
1108
 
    {
1109
 
      break;
1110
 
    }
1111
 
 
1112
 
    if (to_file->reinit_io_cache(internal::WRITE_CACHE,0L,0,0))
1113
 
    {
1114
 
      break;
1115
 
    }
1116
 
 
1117
 
    lastbuff=buffpek_inst;
 
999
    if (reinit_io_cache(from_file,READ_CACHE,0L,0,0))
 
1000
      goto cleanup;
 
1001
    if (reinit_io_cache(to_file,WRITE_CACHE,0L,0,0))
 
1002
      goto cleanup;
 
1003
    lastbuff=buffpek;
1118
1004
    for (i=0 ; i <= *maxbuffer-MERGEBUFF*3/2 ; i+=MERGEBUFF)
1119
1005
    {
1120
1006
      if (merge_buffers(param,from_file,to_file,sort_buffer,lastbuff++,
1121
 
                        buffpek_inst+i,buffpek_inst+i+MERGEBUFF-1,0))
1122
 
      {
1123
 
        goto cleanup;
1124
 
      }
 
1007
                        buffpek+i,buffpek+i+MERGEBUFF-1,0))
 
1008
      goto cleanup;
1125
1009
    }
1126
 
 
1127
1010
    if (merge_buffers(param,from_file,to_file,sort_buffer,lastbuff++,
1128
 
                      buffpek_inst+i,buffpek_inst+ *maxbuffer,0))
1129
 
    {
1130
 
      break;
1131
 
    }
1132
 
 
 
1011
                      buffpek+i,buffpek+ *maxbuffer,0))
 
1012
      break;                                    /* purecov: inspected */
1133
1013
    if (flush_io_cache(to_file))
1134
 
    {
1135
 
      break;
1136
 
    }
1137
 
 
 
1014
      break;                                    /* purecov: inspected */
1138
1015
    temp=from_file; from_file=to_file; to_file=temp;
1139
 
    from_file->setup_io_cache();
1140
 
    to_file->setup_io_cache();
1141
 
    *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;
1142
1019
  }
1143
 
 
1144
1020
cleanup:
1145
 
  to_file->close_cached_file();                 // This holds old result
 
1021
  close_cached_file(to_file);                   // This holds old result
1146
1022
  if (to_file == t_file)
1147
1023
  {
1148
1024
    *t_file=t_file2;                            // Copy result file
1149
 
    t_file->setup_io_cache();
 
1025
    setup_io_cache(t_file);
1150
1026
  }
1151
1027
 
1152
1028
  return(*maxbuffer >= MERGEBUFF2);     /* Return 1 if interrupted */
1160
1036
    (uint32_t)-1 if something goes wrong
1161
1037
*/
1162
1038
 
1163
 
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)
1164
1041
{
1165
1042
  register uint32_t count;
1166
1043
  uint32_t length;
1167
1044
 
1168
 
  if ((count= (uint32_t) min((ha_rows) buffpek_inst->max_keys,buffpek_inst->count)))
 
1045
  if ((count=(uint32_t) cmin((ha_rows) buffpek->max_keys,buffpek->count)))
1169
1046
  {
1170
 
    if (pread(fromfile->file,(unsigned char*) buffpek_inst->base, (length= rec_length*count),buffpek_inst->file_pos) == 0)
1171
 
      return((uint32_t) -1);
1172
 
 
1173
 
    buffpek_inst->key= buffpek_inst->base;
1174
 
    buffpek_inst->file_pos+= length;                    /* New filepos */
1175
 
    buffpek_inst->count-= count;
1176
 
    buffpek_inst->mem_count= count;
 
1047
    if (pread(fromfile->file,(unsigned char*) buffpek->base, (length= rec_length*count),buffpek->file_pos) == 0)
 
1048
      return((uint32_t) -1);                    /* purecov: inspected */
 
1049
    buffpek->key=buffpek->base;
 
1050
    buffpek->file_pos+= length;                 /* New filepos */
 
1051
    buffpek->count-=    count;
 
1052
    buffpek->mem_count= count;
1177
1053
  }
1178
1054
  return (count*rec_length);
1179
1055
} /* read_to_buffer */
1180
1056
 
1181
1057
 
1182
 
class compare_functor
 
1058
/**
 
1059
  Put all room used by freed buffer to use in adjacent buffer.
 
1060
 
 
1061
  Note, that we can't simply distribute memory evenly between all buffers,
 
1062
  because new areas must not overlap with old ones.
 
1063
 
 
1064
  @param[in] queue      list of non-empty buffers, without freed buffer
 
1065
  @param[in] reuse      empty buffer
 
1066
  @param[in] key_length key length
 
1067
*/
 
1068
 
 
1069
void reuse_freed_buff(QUEUE *queue, BUFFPEK *reuse, uint32_t key_length)
1183
1070
{
1184
 
  qsort2_cmp key_compare;
1185
 
  void *key_compare_arg;
1186
 
 
1187
 
  public:
1188
 
  compare_functor(qsort2_cmp in_key_compare, void *in_compare_arg) :
1189
 
    key_compare(in_key_compare),
1190
 
    key_compare_arg(in_compare_arg)
1191
 
  { }
1192
 
  
1193
 
  inline bool operator()(const buffpek *i, const buffpek *j) const
 
1071
  unsigned char *reuse_end= reuse->base + reuse->max_keys * key_length;
 
1072
  for (uint32_t i= 0; i < queue->elements; ++i)
1194
1073
  {
1195
 
    int val= key_compare(key_compare_arg, &i->key, &j->key);
1196
 
 
1197
 
    return (val >= 0);
 
1074
    BUFFPEK *bp= (BUFFPEK *) queue_element(queue, i);
 
1075
    if (bp->base + bp->max_keys * key_length == reuse->base)
 
1076
    {
 
1077
      bp->max_keys+= reuse->max_keys;
 
1078
      return;
 
1079
    }
 
1080
    else if (bp->base == reuse_end)
 
1081
    {
 
1082
      bp->base= reuse->base;
 
1083
      bp->max_keys+= reuse->max_keys;
 
1084
      return;
 
1085
    }
1198
1086
  }
1199
 
};
 
1087
  assert(0);
 
1088
}
1200
1089
 
1201
1090
 
1202
1091
/**
1203
1092
  Merge buffers to one buffer.
1204
1093
 
1205
1094
  @param param        Sort parameter
1206
 
  @param from_file    File with source data (buffpeks point to this file)
 
1095
  @param from_file    File with source data (BUFFPEKs point to this file)
1207
1096
  @param to_file      File to write the sorted result data.
1208
1097
  @param sort_buffer  Buffer for data to store up to MERGEBUFF2 sort keys.
1209
 
  @param lastbuff     OUT Store here buffpek describing data written to to_file
1210
 
  @param Fb           First element in source buffpeks array
1211
 
  @param Tb           Last element in source buffpeks array
 
1098
  @param lastbuff     OUT Store here BUFFPEK describing data written to to_file
 
1099
  @param Fb           First element in source BUFFPEKs array
 
1100
  @param Tb           Last element in source BUFFPEKs array
1212
1101
  @param flag
1213
1102
 
1214
1103
  @retval
1217
1106
    other  error
1218
1107
*/
1219
1108
 
1220
 
int FileSort::merge_buffers(SortParam *param, internal::IO_CACHE *from_file,
1221
 
                            internal::IO_CACHE *to_file, unsigned char *sort_buffer,
1222
 
                            buffpek *lastbuff, buffpek *Fb, buffpek *Tb,
1223
 
                            int flag)
 
1109
int merge_buffers(SORTPARAM *param, IO_CACHE *from_file,
 
1110
                  IO_CACHE *to_file, unsigned char *sort_buffer,
 
1111
                  BUFFPEK *lastbuff, BUFFPEK *Fb, BUFFPEK *Tb,
 
1112
                  int flag)
1224
1113
{
1225
1114
  int error;
1226
1115
  uint32_t rec_length,res_length,offset;
1227
1116
  size_t sort_length;
1228
1117
  uint32_t maxcount;
1229
1118
  ha_rows max_rows,org_max_rows;
1230
 
  internal::my_off_t to_start_filepos;
 
1119
  my_off_t to_start_filepos;
1231
1120
  unsigned char *strpos;
1232
 
  buffpek *buffpek_inst;
 
1121
  BUFFPEK *buffpek;
 
1122
  QUEUE queue;
1233
1123
  qsort2_cmp cmp;
1234
1124
  void *first_cmp_arg;
1235
 
  volatile Session::killed_state_t *killed= getSession().getKilledPtr();
1236
 
  Session::killed_state_t not_killable;
 
1125
  volatile Session::killed_state *killed= &current_session->killed;
 
1126
  Session::killed_state not_killable;
1237
1127
 
1238
 
  getSession().status_var.filesort_merge_passes++;
 
1128
  status_var_increment(current_session->status_var.filesort_merge_passes);
1239
1129
  if (param->not_killable)
1240
1130
  {
1241
1131
    killed= &not_killable;
1254
1144
 
1255
1145
  /* The following will fire if there is not enough space in sort_buffer */
1256
1146
  assert(maxcount!=0);
1257
 
 
 
1147
  
1258
1148
  if (param->unique_buff)
1259
1149
  {
1260
1150
    cmp= param->compare;
1262
1152
  }
1263
1153
  else
1264
1154
  {
1265
 
    cmp= internal::get_ptr_compare(sort_length);
 
1155
    cmp= get_ptr_compare(sort_length);
1266
1156
    first_cmp_arg= (void*) &sort_length;
1267
1157
  }
1268
 
  priority_queue<buffpek *, vector<buffpek *>, compare_functor >
1269
 
    queue(compare_functor(cmp, first_cmp_arg));
1270
 
  for (buffpek_inst= Fb ; buffpek_inst <= Tb ; buffpek_inst++)
 
1158
  if (init_queue(&queue, (uint32_t) (Tb-Fb)+1, offsetof(BUFFPEK,key), 0,
 
1159
                 (queue_compare) cmp, first_cmp_arg))
 
1160
    return(1);                                /* purecov: inspected */
 
1161
  for (buffpek= Fb ; buffpek <= Tb ; buffpek++)
1271
1162
  {
1272
 
    buffpek_inst->base= strpos;
1273
 
    buffpek_inst->max_keys= maxcount;
1274
 
    strpos+= (uint32_t) (error= (int) read_to_buffer(from_file, buffpek_inst,
 
1163
    buffpek->base= strpos;
 
1164
    buffpek->max_keys= maxcount;
 
1165
    strpos+= (uint32_t) (error= (int) read_to_buffer(from_file, buffpek,
1275
1166
                                                                         rec_length));
1276
1167
    if (error == -1)
1277
 
      return -1;
1278
 
 
1279
 
    buffpek_inst->max_keys= buffpek_inst->mem_count;    // If less data in buffers than expected
1280
 
    queue.push(buffpek_inst);
 
1168
      goto err;                                 /* purecov: inspected */
 
1169
    buffpek->max_keys= buffpek->mem_count;      // If less data in buffers than expected
 
1170
    queue_insert(&queue, (unsigned char*) buffpek);
1281
1171
  }
1282
1172
 
1283
1173
  if (param->unique_buff)
1284
1174
  {
1285
 
    /*
 
1175
    /* 
1286
1176
       Called by Unique::get()
1287
1177
       Copy the first argument to param->unique_buff for unique removal.
1288
1178
       Store it also in 'to_file'.
1290
1180
       This is safe as we know that there is always more than one element
1291
1181
       in each block to merge (This is guaranteed by the Unique:: algorithm
1292
1182
    */
1293
 
    buffpek_inst= queue.top();
1294
 
    memcpy(param->unique_buff, buffpek_inst->key, rec_length);
1295
 
    if (my_b_write(to_file, (unsigned char*) buffpek_inst->key, rec_length))
 
1183
    buffpek= (BUFFPEK*) queue_top(&queue);
 
1184
    memcpy(param->unique_buff, buffpek->key, rec_length);
 
1185
    if (my_b_write(to_file, (unsigned char*) buffpek->key, rec_length))
1296
1186
    {
1297
 
      return 1;
 
1187
      error=1; goto err;                        /* purecov: inspected */
1298
1188
    }
1299
 
    buffpek_inst->key+= rec_length;
1300
 
    buffpek_inst->mem_count--;
 
1189
    buffpek->key+= rec_length;
 
1190
    buffpek->mem_count--;
1301
1191
    if (!--max_rows)
1302
1192
    {
1303
 
      error= 0;
1304
 
      goto end;
 
1193
      error= 0;                                       /* purecov: inspected */
 
1194
      goto end;                                       /* purecov: inspected */
1305
1195
    }
1306
 
    /* Top element has been used */
1307
 
    queue.pop();
1308
 
    queue.push(buffpek_inst);
 
1196
    queue_replaced(&queue);                        // Top element has been used
1309
1197
  }
1310
1198
  else
1311
 
  {
1312
1199
    cmp= 0;                                        // Not unique
1313
 
  }
1314
1200
 
1315
 
  while (queue.size() > 1)
 
1201
  while (queue.elements > 1)
1316
1202
  {
1317
1203
    if (*killed)
1318
1204
    {
1319
 
      return 1;
 
1205
      error= 1; goto err;                        /* purecov: inspected */
1320
1206
    }
1321
1207
    for (;;)
1322
1208
    {
1323
 
      buffpek_inst= queue.top();
 
1209
      buffpek= (BUFFPEK*) queue_top(&queue);
1324
1210
      if (cmp)                                        // Remove duplicates
1325
1211
      {
1326
1212
        if (!(*cmp)(first_cmp_arg, &(param->unique_buff),
1327
 
                    (unsigned char**) &buffpek_inst->key))
 
1213
                    (unsigned char**) &buffpek->key))
1328
1214
              goto skip_duplicate;
1329
 
            memcpy(param->unique_buff, buffpek_inst->key, rec_length);
 
1215
            memcpy(param->unique_buff, buffpek->key, rec_length);
1330
1216
      }
1331
1217
      if (flag == 0)
1332
1218
      {
1333
 
        if (my_b_write(to_file,(unsigned char*) buffpek_inst->key, rec_length))
 
1219
        if (my_b_write(to_file,(unsigned char*) buffpek->key, rec_length))
1334
1220
        {
1335
 
          return 1;
 
1221
          error=1; goto err;                        /* purecov: inspected */
1336
1222
        }
1337
1223
      }
1338
1224
      else
1339
1225
      {
1340
 
        if (my_b_write(to_file, (unsigned char*) buffpek_inst->key+offset, res_length))
 
1226
        if (my_b_write(to_file, (unsigned char*) buffpek->key+offset, res_length))
1341
1227
        {
1342
 
          return 1;
 
1228
          error=1; goto err;                        /* purecov: inspected */
1343
1229
        }
1344
1230
      }
1345
1231
      if (!--max_rows)
1346
1232
      {
1347
 
        error= 0;
1348
 
        goto end;
 
1233
        error= 0;                               /* purecov: inspected */
 
1234
        goto end;                               /* purecov: inspected */
1349
1235
      }
1350
1236
 
1351
1237
    skip_duplicate:
1352
 
      buffpek_inst->key+= rec_length;
1353
 
      if (! --buffpek_inst->mem_count)
 
1238
      buffpek->key+= rec_length;
 
1239
      if (! --buffpek->mem_count)
1354
1240
      {
1355
 
        if (!(error= (int) read_to_buffer(from_file,buffpek_inst,
 
1241
        if (!(error= (int) read_to_buffer(from_file,buffpek,
1356
1242
                                          rec_length)))
1357
1243
        {
1358
 
          queue.pop();
 
1244
          queue_remove(&queue,0);
 
1245
          reuse_freed_buff(&queue, buffpek, rec_length);
1359
1246
          break;                        /* One buffer have been removed */
1360
1247
        }
1361
1248
        else if (error == -1)
1362
 
        {
1363
 
          return -1;
1364
 
        }
 
1249
          goto err;                        /* purecov: inspected */
1365
1250
      }
1366
 
      /* Top element has been replaced */
1367
 
      queue.pop();
1368
 
      queue.push(buffpek_inst);
 
1251
      queue_replaced(&queue);              /* Top element has been replaced */
1369
1252
    }
1370
1253
  }
1371
 
  buffpek_inst= queue.top();
1372
 
  buffpek_inst->base= sort_buffer;
1373
 
  buffpek_inst->max_keys= param->keys;
 
1254
  buffpek= (BUFFPEK*) queue_top(&queue);
 
1255
  buffpek->base= sort_buffer;
 
1256
  buffpek->max_keys= param->keys;
1374
1257
 
1375
1258
  /*
1376
1259
    As we know all entries in the buffer are unique, we only have to
1378
1261
  */
1379
1262
  if (cmp)
1380
1263
  {
1381
 
    if (!(*cmp)(first_cmp_arg, &(param->unique_buff), (unsigned char**) &buffpek_inst->key))
 
1264
    if (!(*cmp)(first_cmp_arg, &(param->unique_buff), (unsigned char**) &buffpek->key))
1382
1265
    {
1383
 
      buffpek_inst->key+= rec_length;         // Remove duplicate
1384
 
      --buffpek_inst->mem_count;
 
1266
      buffpek->key+= rec_length;         // Remove duplicate
 
1267
      --buffpek->mem_count;
1385
1268
    }
1386
1269
  }
1387
1270
 
1388
1271
  do
1389
1272
  {
1390
 
    if ((ha_rows) buffpek_inst->mem_count > max_rows)
 
1273
    if ((ha_rows) buffpek->mem_count > max_rows)
1391
1274
    {                                        /* Don't write too many records */
1392
 
      buffpek_inst->mem_count= (uint32_t) max_rows;
1393
 
      buffpek_inst->count= 0;                        /* Don't read more */
 
1275
      buffpek->mem_count= (uint32_t) max_rows;
 
1276
      buffpek->count= 0;                        /* Don't read more */
1394
1277
    }
1395
 
    max_rows-= buffpek_inst->mem_count;
 
1278
    max_rows-= buffpek->mem_count;
1396
1279
    if (flag == 0)
1397
1280
    {
1398
 
      if (my_b_write(to_file,(unsigned char*) buffpek_inst->key,
1399
 
                     (rec_length*buffpek_inst->mem_count)))
 
1281
      if (my_b_write(to_file,(unsigned char*) buffpek->key,
 
1282
                     (rec_length*buffpek->mem_count)))
1400
1283
      {
1401
 
        return 1;
 
1284
        error= 1; goto err;                        /* purecov: inspected */
1402
1285
      }
1403
1286
    }
1404
1287
    else
1405
1288
    {
1406
1289
      register unsigned char *end;
1407
 
      strpos= buffpek_inst->key+offset;
1408
 
      for (end= strpos+buffpek_inst->mem_count*rec_length ;
 
1290
      strpos= buffpek->key+offset;
 
1291
      for (end= strpos+buffpek->mem_count*rec_length ;
1409
1292
           strpos != end ;
1410
1293
           strpos+= rec_length)
1411
 
      {
 
1294
      {     
1412
1295
        if (my_b_write(to_file, (unsigned char *) strpos, res_length))
1413
1296
        {
1414
 
          return 1;
 
1297
          error=1; goto err;                        
1415
1298
        }
1416
1299
      }
1417
1300
    }
1418
1301
  }
1419
 
 
1420
 
  while ((error=(int) read_to_buffer(from_file,buffpek_inst, rec_length))
 
1302
  while ((error=(int) read_to_buffer(from_file,buffpek, rec_length))
1421
1303
         != -1 && error != 0);
1422
1304
 
1423
1305
end:
1424
 
  lastbuff->count= min(org_max_rows-max_rows, param->max_rows);
 
1306
  lastbuff->count= cmin(org_max_rows-max_rows, param->max_rows);
1425
1307
  lastbuff->file_pos= to_start_filepos;
1426
 
 
1427
 
  return error;
 
1308
err:
 
1309
  delete_queue(&queue);
 
1310
  return(error);
1428
1311
} /* merge_buffers */
1429
1312
 
1430
1313
 
1431
1314
        /* Do a merge to output-file (save only positions) */
1432
1315
 
1433
 
int FileSort::merge_index(SortParam *param, unsigned char *sort_buffer,
1434
 
                          buffpek *buffpek_inst, uint32_t maxbuffer,
1435
 
                          internal::IO_CACHE *tempfile, internal::IO_CACHE *outfile)
 
1316
static int merge_index(SORTPARAM *param, unsigned char *sort_buffer,
 
1317
                       BUFFPEK *buffpek, uint32_t maxbuffer,
 
1318
                       IO_CACHE *tempfile, IO_CACHE *outfile)
1436
1319
{
1437
 
  if (merge_buffers(param,tempfile,outfile,sort_buffer,buffpek_inst,buffpek_inst,
1438
 
                    buffpek_inst+maxbuffer,1))
1439
 
    return 1;
1440
 
 
1441
 
  return 0;
 
1320
  if (merge_buffers(param,tempfile,outfile,sort_buffer,buffpek,buffpek,
 
1321
                    buffpek+maxbuffer,1))
 
1322
    return(1);                          /* purecov: inspected */
 
1323
  return(0);
1442
1324
} /* merge_index */
1443
1325
 
1444
1326
 
1458
1340
/**
1459
1341
  Calculate length of sort key.
1460
1342
 
 
1343
  @param session                          Thread handler
1461
1344
  @param sortorder                Order of items to sort
1462
1345
  @param s_length                 Number of items to sort
1463
1346
  @param[out] multi_byte_charset Set to 1 if we are using multi-byte charset
1472
1355
    Total length of sort buffer in bytes
1473
1356
*/
1474
1357
 
1475
 
uint32_t FileSort::sortlength(SortField *sortorder, uint32_t s_length, bool *multi_byte_charset)
 
1358
static uint32_t
 
1359
sortlength(Session *session, SORT_FIELD *sortorder, uint32_t s_length,
 
1360
           bool *multi_byte_charset)
1476
1361
{
1477
1362
  register uint32_t length;
1478
1363
  const CHARSET_INFO *cs;
1502
1387
      sortorder->result_type= sortorder->item->result_type();
1503
1388
      if (sortorder->item->result_as_int64_t())
1504
1389
        sortorder->result_type= INT_RESULT;
1505
 
 
1506
1390
      switch (sortorder->result_type) {
1507
1391
      case STRING_RESULT:
1508
 
        sortorder->length=sortorder->item->max_length;
1509
 
        set_if_smaller(sortorder->length,
1510
 
                       getSession().variables.max_sort_length);
1511
 
        if (use_strnxfrm((cs=sortorder->item->collation.collation)))
1512
 
        {
 
1392
        sortorder->length=sortorder->item->max_length;
 
1393
        set_if_smaller(sortorder->length, session->variables.max_sort_length);
 
1394
        if (use_strnxfrm((cs=sortorder->item->collation.collation)))
 
1395
        { 
1513
1396
          sortorder->length= cs->coll->strnxfrmlen(cs, sortorder->length);
1514
 
          sortorder->need_strxnfrm= 1;
1515
 
          *multi_byte_charset= 1;
1516
 
        }
 
1397
          sortorder->need_strxnfrm= 1;
 
1398
          *multi_byte_charset= 1;
 
1399
        }
1517
1400
        else if (cs == &my_charset_bin)
1518
1401
        {
1519
1402
          /* Store length last to be able to sort blob/varbinary */
1520
1403
          sortorder->suffix_length= suffix_length(sortorder->length);
1521
1404
          sortorder->length+= sortorder->suffix_length;
1522
1405
        }
1523
 
        break;
 
1406
        break;
1524
1407
      case INT_RESULT:
1525
 
        sortorder->length=8;                    // Size of intern int64_t
1526
 
        break;
 
1408
        sortorder->length=8;                    // Size of intern int64_t
 
1409
        break;
1527
1410
      case DECIMAL_RESULT:
1528
1411
        sortorder->length=
1529
 
          class_decimal_get_binary_size(sortorder->item->max_length -
 
1412
          my_decimal_get_binary_size(sortorder->item->max_length - 
1530
1413
                                     (sortorder->item->decimals ? 1 : 0),
1531
1414
                                     sortorder->item->decimals);
1532
1415
        break;
1533
1416
      case REAL_RESULT:
1534
 
        sortorder->length=sizeof(double);
1535
 
        break;
 
1417
        sortorder->length=sizeof(double);
 
1418
        break;
1536
1419
      case ROW_RESULT:
1537
 
        // This case should never be choosen
1538
 
        assert(0);
1539
 
        break;
 
1420
      default: 
 
1421
        // This case should never be choosen
 
1422
        assert(0);
 
1423
        break;
1540
1424
      }
1541
1425
      if (sortorder->item->maybe_null)
1542
 
        length++;                               // Place for NULL marker
 
1426
        length++;                               // Place for NULL marker
1543
1427
    }
1544
 
    set_if_smaller(sortorder->length, (size_t)getSession().variables.max_sort_length);
 
1428
    set_if_smaller(sortorder->length, session->variables.max_sort_length);
1545
1429
    length+=sortorder->length;
1546
1430
  }
1547
1431
  sortorder->field= (Field*) 0;                 // end marker
1555
1439
 
1556
1440
  The function first finds out what fields are used in the result set.
1557
1441
  Then it calculates the length of the buffer to store the values of
1558
 
  these fields together with the value of sort values.
 
1442
  these fields together with the value of sort values. 
1559
1443
  If the calculated length is not greater than max_length_for_sort_data
1560
1444
  the function allocates memory for an array of descriptors containing
1561
1445
  layouts for the values of the non-sorted fields in the buffer and
1562
1446
  fills them.
1563
1447
 
 
1448
  @param session                 Current thread
1564
1449
  @param ptabfield           Array of references to the table fields
1565
1450
  @param sortlength          Total length of sorted fields
1566
1451
  @param[out] plength        Total length of appended fields
1575
1460
    NULL   if we do not store field values with sort data.
1576
1461
*/
1577
1462
 
1578
 
sort_addon_field *FileSort::get_addon_fields(Field **ptabfield, uint32_t sortlength_arg, uint32_t *plength)
 
1463
static SORT_ADDON_FIELD *
 
1464
get_addon_fields(Session *session, Field **ptabfield, uint32_t sortlength, uint32_t *plength)
1579
1465
{
1580
1466
  Field **pfield;
1581
1467
  Field *field;
1582
 
  sort_addon_field *addonf;
 
1468
  SORT_ADDON_FIELD *addonf;
1583
1469
  uint32_t length= 0;
1584
1470
  uint32_t fields= 0;
1585
1471
  uint32_t null_fields= 0;
 
1472
  MY_BITMAP *read_set= (*ptabfield)->table->read_set;
1586
1473
 
1587
1474
  /*
1588
1475
    If there is a reference to a field in the query add it
1590
1477
    Note for future refinement:
1591
1478
    This this a too strong condition.
1592
1479
    Actually we need only the fields referred in the
1593
 
    result set. And for some of them it makes sense to use
 
1480
    result set. And for some of them it makes sense to use 
1594
1481
    the values directly from sorted fields.
1595
1482
  */
1596
1483
  *plength= 0;
1597
1484
 
1598
1485
  for (pfield= ptabfield; (field= *pfield) ; pfield++)
1599
1486
  {
1600
 
    if (!(field->isReadSet()))
 
1487
    if (!bitmap_is_set(read_set, field->field_index))
1601
1488
      continue;
1602
1489
    if (field->flags & BLOB_FLAG)
1603
1490
      return 0;
1605
1492
    if (field->maybe_null())
1606
1493
      null_fields++;
1607
1494
    fields++;
1608
 
  }
 
1495
  } 
1609
1496
  if (!fields)
1610
1497
    return 0;
1611
1498
  length+= (null_fields+7)/8;
1612
1499
 
1613
 
  if (length+sortlength_arg > getSession().variables.max_length_for_sort_data ||
1614
 
      !(addonf= (sort_addon_field *) malloc(sizeof(sort_addon_field)*
1615
 
                                            (fields+1))))
 
1500
  if (length+sortlength > session->variables.max_length_for_sort_data ||
 
1501
      !(addonf= (SORT_ADDON_FIELD *) my_malloc(sizeof(SORT_ADDON_FIELD)*
 
1502
                                               (fields+1), MYF(MY_WME))))
1616
1503
    return 0;
1617
1504
 
1618
1505
  *plength= length;
1620
1507
  null_fields= 0;
1621
1508
  for (pfield= ptabfield; (field= *pfield) ; pfield++)
1622
1509
  {
1623
 
    if (!(field->isReadSet()))
 
1510
    if (!bitmap_is_set(read_set, field->field_index))
1624
1511
      continue;
1625
1512
    addonf->field= field;
1626
1513
    addonf->offset= length;
1640
1527
    addonf++;
1641
1528
  }
1642
1529
  addonf->field= 0;     // Put end marker
1643
 
 
 
1530
  
1644
1531
  return (addonf-fields);
1645
1532
}
1646
1533
 
1660
1547
    void.
1661
1548
*/
1662
1549
 
1663
 
static void
1664
 
unpack_addon_fields(sort_addon_field *addon_field, unsigned char *buff)
 
1550
static void 
 
1551
unpack_addon_fields(struct st_sort_addon_field *addon_field, unsigned char *buff)
1665
1552
{
1666
1553
  Field *field;
1667
 
  sort_addon_field *addonf= addon_field;
 
1554
  SORT_ADDON_FIELD *addonf= addon_field;
1668
1555
 
1669
1556
  for ( ; (field= addonf->field) ; addonf++)
1670
1557
  {
1725
1612
    }
1726
1613
  }
1727
1614
}
1728
 
 
1729
 
} /* namespace drizzled */