00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
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
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;
00078 uint32_t sort_length;
00079 uint32_t ref_length;
00080 uint32_t addon_length;
00081 uint32_t res_length;
00082 uint32_t keys;
00083 ha_rows max_rows,examined_rows;
00084 Table *sort_form;
00085 SortField *local_sortorder;
00086 SortField *end;
00087 sort_addon_field *addon_field;
00088 unsigned char *unique_buff;
00089 bool not_killable;
00090 char *tmp_buffer;
00091
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
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
00207
00208
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
00220
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
00236
00237
00238 param.addon_field= get_addon_fields(table->getFields(),
00239 param.sort_length,
00240 ¶m.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
00257
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
00285
00286
00287 if (records == HA_POS_ERROR)
00288 records--;
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--;
00333 param.sort_form= table;
00334 param.end=(param.local_sortorder=sortorder)+s_length;
00335 if ((records= find_all_keys(¶m,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)
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
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
00374
00375
00376 param.keys=((param.keys*(param.rec_length+sizeof(char*))) / param.rec_length-1);
00377
00378 maxbuffer--;
00379 if (merge_many_buff(¶m,(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(¶m,(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
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 }
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 }
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;
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;
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
00570 save_read_set= sort_form->read_set;
00571 save_write_set= sort_form->write_set;
00572
00573 sort_form->tmp_set.reset();
00574
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
00594 {
00595 if (indexfile)
00596 {
00597 if (indexfile->read(ref_pos, ref_length))
00598 {
00599 error= errno ? errno : -1;
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);
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
00648 if (getSession().is_error())
00649 break;
00650 }
00651 if (quick_select)
00652 {
00653
00654
00655
00656
00657 read_record_info.end_read_record();
00658 }
00659 else
00660 {
00661 (void) file->extra(HA_EXTRA_NO_CACHE);
00662 if (!next_pos)
00663 file->endTableScan();
00664 }
00665
00666 if (getSession().is_error())
00667 return(HA_POS_ERROR);
00668
00669
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 }
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
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 }
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 {
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 {
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
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
00829
00830
00831
00832 assert(0);
00833 memset(to, 0, sort_field->length);
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
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)
00896 to[0]= (unsigned char) (value >> 56);
00897 else
00898 to[0]= (unsigned char) (value >> 56) ^ 128;
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
00938 assert(0);
00939 break;
00940 }
00941 }
00942
00943 if (sort_field->reverse)
00944 {
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
00964
00965
00966
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
01000 memcpy(to, ref_pos, (size_t) ref_length);
01001 }
01002 }
01003
01004
01005
01006
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 {
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
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();
01109 if (to_file == t_file)
01110 {
01111 *t_file=t_file2;
01112 t_file->setup_io_cache();
01113 }
01114
01115 return(*maxbuffer >= MERGEBUFF2);
01116 }
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;
01138 buffpek_inst->count-= count;
01139 buffpek_inst->mem_count= count;
01140 }
01141 return (count*rec_length);
01142 }
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= ¬_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
01219 assert(maxcount!=0);
01220
01221 if (param->unique_buff)
01222 {
01223 cmp= param->compare;
01224 first_cmp_arg= (void *) ¶m->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;
01243 queue.push(buffpek_inst);
01244 }
01245
01246 if (param->unique_buff)
01247 {
01248
01249
01250
01251
01252
01253
01254
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
01270 queue.pop();
01271 queue.push(buffpek_inst);
01272 }
01273 else
01274 {
01275 cmp= 0;
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)
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;
01323 }
01324 else if (error == -1)
01325 {
01326 return -1;
01327 }
01328 }
01329
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
01340
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;
01347 --buffpek_inst->mem_count;
01348 }
01349 }
01350
01351 do
01352 {
01353 if ((ha_rows) buffpek_inst->mem_count > max_rows)
01354 {
01355 buffpek_inst->mem_count= (uint32_t) max_rows;
01356 buffpek_inst->count= 0;
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 }
01391
01392
01393
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 }
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;
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++;
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
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;
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
01500 assert(0);
01501 break;
01502 }
01503 if (sortorder->item->maybe_null)
01504 length++;
01505 }
01506 set_if_smaller(sortorder->length, (size_t)getSession().variables.max_sort_length);
01507 length+=sortorder->length;
01508 }
01509 sortorder->field= (Field*) 0;
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
01551
01552
01553
01554
01555
01556
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;
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
01644
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 {
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)
01674 {
01675 uint32_t i;
01676 for (i=0 ; i < sizeof(nr); i++)
01677 tmp[i]=tmp[i] ^ (unsigned char) 255;
01678 }
01679 else
01680 {
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 }