~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/filesort.cc

  • Committer: Monty Taylor
  • Date: 2010-06-02 22:35:45 UTC
  • mto: This revision was merged to the branch mainline in revision 1586.
  • Revision ID: mordred@inaugust.com-20100602223545-q8ekf9b40a85nwuf
Rearragned unittests into a single exe because of how we need to link it
(thanks lifeless)
Link with server symbols without needing to build a library.
Added an additional atomics test which tests whatever version of the atomics
lib the running platform would actually use.

Show diffs side-by-side

added added

removed removed

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