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  assert(tmp_length == sort_field->length);
863  }
864  else
865  {
866  cs->strnxfrm((unsigned char*)to,length,(const unsigned char*)res->ptr(),length);
867  cs->cset->fill(cs, (char *)to+length,diff,fill_char);
868  }
869  break;
870  }
871  case INT_RESULT:
872  {
873  int64_t value= item->val_int_result();
874  if (maybe_null)
875  {
876  *to++=1;
877  if (item->null_value)
878  {
879  if (maybe_null)
880  memset(to-1, 0, sort_field->length+1);
881  else
882  {
883  memset(to, 0, sort_field->length);
884  }
885  break;
886  }
887  }
888  to[7]= (unsigned char) value;
889  to[6]= (unsigned char) (value >> 8);
890  to[5]= (unsigned char) (value >> 16);
891  to[4]= (unsigned char) (value >> 24);
892  to[3]= (unsigned char) (value >> 32);
893  to[2]= (unsigned char) (value >> 40);
894  to[1]= (unsigned char) (value >> 48);
895  if (item->unsigned_flag) /* Fix sign */
896  to[0]= (unsigned char) (value >> 56);
897  else
898  to[0]= (unsigned char) (value >> 56) ^ 128; /* Reverse signbit */
899  break;
900  }
901  case DECIMAL_RESULT:
902  {
903  type::Decimal dec_buf, *dec_val= item->val_decimal_result(&dec_buf);
904  if (maybe_null)
905  {
906  if (item->null_value)
907  {
908  memset(to, 0, sort_field->length+1);
909  to++;
910  break;
911  }
912  *to++=1;
913  }
914  dec_val->val_binary(E_DEC_FATAL_ERROR, to,
915  item->max_length - (item->decimals ? 1:0),
916  item->decimals);
917  break;
918  }
919  case REAL_RESULT:
920  {
921  double value= item->val_result();
922  if (maybe_null)
923  {
924  if (item->null_value)
925  {
926  memset(to, 0, sort_field->length+1);
927  to++;
928  break;
929  }
930  *to++=1;
931  }
932  change_double_for_sort(value,(unsigned char*) to);
933  break;
934  }
935  case ROW_RESULT:
936  default:
937  // This case should never be choosen
938  assert(0);
939  break;
940  }
941  }
942 
943  if (sort_field->reverse)
944  { /* Revers key */
945  if (maybe_null)
946  to[-1]= ~to[-1];
947  length=sort_field->length;
948  while (length--)
949  {
950  *to = (unsigned char) (~ *to);
951  to++;
952  }
953  }
954  else
955  {
956  to+= sort_field->length;
957  }
958  }
959 
960  if (addon_field)
961  {
962  /*
963  Save field values appended to sorted fields.
964  First null bit indicators are appended then field values follow.
965  In this implementation we use fixed layout for field values -
966  the same for all records.
967  */
968  sort_addon_field *addonf= addon_field;
969  unsigned char *nulls= to;
970  assert(addonf != 0);
971  memset(nulls, 0, addonf->offset);
972  to+= addonf->offset;
973  for ( ; (field= addonf->field) ; addonf++)
974  {
975  if (addonf->null_bit && field->is_null())
976  {
977  nulls[addonf->null_offset]|= addonf->null_bit;
978 #ifdef HAVE_VALGRIND
979  memset(to, 0, addonf->length);
980 #endif
981  }
982  else
983  {
984 #ifdef HAVE_VALGRIND
985  unsigned char *end= field->pack(to, field->ptr);
986  uint32_t local_length= (uint32_t) ((to + addonf->length) - end);
987  assert((int) local_length >= 0);
988  if (local_length)
989  memset(end, 0, local_length);
990 #else
991  (void) field->pack(to, field->ptr);
992 #endif
993  }
994  to+= addonf->length;
995  }
996  }
997  else
998  {
999  /* Save filepos last */
1000  memcpy(to, ref_pos, (size_t) ref_length);
1001  }
1002 }
1003 
1004 
1005 /*
1006  fields used by sorting in the sorted table's read set
1007 */
1008 
1009 void SortParam::register_used_fields()
1010 {
1011  SortField *sort_field;
1012  Table *table= sort_form;
1013 
1014  for (sort_field= local_sortorder ;
1015  sort_field != end ;
1016  sort_field++)
1017  {
1018  Field *field;
1019  if ((field= sort_field->field))
1020  {
1021  if (field->getTable() == table)
1022  table->setReadSet(field->position());
1023  }
1024  else
1025  { // Item
1026  sort_field->item->walk(&Item::register_field_in_read_map, 1,
1027  (unsigned char *) table);
1028  }
1029  }
1030 
1031  if (addon_field)
1032  {
1033  sort_addon_field *addonf= addon_field;
1034  Field *field;
1035  for ( ; (field= addonf->field) ; addonf++)
1036  table->setReadSet(field->position());
1037  }
1038  else
1039  {
1040  /* Save filepos last */
1041  table->prepare_for_position();
1042  }
1043 }
1044 
1045 
1046 void SortParam::save_index(unsigned char **sort_keys, uint32_t count, filesort_info *table_sort)
1047 {
1048  internal::my_string_ptr_sort((unsigned char*) sort_keys, (uint32_t) count, sort_length);
1049  uint32_t offset= rec_length - res_length;
1050 
1051  if ((ha_rows) count > max_rows)
1052  count=(uint32_t) max_rows;
1053 
1054  unsigned char* to= table_sort->record_pointers= (unsigned char*) malloc(res_length*count);
1055 
1056  for (unsigned char **end_ptr= sort_keys+count ; sort_keys != end_ptr ; sort_keys++)
1057  {
1058  memcpy(to, *sort_keys+offset, res_length);
1059  to+= res_length;
1060  }
1061 }
1062 
1063 
1066 int FileSort::merge_many_buff(SortParam *param, unsigned char *sort_buffer,
1067  buffpek *buffpek_inst, uint32_t *maxbuffer, internal::io_cache_st *t_file)
1068 {
1069  internal::io_cache_st t_file2,*from_file,*to_file,*temp;
1070  buffpek *lastbuff;
1071 
1072  if (*maxbuffer < MERGEBUFF2)
1073  return 0;
1074  if (t_file->flush() ||
1075  t_file2.open_cached_file(drizzle_tmpdir.c_str(),TEMP_PREFIX,DISK_BUFFER_SIZE, MYF(MY_WME)))
1076  {
1077  return 1;
1078  }
1079 
1080  from_file= t_file ; to_file= &t_file2;
1081  while (*maxbuffer >= MERGEBUFF2)
1082  {
1083  if (from_file->reinit_io_cache(internal::READ_CACHE, 0, 0, 0)
1084  || to_file->reinit_io_cache(internal::WRITE_CACHE, 0, 0, 0))
1085  break;
1086 
1087  uint32_t i= 0;
1088  lastbuff= buffpek_inst;
1089  for (; i <= *maxbuffer - MERGEBUFF * 3 / 2; i += MERGEBUFF)
1090  {
1091  if (merge_buffers(param, from_file, to_file, sort_buffer, lastbuff++, buffpek_inst + i, buffpek_inst + i + MERGEBUFF - 1, 0))
1092  {
1093  goto cleanup;
1094  }
1095  }
1096 
1097  if (merge_buffers(param, from_file, to_file, sort_buffer, lastbuff++, buffpek_inst + i, buffpek_inst + *maxbuffer, 0)
1098  || to_file->flush())
1099  break;
1100 
1101  temp=from_file; from_file=to_file; to_file=temp;
1102  from_file->setup_io_cache();
1103  to_file->setup_io_cache();
1104  *maxbuffer= (uint32_t) (lastbuff-buffpek_inst)-1;
1105  }
1106 
1107 cleanup:
1108  to_file->close_cached_file(); // This holds old result
1109  if (to_file == t_file)
1110  {
1111  *t_file=t_file2; // Copy result file
1112  t_file->setup_io_cache();
1113  }
1114 
1115  return(*maxbuffer >= MERGEBUFF2); /* Return 1 if interrupted */
1116 } /* merge_many_buff */
1117 
1118 
1126 uint32_t FileSort::read_to_buffer(internal::io_cache_st *fromfile, buffpek *buffpek_inst, uint32_t rec_length)
1127 {
1128  uint32_t count;
1129  uint32_t length;
1130 
1131  if ((count= (uint32_t) min((ha_rows) buffpek_inst->max_keys,buffpek_inst->count)))
1132  {
1133  if (pread(fromfile->file,(unsigned char*) buffpek_inst->base, (length= rec_length*count),buffpek_inst->file_pos) == 0)
1134  return((uint32_t) -1);
1135 
1136  buffpek_inst->key= buffpek_inst->base;
1137  buffpek_inst->file_pos+= length; /* New filepos */
1138  buffpek_inst->count-= count;
1139  buffpek_inst->mem_count= count;
1140  }
1141  return (count*rec_length);
1142 } /* read_to_buffer */
1143 
1144 
1146 {
1147  qsort2_cmp key_compare;
1148  void *key_compare_arg;
1149 
1150  public:
1151  compare_functor(qsort2_cmp in_key_compare, void *in_compare_arg) :
1152  key_compare(in_key_compare),
1153  key_compare_arg(in_compare_arg)
1154  { }
1155 
1156  inline bool operator()(const buffpek *i, const buffpek *j) const
1157  {
1158  int val= key_compare(key_compare_arg, &i->key, &j->key);
1159 
1160  return (val >= 0);
1161  }
1162 };
1163 
1164 
1184  internal::io_cache_st *to_file, unsigned char *sort_buffer,
1185  buffpek *lastbuff, buffpek *Fb, buffpek *Tb,
1186  int flag)
1187 {
1188  int error;
1189  uint32_t rec_length,res_length,offset;
1190  size_t sort_length;
1191  uint32_t maxcount;
1192  ha_rows max_rows,org_max_rows;
1193  internal::my_off_t to_start_filepos;
1194  unsigned char *strpos;
1195  buffpek *buffpek_inst;
1196  qsort2_cmp cmp;
1197  void *first_cmp_arg;
1198  volatile Session::killed_state_t *killed= getSession().getKilledPtr();
1199  Session::killed_state_t not_killable;
1200 
1201  getSession().status_var.filesort_merge_passes++;
1202  if (param->not_killable)
1203  {
1204  killed= &not_killable;
1205  not_killable= Session::NOT_KILLED;
1206  }
1207 
1208  error=0;
1209  rec_length= param->rec_length;
1210  res_length= param->res_length;
1211  sort_length= param->sort_length;
1212  offset= rec_length-res_length;
1213  maxcount= (uint32_t) (param->keys/((uint32_t) (Tb-Fb) +1));
1214  to_start_filepos= to_file->tell();
1215  strpos= (unsigned char*) sort_buffer;
1216  org_max_rows=max_rows= param->max_rows;
1217 
1218  /* The following will fire if there is not enough space in sort_buffer */
1219  assert(maxcount!=0);
1220 
1221  if (param->unique_buff)
1222  {
1223  cmp= param->compare;
1224  first_cmp_arg= (void *) &param->cmp_context;
1225  }
1226  else
1227  {
1228  cmp= internal::get_ptr_compare(sort_length);
1229  first_cmp_arg= (void*) &sort_length;
1230  }
1231  priority_queue<buffpek *, vector<buffpek *>, compare_functor >
1232  queue(compare_functor(cmp, first_cmp_arg));
1233  for (buffpek_inst= Fb ; buffpek_inst <= Tb ; buffpek_inst++)
1234  {
1235  buffpek_inst->base= strpos;
1236  buffpek_inst->max_keys= maxcount;
1237  strpos+= (uint32_t) (error= (int) read_to_buffer(from_file, buffpek_inst,
1238  rec_length));
1239  if (error == -1)
1240  return -1;
1241 
1242  buffpek_inst->max_keys= buffpek_inst->mem_count; // If less data in buffers than expected
1243  queue.push(buffpek_inst);
1244  }
1245 
1246  if (param->unique_buff)
1247  {
1248  /*
1249  Called by Unique::get()
1250  Copy the first argument to param->unique_buff for unique removal.
1251  Store it also in 'to_file'.
1252 
1253  This is safe as we know that there is always more than one element
1254  in each block to merge (This is guaranteed by the Unique:: algorithm
1255  */
1256  buffpek_inst= queue.top();
1257  memcpy(param->unique_buff, buffpek_inst->key, rec_length);
1258  if (to_file->write(buffpek_inst->key, rec_length))
1259  {
1260  return 1;
1261  }
1262  buffpek_inst->key+= rec_length;
1263  buffpek_inst->mem_count--;
1264  if (!--max_rows)
1265  {
1266  error= 0;
1267  goto end;
1268  }
1269  /* Top element has been used */
1270  queue.pop();
1271  queue.push(buffpek_inst);
1272  }
1273  else
1274  {
1275  cmp= 0; // Not unique
1276  }
1277 
1278  while (queue.size() > 1)
1279  {
1280  if (*killed)
1281  {
1282  return 1;
1283  }
1284  for (;;)
1285  {
1286  buffpek_inst= queue.top();
1287  if (cmp) // Remove duplicates
1288  {
1289  if (!(*cmp)(first_cmp_arg, &(param->unique_buff),
1290  (unsigned char**) &buffpek_inst->key))
1291  goto skip_duplicate;
1292  memcpy(param->unique_buff, buffpek_inst->key, rec_length);
1293  }
1294  if (flag == 0)
1295  {
1296  if (to_file->write(buffpek_inst->key, rec_length))
1297  {
1298  return 1;
1299  }
1300  }
1301  else
1302  {
1303  if (to_file->write(buffpek_inst->key+offset, res_length))
1304  {
1305  return 1;
1306  }
1307  }
1308  if (!--max_rows)
1309  {
1310  error= 0;
1311  goto end;
1312  }
1313 
1314  skip_duplicate:
1315  buffpek_inst->key+= rec_length;
1316  if (! --buffpek_inst->mem_count)
1317  {
1318  if (!(error= (int) read_to_buffer(from_file,buffpek_inst,
1319  rec_length)))
1320  {
1321  queue.pop();
1322  break; /* One buffer have been removed */
1323  }
1324  else if (error == -1)
1325  {
1326  return -1;
1327  }
1328  }
1329  /* Top element has been replaced */
1330  queue.pop();
1331  queue.push(buffpek_inst);
1332  }
1333  }
1334  buffpek_inst= queue.top();
1335  buffpek_inst->base= sort_buffer;
1336  buffpek_inst->max_keys= param->keys;
1337 
1338  /*
1339  As we know all entries in the buffer are unique, we only have to
1340  check if the first one is the same as the last one we wrote
1341  */
1342  if (cmp)
1343  {
1344  if (!(*cmp)(first_cmp_arg, &(param->unique_buff), (unsigned char**) &buffpek_inst->key))
1345  {
1346  buffpek_inst->key+= rec_length; // Remove duplicate
1347  --buffpek_inst->mem_count;
1348  }
1349  }
1350 
1351  do
1352  {
1353  if ((ha_rows) buffpek_inst->mem_count > max_rows)
1354  { /* Don't write too many records */
1355  buffpek_inst->mem_count= (uint32_t) max_rows;
1356  buffpek_inst->count= 0; /* Don't read more */
1357  }
1358  max_rows-= buffpek_inst->mem_count;
1359  if (flag == 0)
1360  {
1361  if (to_file->write(buffpek_inst->key, (rec_length*buffpek_inst->mem_count)))
1362  {
1363  return 1;
1364  }
1365  }
1366  else
1367  {
1368  unsigned char *end;
1369  strpos= buffpek_inst->key+offset;
1370  for (end= strpos+buffpek_inst->mem_count*rec_length ;
1371  strpos != end ;
1372  strpos+= rec_length)
1373  {
1374  if (to_file->write(strpos, res_length))
1375  {
1376  return 1;
1377  }
1378  }
1379  }
1380  }
1381 
1382  while ((error=(int) read_to_buffer(from_file,buffpek_inst, rec_length))
1383  != -1 && error != 0);
1384 
1385 end:
1386  lastbuff->count= min(org_max_rows-max_rows, param->max_rows);
1387  lastbuff->file_pos= to_start_filepos;
1388 
1389  return error;
1390 } /* merge_buffers */
1391 
1392 
1393  /* Do a merge to output-file (save only positions) */
1394 
1395 int FileSort::merge_index(SortParam *param, unsigned char *sort_buffer,
1396  buffpek *buffpek_inst, uint32_t maxbuffer,
1397  internal::io_cache_st *tempfile, internal::io_cache_st *outfile)
1398 {
1399  if (merge_buffers(param,tempfile,outfile,sort_buffer,buffpek_inst,buffpek_inst,
1400  buffpek_inst+maxbuffer,1))
1401  return 1;
1402 
1403  return 0;
1404 } /* merge_index */
1405 
1406 
1407 static uint32_t suffix_length(uint32_t string_length)
1408 {
1409  if (string_length < 256)
1410  return 1;
1411  if (string_length < 256L*256L)
1412  return 2;
1413  if (string_length < 256L*256L*256L)
1414  return 3;
1415  return 4; // Can't sort longer than 4G
1416 }
1417 
1418 
1419 
1437 uint32_t FileSort::sortlength(SortField *sortorder, uint32_t s_length, bool *multi_byte_charset)
1438 {
1439  uint32_t length;
1440  const charset_info_st *cs;
1441  *multi_byte_charset= 0;
1442 
1443  length=0;
1444  for (; s_length-- ; sortorder++)
1445  {
1446  sortorder->need_strxnfrm= 0;
1447  sortorder->suffix_length= 0;
1448  if (sortorder->field)
1449  {
1450  cs= sortorder->field->sort_charset();
1451  sortorder->length= sortorder->field->sort_length();
1452  cs= sortorder->field->sort_charset();
1453  if (cs->use_strnxfrm())
1454  {
1455  sortorder->need_strxnfrm= 1;
1456  *multi_byte_charset= 1;
1457  sortorder->length= cs->coll->strnxfrmlen(cs, sortorder->length);
1458  }
1459  if (sortorder->field->maybe_null())
1460  length++; // Place for NULL marker
1461  }
1462  else
1463  {
1464  sortorder->result_type= sortorder->item->result_type();
1465  if (sortorder->item->result_as_int64_t())
1466  sortorder->result_type= INT_RESULT;
1467 
1468  switch (sortorder->result_type) {
1469  case STRING_RESULT:
1470  sortorder->length=sortorder->item->max_length;
1471  set_if_smaller(sortorder->length, getSession().variables.max_sort_length);
1472  cs= sortorder->item->collation.collation;
1473  if (cs->use_strnxfrm())
1474  {
1475  sortorder->length= cs->coll->strnxfrmlen(cs, sortorder->length);
1476  sortorder->need_strxnfrm= 1;
1477  *multi_byte_charset= 1;
1478  }
1479  else if (cs == &my_charset_bin)
1480  {
1481  /* Store length last to be able to sort blob/varbinary */
1482  sortorder->suffix_length= suffix_length(sortorder->length);
1483  sortorder->length+= sortorder->suffix_length;
1484  }
1485  break;
1486  case INT_RESULT:
1487  sortorder->length=8; // Size of intern int64_t
1488  break;
1489  case DECIMAL_RESULT:
1490  sortorder->length=
1491  class_decimal_get_binary_size(sortorder->item->max_length -
1492  (sortorder->item->decimals ? 1 : 0),
1493  sortorder->item->decimals);
1494  break;
1495  case REAL_RESULT:
1496  sortorder->length=sizeof(double);
1497  break;
1498  case ROW_RESULT:
1499  // This case should never be choosen
1500  assert(0);
1501  break;
1502  }
1503  if (sortorder->item->maybe_null)
1504  length++; // Place for NULL marker
1505  }
1506  set_if_smaller(sortorder->length, (size_t)getSession().variables.max_sort_length);
1507  length+=sortorder->length;
1508  }
1509  sortorder->field= (Field*) 0; // end marker
1510  return length;
1511 }
1512 
1513 
1540 sort_addon_field *FileSort::get_addon_fields(Field **ptabfield, uint32_t sortlength_arg, uint32_t *plength)
1541 {
1542  Field **pfield;
1543  Field *field;
1544  sort_addon_field *addonf;
1545  uint32_t length= 0;
1546  uint32_t fields= 0;
1547  uint32_t null_fields= 0;
1548 
1549  /*
1550  If there is a reference to a field in the query add it
1551  to the the set of appended fields.
1552  Note for future refinement:
1553  This this a too strong condition.
1554  Actually we need only the fields referred in the
1555  result set. And for some of them it makes sense to use
1556  the values directly from sorted fields.
1557  */
1558  *plength= 0;
1559 
1560  for (pfield= ptabfield; (field= *pfield) ; pfield++)
1561  {
1562  if (!(field->isReadSet()))
1563  continue;
1564  if (field->flags & BLOB_FLAG)
1565  return 0;
1566  length+= field->max_packed_col_length(field->pack_length());
1567  if (field->maybe_null())
1568  null_fields++;
1569  fields++;
1570  }
1571  if (!fields)
1572  return 0;
1573  length+= (null_fields+7)/8;
1574 
1575  if (length+sortlength_arg > getSession().variables.max_length_for_sort_data)
1576  return 0;
1577  addonf= (sort_addon_field *) malloc(sizeof(sort_addon_field) * (fields+1));
1578 
1579  *plength= length;
1580  length= (null_fields+7)/8;
1581  null_fields= 0;
1582  for (pfield= ptabfield; (field= *pfield) ; pfield++)
1583  {
1584  if (!(field->isReadSet()))
1585  continue;
1586  addonf->field= field;
1587  addonf->offset= length;
1588  if (field->maybe_null())
1589  {
1590  addonf->null_offset= null_fields/8;
1591  addonf->null_bit= 1<<(null_fields & 7);
1592  null_fields++;
1593  }
1594  else
1595  {
1596  addonf->null_offset= 0;
1597  addonf->null_bit= 0;
1598  }
1599  addonf->length= field->max_packed_col_length(field->pack_length());
1600  length+= addonf->length;
1601  addonf++;
1602  }
1603  addonf->field= 0; // Put end marker
1604 
1605  return (addonf-fields);
1606 }
1607 
1608 
1624 static void
1625 unpack_addon_fields(sort_addon_field *addon_field, unsigned char *buff)
1626 {
1627  Field *field;
1628  sort_addon_field *addonf= addon_field;
1629 
1630  for ( ; (field= addonf->field) ; addonf++)
1631  {
1632  if (addonf->null_bit && (addonf->null_bit & buff[addonf->null_offset]))
1633  {
1634  field->set_null();
1635  continue;
1636  }
1637  field->set_notnull();
1638  field->unpack(field->ptr, buff + addonf->offset);
1639  }
1640 }
1641 
1642 /*
1643 ** functions to change a double or float to a sortable string
1644 ** The following should work for IEEE
1645 */
1646 
1647 #define DBL_EXP_DIG (sizeof(double)*8-DBL_MANT_DIG)
1648 
1649 void change_double_for_sort(double nr,unsigned char *to)
1650 {
1651  unsigned char *tmp=(unsigned char*) to;
1652  if (nr == 0.0)
1653  { /* Change to zero string */
1654  tmp[0]=(unsigned char) 128;
1655  memset(tmp+1, 0, sizeof(nr)-1);
1656  }
1657  else
1658  {
1659 #ifdef WORDS_BIGENDIAN
1660  memcpy(tmp,&nr,sizeof(nr));
1661 #else
1662  {
1663  unsigned char *ptr= (unsigned char*) &nr;
1664 #if defined(__FLOAT_WORD_ORDER) && (__FLOAT_WORD_ORDER == __BIG_ENDIAN)
1665  tmp[0]= ptr[3]; tmp[1]=ptr[2]; tmp[2]= ptr[1]; tmp[3]=ptr[0];
1666  tmp[4]= ptr[7]; tmp[5]=ptr[6]; tmp[6]= ptr[5]; tmp[7]=ptr[4];
1667 #else
1668  tmp[0]= ptr[7]; tmp[1]=ptr[6]; tmp[2]= ptr[5]; tmp[3]=ptr[4];
1669  tmp[4]= ptr[3]; tmp[5]=ptr[2]; tmp[6]= ptr[1]; tmp[7]=ptr[0];
1670 #endif
1671  }
1672 #endif
1673  if (tmp[0] & 128) /* Negative */
1674  { /* make complement */
1675  uint32_t i;
1676  for (i=0 ; i < sizeof(nr); i++)
1677  tmp[i]=tmp[i] ^ (unsigned char) 255;
1678  }
1679  else
1680  { /* Set high and move exponent one up */
1681  uint16_t exp_part=(((uint16_t) tmp[0] << 8) | (uint16_t) tmp[1] |
1682  (uint16_t) 32768);
1683  exp_part+= (uint16_t) 1 << (16-1-DBL_EXP_DIG);
1684  tmp[0]= (unsigned char) (exp_part >> 8);
1685  tmp[1]= (unsigned char) exp_part;
1686  }
1687  }
1688 }
1689 
1690 } /* 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:1066
uint32_t suffix_length
Definition: sort_field.h:36
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:1540
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:1183
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:1625
uint32_t sortlength(SortField *sortorder, uint32_t s_length, bool *multi_byte_charset)
Definition: filesort.cc:1437
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:1126
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