~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to sql/filesort.cc

  • Committer: brian
  • Date: 2008-06-25 05:29:13 UTC
  • Revision ID: brian@localhost.localdomain-20080625052913-6upwo0jsrl4lnapl
clean slate

Show diffs side-by-side

added added

removed removed

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