Drizzled Public API Documentation

filesort.cc
Go to the documentation of this file.
00001 /* Copyright (C) 2000-2006 MySQL AB
00002 
00003    This program is free software; you can redistribute it and/or modify
00004    it under the terms of the GNU General Public License as published by
00005    the Free Software Foundation; version 2 of the License.
00006 
00007    This program is distributed in the hope that it will be useful,
00008    but WITHOUT ANY WARRANTY; without even the implied warranty of
00009    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00010    GNU General Public License for more details.
00011 
00012    You should have received a copy of the GNU General Public License
00013    along with this program; if not, write to the Free Software
00014    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */
00015 
00016 
00024 #include <config.h>
00025 
00026 #include <float.h>
00027 #include <limits.h>
00028 
00029 #include <queue>
00030 #include <algorithm>
00031 #include <iostream>
00032 
00033 #include <drizzled/drizzled.h>
00034 #include <drizzled/sql_sort.h>
00035 #include <drizzled/filesort.h>
00036 #include <drizzled/error.h>
00037 #include <drizzled/probes.h>
00038 #include <drizzled/session.h>
00039 #include <drizzled/table.h>
00040 #include <drizzled/table_list.h>
00041 #include <drizzled/optimizer/range.h>
00042 #include <drizzled/records.h>
00043 #include <drizzled/internal/iocache.h>
00044 #include <drizzled/internal/my_sys.h>
00045 #include <plugin/myisam/myisam.h>
00046 #include <drizzled/plugin/transactional_storage_engine.h>
00047 #include <drizzled/atomics.h>
00048 #include <drizzled/global_buffer.h>
00049 #include <drizzled/sort_field.h>
00050 #include <drizzled/item/subselect.h>
00051 #include <drizzled/statistics_variables.h>
00052 #include <drizzled/system_variables.h>
00053 
00054 using namespace std;
00055 
00056 namespace drizzled {
00057 
00058 /* Defines used by filesort and uniques */
00059 #define MERGEBUFF   7
00060 #define MERGEBUFF2    15
00061 
00062 class BufferCompareContext
00063 {
00064 public:
00065   qsort_cmp2 key_compare;
00066   void *key_compare_arg;
00067 
00068   BufferCompareContext() :
00069     key_compare(0),
00070     key_compare_arg(0)
00071   { }
00072 
00073 };
00074 
00075 class SortParam {
00076 public:
00077   uint32_t rec_length;          /* Length of sorted records */
00078   uint32_t sort_length;     /* Length of sorted columns */
00079   uint32_t ref_length;      /* Length of record ref. */
00080   uint32_t addon_length;        /* Length of added packed fields */
00081   uint32_t res_length;          /* Length of records in final sorted file/buffer */
00082   uint32_t keys;        /* Max keys / buffer */
00083   ha_rows max_rows,examined_rows;
00084   Table *sort_form;     /* For quicker make_sortkey */
00085   SortField *local_sortorder;
00086   SortField *end;
00087   sort_addon_field *addon_field; /* Descriptors for companion fields */
00088   unsigned char *unique_buff;
00089   bool not_killable;
00090   char *tmp_buffer;
00091   /* The fields below are used only by Unique class */
00092   qsort2_cmp compare;
00093   BufferCompareContext cmp_context;
00094 
00095   SortParam() :
00096     rec_length(0),
00097     sort_length(0),
00098     ref_length(0),
00099     addon_length(0),
00100     res_length(0),
00101     keys(0),
00102     max_rows(0),
00103     examined_rows(0),
00104     sort_form(0),
00105     local_sortorder(0),
00106     end(0),
00107     addon_field(0),
00108     unique_buff(0),
00109     not_killable(0),
00110     tmp_buffer(0),
00111     compare(0)
00112   {
00113   }
00114 
00115   ~SortParam()
00116   {
00117     free(tmp_buffer);
00118   }
00119 
00120   int write_keys(unsigned char * *sort_keys,
00121                  uint32_t count,
00122                  internal::io_cache_st *buffer_file,
00123                  internal::io_cache_st *tempfile);
00124 
00125   void make_sortkey(unsigned char *to,
00126                     unsigned char *ref_pos);
00127   void register_used_fields();
00128   void save_index(unsigned char **sort_keys,
00129                   uint32_t count,
00130                   filesort_info *table_sort);
00131 
00132 };
00133 
00134 /* functions defined in this file */
00135 
00136 static char **make_char_array(char **old_pos, uint32_t fields,
00137                               uint32_t length);
00138 
00139 static unsigned char *read_buffpek_from_file(internal::io_cache_st *buffer_file,
00140                                              uint32_t count,
00141                                              unsigned char *buf);
00142 
00143 static uint32_t suffix_length(uint32_t string_length);
00144 static void unpack_addon_fields(sort_addon_field *addon_field,
00145                                 unsigned char *buff);
00146 
00147 FileSort::FileSort(Session &arg) :
00148   _session(arg)
00149 { 
00150 }
00151 
00187 ha_rows FileSort::run(Table *table, SortField *sortorder, uint32_t s_length,
00188                       optimizer::SqlSelect *select, ha_rows max_rows,
00189                       bool sort_positions, ha_rows &examined_rows)
00190 {
00191   int error= 1;
00192   uint32_t memavl= 0, min_sort_memory;
00193   uint32_t maxbuffer;
00194   size_t allocated_sort_memory= 0;
00195   buffpek *buffpek_inst= 0;
00196   ha_rows records= HA_POS_ERROR;
00197   unsigned char **sort_keys= 0;
00198   internal::io_cache_st tempfile;
00199   internal::io_cache_st buffpek_pointers;
00200   internal::io_cache_st *selected_records_file;
00201   internal::io_cache_st *outfile;
00202   SortParam param;
00203   bool multi_byte_charset;
00204 
00205   /*
00206     Don't use table->sort in filesort as it is also used by
00207     QuickIndexMergeSelect. Work with a copy and put it back at the end
00208     when index_merge select has finished with it.
00209   */
00210   filesort_info table_sort(table->sort);
00211   table->sort.io_cache= NULL;
00212 
00213   TableList *tab= table->pos_in_table_list;
00214   Item_subselect *subselect= tab ? tab->containing_subselect() : 0;
00215 
00216   DRIZZLE_FILESORT_START(table->getShare()->getSchemaName(), table->getShare()->getTableName());
00217 
00218   /*
00219    Release InnoDB's adaptive hash index latch (if holding) before
00220    running a sort.
00221   */
00222   plugin::TransactionalStorageEngine::releaseTemporaryLatches(&getSession());
00223 
00224 
00225   outfile= table_sort.io_cache;
00226   assert(tempfile.buffer == 0);
00227   assert(buffpek_pointers.buffer == 0);
00228 
00229   param.sort_length= sortlength(sortorder, s_length, &multi_byte_charset);
00230   param.ref_length= table->cursor->ref_length;
00231 
00232   if (!(table->cursor->getEngine()->check_flag(HTON_BIT_FAST_KEY_READ)) && !sort_positions)
00233   {
00234     /*
00235       Get the descriptors of all fields whose values are appended
00236       to sorted fields and get its total length in param.spack_length.
00237     */
00238     param.addon_field= get_addon_fields(table->getFields(),
00239                                         param.sort_length,
00240                                         &param.addon_length);
00241   }
00242 
00243   table_sort.addon_buf= 0;
00244   table_sort.addon_length= param.addon_length;
00245   table_sort.addon_field= param.addon_field;
00246   table_sort.unpack= unpack_addon_fields;
00247   if (param.addon_field)
00248   {
00249     param.res_length= param.addon_length;
00250     table_sort.addon_buf= (unsigned char *) malloc(param.addon_length);
00251   }
00252   else
00253   {
00254     param.res_length= param.ref_length;
00255     /*
00256       The reference to the record is considered
00257       as an additional sorted field
00258     */
00259     param.sort_length+= param.ref_length;
00260   }
00261   param.rec_length= param.sort_length+param.addon_length;
00262   param.max_rows= max_rows;
00263 
00264   if (select && select->quick)
00265   {
00266     getSession().status_var.filesort_range_count++;
00267   }
00268   else
00269   {
00270     getSession().status_var.filesort_scan_count++;
00271   }
00272 #ifdef CAN_TRUST_RANGE
00273   if (select && select->quick && select->quick->records > 0L)
00274   {
00275     records= min((ha_rows) (select->quick->records*2+EXTRA_RECORDS*2),
00276                  table->cursor->stats.records)+EXTRA_RECORDS;
00277     selected_records_file=0;
00278   }
00279   else
00280 #endif
00281   {
00282     records= table->cursor->estimate_rows_upper_bound();
00283     /*
00284       If number of records is not known, use as much of sort buffer
00285       as possible.
00286     */
00287     if (records == HA_POS_ERROR)
00288       records--;  // we use 'records+1' below.
00289     selected_records_file= 0;
00290   }
00291 
00292   if (multi_byte_charset)
00293     param.tmp_buffer= (char*) malloc(param.sort_length);
00294 
00295   memavl= getSession().variables.sortbuff_size;
00296   min_sort_memory= max((uint32_t)MIN_SORT_MEMORY, param.sort_length*MERGEBUFF2);
00297   while (memavl >= min_sort_memory)
00298   {
00299     uint32_t old_memavl;
00300     uint32_t keys= memavl/(param.rec_length+sizeof(char*));
00301     param.keys= (uint32_t) min(records+1, (ha_rows)keys);
00302 
00303     allocated_sort_memory= param.keys * param.rec_length;
00304     if (not global_sort_buffer.add(allocated_sort_memory))
00305     {
00306       my_error(ER_OUT_OF_GLOBAL_SORTMEMORY, MYF(ME_ERROR+ME_WAITTANG));
00307       goto err;
00308     }
00309 
00310     if ((table_sort.sort_keys=
00311    (unsigned char **) make_char_array((char **) table_sort.sort_keys,
00312                                             param.keys, param.rec_length)))
00313       break;
00314 
00315     global_sort_buffer.sub(allocated_sort_memory);
00316     old_memavl= memavl;
00317     if ((memavl= memavl/4*3) < min_sort_memory && old_memavl > min_sort_memory)
00318       memavl= min_sort_memory;
00319   }
00320   sort_keys= table_sort.sort_keys;
00321   if (memavl < min_sort_memory)
00322   {
00323     my_error(ER_OUT_OF_SORTMEMORY,MYF(ME_ERROR+ME_WAITTANG));
00324     goto err;
00325   }
00326 
00327   if (buffpek_pointers.open_cached_file(drizzle_tmpdir.c_str(),TEMP_PREFIX, DISK_BUFFER_SIZE, MYF(MY_WME)))
00328   {
00329     goto err;
00330   }
00331 
00332   param.keys--;       /* TODO: check why we do this */
00333   param.sort_form= table;
00334   param.end=(param.local_sortorder=sortorder)+s_length;
00335   if ((records= find_all_keys(&param,select,sort_keys, &buffpek_pointers,
00336                               &tempfile, selected_records_file)) == HA_POS_ERROR)
00337   {
00338     goto err;
00339   }
00340   maxbuffer= (uint32_t)(buffpek_pointers.tell() / sizeof(*buffpek_inst));
00341 
00342   if (maxbuffer == 0)     // The whole set is in memory
00343   {
00344     param.save_index(sort_keys,(uint32_t) records, &table_sort);
00345   }
00346   else
00347   {
00348     if (table_sort.buffpek && table_sort.buffpek_len < maxbuffer)
00349     {
00350       free(table_sort.buffpek);
00351       table_sort.buffpek = 0;
00352     }
00353     if (!(table_sort.buffpek=
00354           (unsigned char *) read_buffpek_from_file(&buffpek_pointers, maxbuffer, table_sort.buffpek)))
00355     {
00356       goto err;
00357     }
00358     buffpek_inst= (buffpek *) table_sort.buffpek;
00359     table_sort.buffpek_len= maxbuffer;
00360     buffpek_pointers.close_cached_file();
00361   /* Open cached file if it isn't open */
00362     if (not outfile->inited() && outfile->open_cached_file(drizzle_tmpdir.c_str(),TEMP_PREFIX,READ_RECORD_BUFFER, MYF(MY_WME)))
00363     {
00364       goto err;
00365     }
00366 
00367     if (outfile->reinit_io_cache(internal::WRITE_CACHE,0L,0,0))
00368     {
00369       goto err;
00370     }
00371 
00372     /*
00373       Use also the space previously used by string pointers in sort_buffer
00374       for temporary key storage.
00375     */
00376     param.keys=((param.keys*(param.rec_length+sizeof(char*))) / param.rec_length-1);
00377 
00378     maxbuffer--;        // Offset from 0
00379     if (merge_many_buff(&param,(unsigned char*) sort_keys,buffpek_inst,&maxbuffer, &tempfile))
00380     {
00381       goto err;
00382     }
00383 
00384     if (tempfile.flush() || tempfile.reinit_io_cache(internal::READ_CACHE,0L,0,0))
00385     {
00386       goto err;
00387     }
00388 
00389     if (merge_index(&param,(unsigned char*) sort_keys,buffpek_inst,maxbuffer,&tempfile, outfile))
00390     {
00391       goto err;
00392     }
00393   }
00394 
00395   if (records > param.max_rows)
00396   {
00397     records= param.max_rows;
00398   }
00399   error =0;
00400 
00401  err:
00402   if (not subselect || not subselect->is_uncacheable())
00403   {
00404     free(sort_keys);
00405     table_sort.sort_keys= 0;
00406     free(buffpek_inst);
00407     table_sort.buffpek= 0;
00408     table_sort.buffpek_len= 0;
00409   }
00410 
00411   tempfile.close_cached_file();
00412   buffpek_pointers.close_cached_file();
00413 
00414   if (outfile->inited())
00415   {
00416     if (outfile->flush())
00417     {
00418       error= 1;
00419     }
00420     {
00421       internal::my_off_t save_pos= outfile->pos_in_file;
00422       /* For following reads */
00423       if (outfile->reinit_io_cache(internal::READ_CACHE,0L,0,0))
00424       {
00425         error=1;
00426       }
00427       outfile->end_of_file=save_pos;
00428     }
00429   }
00430 
00431   if (error)
00432   {
00433     my_message(ER_FILSORT_ABORT, ER(ER_FILSORT_ABORT),
00434                MYF(ME_ERROR+ME_WAITTANG));
00435   }
00436   else
00437   {
00438     getSession().status_var.filesort_rows+= (uint32_t) records;
00439   }
00440   examined_rows= param.examined_rows;
00441   global_sort_buffer.sub(allocated_sort_memory);
00442   table->sort= table_sort;
00443   DRIZZLE_FILESORT_DONE(error, records);
00444   return (error ? HA_POS_ERROR : records);
00445 } /* filesort */
00446 
00449 static char **make_char_array(char **old_pos, uint32_t fields,
00450                               uint32_t length)
00451 {
00452   if (not old_pos)
00453     old_pos= (char**) malloc((uint32_t) fields * (length + sizeof(char*)));
00454   char** pos= old_pos; 
00455   char* char_pos= ((char*) (pos+fields)) - length;
00456   while (fields--) 
00457     *(pos++) = (char_pos+= length);
00458 
00459   return old_pos;
00460 } /* make_char_array */
00461 
00462 
00465 static unsigned char *read_buffpek_from_file(internal::io_cache_st *buffpek_pointers, uint32_t count, unsigned char *buf)
00466 {
00467   uint32_t length= sizeof(buffpek)*count;
00468   unsigned char *tmp= buf;
00469   if (count > UINT_MAX/sizeof(buffpek))
00470     return 0; /* sizeof(buffpek)*count will overflow */
00471   if (!tmp)
00472     tmp= (unsigned char *)malloc(length);
00473   {
00474     if (buffpek_pointers->reinit_io_cache(internal::READ_CACHE,0L,0,0) ||
00475       buffpek_pointers->read(tmp, length))
00476     {
00477       free(tmp);
00478       tmp= 0;
00479     }
00480   }
00481   return tmp;
00482 }
00483 
00484 
00522 ha_rows FileSort::find_all_keys(SortParam *param, 
00523                                 optimizer::SqlSelect *select,
00524                                 unsigned char **sort_keys,
00525                                 internal::io_cache_st *buffpek_pointers,
00526                                 internal::io_cache_st *tempfile, internal::io_cache_st *indexfile)
00527 {
00528   int error,flag,quick_select;
00529   uint32_t idx,indexpos,ref_length;
00530   unsigned char *ref_pos,*next_pos,ref_buff[MAX_REFLENGTH];
00531   internal::my_off_t record;
00532   Table *sort_form;
00533   volatile Session::killed_state_t *killed= getSession().getKilledPtr();
00534   Cursor *file;
00535   boost::dynamic_bitset<> *save_read_set= NULL;
00536   boost::dynamic_bitset<> *save_write_set= NULL;
00537 
00538   idx=indexpos=0;
00539   error=quick_select=0;
00540   sort_form=param->sort_form;
00541   file= sort_form->cursor;
00542   ref_length=param->ref_length;
00543   ref_pos= ref_buff;
00544   quick_select=select && select->quick;
00545   record=0;
00546   flag= ((!indexfile && ! file->isOrdered())
00547    || quick_select);
00548   if (indexfile || flag)
00549     ref_pos= &file->ref[0];
00550   next_pos=ref_pos;
00551   if (! indexfile && ! quick_select)
00552   {
00553     next_pos=(unsigned char*) 0;      /* Find records in sequence */
00554     if (file->startTableScan(1))
00555       return(HA_POS_ERROR);
00556     file->extra_opt(HA_EXTRA_CACHE, getSession().variables.read_buff_size);
00557   }
00558 
00559   ReadRecord read_record_info;
00560   if (quick_select)
00561   {
00562     if (select->quick->reset())
00563       return(HA_POS_ERROR);
00564 
00565     if (read_record_info.init_read_record(&getSession(), select->quick->head, select, 1, 1))
00566       return(HA_POS_ERROR);
00567   }
00568 
00569   /* Remember original bitmaps */
00570   save_read_set=  sort_form->read_set;
00571   save_write_set= sort_form->write_set;
00572   /* Set up temporary column read map for columns used by sort */
00573   sort_form->tmp_set.reset();
00574   /* Temporary set for register_used_fields and register_field_in_read_map */
00575   sort_form->read_set= &sort_form->tmp_set;
00576   param->register_used_fields();
00577   if (select && select->cond)
00578     select->cond->walk(&Item::register_field_in_read_map, 1,
00579                        (unsigned char*) sort_form);
00580   sort_form->column_bitmaps_set(sort_form->tmp_set, sort_form->tmp_set);
00581 
00582   for (;;)
00583   {
00584     if (quick_select)
00585     {
00586       if ((error= read_record_info.read_record(&read_record_info)))
00587       {
00588         error= HA_ERR_END_OF_FILE;
00589         break;
00590       }
00591       file->position(sort_form->getInsertRecord());
00592     }
00593     else          /* Not quick-select */
00594     {
00595       if (indexfile)
00596       {
00597   if (indexfile->read(ref_pos, ref_length))
00598   {
00599     error= errno ? errno : -1;    /* Abort */
00600     break;
00601   }
00602   error=file->rnd_pos(sort_form->getInsertRecord(),next_pos);
00603       }
00604       else
00605       {
00606   error=file->rnd_next(sort_form->getInsertRecord());
00607 
00608   if (!flag)
00609   {
00610     internal::my_store_ptr(ref_pos,ref_length,record); // Position to row
00611     record+= sort_form->getShare()->db_record_offset;
00612   }
00613   else if (!error)
00614     file->position(sort_form->getInsertRecord());
00615       }
00616       if (error && error != HA_ERR_RECORD_DELETED)
00617   break;
00618     }
00619 
00620     if (*killed)
00621     {
00622       if (!indexfile && !quick_select)
00623       {
00624         (void) file->extra(HA_EXTRA_NO_CACHE);
00625         file->endTableScan();
00626       }
00627       return(HA_POS_ERROR);
00628     }
00629     if (error == 0)
00630       param->examined_rows++;
00631     if (error == 0 && (!select || select->skip_record() == 0))
00632     {
00633       if (idx == param->keys)
00634       {
00635   if (param->write_keys(sort_keys, idx, buffpek_pointers, tempfile))
00636     return(HA_POS_ERROR);
00637   idx=0;
00638   indexpos++;
00639       }
00640       param->make_sortkey(sort_keys[idx++], ref_pos);
00641     }
00642     else
00643     {
00644       file->unlock_row();
00645     }
00646 
00647     /* It does not make sense to read more keys in case of a fatal error */
00648     if (getSession().is_error())
00649       break;
00650   }
00651   if (quick_select)
00652   {
00653     /*
00654       index_merge quick select uses table->sort when retrieving rows, so free
00655       resoures it has allocated.
00656     */
00657     read_record_info.end_read_record();
00658   }
00659   else
00660   {
00661     (void) file->extra(HA_EXTRA_NO_CACHE);  /* End cacheing of records */
00662     if (!next_pos)
00663       file->endTableScan();
00664   }
00665 
00666   if (getSession().is_error())
00667     return(HA_POS_ERROR);
00668 
00669   /* Signal we should use orignal column read and write maps */
00670   sort_form->column_bitmaps_set(*save_read_set, *save_write_set);
00671 
00672   if (error != HA_ERR_END_OF_FILE)
00673   {
00674     sort_form->print_error(error,MYF(ME_ERROR | ME_WAITTANG));
00675     return(HA_POS_ERROR);
00676   }
00677 
00678   if (indexpos && idx && param->write_keys(sort_keys,idx,buffpek_pointers,tempfile))
00679   {
00680     return(HA_POS_ERROR);
00681   }
00682 
00683   return tempfile->inited() ? (ha_rows) (tempfile->tell() / param->rec_length) : idx;
00684 } /* find_all_keys */
00685 
00686 
00709 int SortParam::write_keys(unsigned char **sort_keys, uint32_t count,
00710                           internal::io_cache_st *buffpek_pointers, internal::io_cache_st *tempfile)
00711 {
00712   buffpek buffpek;
00713 
00714   internal::my_string_ptr_sort((unsigned char*) sort_keys, (uint32_t) count, sort_length);
00715   if (not tempfile->inited() &&
00716       tempfile->open_cached_file(drizzle_tmpdir.c_str(), TEMP_PREFIX, DISK_BUFFER_SIZE, MYF(MY_WME)))
00717   {
00718     return 1;
00719   }
00720   /* check we won't have more buffpeks than we can possibly keep in memory */
00721   if (buffpek_pointers->tell() + sizeof(buffpek) > UINT_MAX)
00722   {
00723     return 1;
00724   }
00725 
00726   buffpek.file_pos= tempfile->tell();
00727   if ((ha_rows) count > max_rows)
00728     count=(uint32_t) max_rows;
00729 
00730   buffpek.count=(ha_rows) count;
00731 
00732   for (unsigned char **ptr= sort_keys + count ; sort_keys != ptr ; sort_keys++)
00733   {
00734     if (tempfile->write(*sort_keys, rec_length))
00735     {
00736       return 1;
00737     }
00738   }
00739 
00740   if (buffpek_pointers->write(&buffpek, sizeof(buffpek)))
00741   {
00742     return 1;
00743   }
00744 
00745   return 0;
00746 } /* write_keys */
00747 
00748 
00753 static inline void store_length(unsigned char *to, uint32_t length, uint32_t pack_length)
00754 {
00755   switch (pack_length) {
00756   case 1:
00757     *to= (unsigned char) length;
00758     break;
00759   case 2:
00760     mi_int2store(to, length);
00761     break;
00762   case 3:
00763     mi_int3store(to, length);
00764     break;
00765   default:
00766     mi_int4store(to, length);
00767     break;
00768   }
00769 }
00770 
00771 
00774 void SortParam::make_sortkey(unsigned char *to, unsigned char *ref_pos)
00775 {
00776   Field *field;
00777   SortField *sort_field;
00778   size_t length;
00779 
00780   for (sort_field= local_sortorder ;
00781        sort_field != end ;
00782        sort_field++)
00783   {
00784     bool maybe_null=0;
00785     if ((field=sort_field->field))
00786     {           // Field
00787       if (field->maybe_null())
00788       {
00789   if (field->is_null())
00790   {
00791     if (sort_field->reverse)
00792       memset(to, 255, sort_field->length+1);
00793     else
00794       memset(to, 0, sort_field->length+1);
00795     to+= sort_field->length+1;
00796     continue;
00797   }
00798   else
00799     *to++=1;
00800       }
00801       field->sort_string(to, sort_field->length);
00802     }
00803     else
00804     {           // Item
00805       Item *item=sort_field->item;
00806       maybe_null= item->maybe_null;
00807 
00808       switch (sort_field->result_type) {
00809       case STRING_RESULT:
00810         {
00811           const charset_info_st * const cs=item->collation.collation;
00812           char fill_char= ((cs->state & MY_CS_BINSORT) ? (char) 0 : ' ');
00813           int diff;
00814           uint32_t sort_field_length;
00815 
00816           if (maybe_null)
00817             *to++=1;
00818           /* All item->str() to use some extra byte for end null.. */
00819           String tmp((char*) to,sort_field->length+4,cs);
00820           String *res= item->str_result(&tmp);
00821           if (!res)
00822           {
00823             if (maybe_null)
00824               memset(to-1, 0, sort_field->length+1);
00825             else
00826             {
00827               /*
00828                 This should only happen during extreme conditions if we run out
00829                 of memory or have an item marked not null when it can be null.
00830                 This code is here mainly to avoid a hard crash in this case.
00831               */
00832               assert(0);
00833               memset(to, 0, sort_field->length);  // Avoid crash
00834             }
00835             break;
00836           }
00837           length= res->length();
00838           sort_field_length= sort_field->length - sort_field->suffix_length;
00839           diff=(int) (sort_field_length - length);
00840           if (diff < 0)
00841           {
00842             diff=0;
00843             length= sort_field_length;
00844           }
00845           if (sort_field->suffix_length)
00846           {
00847             /* Store length last in result_string */
00848             store_length(to + sort_field_length, length,
00849                          sort_field->suffix_length);
00850           }
00851           if (sort_field->need_strxnfrm)
00852           {
00853             char *from=(char*) res->ptr();
00854             uint32_t tmp_length;
00855             if ((unsigned char*) from == to)
00856             {
00857               set_if_smaller(length,sort_field->length);
00858               memcpy(tmp_buffer,from,length);
00859               from= tmp_buffer;
00860             }
00861             tmp_length= cs->strnxfrm(to,sort_field->length, (unsigned char*) from, length);
00862             assert(tmp_length == sort_field->length);
00863           }
00864           else
00865           {
00866             cs->strnxfrm((unsigned char*)to,length,(const unsigned char*)res->ptr(),length);
00867             cs->cset->fill(cs, (char *)to+length,diff,fill_char);
00868           }
00869           break;
00870         }
00871       case INT_RESULT:
00872         {
00873           int64_t value= item->val_int_result();
00874           if (maybe_null)
00875           {
00876             *to++=1;
00877             if (item->null_value)
00878             {
00879               if (maybe_null)
00880                 memset(to-1, 0, sort_field->length+1);
00881               else
00882               {
00883                 memset(to, 0, sort_field->length);
00884               }
00885               break;
00886             }
00887           }
00888           to[7]= (unsigned char) value;
00889           to[6]= (unsigned char) (value >> 8);
00890           to[5]= (unsigned char) (value >> 16);
00891           to[4]= (unsigned char) (value >> 24);
00892           to[3]= (unsigned char) (value >> 32);
00893           to[2]= (unsigned char) (value >> 40);
00894           to[1]= (unsigned char) (value >> 48);
00895           if (item->unsigned_flag)                    /* Fix sign */
00896             to[0]= (unsigned char) (value >> 56);
00897           else
00898             to[0]= (unsigned char) (value >> 56) ^ 128; /* Reverse signbit */
00899           break;
00900         }
00901       case DECIMAL_RESULT:
00902         {
00903           type::Decimal dec_buf, *dec_val= item->val_decimal_result(&dec_buf);
00904           if (maybe_null)
00905           {
00906             if (item->null_value)
00907             {
00908               memset(to, 0, sort_field->length+1);
00909               to++;
00910               break;
00911             }
00912             *to++=1;
00913           }
00914           dec_val->val_binary(E_DEC_FATAL_ERROR, to,
00915                               item->max_length - (item->decimals ? 1:0),
00916                               item->decimals);
00917           break;
00918         }
00919       case REAL_RESULT:
00920         {
00921           double value= item->val_result();
00922           if (maybe_null)
00923           {
00924             if (item->null_value)
00925             {
00926               memset(to, 0, sort_field->length+1);
00927               to++;
00928               break;
00929             }
00930             *to++=1;
00931           }
00932           change_double_for_sort(value,(unsigned char*) to);
00933           break;
00934         }
00935       case ROW_RESULT:
00936       default:
00937         // This case should never be choosen
00938         assert(0);
00939         break;
00940       }
00941     }
00942 
00943     if (sort_field->reverse)
00944     {             /* Revers key */
00945       if (maybe_null)
00946         to[-1]= ~to[-1];
00947       length=sort_field->length;
00948       while (length--)
00949       {
00950   *to = (unsigned char) (~ *to);
00951   to++;
00952       }
00953     }
00954     else
00955     {
00956       to+= sort_field->length;
00957     }
00958   }
00959 
00960   if (addon_field)
00961   {
00962     /*
00963       Save field values appended to sorted fields.
00964       First null bit indicators are appended then field values follow.
00965       In this implementation we use fixed layout for field values -
00966       the same for all records.
00967     */
00968     sort_addon_field *addonf= addon_field;
00969     unsigned char *nulls= to;
00970     assert(addonf != 0);
00971     memset(nulls, 0, addonf->offset);
00972     to+= addonf->offset;
00973     for ( ; (field= addonf->field) ; addonf++)
00974     {
00975       if (addonf->null_bit && field->is_null())
00976       {
00977         nulls[addonf->null_offset]|= addonf->null_bit;
00978 #ifdef HAVE_VALGRIND
00979   memset(to, 0, addonf->length);
00980 #endif
00981       }
00982       else
00983       {
00984 #ifdef HAVE_VALGRIND
00985         unsigned char *end= field->pack(to, field->ptr);
00986   uint32_t local_length= (uint32_t) ((to + addonf->length) - end);
00987   assert((int) local_length >= 0);
00988   if (local_length)
00989     memset(end, 0, local_length);
00990 #else
00991         (void) field->pack(to, field->ptr);
00992 #endif
00993       }
00994       to+= addonf->length;
00995     }
00996   }
00997   else
00998   {
00999     /* Save filepos last */
01000     memcpy(to, ref_pos, (size_t) ref_length);
01001   }
01002 }
01003 
01004 
01005 /*
01006   fields used by sorting in the sorted table's read set
01007 */
01008 
01009 void SortParam::register_used_fields()
01010 {
01011   SortField *sort_field;
01012   Table *table= sort_form;
01013 
01014   for (sort_field= local_sortorder ;
01015        sort_field != end ;
01016        sort_field++)
01017   {
01018     Field *field;
01019     if ((field= sort_field->field))
01020     {
01021       if (field->getTable() == table)
01022         table->setReadSet(field->position());
01023     }
01024     else
01025     {           // Item
01026       sort_field->item->walk(&Item::register_field_in_read_map, 1,
01027                              (unsigned char *) table);
01028     }
01029   }
01030 
01031   if (addon_field)
01032   {
01033     sort_addon_field *addonf= addon_field;
01034     Field *field;
01035     for ( ; (field= addonf->field) ; addonf++)
01036       table->setReadSet(field->position());
01037   }
01038   else
01039   {
01040     /* Save filepos last */
01041     table->prepare_for_position();
01042   }
01043 }
01044 
01045 
01046 void SortParam::save_index(unsigned char **sort_keys, uint32_t count, filesort_info *table_sort)
01047 {
01048   internal::my_string_ptr_sort((unsigned char*) sort_keys, (uint32_t) count, sort_length);
01049   uint32_t offset= rec_length - res_length;
01050 
01051   if ((ha_rows) count > max_rows)
01052     count=(uint32_t) max_rows;
01053 
01054   unsigned char* to= table_sort->record_pointers= (unsigned char*) malloc(res_length*count);
01055 
01056   for (unsigned char **end_ptr= sort_keys+count ; sort_keys != end_ptr ; sort_keys++)
01057   {
01058     memcpy(to, *sort_keys+offset, res_length);
01059     to+= res_length;
01060   }
01061 }
01062 
01063 
01066 int FileSort::merge_many_buff(SortParam *param, unsigned char *sort_buffer,
01067                               buffpek *buffpek_inst, uint32_t *maxbuffer, internal::io_cache_st *t_file)
01068 {
01069   internal::io_cache_st t_file2,*from_file,*to_file,*temp;
01070   buffpek *lastbuff;
01071 
01072   if (*maxbuffer < MERGEBUFF2)
01073     return 0;
01074   if (t_file->flush() ||
01075       t_file2.open_cached_file(drizzle_tmpdir.c_str(),TEMP_PREFIX,DISK_BUFFER_SIZE, MYF(MY_WME)))
01076   {
01077     return 1;
01078   }
01079 
01080   from_file= t_file ; to_file= &t_file2;
01081   while (*maxbuffer >= MERGEBUFF2)
01082   {
01083     if (from_file->reinit_io_cache(internal::READ_CACHE, 0, 0, 0)
01084       || to_file->reinit_io_cache(internal::WRITE_CACHE, 0, 0, 0))
01085       break;
01086 
01087     uint32_t i= 0;
01088     lastbuff= buffpek_inst;
01089     for (; i <= *maxbuffer - MERGEBUFF * 3 / 2; i += MERGEBUFF)
01090     {
01091       if (merge_buffers(param, from_file, to_file, sort_buffer, lastbuff++, buffpek_inst + i, buffpek_inst + i + MERGEBUFF - 1, 0))
01092       {
01093         goto cleanup;
01094       }
01095     }
01096 
01097     if (merge_buffers(param, from_file, to_file, sort_buffer, lastbuff++, buffpek_inst + i, buffpek_inst + *maxbuffer, 0)
01098       || to_file->flush())
01099       break;
01100 
01101     temp=from_file; from_file=to_file; to_file=temp;
01102     from_file->setup_io_cache();
01103     to_file->setup_io_cache();
01104     *maxbuffer= (uint32_t) (lastbuff-buffpek_inst)-1;
01105   }
01106 
01107 cleanup:
01108   to_file->close_cached_file();     // This holds old result
01109   if (to_file == t_file)
01110   {
01111     *t_file=t_file2;        // Copy result file
01112     t_file->setup_io_cache();
01113   }
01114 
01115   return(*maxbuffer >= MERGEBUFF2); /* Return 1 if interrupted */
01116 } /* merge_many_buff */
01117 
01118 
01126 uint32_t FileSort::read_to_buffer(internal::io_cache_st *fromfile, buffpek *buffpek_inst, uint32_t rec_length)
01127 {
01128   uint32_t count;
01129   uint32_t length;
01130 
01131   if ((count= (uint32_t) min((ha_rows) buffpek_inst->max_keys,buffpek_inst->count)))
01132   {
01133     if (pread(fromfile->file,(unsigned char*) buffpek_inst->base, (length= rec_length*count),buffpek_inst->file_pos) == 0)
01134       return((uint32_t) -1);
01135 
01136     buffpek_inst->key= buffpek_inst->base;
01137     buffpek_inst->file_pos+= length;      /* New filepos */
01138     buffpek_inst->count-= count;
01139     buffpek_inst->mem_count= count;
01140   }
01141   return (count*rec_length);
01142 } /* read_to_buffer */
01143 
01144 
01145 class compare_functor
01146 {
01147   qsort2_cmp key_compare;
01148   void *key_compare_arg;
01149 
01150   public:
01151   compare_functor(qsort2_cmp in_key_compare, void *in_compare_arg) :
01152     key_compare(in_key_compare),
01153     key_compare_arg(in_compare_arg)
01154   { }
01155   
01156   inline bool operator()(const buffpek *i, const buffpek *j) const
01157   {
01158     int val= key_compare(key_compare_arg, &i->key, &j->key);
01159 
01160     return (val >= 0);
01161   }
01162 };
01163 
01164 
01183 int FileSort::merge_buffers(SortParam *param, internal::io_cache_st *from_file,
01184                             internal::io_cache_st *to_file, unsigned char *sort_buffer,
01185                             buffpek *lastbuff, buffpek *Fb, buffpek *Tb,
01186                             int flag)
01187 {
01188   int error;
01189   uint32_t rec_length,res_length,offset;
01190   size_t sort_length;
01191   uint32_t maxcount;
01192   ha_rows max_rows,org_max_rows;
01193   internal::my_off_t to_start_filepos;
01194   unsigned char *strpos;
01195   buffpek *buffpek_inst;
01196   qsort2_cmp cmp;
01197   void *first_cmp_arg;
01198   volatile Session::killed_state_t *killed= getSession().getKilledPtr();
01199   Session::killed_state_t not_killable;
01200 
01201   getSession().status_var.filesort_merge_passes++;
01202   if (param->not_killable)
01203   {
01204     killed= &not_killable;
01205     not_killable= Session::NOT_KILLED;
01206   }
01207 
01208   error=0;
01209   rec_length= param->rec_length;
01210   res_length= param->res_length;
01211   sort_length= param->sort_length;
01212   offset= rec_length-res_length;
01213   maxcount= (uint32_t) (param->keys/((uint32_t) (Tb-Fb) +1));
01214   to_start_filepos= to_file->tell();
01215   strpos= (unsigned char*) sort_buffer;
01216   org_max_rows=max_rows= param->max_rows;
01217 
01218   /* The following will fire if there is not enough space in sort_buffer */
01219   assert(maxcount!=0);
01220 
01221   if (param->unique_buff)
01222   {
01223     cmp= param->compare;
01224     first_cmp_arg= (void *) &param->cmp_context;
01225   }
01226   else
01227   {
01228     cmp= internal::get_ptr_compare(sort_length);
01229     first_cmp_arg= (void*) &sort_length;
01230   }
01231   priority_queue<buffpek *, vector<buffpek *>, compare_functor >
01232     queue(compare_functor(cmp, first_cmp_arg));
01233   for (buffpek_inst= Fb ; buffpek_inst <= Tb ; buffpek_inst++)
01234   {
01235     buffpek_inst->base= strpos;
01236     buffpek_inst->max_keys= maxcount;
01237     strpos+= (uint32_t) (error= (int) read_to_buffer(from_file, buffpek_inst,
01238                                                                          rec_length));
01239     if (error == -1)
01240       return -1;
01241 
01242     buffpek_inst->max_keys= buffpek_inst->mem_count;  // If less data in buffers than expected
01243     queue.push(buffpek_inst);
01244   }
01245 
01246   if (param->unique_buff)
01247   {
01248     /*
01249        Called by Unique::get()
01250        Copy the first argument to param->unique_buff for unique removal.
01251        Store it also in 'to_file'.
01252 
01253        This is safe as we know that there is always more than one element
01254        in each block to merge (This is guaranteed by the Unique:: algorithm
01255     */
01256     buffpek_inst= queue.top();
01257     memcpy(param->unique_buff, buffpek_inst->key, rec_length);
01258     if (to_file->write(buffpek_inst->key, rec_length))
01259     {
01260       return 1;
01261     }
01262     buffpek_inst->key+= rec_length;
01263     buffpek_inst->mem_count--;
01264     if (!--max_rows)
01265     {
01266       error= 0;
01267       goto end;
01268     }
01269     /* Top element has been used */
01270     queue.pop();
01271     queue.push(buffpek_inst);
01272   }
01273   else
01274   {
01275     cmp= 0;                                        // Not unique
01276   }
01277 
01278   while (queue.size() > 1)
01279   {
01280     if (*killed)
01281     {
01282       return 1;
01283     }
01284     for (;;)
01285     {
01286       buffpek_inst= queue.top();
01287       if (cmp)                                        // Remove duplicates
01288       {
01289         if (!(*cmp)(first_cmp_arg, &(param->unique_buff),
01290                     (unsigned char**) &buffpek_inst->key))
01291               goto skip_duplicate;
01292             memcpy(param->unique_buff, buffpek_inst->key, rec_length);
01293       }
01294       if (flag == 0)
01295       {
01296         if (to_file->write(buffpek_inst->key, rec_length))
01297         {
01298           return 1;
01299         }
01300       }
01301       else
01302       {
01303         if (to_file->write(buffpek_inst->key+offset, res_length))
01304         {
01305           return 1;
01306         }
01307       }
01308       if (!--max_rows)
01309       {
01310         error= 0;
01311         goto end;
01312       }
01313 
01314     skip_duplicate:
01315       buffpek_inst->key+= rec_length;
01316       if (! --buffpek_inst->mem_count)
01317       {
01318         if (!(error= (int) read_to_buffer(from_file,buffpek_inst,
01319                                           rec_length)))
01320         {
01321           queue.pop();
01322           break;                        /* One buffer have been removed */
01323         }
01324         else if (error == -1)
01325         {
01326           return -1;
01327         }
01328       }
01329       /* Top element has been replaced */
01330       queue.pop();
01331       queue.push(buffpek_inst);
01332     }
01333   }
01334   buffpek_inst= queue.top();
01335   buffpek_inst->base= sort_buffer;
01336   buffpek_inst->max_keys= param->keys;
01337 
01338   /*
01339     As we know all entries in the buffer are unique, we only have to
01340     check if the first one is the same as the last one we wrote
01341   */
01342   if (cmp)
01343   {
01344     if (!(*cmp)(first_cmp_arg, &(param->unique_buff), (unsigned char**) &buffpek_inst->key))
01345     {
01346       buffpek_inst->key+= rec_length;         // Remove duplicate
01347       --buffpek_inst->mem_count;
01348     }
01349   }
01350 
01351   do
01352   {
01353     if ((ha_rows) buffpek_inst->mem_count > max_rows)
01354     {                                        /* Don't write too many records */
01355       buffpek_inst->mem_count= (uint32_t) max_rows;
01356       buffpek_inst->count= 0;                        /* Don't read more */
01357     }
01358     max_rows-= buffpek_inst->mem_count;
01359     if (flag == 0)
01360     {
01361       if (to_file->write(buffpek_inst->key, (rec_length*buffpek_inst->mem_count)))
01362       {
01363         return 1;
01364       }
01365     }
01366     else
01367     {
01368       unsigned char *end;
01369       strpos= buffpek_inst->key+offset;
01370       for (end= strpos+buffpek_inst->mem_count*rec_length ;
01371            strpos != end ;
01372            strpos+= rec_length)
01373       {
01374         if (to_file->write(strpos, res_length))
01375         {
01376           return 1;
01377         }
01378       }
01379     }
01380   }
01381 
01382   while ((error=(int) read_to_buffer(from_file,buffpek_inst, rec_length))
01383          != -1 && error != 0);
01384 
01385 end:
01386   lastbuff->count= min(org_max_rows-max_rows, param->max_rows);
01387   lastbuff->file_pos= to_start_filepos;
01388 
01389   return error;
01390 } /* merge_buffers */
01391 
01392 
01393   /* Do a merge to output-file (save only positions) */
01394 
01395 int FileSort::merge_index(SortParam *param, unsigned char *sort_buffer,
01396                           buffpek *buffpek_inst, uint32_t maxbuffer,
01397                           internal::io_cache_st *tempfile, internal::io_cache_st *outfile)
01398 {
01399   if (merge_buffers(param,tempfile,outfile,sort_buffer,buffpek_inst,buffpek_inst,
01400         buffpek_inst+maxbuffer,1))
01401     return 1;
01402 
01403   return 0;
01404 } /* merge_index */
01405 
01406 
01407 static uint32_t suffix_length(uint32_t string_length)
01408 {
01409   if (string_length < 256)
01410     return 1;
01411   if (string_length < 256L*256L)
01412     return 2;
01413   if (string_length < 256L*256L*256L)
01414     return 3;
01415   return 4;                                     // Can't sort longer than 4G
01416 }
01417 
01418 
01419 
01437 uint32_t FileSort::sortlength(SortField *sortorder, uint32_t s_length, bool *multi_byte_charset)
01438 {
01439   uint32_t length;
01440   const charset_info_st *cs;
01441   *multi_byte_charset= 0;
01442 
01443   length=0;
01444   for (; s_length-- ; sortorder++)
01445   {
01446     sortorder->need_strxnfrm= 0;
01447     sortorder->suffix_length= 0;
01448     if (sortorder->field)
01449     {
01450       cs= sortorder->field->sort_charset();
01451       sortorder->length= sortorder->field->sort_length();
01452       cs= sortorder->field->sort_charset();
01453       if (cs->use_strnxfrm())
01454       {
01455         sortorder->need_strxnfrm= 1;
01456         *multi_byte_charset= 1;
01457         sortorder->length= cs->coll->strnxfrmlen(cs, sortorder->length);
01458       }
01459       if (sortorder->field->maybe_null())
01460   length++;       // Place for NULL marker
01461     }
01462     else
01463     {
01464       sortorder->result_type= sortorder->item->result_type();
01465       if (sortorder->item->result_as_int64_t())
01466         sortorder->result_type= INT_RESULT;
01467 
01468       switch (sortorder->result_type) {
01469       case STRING_RESULT:
01470         sortorder->length=sortorder->item->max_length;
01471         set_if_smaller(sortorder->length, getSession().variables.max_sort_length);
01472         cs= sortorder->item->collation.collation;
01473         if (cs->use_strnxfrm())
01474         {
01475           sortorder->length= cs->coll->strnxfrmlen(cs, sortorder->length);
01476           sortorder->need_strxnfrm= 1;
01477           *multi_byte_charset= 1;
01478         }
01479         else if (cs == &my_charset_bin)
01480         {
01481           /* Store length last to be able to sort blob/varbinary */
01482           sortorder->suffix_length= suffix_length(sortorder->length);
01483           sortorder->length+= sortorder->suffix_length;
01484         }
01485         break;
01486       case INT_RESULT:
01487         sortorder->length=8;      // Size of intern int64_t
01488         break;
01489       case DECIMAL_RESULT:
01490         sortorder->length=
01491           class_decimal_get_binary_size(sortorder->item->max_length -
01492                                      (sortorder->item->decimals ? 1 : 0),
01493                                      sortorder->item->decimals);
01494         break;
01495       case REAL_RESULT:
01496         sortorder->length=sizeof(double);
01497         break;
01498       case ROW_RESULT:
01499         // This case should never be choosen
01500         assert(0);
01501         break;
01502       }
01503       if (sortorder->item->maybe_null)
01504         length++;       // Place for NULL marker
01505     }
01506     set_if_smaller(sortorder->length, (size_t)getSession().variables.max_sort_length);
01507     length+=sortorder->length;
01508   }
01509   sortorder->field= (Field*) 0;     // end marker
01510   return length;
01511 }
01512 
01513 
01540 sort_addon_field *FileSort::get_addon_fields(Field **ptabfield, uint32_t sortlength_arg, uint32_t *plength)
01541 {
01542   Field **pfield;
01543   Field *field;
01544   sort_addon_field *addonf;
01545   uint32_t length= 0;
01546   uint32_t fields= 0;
01547   uint32_t null_fields= 0;
01548 
01549   /*
01550     If there is a reference to a field in the query add it
01551     to the the set of appended fields.
01552     Note for future refinement:
01553     This this a too strong condition.
01554     Actually we need only the fields referred in the
01555     result set. And for some of them it makes sense to use
01556     the values directly from sorted fields.
01557   */
01558   *plength= 0;
01559 
01560   for (pfield= ptabfield; (field= *pfield) ; pfield++)
01561   {
01562     if (!(field->isReadSet()))
01563       continue;
01564     if (field->flags & BLOB_FLAG)
01565       return 0;
01566     length+= field->max_packed_col_length(field->pack_length());
01567     if (field->maybe_null())
01568       null_fields++;
01569     fields++;
01570   }
01571   if (!fields)
01572     return 0;
01573   length+= (null_fields+7)/8;
01574 
01575   if (length+sortlength_arg > getSession().variables.max_length_for_sort_data)
01576     return 0;
01577   addonf= (sort_addon_field *) malloc(sizeof(sort_addon_field) * (fields+1));
01578 
01579   *plength= length;
01580   length= (null_fields+7)/8;
01581   null_fields= 0;
01582   for (pfield= ptabfield; (field= *pfield) ; pfield++)
01583   {
01584     if (!(field->isReadSet()))
01585       continue;
01586     addonf->field= field;
01587     addonf->offset= length;
01588     if (field->maybe_null())
01589     {
01590       addonf->null_offset= null_fields/8;
01591       addonf->null_bit= 1<<(null_fields & 7);
01592       null_fields++;
01593     }
01594     else
01595     {
01596       addonf->null_offset= 0;
01597       addonf->null_bit= 0;
01598     }
01599     addonf->length= field->max_packed_col_length(field->pack_length());
01600     length+= addonf->length;
01601     addonf++;
01602   }
01603   addonf->field= 0;     // Put end marker
01604 
01605   return (addonf-fields);
01606 }
01607 
01608 
01624 static void
01625 unpack_addon_fields(sort_addon_field *addon_field, unsigned char *buff)
01626 {
01627   Field *field;
01628   sort_addon_field *addonf= addon_field;
01629 
01630   for ( ; (field= addonf->field) ; addonf++)
01631   {
01632     if (addonf->null_bit && (addonf->null_bit & buff[addonf->null_offset]))
01633     {
01634       field->set_null();
01635       continue;
01636     }
01637     field->set_notnull();
01638     field->unpack(field->ptr, buff + addonf->offset);
01639   }
01640 }
01641 
01642 /*
01643 ** functions to change a double or float to a sortable string
01644 ** The following should work for IEEE
01645 */
01646 
01647 #define DBL_EXP_DIG (sizeof(double)*8-DBL_MANT_DIG)
01648 
01649 void change_double_for_sort(double nr,unsigned char *to)
01650 {
01651   unsigned char *tmp=(unsigned char*) to;
01652   if (nr == 0.0)
01653   {           /* Change to zero string */
01654     tmp[0]=(unsigned char) 128;
01655     memset(tmp+1, 0, sizeof(nr)-1);
01656   }
01657   else
01658   {
01659 #ifdef WORDS_BIGENDIAN
01660     memcpy(tmp,&nr,sizeof(nr));
01661 #else
01662     {
01663       unsigned char *ptr= (unsigned char*) &nr;
01664 #if defined(__FLOAT_WORD_ORDER) && (__FLOAT_WORD_ORDER == __BIG_ENDIAN)
01665       tmp[0]= ptr[3]; tmp[1]=ptr[2]; tmp[2]= ptr[1]; tmp[3]=ptr[0];
01666       tmp[4]= ptr[7]; tmp[5]=ptr[6]; tmp[6]= ptr[5]; tmp[7]=ptr[4];
01667 #else
01668       tmp[0]= ptr[7]; tmp[1]=ptr[6]; tmp[2]= ptr[5]; tmp[3]=ptr[4];
01669       tmp[4]= ptr[3]; tmp[5]=ptr[2]; tmp[6]= ptr[1]; tmp[7]=ptr[0];
01670 #endif
01671     }
01672 #endif
01673     if (tmp[0] & 128)       /* Negative */
01674     {           /* make complement */
01675       uint32_t i;
01676       for (i=0 ; i < sizeof(nr); i++)
01677   tmp[i]=tmp[i] ^ (unsigned char) 255;
01678     }
01679     else
01680     {         /* Set high and move exponent one up */
01681       uint16_t exp_part=(((uint16_t) tmp[0] << 8) | (uint16_t) tmp[1] |
01682            (uint16_t) 32768);
01683       exp_part+= (uint16_t) 1 << (16-1-DBL_EXP_DIG);
01684       tmp[0]= (unsigned char) (exp_part >> 8);
01685       tmp[1]= (unsigned char) exp_part;
01686     }
01687   }
01688 }
01689 
01690 } /* namespace drizzled */