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