~drizzle-trunk/drizzle/development

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