Drizzled Public API Documentation

filesort.cc
Go to the documentation of this file.
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
15 
16 
24 #include <config.h>
25 
26 #include <float.h>
27 #include <limits.h>
28 
29 #include <queue>
30 #include <algorithm>
31 #include <iostream>
32 
33 #include <drizzled/drizzled.h>
34 #include <drizzled/sql_sort.h>
35 #include <drizzled/filesort.h>
36 #include <drizzled/error.h>
37 #include <drizzled/probes.h>
38 #include <drizzled/session.h>
39 #include <drizzled/table.h>
40 #include <drizzled/table_list.h>
41 #include <drizzled/optimizer/range.h>
42 #include <drizzled/records.h>
43 #include <drizzled/internal/iocache.h>
44 #include <drizzled/internal/my_sys.h>
45 #include <plugin/myisam/myisam.h>
46 #include <drizzled/plugin/transactional_storage_engine.h>
47 #include <drizzled/atomics.h>
48 #include <drizzled/global_buffer.h>
49 #include <drizzled/sort_field.h>
50 #include <drizzled/item/subselect.h>
51 #include <drizzled/statistics_variables.h>
52 #include <drizzled/system_variables.h>
53 
54 using namespace std;
55 
56 namespace drizzled {
57 
58 /* Defines used by filesort and uniques */
59 #define MERGEBUFF 7
60 #define MERGEBUFF2 15
61 
63 {
64 public:
65  qsort_cmp2 key_compare;
66  void *key_compare_arg;
67 
69  key_compare(0),
70  key_compare_arg(0)
71  { }
72 
73 };
74 
75 class SortParam {
76 public:
77  uint32_t rec_length; /* Length of sorted records */
78  uint32_t sort_length; /* Length of sorted columns */
79  uint32_t ref_length; /* Length of record ref. */
80  uint32_t addon_length; /* Length of added packed fields */
81  uint32_t res_length; /* Length of records in final sorted file/buffer */
82  uint32_t keys; /* Max keys / buffer */
83  ha_rows max_rows,examined_rows;
84  Table *sort_form; /* For quicker make_sortkey */
85  SortField *local_sortorder;
86  SortField *end;
87  sort_addon_field *addon_field; /* Descriptors for companion fields */
88  unsigned char *unique_buff;
89  bool not_killable;
90  char *tmp_buffer;
91  /* The fields below are used only by Unique class */
92  qsort2_cmp compare;
93  BufferCompareContext cmp_context;
94 
95  SortParam() :
96  rec_length(0),
97  sort_length(0),
98  ref_length(0),
99  addon_length(0),
100  res_length(0),
101  keys(0),
102  max_rows(0),
103  examined_rows(0),
104  sort_form(0),
105  local_sortorder(0),
106  end(0),
107  addon_field(0),
108  unique_buff(0),
109  not_killable(0),
110  tmp_buffer(0),
111  compare(0)
112  {
113  }
114 
115  ~SortParam()
116  {
117  free(tmp_buffer);
118  }
119 
120  int write_keys(unsigned char * *sort_keys,
121  uint32_t count,
122  internal::io_cache_st *buffer_file,
123  internal::io_cache_st *tempfile);
124 
125  void make_sortkey(unsigned char *to,
126  unsigned char *ref_pos);
127  void register_used_fields();
128  void save_index(unsigned char **sort_keys,
129  uint32_t count,
130  filesort_info *table_sort);
131 
132 };
133 
134 /* functions defined in this file */
135 
136 static char **make_char_array(char **old_pos, uint32_t fields,
137  uint32_t length);
138 
139 static unsigned char *read_buffpek_from_file(internal::io_cache_st *buffer_file,
140  uint32_t count,
141  unsigned char *buf);
142 
143 static uint32_t suffix_length(uint32_t string_length);
144 static void unpack_addon_fields(sort_addon_field *addon_field,
145  unsigned char *buff);
146 
147 FileSort::FileSort(Session &arg) :
148  _session(arg)
149 {
150 }
151 
187 ha_rows FileSort::run(Table *table, SortField *sortorder, uint32_t s_length,
188  optimizer::SqlSelect *select, ha_rows max_rows,
189  bool sort_positions, ha_rows &examined_rows)
190 {
191  int error= 1;
192  uint32_t memavl= 0, min_sort_memory;
193  uint32_t maxbuffer;
194  size_t allocated_sort_memory= 0;
195  buffpek *buffpek_inst= 0;
196  ha_rows records= HA_POS_ERROR;
197  unsigned char **sort_keys= 0;
198  internal::io_cache_st tempfile;
199  internal::io_cache_st buffpek_pointers;
200  internal::io_cache_st *selected_records_file;
201  internal::io_cache_st *outfile;
202  SortParam param;
203  bool multi_byte_charset;
204 
205  /*
206  Don't use table->sort in filesort as it is also used by
207  QuickIndexMergeSelect. Work with a copy and put it back at the end
208  when index_merge select has finished with it.
209  */
210  filesort_info table_sort(table->sort);
211  table->sort.io_cache= NULL;
212 
213  TableList *tab= table->pos_in_table_list;
214  Item_subselect *subselect= tab ? tab->containing_subselect() : 0;
215 
216  DRIZZLE_FILESORT_START(table->getShare()->getSchemaName(), table->getShare()->getTableName());
217 
218  /*
219  Release InnoDB's adaptive hash index latch (if holding) before
220  running a sort.
221  */
223 
224 
225  outfile= table_sort.io_cache;
226  assert(tempfile.buffer == 0);
227  assert(buffpek_pointers.buffer == 0);
228 
229  param.sort_length= sortlength(sortorder, s_length, &multi_byte_charset);
230  param.ref_length= table->cursor->ref_length;
231 
232  if (!(table->cursor->getEngine()->check_flag(HTON_BIT_FAST_KEY_READ)) && !sort_positions)
233  {
234  /*
235  Get the descriptors of all fields whose values are appended
236  to sorted fields and get its total length in param.spack_length.
237  */
238  param.addon_field= get_addon_fields(table->getFields(),
239  param.sort_length,
240  &param.addon_length);
241  }
242 
243  table_sort.addon_buf= 0;
244  table_sort.addon_length= param.addon_length;
245  table_sort.addon_field= param.addon_field;
246  table_sort.unpack= unpack_addon_fields;
247  if (param.addon_field)
248  {
249  param.res_length= param.addon_length;
250  table_sort.addon_buf= (unsigned char *) malloc(param.addon_length);
251  }
252  else
253  {
254  param.res_length= param.ref_length;
255  /*
256  The reference to the record is considered
257  as an additional sorted field
258  */
259  param.sort_length+= param.ref_length;
260  }
261  param.rec_length= param.sort_length+param.addon_length;
262  param.max_rows= max_rows;
263 
264  if (select && select->quick)
265  {
266  getSession().status_var.filesort_range_count++;
267  }
268  else
269  {
270  getSession().status_var.filesort_scan_count++;
271  }
272 #ifdef CAN_TRUST_RANGE
273  if (select && select->quick && select->quick->records > 0L)
274  {
275  records= min((ha_rows) (select->quick->records*2+EXTRA_RECORDS*2),
276  table->cursor->stats.records)+EXTRA_RECORDS;
277  selected_records_file=0;
278  }
279  else
280 #endif
281  {
282  records= table->cursor->estimate_rows_upper_bound();
283  /*
284  If number of records is not known, use as much of sort buffer
285  as possible.
286  */
287  if (records == HA_POS_ERROR)
288  records--; // we use 'records+1' below.
289  selected_records_file= 0;
290  }
291 
292  if (multi_byte_charset)
293  param.tmp_buffer= (char*) malloc(param.sort_length);
294 
295  memavl= getSession().variables.sortbuff_size;
296  min_sort_memory= max((uint32_t)MIN_SORT_MEMORY, param.sort_length*MERGEBUFF2);
297  while (memavl >= min_sort_memory)
298  {
299  uint32_t old_memavl;
300  uint32_t keys= memavl/(param.rec_length+sizeof(char*));
301  param.keys= (uint32_t) min(records+1, (ha_rows)keys);
302 
303  allocated_sort_memory= param.keys * param.rec_length;
304  if (not global_sort_buffer.add(allocated_sort_memory))
305  {
306  my_error(ER_OUT_OF_GLOBAL_SORTMEMORY, MYF(ME_ERROR+ME_WAITTANG));
307  goto err;
308  }
309 
310  if ((table_sort.sort_keys=
311  (unsigned char **) make_char_array((char **) table_sort.sort_keys,
312  param.keys, param.rec_length)))
313  break;
314 
315  global_sort_buffer.sub(allocated_sort_memory);
316  old_memavl= memavl;
317  if ((memavl= memavl/4*3) < min_sort_memory && old_memavl > min_sort_memory)
318  memavl= min_sort_memory;
319  }
320  sort_keys= table_sort.sort_keys;
321  if (memavl < min_sort_memory)
322  {
323  my_error(ER_OUT_OF_SORTMEMORY,MYF(ME_ERROR+ME_WAITTANG));
324  goto err;
325  }
326 
327  if (buffpek_pointers.open_cached_file(drizzle_tmpdir.c_str(),TEMP_PREFIX, DISK_BUFFER_SIZE, MYF(MY_WME)))
328  {
329  goto err;
330  }
331 
332  param.keys--; /* TODO: check why we do this */
333  param.sort_form= table;
334  param.end=(param.local_sortorder=sortorder)+s_length;
335  if ((records= find_all_keys(&param,select,sort_keys, &buffpek_pointers,
336  &tempfile, selected_records_file)) == HA_POS_ERROR)
337  {
338  goto err;
339  }
340  maxbuffer= (uint32_t)(buffpek_pointers.tell() / sizeof(*buffpek_inst));
341 
342  if (maxbuffer == 0) // The whole set is in memory
343  {
344  param.save_index(sort_keys,(uint32_t) records, &table_sort);
345  }
346  else
347  {
348  if (table_sort.buffpek && table_sort.buffpek_len < maxbuffer)
349  {
350  free(table_sort.buffpek);
351  table_sort.buffpek = 0;
352  }
353  if (!(table_sort.buffpek=
354  (unsigned char *) read_buffpek_from_file(&buffpek_pointers, maxbuffer, table_sort.buffpek)))
355  {
356  goto err;
357  }
358  buffpek_inst= (buffpek *) table_sort.buffpek;
359  table_sort.buffpek_len= maxbuffer;
360  buffpek_pointers.close_cached_file();
361  /* Open cached file if it isn't open */
362  if (not outfile->inited() && outfile->open_cached_file(drizzle_tmpdir.c_str(),TEMP_PREFIX,READ_RECORD_BUFFER, MYF(MY_WME)))
363  {
364  goto err;
365  }
366 
367  if (outfile->reinit_io_cache(internal::WRITE_CACHE,0L,0,0))
368  {
369  goto err;
370  }
371 
372  /*
373  Use also the space previously used by string pointers in sort_buffer
374  for temporary key storage.
375  */
376  param.keys=((param.keys*(param.rec_length+sizeof(char*))) / param.rec_length-1);
377 
378  maxbuffer--; // Offset from 0
379  if (merge_many_buff(&param,(unsigned char*) sort_keys,buffpek_inst,&maxbuffer, &tempfile))
380  {
381  goto err;
382  }
383 
384  if (tempfile.flush() || tempfile.reinit_io_cache(internal::READ_CACHE,0L,0,0))
385  {
386  goto err;
387  }
388 
389  if (merge_index(&param,(unsigned char*) sort_keys,buffpek_inst,maxbuffer,&tempfile, outfile))
390  {
391  goto err;
392  }
393  }
394 
395  if (records > param.max_rows)
396  {
397  records= param.max_rows;
398  }
399  error =0;
400 
401  err:
402  if (not subselect || not subselect->is_uncacheable())
403  {
404  free(sort_keys);
405  table_sort.sort_keys= 0;
406  free(buffpek_inst);
407  table_sort.buffpek= 0;
408  table_sort.buffpek_len= 0;
409  }
410 
411  tempfile.close_cached_file();
412  buffpek_pointers.close_cached_file();
413 
414  if (outfile->inited())
415  {
416  if (outfile->flush())
417  {
418  error= 1;
419  }
420  {
421  internal::my_off_t save_pos= outfile->pos_in_file;
422  /* For following reads */
423  if (outfile->reinit_io_cache(internal::READ_CACHE,0L,0,0))
424  {
425  error=1;
426  }
427  outfile->end_of_file=save_pos;
428  }
429  }
430 
431  if (error)
432  {
433  my_message(ER_FILSORT_ABORT, ER(ER_FILSORT_ABORT),
434  MYF(ME_ERROR+ME_WAITTANG));
435  }
436  else
437  {
438  getSession().status_var.filesort_rows+= (uint32_t) records;
439  }
440  examined_rows= param.examined_rows;
441  global_sort_buffer.sub(allocated_sort_memory);
442  table->sort= table_sort;
443  DRIZZLE_FILESORT_DONE(error, records);
444  return (error ? HA_POS_ERROR : records);
445 } /* filesort */
446 
449 static char **make_char_array(char **old_pos, uint32_t fields,
450  uint32_t length)
451 {
452  if (not old_pos)
453  old_pos= (char**) malloc((uint32_t) fields * (length + sizeof(char*)));
454  char** pos= old_pos;
455  char* char_pos= ((char*) (pos+fields)) - length;
456  while (fields--)
457  *(pos++) = (char_pos+= length);
458 
459  return old_pos;
460 } /* make_char_array */
461 
462 
465 static unsigned char *read_buffpek_from_file(internal::io_cache_st *buffpek_pointers, uint32_t count, unsigned char *buf)
466 {
467  uint32_t length= sizeof(buffpek)*count;
468  unsigned char *tmp= buf;
469  if (count > UINT_MAX/sizeof(buffpek))
470  return 0; /* sizeof(buffpek)*count will overflow */
471  if (!tmp)
472  tmp= (unsigned char *)malloc(length);
473  {
474  if (buffpek_pointers->reinit_io_cache(internal::READ_CACHE,0L,0,0) ||
475  buffpek_pointers->read(tmp, length))
476  {
477  free(tmp);
478  tmp= 0;
479  }
480  }
481  return tmp;
482 }
483 
484 
523  optimizer::SqlSelect *select,
524  unsigned char **sort_keys,
525  internal::io_cache_st *buffpek_pointers,
526  internal::io_cache_st *tempfile, internal::io_cache_st *indexfile)
527 {
528  int error,flag,quick_select;
529  uint32_t idx,indexpos,ref_length;
530  unsigned char *ref_pos,*next_pos,ref_buff[MAX_REFLENGTH];
531  internal::my_off_t record;
532  Table *sort_form;
533  volatile Session::killed_state_t *killed= getSession().getKilledPtr();
534  Cursor *file;
535  boost::dynamic_bitset<> *save_read_set= NULL;
536  boost::dynamic_bitset<> *save_write_set= NULL;
537 
538  idx=indexpos=0;
539  error=quick_select=0;
540  sort_form=param->sort_form;
541  file= sort_form->cursor;
542  ref_length=param->ref_length;
543  ref_pos= ref_buff;
544  quick_select=select && select->quick;
545  record=0;
546  flag= ((!indexfile && ! file->isOrdered())
547  || quick_select);
548  if (indexfile || flag)
549  ref_pos= &file->ref[0];
550  next_pos=ref_pos;
551  if (! indexfile && ! quick_select)
552  {
553  next_pos=(unsigned char*) 0; /* Find records in sequence */
554  if (file->startTableScan(1))
555  return(HA_POS_ERROR);
556  file->extra_opt(HA_EXTRA_CACHE, getSession().variables.read_buff_size);
557  }
558 
559  ReadRecord read_record_info;
560  if (quick_select)
561  {
562  if (select->quick->reset())
563  return(HA_POS_ERROR);
564 
565  if (read_record_info.init_read_record(&getSession(), select->quick->head, select, 1, 1))
566  return(HA_POS_ERROR);
567  }
568 
569  /* Remember original bitmaps */
570  save_read_set= sort_form->read_set;
571  save_write_set= sort_form->write_set;
572  /* Set up temporary column read map for columns used by sort */
573  sort_form->tmp_set.reset();
574  /* Temporary set for register_used_fields and register_field_in_read_map */
575  sort_form->read_set= &sort_form->tmp_set;
576  param->register_used_fields();
577  if (select && select->cond)
578  select->cond->walk(&Item::register_field_in_read_map, 1,
579  (unsigned char*) sort_form);
580  sort_form->column_bitmaps_set(sort_form->tmp_set, sort_form->tmp_set);
581 
582  for (;;)
583  {
584  if (quick_select)
585  {
586  if ((error= read_record_info.read_record(&read_record_info)))
587  {
588  error= HA_ERR_END_OF_FILE;
589  break;
590  }
591  file->position(sort_form->getInsertRecord());
592  }
593  else /* Not quick-select */
594  {
595  if (indexfile)
596  {
597  if (indexfile->read(ref_pos, ref_length))
598  {
599  error= errno ? errno : -1; /* Abort */
600  break;
601  }
602  error=file->rnd_pos(sort_form->getInsertRecord(),next_pos);
603  }
604  else
605  {
606  error=file->rnd_next(sort_form->getInsertRecord());
607 
608  if (!flag)
609  {
610  internal::my_store_ptr(ref_pos,ref_length,record); // Position to row
611  record+= sort_form->getShare()->db_record_offset;
612  }
613  else if (!error)
614  file->position(sort_form->getInsertRecord());
615  }
616  if (error && error != HA_ERR_RECORD_DELETED)
617  break;
618  }
619 
620  if (*killed)
621  {
622  if (!indexfile && !quick_select)
623  {
624  (void) file->extra(HA_EXTRA_NO_CACHE);
625  file->endTableScan();
626  }
627  return(HA_POS_ERROR);
628  }
629  if (error == 0)
630  param->examined_rows++;
631  if (error == 0 && (!select || select->skip_record() == 0))
632  {
633  if (idx == param->keys)
634  {
635  if (param->write_keys(sort_keys, idx, buffpek_pointers, tempfile))
636  return(HA_POS_ERROR);
637  idx=0;
638  indexpos++;
639  }
640  param->make_sortkey(sort_keys[idx++], ref_pos);
641  }
642  else
643  {
644  file->unlock_row();
645  }
646 
647  /* It does not make sense to read more keys in case of a fatal error */
648  if (getSession().is_error())
649  break;
650  }
651  if (quick_select)
652  {
653  /*
654  index_merge quick select uses table->sort when retrieving rows, so free
655  resoures it has allocated.
656  */
657  read_record_info.end_read_record();
658  }
659  else
660  {
661  (void) file->extra(HA_EXTRA_NO_CACHE); /* End cacheing of records */
662  if (!next_pos)
663  file->endTableScan();
664  }
665 
666  if (getSession().is_error())
667  return(HA_POS_ERROR);
668 
669  /* Signal we should use orignal column read and write maps */
670  sort_form->column_bitmaps_set(*save_read_set, *save_write_set);
671 
672  if (error != HA_ERR_END_OF_FILE)
673  {
674  sort_form->print_error(error,MYF(ME_ERROR | ME_WAITTANG));
675  return(HA_POS_ERROR);
676  }
677 
678  if (indexpos && idx && param->write_keys(sort_keys,idx,buffpek_pointers,tempfile))
679  {
680  return(HA_POS_ERROR);
681  }
682 
683  return tempfile->inited() ? (ha_rows) (tempfile->tell() / param->rec_length) : idx;
684 } /* find_all_keys */
685 
686 
709 int SortParam::write_keys(unsigned char **sort_keys, uint32_t count,
710  internal::io_cache_st *buffpek_pointers, internal::io_cache_st *tempfile)
711 {
713 
714  internal::my_string_ptr_sort((unsigned char*) sort_keys, (uint32_t) count, sort_length);
715  if (not tempfile->inited() &&
716  tempfile->open_cached_file(drizzle_tmpdir.c_str(), TEMP_PREFIX, DISK_BUFFER_SIZE, MYF(MY_WME)))
717  {
718  return 1;
719  }
720  /* check we won't have more buffpeks than we can possibly keep in memory */
721  if (buffpek_pointers->tell() + sizeof(buffpek) > UINT_MAX)
722  {
723  return 1;
724  }
725 
726  buffpek.file_pos= tempfile->tell();
727  if ((ha_rows) count > max_rows)
728  count=(uint32_t) max_rows;
729 
730  buffpek.count=(ha_rows) count;
731 
732  for (unsigned char **ptr= sort_keys + count ; sort_keys != ptr ; sort_keys++)
733  {
734  if (tempfile->write(*sort_keys, rec_length))
735  {
736  return 1;
737  }
738  }
739 
740  if (buffpek_pointers->write(&buffpek, sizeof(buffpek)))
741  {
742  return 1;
743  }
744 
745  return 0;
746 } /* write_keys */
747 
748 
753 static inline void store_length(unsigned char *to, uint32_t length, uint32_t pack_length)
754 {
755  switch (pack_length) {
756  case 1:
757  *to= (unsigned char) length;
758  break;
759  case 2:
760  mi_int2store(to, length);
761  break;
762  case 3:
763  mi_int3store(to, length);
764  break;
765  default:
766  mi_int4store(to, length);
767  break;
768  }
769 }
770 
771 
774 void SortParam::make_sortkey(unsigned char *to, unsigned char *ref_pos)
775 {
776  Field *field;
777  SortField *sort_field;
778  size_t length;
779 
780  for (sort_field= local_sortorder ;
781  sort_field != end ;
782  sort_field++)
783  {
784  bool maybe_null=0;
785  if ((field=sort_field->field))
786  { // Field
787  if (field->maybe_null())
788  {
789  if (field->is_null())
790  {
791  if (sort_field->reverse)
792  memset(to, 255, sort_field->length+1);
793  else
794  memset(to, 0, sort_field->length+1);
795  to+= sort_field->length+1;
796  continue;
797  }
798  else
799  *to++=1;
800  }
801  field->sort_string(to, sort_field->length);
802  }
803  else
804  { // Item
805  Item *item=sort_field->item;
806  maybe_null= item->maybe_null;
807 
808  switch (sort_field->result_type) {
809  case STRING_RESULT:
810  {
811  const charset_info_st * const cs=item->collation.collation;
812  char fill_char= ((cs->state & MY_CS_BINSORT) ? (char) 0 : ' ');
813  int diff;
814  uint32_t sort_field_length;
815 
816  if (maybe_null)
817  *to++=1;
818  /* All item->str() to use some extra byte for end null.. */
819  String tmp((char*) to,sort_field->length+4,cs);
820  String *res= item->str_result(&tmp);
821  if (!res)
822  {
823  if (maybe_null)
824  memset(to-1, 0, sort_field->length+1);
825  else
826  {
827  /*
828  This should only happen during extreme conditions if we run out
829  of memory or have an item marked not null when it can be null.
830  This code is here mainly to avoid a hard crash in this case.
831  */
832  assert(0);
833  memset(to, 0, sort_field->length); // Avoid crash
834  }
835  break;
836  }
837  length= res->length();
838  sort_field_length= sort_field->length - sort_field->suffix_length;
839  diff=(int) (sort_field_length - length);
840  if (diff < 0)
841  {
842  diff=0;
843  length= sort_field_length;
844  }
845  if (sort_field->suffix_length)
846  {
847  /* Store length last in result_string */
848  store_length(to + sort_field_length, length,
849  sort_field->suffix_length);
850  }
851  if (sort_field->need_strxnfrm)
852  {
853  char *from=(char*) res->ptr();
854  uint32_t tmp_length;
855  if ((unsigned char*) from == to)
856  {
857  set_if_smaller(length,sort_field->length);
858  memcpy(tmp_buffer,from,length);
859  from= tmp_buffer;
860  }
861  tmp_length= cs->strnxfrm(to,sort_field->length, (unsigned char*) from, length);
862  (void)(tmp_length);
863  assert(tmp_length == sort_field->length);
864  }
865  else
866  {
867  cs->strnxfrm((unsigned char*)to,length,(const unsigned char*)res->ptr(),length);
868  cs->cset->fill(cs, (char *)to+length,diff,fill_char);
869  }
870  break;
871  }
872  case INT_RESULT:
873  {
874  int64_t value= item->val_int_result();
875  if (maybe_null)
876  {
877  *to++=1;
878  if (item->null_value)
879  {
880  if (maybe_null)
881  memset(to-1, 0, sort_field->length+1);
882  else
883  {
884  memset(to, 0, sort_field->length);
885  }
886  break;
887  }
888  }
889  to[7]= (unsigned char) value;
890  to[6]= (unsigned char) (value >> 8);
891  to[5]= (unsigned char) (value >> 16);
892  to[4]= (unsigned char) (value >> 24);
893  to[3]= (unsigned char) (value >> 32);
894  to[2]= (unsigned char) (value >> 40);
895  to[1]= (unsigned char) (value >> 48);
896  if (item->unsigned_flag) /* Fix sign */
897  to[0]= (unsigned char) (value >> 56);
898  else
899  to[0]= (unsigned char) (value >> 56) ^ 128; /* Reverse signbit */
900  break;
901  }
902  case DECIMAL_RESULT:
903  {
904  type::Decimal dec_buf, *dec_val= item->val_decimal_result(&dec_buf);
905  if (maybe_null)
906  {
907  if (item->null_value)
908  {
909  memset(to, 0, sort_field->length+1);
910  to++;
911  break;
912  }
913  *to++=1;
914  }
915  dec_val->val_binary(E_DEC_FATAL_ERROR, to,
916  item->max_length - (item->decimals ? 1:0),
917  item->decimals);
918  break;
919  }
920  case REAL_RESULT:
921  {
922  double value= item->val_result();
923  if (maybe_null)
924  {
925  if (item->null_value)
926  {
927  memset(to, 0, sort_field->length+1);
928  to++;
929  break;
930  }
931  *to++=1;
932  }
933  change_double_for_sort(value,(unsigned char*) to);
934  break;
935  }
936  case ROW_RESULT:
937  default:
938  // This case should never be choosen
939  assert(0);
940  break;
941  }
942  }
943 
944  if (sort_field->reverse)
945  { /* Revers key */
946  if (maybe_null)
947  to[-1]= ~to[-1];
948  length=sort_field->length;
949  while (length--)
950  {
951  *to = (unsigned char) (~ *to);
952  to++;
953  }
954  }
955  else
956  {
957  to+= sort_field->length;
958  }
959  }
960 
961  if (addon_field)
962  {
963  /*
964  Save field values appended to sorted fields.
965  First null bit indicators are appended then field values follow.
966  In this implementation we use fixed layout for field values -
967  the same for all records.
968  */
969  sort_addon_field *addonf= addon_field;
970  unsigned char *nulls= to;
971  assert(addonf != 0);
972  memset(nulls, 0, addonf->offset);
973  to+= addonf->offset;
974  for ( ; (field= addonf->field) ; addonf++)
975  {
976  if (addonf->null_bit && field->is_null())
977  {
978  nulls[addonf->null_offset]|= addonf->null_bit;
979 #ifdef HAVE_VALGRIND
980  memset(to, 0, addonf->length);
981 #endif
982  }
983  else
984  {
985 #ifdef HAVE_VALGRIND
986  unsigned char *end= field->pack(to, field->ptr);
987  uint32_t local_length= (uint32_t) ((to + addonf->length) - end);
988  assert((int) local_length >= 0);
989  if (local_length)
990  memset(end, 0, local_length);
991 #else
992  (void) field->pack(to, field->ptr);
993 #endif
994  }
995  to+= addonf->length;
996  }
997  }
998  else
999  {
1000  /* Save filepos last */
1001  memcpy(to, ref_pos, (size_t) ref_length);
1002  }
1003 }
1004 
1005 
1006 /*
1007  fields used by sorting in the sorted table's read set
1008 */
1009 
1010 void SortParam::register_used_fields()
1011 {
1012  SortField *sort_field;
1013  Table *table= sort_form;
1014 
1015  for (sort_field= local_sortorder ;
1016  sort_field != end ;
1017  sort_field++)
1018  {
1019  Field *field;
1020  if ((field= sort_field->field))
1021  {
1022  if (field->getTable() == table)
1023  table->setReadSet(field->position());
1024  }
1025  else
1026  { // Item
1027  sort_field->item->walk(&Item::register_field_in_read_map, 1,
1028  (unsigned char *) table);
1029  }
1030  }
1031 
1032  if (addon_field)
1033  {
1034  sort_addon_field *addonf= addon_field;
1035  Field *field;
1036  for ( ; (field= addonf->field) ; addonf++)
1037  table->setReadSet(field->position());
1038  }
1039  else
1040  {
1041  /* Save filepos last */
1042  table->prepare_for_position();
1043  }
1044 }
1045 
1046 
1047 void SortParam::save_index(unsigned char **sort_keys, uint32_t count, filesort_info *table_sort)
1048 {
1049  internal::my_string_ptr_sort((unsigned char*) sort_keys, (uint32_t) count, sort_length);
1050  uint32_t offset= rec_length - res_length;
1051 
1052  if ((ha_rows) count > max_rows)
1053  count=(uint32_t) max_rows;
1054 
1055  unsigned char* to= table_sort->record_pointers= (unsigned char*) malloc(res_length*count);
1056 
1057  for (unsigned char **end_ptr= sort_keys+count ; sort_keys != end_ptr ; sort_keys++)
1058  {
1059  memcpy(to, *sort_keys+offset, res_length);
1060  to+= res_length;
1061  }
1062 }
1063 
1064 
1067 int FileSort::merge_many_buff(SortParam *param, unsigned char *sort_buffer,
1068  buffpek *buffpek_inst, uint32_t *maxbuffer, internal::io_cache_st *t_file)
1069 {
1070  internal::io_cache_st t_file2,*from_file,*to_file,*temp;
1071  buffpek *lastbuff;
1072 
1073  if (*maxbuffer < MERGEBUFF2)
1074  return 0;
1075  if (t_file->flush() ||
1076  t_file2.open_cached_file(drizzle_tmpdir.c_str(),TEMP_PREFIX,DISK_BUFFER_SIZE, MYF(MY_WME)))
1077  {
1078  return 1;
1079  }
1080 
1081  from_file= t_file ; to_file= &t_file2;
1082  while (*maxbuffer >= MERGEBUFF2)
1083  {
1084  if (from_file->reinit_io_cache(internal::READ_CACHE, 0, 0, 0)
1085  || to_file->reinit_io_cache(internal::WRITE_CACHE, 0, 0, 0))
1086  break;
1087 
1088  uint32_t i= 0;
1089  lastbuff= buffpek_inst;
1090  for (; i <= *maxbuffer - MERGEBUFF * 3 / 2; i += MERGEBUFF)
1091  {
1092  if (merge_buffers(param, from_file, to_file, sort_buffer, lastbuff++, buffpek_inst + i, buffpek_inst + i + MERGEBUFF - 1, 0))
1093  {
1094  goto cleanup;
1095  }
1096  }
1097 
1098  if (merge_buffers(param, from_file, to_file, sort_buffer, lastbuff++, buffpek_inst + i, buffpek_inst + *maxbuffer, 0)
1099  || to_file->flush())
1100  break;
1101 
1102  temp=from_file; from_file=to_file; to_file=temp;
1103  from_file->setup_io_cache();
1104  to_file->setup_io_cache();
1105  *maxbuffer= (uint32_t) (lastbuff-buffpek_inst)-1;
1106  }
1107 
1108 cleanup:
1109  to_file->close_cached_file(); // This holds old result
1110  if (to_file == t_file)
1111  {
1112  *t_file=t_file2; // Copy result file
1113  t_file->setup_io_cache();
1114  }
1115 
1116  return(*maxbuffer >= MERGEBUFF2); /* Return 1 if interrupted */
1117 } /* merge_many_buff */
1118 
1119 
1127 uint32_t FileSort::read_to_buffer(internal::io_cache_st *fromfile, buffpek *buffpek_inst, uint32_t rec_length)
1128 {
1129  uint32_t count;
1130  uint32_t length;
1131 
1132  if ((count= (uint32_t) min((ha_rows) buffpek_inst->max_keys,buffpek_inst->count)))
1133  {
1134  if (pread(fromfile->file,(unsigned char*) buffpek_inst->base, (length= rec_length*count),buffpek_inst->file_pos) == 0)
1135  return((uint32_t) -1);
1136 
1137  buffpek_inst->key= buffpek_inst->base;
1138  buffpek_inst->file_pos+= length; /* New filepos */
1139  buffpek_inst->count-= count;
1140  buffpek_inst->mem_count= count;
1141  }
1142  return (count*rec_length);
1143 } /* read_to_buffer */
1144 
1145 
1147 {
1148  qsort2_cmp key_compare;
1149  void *key_compare_arg;
1150 
1151  public:
1152  compare_functor(qsort2_cmp in_key_compare, void *in_compare_arg) :
1153  key_compare(in_key_compare),
1154  key_compare_arg(in_compare_arg)
1155  { }
1156 
1157  inline bool operator()(const buffpek *i, const buffpek *j) const
1158  {
1159  int val= key_compare(key_compare_arg, &i->key, &j->key);
1160 
1161  return (val >= 0);
1162  }
1163 };
1164 
1165 
1185  internal::io_cache_st *to_file, unsigned char *sort_buffer,
1186  buffpek *lastbuff, buffpek *Fb, buffpek *Tb,
1187  int flag)
1188 {
1189  int error;
1190  uint32_t rec_length,res_length,offset;
1191  size_t sort_length;
1192  uint32_t maxcount;
1193  ha_rows max_rows,org_max_rows;
1194  internal::my_off_t to_start_filepos;
1195  unsigned char *strpos;
1196  buffpek *buffpek_inst;
1197  qsort2_cmp cmp;
1198  void *first_cmp_arg;
1199  volatile Session::killed_state_t *killed= getSession().getKilledPtr();
1200  Session::killed_state_t not_killable;
1201 
1202  getSession().status_var.filesort_merge_passes++;
1203  if (param->not_killable)
1204  {
1205  killed= &not_killable;
1206  not_killable= Session::NOT_KILLED;
1207  }
1208 
1209  error=0;
1210  rec_length= param->rec_length;
1211  res_length= param->res_length;
1212  sort_length= param->sort_length;
1213  offset= rec_length-res_length;
1214  maxcount= (uint32_t) (param->keys/((uint32_t) (Tb-Fb) +1));
1215  to_start_filepos= to_file->tell();
1216  strpos= (unsigned char*) sort_buffer;
1217  org_max_rows=max_rows= param->max_rows;
1218 
1219  /* The following will fire if there is not enough space in sort_buffer */
1220  assert(maxcount!=0);
1221 
1222  if (param->unique_buff)
1223  {
1224  cmp= param->compare;
1225  first_cmp_arg= (void *) &param->cmp_context;
1226  }
1227  else
1228  {
1229  cmp= internal::get_ptr_compare(sort_length);
1230  first_cmp_arg= (void*) &sort_length;
1231  }
1232  priority_queue<buffpek *, vector<buffpek *>, compare_functor >
1233  queue(compare_functor(cmp, first_cmp_arg));
1234  for (buffpek_inst= Fb ; buffpek_inst <= Tb ; buffpek_inst++)
1235  {
1236  buffpek_inst->base= strpos;
1237  buffpek_inst->max_keys= maxcount;
1238  strpos+= (uint32_t) (error= (int) read_to_buffer(from_file, buffpek_inst,
1239  rec_length));
1240  if (error == -1)
1241  return -1;
1242 
1243  buffpek_inst->max_keys= buffpek_inst->mem_count; // If less data in buffers than expected
1244  queue.push(buffpek_inst);
1245  }
1246 
1247  if (param->unique_buff)
1248  {
1249  /*
1250  Called by Unique::get()
1251  Copy the first argument to param->unique_buff for unique removal.
1252  Store it also in 'to_file'.
1253 
1254  This is safe as we know that there is always more than one element
1255  in each block to merge (This is guaranteed by the Unique:: algorithm
1256  */
1257  buffpek_inst= queue.top();
1258  memcpy(param->unique_buff, buffpek_inst->key, rec_length);
1259  if (to_file->write(buffpek_inst->key, rec_length))
1260  {
1261  return 1;
1262  }
1263  buffpek_inst->key+= rec_length;
1264  buffpek_inst->mem_count--;
1265  if (!--max_rows)
1266  {
1267  error= 0;
1268  goto end;
1269  }
1270  /* Top element has been used */
1271  queue.pop();
1272  queue.push(buffpek_inst);
1273  }
1274  else
1275  {
1276  cmp= 0; // Not unique
1277  }
1278 
1279  while (queue.size() > 1)
1280  {
1281  if (*killed)
1282  {
1283  return 1;
1284  }
1285  for (;;)
1286  {
1287  buffpek_inst= queue.top();
1288  if (cmp) // Remove duplicates
1289  {
1290  if (!(*cmp)(first_cmp_arg, &(param->unique_buff),
1291  (unsigned char**) &buffpek_inst->key))
1292  goto skip_duplicate;
1293  memcpy(param->unique_buff, buffpek_inst->key, rec_length);
1294  }
1295  if (flag == 0)
1296  {
1297  if (to_file->write(buffpek_inst->key, rec_length))
1298  {
1299  return 1;
1300  }
1301  }
1302  else
1303  {
1304  if (to_file->write(buffpek_inst->key+offset, res_length))
1305  {
1306  return 1;
1307  }
1308  }
1309  if (!--max_rows)
1310  {
1311  error= 0;
1312  goto end;
1313  }
1314 
1315  skip_duplicate:
1316  buffpek_inst->key+= rec_length;
1317  if (! --buffpek_inst->mem_count)
1318  {
1319  if (!(error= (int) read_to_buffer(from_file,buffpek_inst,
1320  rec_length)))
1321  {
1322  queue.pop();
1323  break; /* One buffer have been removed */
1324  }
1325  else if (error == -1)
1326  {
1327  return -1;
1328  }
1329  }
1330  /* Top element has been replaced */
1331  queue.pop();
1332  queue.push(buffpek_inst);
1333  }
1334  }
1335  buffpek_inst= queue.top();
1336  buffpek_inst->base= sort_buffer;
1337  buffpek_inst->max_keys= param->keys;
1338 
1339  /*
1340  As we know all entries in the buffer are unique, we only have to
1341  check if the first one is the same as the last one we wrote
1342  */
1343  if (cmp)
1344  {
1345  if (!(*cmp)(first_cmp_arg, &(param->unique_buff), (unsigned char**) &buffpek_inst->key))
1346  {
1347  buffpek_inst->key+= rec_length; // Remove duplicate
1348  --buffpek_inst->mem_count;
1349  }
1350  }
1351 
1352  do
1353  {
1354  if ((ha_rows) buffpek_inst->mem_count > max_rows)
1355  { /* Don't write too many records */
1356  buffpek_inst->mem_count= (uint32_t) max_rows;
1357  buffpek_inst->count= 0; /* Don't read more */
1358  }
1359  max_rows-= buffpek_inst->mem_count;
1360  if (flag == 0)
1361  {
1362  if (to_file->write(buffpek_inst->key, (rec_length*buffpek_inst->mem_count)))
1363  {
1364  return 1;
1365  }
1366  }
1367  else
1368  {
1369  unsigned char *end;
1370  strpos= buffpek_inst->key+offset;
1371  for (end= strpos+buffpek_inst->mem_count*rec_length ;
1372  strpos != end ;
1373  strpos+= rec_length)
1374  {
1375  if (to_file->write(strpos, res_length))
1376  {
1377  return 1;
1378  }
1379  }
1380  }
1381  }
1382 
1383  while ((error=(int) read_to_buffer(from_file,buffpek_inst, rec_length))
1384  != -1 && error != 0);
1385 
1386 end:
1387  lastbuff->count= min(org_max_rows-max_rows, param->max_rows);
1388  lastbuff->file_pos= to_start_filepos;
1389 
1390  return error;
1391 } /* merge_buffers */
1392 
1393 
1394  /* Do a merge to output-file (save only positions) */
1395 
1396 int FileSort::merge_index(SortParam *param, unsigned char *sort_buffer,
1397  buffpek *buffpek_inst, uint32_t maxbuffer,
1398  internal::io_cache_st *tempfile, internal::io_cache_st *outfile)
1399 {
1400  if (merge_buffers(param,tempfile,outfile,sort_buffer,buffpek_inst,buffpek_inst,
1401  buffpek_inst+maxbuffer,1))
1402  return 1;
1403 
1404  return 0;
1405 } /* merge_index */
1406 
1407 
1408 static uint32_t suffix_length(uint32_t string_length)
1409 {
1410  if (string_length < 256)
1411  return 1;
1412  if (string_length < 256L*256L)
1413  return 2;
1414  if (string_length < 256L*256L*256L)
1415  return 3;
1416  return 4; // Can't sort longer than 4G
1417 }
1418 
1419 
1420 
1438 uint32_t FileSort::sortlength(SortField *sortorder, uint32_t s_length, bool *multi_byte_charset)
1439 {
1440  uint32_t length;
1441  const charset_info_st *cs;
1442  *multi_byte_charset= 0;
1443 
1444  length=0;
1445  for (; s_length-- ; sortorder++)
1446  {
1447  sortorder->need_strxnfrm= 0;
1448  sortorder->suffix_length= 0;
1449  if (sortorder->field)
1450  {
1451  cs= sortorder->field->sort_charset();
1452  sortorder->length= sortorder->field->sort_length();
1453  cs= sortorder->field->sort_charset();
1454  if (cs->use_strnxfrm())
1455  {
1456  sortorder->need_strxnfrm= 1;
1457  *multi_byte_charset= 1;
1458  sortorder->length= cs->coll->strnxfrmlen(cs, sortorder->length);
1459  }
1460  if (sortorder->field->maybe_null())
1461  length++; // Place for NULL marker
1462  }
1463  else
1464  {
1465  sortorder->result_type= sortorder->item->result_type();
1466  if (sortorder->item->result_as_int64_t())
1467  sortorder->result_type= INT_RESULT;
1468 
1469  switch (sortorder->result_type) {
1470  case STRING_RESULT:
1471  sortorder->length=sortorder->item->max_length;
1472  set_if_smaller(sortorder->length, getSession().variables.max_sort_length);
1473  cs= sortorder->item->collation.collation;
1474  if (cs->use_strnxfrm())
1475  {
1476  sortorder->length= cs->coll->strnxfrmlen(cs, sortorder->length);
1477  sortorder->need_strxnfrm= 1;
1478  *multi_byte_charset= 1;
1479  }
1480  else if (cs == &my_charset_bin)
1481  {
1482  /* Store length last to be able to sort blob/varbinary */
1483  sortorder->suffix_length= suffix_length(sortorder->length);
1484  sortorder->length+= sortorder->suffix_length;
1485  }
1486  break;
1487  case INT_RESULT:
1488  sortorder->length=8; // Size of intern int64_t
1489  break;
1490  case DECIMAL_RESULT:
1491  sortorder->length=
1492  class_decimal_get_binary_size(sortorder->item->max_length -
1493  (sortorder->item->decimals ? 1 : 0),
1494  sortorder->item->decimals);
1495  break;
1496  case REAL_RESULT:
1497  sortorder->length=sizeof(double);
1498  break;
1499  case ROW_RESULT:
1500  // This case should never be choosen
1501  assert(0);
1502  break;
1503  }
1504  if (sortorder->item->maybe_null)
1505  length++; // Place for NULL marker
1506  }
1507  set_if_smaller(sortorder->length, (size_t)getSession().variables.max_sort_length);
1508  length+=sortorder->length;
1509  }
1510  sortorder->field= (Field*) 0; // end marker
1511  return length;
1512 }
1513 
1514 
1541 sort_addon_field *FileSort::get_addon_fields(Field **ptabfield, uint32_t sortlength_arg, uint32_t *plength)
1542 {
1543  Field **pfield;
1544  Field *field;
1545  sort_addon_field *addonf;
1546  uint32_t length= 0;
1547  uint32_t fields= 0;
1548  uint32_t null_fields= 0;
1549 
1550  /*
1551  If there is a reference to a field in the query add it
1552  to the the set of appended fields.
1553  Note for future refinement:
1554  This this a too strong condition.
1555  Actually we need only the fields referred in the
1556  result set. And for some of them it makes sense to use
1557  the values directly from sorted fields.
1558  */
1559  *plength= 0;
1560 
1561  for (pfield= ptabfield; (field= *pfield) ; pfield++)
1562  {
1563  if (!(field->isReadSet()))
1564  continue;
1565  if (field->flags & BLOB_FLAG)
1566  return 0;
1567  length+= field->max_packed_col_length(field->pack_length());
1568  if (field->maybe_null())
1569  null_fields++;
1570  fields++;
1571  }
1572  if (!fields)
1573  return 0;
1574  length+= (null_fields+7)/8;
1575 
1576  if (length+sortlength_arg > getSession().variables.max_length_for_sort_data)
1577  return 0;
1578  addonf= (sort_addon_field *) malloc(sizeof(sort_addon_field) * (fields+1));
1579 
1580  *plength= length;
1581  length= (null_fields+7)/8;
1582  null_fields= 0;
1583  for (pfield= ptabfield; (field= *pfield) ; pfield++)
1584  {
1585  if (!(field->isReadSet()))
1586  continue;
1587  addonf->field= field;
1588  addonf->offset= length;
1589  if (field->maybe_null())
1590  {
1591  addonf->null_offset= null_fields/8;
1592  addonf->null_bit= 1<<(null_fields & 7);
1593  null_fields++;
1594  }
1595  else
1596  {
1597  addonf->null_offset= 0;
1598  addonf->null_bit= 0;
1599  }
1600  addonf->length= field->max_packed_col_length(field->pack_length());
1601  length+= addonf->length;
1602  addonf++;
1603  }
1604  addonf->field= 0; // Put end marker
1605 
1606  return (addonf-fields);
1607 }
1608 
1609 
1625 static void
1626 unpack_addon_fields(sort_addon_field *addon_field, unsigned char *buff)
1627 {
1628  Field *field;
1629  sort_addon_field *addonf= addon_field;
1630 
1631  for ( ; (field= addonf->field) ; addonf++)
1632  {
1633  if (addonf->null_bit && (addonf->null_bit & buff[addonf->null_offset]))
1634  {
1635  field->set_null();
1636  continue;
1637  }
1638  field->set_notnull();
1639  field->unpack(field->ptr, buff + addonf->offset);
1640  }
1641 }
1642 
1643 /*
1644 ** functions to change a double or float to a sortable string
1645 ** The following should work for IEEE
1646 */
1647 
1648 #define DBL_EXP_DIG (sizeof(double)*8-DBL_MANT_DIG)
1649 
1650 void change_double_for_sort(double nr,unsigned char *to)
1651 {
1652  unsigned char *tmp=(unsigned char*) to;
1653  if (nr == 0.0)
1654  { /* Change to zero string */
1655  tmp[0]=(unsigned char) 128;
1656  memset(tmp+1, 0, sizeof(nr)-1);
1657  }
1658  else
1659  {
1660 #ifdef WORDS_BIGENDIAN
1661  memcpy(tmp,&nr,sizeof(nr));
1662 #else
1663  {
1664  unsigned char *ptr= (unsigned char*) &nr;
1665 #if defined(__FLOAT_WORD_ORDER) && (__FLOAT_WORD_ORDER == __BIG_ENDIAN)
1666  tmp[0]= ptr[3]; tmp[1]=ptr[2]; tmp[2]= ptr[1]; tmp[3]=ptr[0];
1667  tmp[4]= ptr[7]; tmp[5]=ptr[6]; tmp[6]= ptr[5]; tmp[7]=ptr[4];
1668 #else
1669  tmp[0]= ptr[7]; tmp[1]=ptr[6]; tmp[2]= ptr[5]; tmp[3]=ptr[4];
1670  tmp[4]= ptr[3]; tmp[5]=ptr[2]; tmp[6]= ptr[1]; tmp[7]=ptr[0];
1671 #endif
1672  }
1673 #endif
1674  if (tmp[0] & 128) /* Negative */
1675  { /* make complement */
1676  uint32_t i;
1677  for (i=0 ; i < sizeof(nr); i++)
1678  tmp[i]=tmp[i] ^ (unsigned char) 255;
1679  }
1680  else
1681  { /* Set high and move exponent one up */
1682  uint16_t exp_part=(((uint16_t) tmp[0] << 8) | (uint16_t) tmp[1] |
1683  (uint16_t) 32768);
1684  exp_part+= (uint16_t) 1 << (16-1-DBL_EXP_DIG);
1685  tmp[0]= (unsigned char) (exp_part >> 8);
1686  tmp[1]= (unsigned char) exp_part;
1687  }
1688  }
1689 }
1690 
1691 } /* namespace drizzled */
virtual uint32_t pack_length() const
Definition: field.cc:707
int merge_many_buff(SortParam *param, unsigned char *sort_buffer, buffpek *buffpek, uint32_t *maxbuffer, internal::io_cache_st *t_file)
Definition: filesort.cc:1067
uint32_t suffix_length
Definition: sort_field.h:36
TODO: Rename this file - func.h is stupid.
virtual unsigned char * pack(unsigned char *to, const unsigned char *from, uint32_t max_length, bool low_byte_first)
Definition: field.cc:955
QuickSelectInterface * quick
Definition: range.h:277
Item_result result_type
Definition: sort_field.h:37
ha_rows find_all_keys(SortParam *param, optimizer::SqlSelect *select, unsigned char **sort_keys, internal::io_cache_st *buffpek_pointers, internal::io_cache_st *tempfile, internal::io_cache_st *indexfile)
Definition: filesort.cc:522
bool null_value
Definition: item.h:122
sort_addon_field * get_addon_fields(Field **ptabfield, uint32_t sortlength, uint32_t *plength)
Definition: filesort.cc:1541
virtual bool result_as_int64_t()
Definition: item.cc:683
int merge_buffers(SortParam *param, internal::io_cache_st *from_file, internal::io_cache_st *to_file, unsigned char *sort_buffer, buffpek *lastbuff, buffpek *Fb, buffpek *Tb, int flag)
Definition: filesort.cc:1184
static unsigned char * read_buffpek_from_file(internal::io_cache_st *buffer_file, uint32_t count, unsigned char *buf)
Definition: filesort.cc:465
bool maybe_null
Definition: item.h:121
virtual ha_rows estimate_rows_upper_bound()
Definition: cursor.h:288
ha_rows run(Table *table, SortField *sortorder, uint32_t s_length, optimizer::SqlSelect *select, ha_rows max_rows, bool sort_positions, ha_rows &examined_rows)
Definition: filesort.cc:187
static char ** make_char_array(char **old_pos, uint32_t fields, uint32_t length)
Definition: filesort.cc:449
virtual const unsigned char * unpack(unsigned char *to, const unsigned char *from, uint32_t param_data, bool low_byte_first)
Definition: field.cc:968
static void store_length(unsigned char *to, uint32_t length, uint32_t pack_length)
Definition: filesort.cc:753
static void unpack_addon_fields(sort_addon_field *addon_field, unsigned char *buff)
Definition: filesort.cc:1626
uint32_t sortlength(SortField *sortorder, uint32_t s_length, bool *multi_byte_charset)
Definition: filesort.cc:1438
Cursor * cursor
Definition: table.h:68
int write_keys(unsigned char **sort_keys, uint32_t count, internal::io_cache_st *buffer_file, internal::io_cache_st *tempfile)
Definition: filesort.cc:709
uint32_t ref_length
Definition: cursor.h:159
drizzle_system_variables & variables
Definition: session.h:199
bool reinit_io_cache(cache_type type_arg, my_off_t seek_offset, bool use_async_io, bool clear_cache)
Reset the cache.
Definition: mf_iocache.cc:280
void setup_io_cache()
Setup internal pointers inside io_cache_st.
Definition: mf_iocache.cc:121
uint32_t read_to_buffer(internal::io_cache_st *fromfile, buffpek *buffpek, uint32_t sort_length)
Definition: filesort.cc:1127
void make_sortkey(unsigned char *to, unsigned char *ref_pos)
Definition: filesort.cc:774
unsigned char * ptr
Definition: field.h:71
Item_subselect * containing_subselect()
Definition: table_list.cc:140