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