24
#include <drizzled/server_includes.h>
25
#include <drizzled/sql_sort.h>
26
#include <drizzled/error.h>
27
#include <drizzled/probes.h>
28
#include <drizzled/session.h>
29
#include <drizzled/table.h>
30
#include <drizzled/table_list.h>
32
/* functions defined in this file */
34
static char **make_char_array(char **old_pos, register uint32_t fields,
35
uint32_t length, myf my_flag);
36
static unsigned char *read_buffpek_from_file(IO_CACHE *buffer_file, uint32_t count,
24
#include "mysql_priv.h"
26
#include <drizzled/drizzled_error_messages.h>
28
/// How to write record_ref.
29
#define WRITE_REF(file,from) \
30
if (my_b_write((file),(uchar*) (from),param->ref_length)) \
33
/* functions defined in this file */
35
static char **make_char_array(char **old_pos, register uint fields,
36
uint length, myf my_flag);
37
static uchar *read_buffpek_from_file(IO_CACHE *buffer_file, uint count,
38
39
static ha_rows find_all_keys(SORTPARAM *param,SQL_SELECT *select,
39
unsigned char * *sort_keys, IO_CACHE *buffer_file,
40
uchar * *sort_keys, IO_CACHE *buffer_file,
40
41
IO_CACHE *tempfile,IO_CACHE *indexfile);
41
static int write_keys(SORTPARAM *param,unsigned char * *sort_keys,
42
uint32_t count, IO_CACHE *buffer_file, IO_CACHE *tempfile);
43
static void make_sortkey(SORTPARAM *param,unsigned char *to, unsigned char *ref_pos);
42
static int write_keys(SORTPARAM *param,uchar * *sort_keys,
43
uint count, IO_CACHE *buffer_file, IO_CACHE *tempfile);
44
static void make_sortkey(SORTPARAM *param,uchar *to, uchar *ref_pos);
44
45
static void register_used_fields(SORTPARAM *param);
45
static int merge_index(SORTPARAM *param,unsigned char *sort_buffer,
46
static int merge_index(SORTPARAM *param,uchar *sort_buffer,
47
uint32_t maxbuffer,IO_CACHE *tempfile,
48
uint maxbuffer,IO_CACHE *tempfile,
48
49
IO_CACHE *outfile);
49
static bool save_index(SORTPARAM *param,unsigned char **sort_keys, uint32_t count,
50
filesort_info_st *table_sort);
51
static uint32_t suffix_length(uint32_t string_length);
52
static uint32_t sortlength(Session *session, SORT_FIELD *sortorder, uint32_t s_length,
50
static bool save_index(SORTPARAM *param,uchar **sort_keys, uint count,
51
FILESORT_INFO *table_sort);
52
static uint suffix_length(ulong string_length);
53
static uint sortlength(THD *thd, SORT_FIELD *sortorder, uint s_length,
53
54
bool *multi_byte_charset);
54
static SORT_ADDON_FIELD *get_addon_fields(Session *session, Field **ptabfield,
55
uint32_t sortlength, uint32_t *plength);
55
static SORT_ADDON_FIELD *get_addon_fields(THD *thd, Field **ptabfield,
56
uint sortlength, uint *plength);
56
57
static void unpack_addon_fields(struct st_sort_addon_field *addon_field,
60
61
Creates a set of pointers that can be used to read the rows
67
68
The result set is stored in table->io_cache or
68
69
table->record_pointers.
70
@param session Current thread
71
@param thd Current thread
71
72
@param table Table to sort
72
73
@param sortorder How to sort the table
73
74
@param s_length Number of elements in sortorder
74
75
@param select condition to apply to the rows
75
76
@param max_rows Return only this many rows
76
77
@param sort_positions Set to 1 if we want to force sorting by position
77
(Needed by UPDATE/INSERT or ALTER Table)
78
(Needed by UPDATE/INSERT or ALTER TABLE)
78
79
@param examined_rows Store number of examined rows here
91
92
examined_rows will be set to number of examined rows
94
ha_rows filesort(Session *session, Table *table, SORT_FIELD *sortorder, uint32_t s_length,
95
ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length,
95
96
SQL_SELECT *select, ha_rows max_rows,
96
97
bool sort_positions, ha_rows *examined_rows)
99
uint32_t memavl, min_sort_memory;
100
ulong memavl, min_sort_memory;
101
102
BUFFPEK *buffpek;
102
103
ha_rows records= HA_POS_ERROR;
103
unsigned char **sort_keys= 0;
104
uchar **sort_keys= 0;
104
105
IO_CACHE tempfile, buffpek_pointers, *selected_records_file, *outfile;
106
107
bool multi_byte_charset;
108
filesort_info_st table_sort;
109
TableList *tab= table->pos_in_table_list;
109
FILESORT_INFO table_sort;
110
TABLE_LIST *tab= table->pos_in_table_list;
110
111
Item_subselect *subselect= tab ? tab->containing_subselect() : 0;
112
DRIZZLE_FILESORT_START();
113
MYSQL_FILESORT_START();
115
116
Release InnoDB's adaptive hash index latch (if holding) before
118
ha_release_temporary_latches(session);
119
ha_release_temporary_latches(thd);
121
122
Don't use table->sort in filesort as it is also used by
122
123
QUICK_INDEX_MERGE_SELECT. Work with a copy and put it back at the end
123
124
when index_merge select has finished with it.
125
memcpy(&table_sort, &table->sort, sizeof(filesort_info_st));
126
memcpy(&table_sort, &table->sort, sizeof(FILESORT_INFO));
126
127
table->sort.io_cache= NULL;
128
129
outfile= table_sort.io_cache;
201
202
!(param.tmp_buffer= (char*) my_malloc(param.sort_length,MYF(MY_WME))))
204
memavl= session->variables.sortbuff_size;
205
min_sort_memory= cmax((uint32_t)MIN_SORT_MEMORY, param.sort_length*MERGEBUFF2);
205
memavl= thd->variables.sortbuff_size;
206
min_sort_memory= max(MIN_SORT_MEMORY, param.sort_length*MERGEBUFF2);
206
207
while (memavl >= min_sort_memory)
209
uint32_t keys= memavl/(param.rec_length+sizeof(char*));
210
param.keys=(uint32_t) cmin(records+1, keys);
210
ulong keys= memavl/(param.rec_length+sizeof(char*));
211
param.keys=(uint) min(records+1, keys);
211
212
if ((table_sort.sort_keys=
212
(unsigned char **) make_char_array((char **) table_sort.sort_keys,
213
(uchar **) make_char_array((char **) table_sort.sort_keys,
213
214
param.keys, param.rec_length, MYF(0))))
215
216
old_memavl=memavl;
233
234
&tempfile, selected_records_file)) ==
236
maxbuffer= (uint32_t) (my_b_tell(&buffpek_pointers)/sizeof(*buffpek));
237
maxbuffer= (uint) (my_b_tell(&buffpek_pointers)/sizeof(*buffpek));
238
239
if (maxbuffer == 0) // The whole set is in memory
240
if (save_index(¶m,sort_keys,(uint32_t) records, &table_sort))
241
if (save_index(¶m,sort_keys,(uint) records, &table_sort))
245
246
if (table_sort.buffpek && table_sort.buffpek_len < maxbuffer)
247
if (table_sort.buffpek)
248
free(table_sort.buffpek);
248
x_free(table_sort.buffpek);
249
249
table_sort.buffpek= 0;
251
251
if (!(table_sort.buffpek=
252
(unsigned char *) read_buffpek_from_file(&buffpek_pointers, maxbuffer,
252
(uchar *) read_buffpek_from_file(&buffpek_pointers, maxbuffer,
253
253
table_sort.buffpek)))
255
255
buffpek= (BUFFPEK *) table_sort.buffpek;
270
270
param.keys=((param.keys*(param.rec_length+sizeof(char*))) /
271
271
param.rec_length-1);
272
272
maxbuffer--; // Offset from 0
273
if (merge_many_buff(¶m,(unsigned char*) sort_keys,buffpek,&maxbuffer,
273
if (merge_many_buff(¶m,(uchar*) sort_keys,buffpek,&maxbuffer,
276
276
if (flush_io_cache(&tempfile) ||
277
277
reinit_io_cache(&tempfile,READ_CACHE,0L,0,0))
279
if (merge_index(¶m,(unsigned char*) sort_keys,buffpek,maxbuffer,&tempfile,
279
if (merge_index(¶m,(uchar*) sort_keys,buffpek,maxbuffer,&tempfile,
316
313
my_message(ER_FILSORT_ABORT, ER(ER_FILSORT_ABORT),
317
314
MYF(ME_ERROR+ME_WAITTANG));
319
statistic_add(session->status_var.filesort_rows,
320
(uint32_t) records, &LOCK_status);
316
statistic_add(thd->status_var.filesort_rows,
317
(ulong) records, &LOCK_status);
321
318
*examined_rows= param.examined_rows;
322
memcpy(&table->sort, &table_sort, sizeof(filesort_info_st));
323
DRIZZLE_FILESORT_END();
319
memcpy(&table->sort, &table_sort, sizeof(FILESORT_INFO));
320
MYSQL_FILESORT_END();
324
321
return(error ? HA_POS_ERROR : records);
328
void filesort_free_buffers(Table *table, bool full)
325
void filesort_free_buffers(TABLE *table, bool full)
330
327
if (table->sort.record_pointers)
332
free((unsigned char*) table->sort.record_pointers);
329
my_free((uchar*) table->sort.record_pointers,MYF(0));
333
330
table->sort.record_pointers=0;
337
334
if (table->sort.sort_keys )
339
if ((unsigned char*) table->sort.sort_keys)
340
free((unsigned char*) table->sort.sort_keys);
336
x_free((uchar*) table->sort.sort_keys);
341
337
table->sort.sort_keys= 0;
343
339
if (table->sort.buffpek)
345
if ((unsigned char*) table->sort.buffpek)
346
free((unsigned char*) table->sort.buffpek);
341
x_free((uchar*) table->sort.buffpek);
347
342
table->sort.buffpek= 0;
348
343
table->sort.buffpek_len= 0;
351
346
if (table->sort.addon_buf)
353
free((char *) table->sort.addon_buf);
354
free((char *) table->sort.addon_field);
348
my_free((char *) table->sort.addon_buf, MYF(0));
349
my_free((char *) table->sort.addon_field, MYF(MY_ALLOW_ZERO_PTR));
355
350
table->sort.addon_buf=0;
356
351
table->sort.addon_field=0;
380
375
/** Read 'count' number of buffer pointers into memory. */
382
static unsigned char *read_buffpek_from_file(IO_CACHE *buffpek_pointers, uint32_t count,
377
static uchar *read_buffpek_from_file(IO_CACHE *buffpek_pointers, uint count,
385
uint32_t length= sizeof(BUFFPEK)*count;
386
unsigned char *tmp= buf;
380
ulong length= sizeof(BUFFPEK)*count;
387
382
if (count > UINT_MAX/sizeof(BUFFPEK))
388
383
return 0; /* sizeof(BUFFPEK)*count will overflow */
390
tmp= (unsigned char *)my_malloc(length, MYF(MY_WME));
385
tmp= (uchar *)my_malloc(length, MYF(MY_WME));
393
388
if (reinit_io_cache(buffpek_pointers,READ_CACHE,0L,0,0) ||
394
my_b_read(buffpek_pointers, (unsigned char*) tmp, length))
389
my_b_read(buffpek_pointers, (uchar*) tmp, length))
391
my_free((char*) tmp, MYF(0));
441
436
static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select,
442
unsigned char **sort_keys,
443
438
IO_CACHE *buffpek_pointers,
444
439
IO_CACHE *tempfile, IO_CACHE *indexfile)
446
441
int error,flag,quick_select;
447
uint32_t idx,indexpos,ref_length;
448
unsigned char *ref_pos,*next_pos,ref_buff[MAX_REFLENGTH];
442
uint idx,indexpos,ref_length;
443
uchar *ref_pos,*next_pos,ref_buff[MAX_REFLENGTH];
451
Session *session= current_session;
452
volatile Session::killed_state *killed= &session->killed;
446
THD *thd= current_thd;
447
volatile THD::killed_state *killed= &thd->killed;
454
449
MY_BITMAP *save_read_set, *save_write_set;
625
write_keys(SORTPARAM *param, register unsigned char **sort_keys, uint32_t count,
617
write_keys(SORTPARAM *param, register uchar **sort_keys, uint count,
626
618
IO_CACHE *buffpek_pointers, IO_CACHE *tempfile)
628
620
size_t sort_length, rec_length;
632
624
sort_length= param->sort_length;
633
625
rec_length= param->rec_length;
634
my_string_ptr_sort((unsigned char*) sort_keys, (uint32_t) count, sort_length);
626
my_string_ptr_sort((uchar*) sort_keys, (uint) count, sort_length);
635
627
if (!my_b_inited(tempfile) &&
636
open_cached_file(tempfile, drizzle_tmpdir, TEMP_PREFIX, DISK_BUFFER_SIZE,
628
open_cached_file(tempfile, mysql_tmpdir, TEMP_PREFIX, DISK_BUFFER_SIZE,
638
630
goto err; /* purecov: inspected */
639
631
/* check we won't have more buffpeks than we can possibly keep in memory */
642
634
buffpek.file_pos= my_b_tell(tempfile);
643
635
if ((ha_rows) count > param->max_rows)
644
count=(uint32_t) param->max_rows; /* purecov: inspected */
636
count=(uint) param->max_rows; /* purecov: inspected */
645
637
buffpek.count=(ha_rows) count;
646
638
for (end=sort_keys+count ; sort_keys != end ; sort_keys++)
647
if (my_b_write(tempfile, (unsigned char*) *sort_keys, (uint32_t) rec_length))
639
if (my_b_write(tempfile, (uchar*) *sort_keys, (uint) rec_length))
649
if (my_b_write(buffpek_pointers, (unsigned char*) &buffpek, sizeof(buffpek)))
641
if (my_b_write(buffpek_pointers, (uchar*) &buffpek, sizeof(buffpek)))
762
754
if (sort_field->need_strxnfrm)
764
756
char *from=(char*) res->ptr();
766
if ((unsigned char*) from == to)
758
if ((uchar*) from == to)
768
760
set_if_smaller(length,sort_field->length);
769
761
memcpy(param->tmp_buffer,from,length);
770
762
from=param->tmp_buffer;
772
764
tmp_length= my_strnxfrm(cs,to,sort_field->length,
773
(unsigned char*) from, length);
765
(uchar*) from, length);
774
766
assert(tmp_length == sort_field->length);
778
my_strnxfrm(cs,(unsigned char*)to,length,(const unsigned char*)res->ptr(),length);
770
my_strnxfrm(cs,(uchar*)to,length,(const uchar*)res->ptr(),length);
779
771
cs->cset->fill(cs, (char *)to+length,diff,fill_char);
789
781
if (item->null_value)
792
memset(to-1, 0, sort_field->length+1);
784
memset((char*) to-1, 0, sort_field->length+1);
795
memset(to, 0, sort_field->length);
787
memset((char*) to, 0, sort_field->length);
800
to[7]= (unsigned char) value;
801
to[6]= (unsigned char) (value >> 8);
802
to[5]= (unsigned char) (value >> 16);
803
to[4]= (unsigned char) (value >> 24);
804
to[3]= (unsigned char) (value >> 32);
805
to[2]= (unsigned char) (value >> 40);
806
to[1]= (unsigned char) (value >> 48);
807
if (item->unsigned_flag) /* Fix sign */
808
to[0]= (unsigned char) (value >> 56);
810
to[0]= (unsigned char) (value >> 56) ^ 128; /* Reverse signbit */
792
#if SIZEOF_LONG_LONG > 4
793
to[7]= (uchar) value;
794
to[6]= (uchar) (value >> 8);
795
to[5]= (uchar) (value >> 16);
796
to[4]= (uchar) (value >> 24);
797
to[3]= (uchar) (value >> 32);
798
to[2]= (uchar) (value >> 40);
799
to[1]= (uchar) (value >> 48);
800
if (item->unsigned_flag) /* Fix sign */
801
to[0]= (uchar) (value >> 56);
803
to[0]= (uchar) (value >> 56) ^ 128; /* Reverse signbit */
805
to[3]= (uchar) value;
806
to[2]= (uchar) (value >> 8);
807
to[1]= (uchar) (value >> 16);
808
if (item->unsigned_flag) /* Fix sign */
809
to[0]= (uchar) (value >> 24);
811
to[0]= (uchar) (value >> 24) ^ 128; /* Reverse signbit */
813
815
case DECIMAL_RESULT:
957
static bool save_index(SORTPARAM *param, unsigned char **sort_keys, uint32_t count,
958
filesort_info_st *table_sort)
959
static bool save_index(SORTPARAM *param, uchar **sort_keys, uint count,
960
FILESORT_INFO *table_sort)
960
uint32_t offset,res_length;
962
uint offset,res_length;
963
my_string_ptr_sort((unsigned char*) sort_keys, (uint32_t) count, param->sort_length);
965
my_string_ptr_sort((uchar*) sort_keys, (uint) count, param->sort_length);
964
966
res_length= param->res_length;
965
967
offset= param->rec_length-res_length;
966
968
if ((ha_rows) count > param->max_rows)
967
count=(uint32_t) param->max_rows;
969
count=(uint) param->max_rows;
968
970
if (!(to= table_sort->record_pointers=
969
(unsigned char*) my_malloc(res_length*count, MYF(MY_WME))))
971
(uchar*) my_malloc(res_length*count, MYF(MY_WME))))
970
972
return(1); /* purecov: inspected */
971
for (unsigned char **end= sort_keys+count ; sort_keys != end ; sort_keys++)
973
for (uchar **end= sort_keys+count ; sort_keys != end ; sort_keys++)
973
975
memcpy(to, *sort_keys+offset, res_length);
980
982
/** Merge buffers to make < MERGEBUFF2 buffers. */
982
int merge_many_buff(SORTPARAM *param, unsigned char *sort_buffer,
983
BUFFPEK *buffpek, uint32_t *maxbuffer, IO_CACHE *t_file)
984
int merge_many_buff(SORTPARAM *param, uchar *sort_buffer,
985
BUFFPEK *buffpek, uint *maxbuffer, IO_CACHE *t_file)
986
988
IO_CACHE t_file2,*from_file,*to_file,*temp;
987
989
BUFFPEK *lastbuff;
989
991
if (*maxbuffer < MERGEBUFF2)
990
992
return(0); /* purecov: inspected */
991
993
if (flush_io_cache(t_file) ||
992
open_cached_file(&t_file2,drizzle_tmpdir,TEMP_PREFIX,DISK_BUFFER_SIZE,
994
open_cached_file(&t_file2,mysql_tmpdir,TEMP_PREFIX,DISK_BUFFER_SIZE,
994
996
return(1); /* purecov: inspected */
1033
1035
Read data to buffer.
1036
(uint32_t)-1 if something goes wrong
1038
(uint)-1 if something goes wrong
1039
uint32_t read_to_buffer(IO_CACHE *fromfile, BUFFPEK *buffpek,
1040
uint32_t rec_length)
1041
uint read_to_buffer(IO_CACHE *fromfile, BUFFPEK *buffpek,
1042
register uint32_t count;
1044
register uint count;
1045
if ((count=(uint32_t) cmin((ha_rows) buffpek->max_keys,buffpek->count)))
1047
if ((count=(uint) min((ha_rows) buffpek->max_keys,buffpek->count)))
1047
if (pread(fromfile->file,(unsigned char*) buffpek->base, (length= rec_length*count),buffpek->file_pos) == 0)
1048
return((uint32_t) -1); /* purecov: inspected */
1049
if (pread(fromfile->file,(uchar*) buffpek->base, (length= rec_length*count),buffpek->file_pos) == 0)
1050
return((uint) -1); /* purecov: inspected */
1049
1051
buffpek->key=buffpek->base;
1050
1052
buffpek->file_pos+= length; /* New filepos */
1051
1053
buffpek->count-= count;
1109
1111
int merge_buffers(SORTPARAM *param, IO_CACHE *from_file,
1110
IO_CACHE *to_file, unsigned char *sort_buffer,
1112
IO_CACHE *to_file, uchar *sort_buffer,
1111
1113
BUFFPEK *lastbuff, BUFFPEK *Fb, BUFFPEK *Tb,
1115
uint32_t rec_length,res_length,offset;
1117
uint rec_length,res_length,offset;
1116
1118
size_t sort_length;
1118
1120
ha_rows max_rows,org_max_rows;
1119
1121
my_off_t to_start_filepos;
1120
unsigned char *strpos;
1121
1123
BUFFPEK *buffpek;
1123
1125
qsort2_cmp cmp;
1124
1126
void *first_cmp_arg;
1125
volatile Session::killed_state *killed= ¤t_session->killed;
1126
Session::killed_state not_killable;
1127
volatile THD::killed_state *killed= ¤t_thd->killed;
1128
THD::killed_state not_killable;
1128
status_var_increment(current_session->status_var.filesort_merge_passes);
1130
status_var_increment(current_thd->status_var.filesort_merge_passes);
1129
1131
if (param->not_killable)
1131
1133
killed= ¬_killable;
1132
not_killable= Session::NOT_KILLED;
1134
not_killable= THD::NOT_KILLED;
1155
1157
cmp= get_ptr_compare(sort_length);
1156
1158
first_cmp_arg= (void*) &sort_length;
1158
if (init_queue(&queue, (uint32_t) (Tb-Fb)+1, offsetof(BUFFPEK,key), 0,
1160
if (init_queue(&queue, (uint) (Tb-Fb)+1, offsetof(BUFFPEK,key), 0,
1159
1161
(queue_compare) cmp, first_cmp_arg))
1160
1162
return(1); /* purecov: inspected */
1161
1163
for (buffpek= Fb ; buffpek <= Tb ; buffpek++)
1163
1165
buffpek->base= strpos;
1164
1166
buffpek->max_keys= maxcount;
1165
strpos+= (uint32_t) (error= (int) read_to_buffer(from_file, buffpek,
1167
strpos+= (uint) (error= (int) read_to_buffer(from_file, buffpek,
1167
1169
if (error == -1)
1168
1170
goto err; /* purecov: inspected */
1169
1171
buffpek->max_keys= buffpek->mem_count; // If less data in buffers than expected
1170
queue_insert(&queue, (unsigned char*) buffpek);
1172
queue_insert(&queue, (uchar*) buffpek);
1173
1175
if (param->unique_buff)
1210
1212
if (cmp) // Remove duplicates
1212
1214
if (!(*cmp)(first_cmp_arg, &(param->unique_buff),
1213
(unsigned char**) &buffpek->key))
1215
(uchar**) &buffpek->key))
1214
1216
goto skip_duplicate;
1215
memcpy(param->unique_buff, buffpek->key, rec_length);
1217
memcpy(param->unique_buff, (uchar*) buffpek->key, rec_length);
1219
if (my_b_write(to_file,(unsigned char*) buffpek->key, rec_length))
1221
if (my_b_write(to_file,(uchar*) buffpek->key, rec_length))
1221
1223
error=1; goto err; /* purecov: inspected */
1226
if (my_b_write(to_file, (unsigned char*) buffpek->key+offset, res_length))
1228
if (my_b_write(to_file, (uchar*) buffpek->key+offset, res_length))
1228
1230
error=1; goto err; /* purecov: inspected */
1314
1316
/* Do a merge to output-file (save only positions) */
1316
static int merge_index(SORTPARAM *param, unsigned char *sort_buffer,
1317
BUFFPEK *buffpek, uint32_t maxbuffer,
1318
static int merge_index(SORTPARAM *param, uchar *sort_buffer,
1319
BUFFPEK *buffpek, uint maxbuffer,
1318
1320
IO_CACHE *tempfile, IO_CACHE *outfile)
1320
1322
if (merge_buffers(param,tempfile,outfile,sort_buffer,buffpek,buffpek,
1599
1605
if (tmp[0] & 128) /* Negative */
1600
1606
{ /* make complement */
1602
1608
for (i=0 ; i < sizeof(nr); i++)
1603
tmp[i]=tmp[i] ^ (unsigned char) 255;
1609
tmp[i]=tmp[i] ^ (uchar) 255;
1606
1612
{ /* Set high and move exponent one up */
1607
uint16_t exp_part=(((uint16_t) tmp[0] << 8) | (uint16_t) tmp[1] |
1609
exp_part+= (uint16_t) 1 << (16-1-DBL_EXP_DIG);
1610
tmp[0]= (unsigned char) (exp_part >> 8);
1611
tmp[1]= (unsigned char) exp_part;
1613
ushort exp_part=(((ushort) tmp[0] << 8) | (ushort) tmp[1] |
1615
exp_part+= (ushort) 1 << (16-1-DBL_EXP_DIG);
1616
tmp[0]= (uchar) (exp_part >> 8);
1617
tmp[1]= (uchar) exp_part;