~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/filesort.cc

  • Committer: Brian Aker
  • Date: 2008-10-29 13:46:43 UTC
  • Revision ID: brian@tangent.org-20081029134643-z6jcwjvyruhk2vlu
Updates for ignore file.

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