~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/filesort.cc

  • Committer: Toru Maesaka
  • Date: 2008-12-17 07:16:37 UTC
  • mto: (685.1.40 devel) (713.1.5 devel)
  • mto: This revision was merged to the branch mainline in revision 713.
  • Revision ID: dev@torum.net-20081217071637-7j9040w7lpms77r2
Removed my_time() and added error checking

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* Copyright (C) 2000-2006 MySQL AB  
 
1
/* Copyright (C) 2000-2006 MySQL AB
2
2
 
3
3
   This program is free software; you can redistribute it and/or modify
4
4
   it under the terms of the GNU General Public License as published by
22
22
*/
23
23
 
24
24
#include <drizzled/server_includes.h>
25
 
#include "sql_sort.h"
26
 
#include <drizzled/drizzled_error_messages.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>
27
31
 
28
 
        /* functions defined in this file */
 
32
/* functions defined in this file */
29
33
 
30
34
static char **make_char_array(char **old_pos, register uint32_t fields,
31
 
                              uint32_t length, myf my_flag);
 
35
                              uint32_t length);
32
36
static unsigned char *read_buffpek_from_file(IO_CACHE *buffer_file, uint32_t count,
33
37
                                     unsigned char *buf);
34
38
static ha_rows find_all_keys(SORTPARAM *param,SQL_SELECT *select,
42
46
                       BUFFPEK *buffpek,
43
47
                       uint32_t maxbuffer,IO_CACHE *tempfile,
44
48
                       IO_CACHE *outfile);
45
 
static bool save_index(SORTPARAM *param,unsigned char **sort_keys, uint32_t count, 
 
49
static bool save_index(SORTPARAM *param,unsigned char **sort_keys, uint32_t count,
46
50
                       filesort_info_st *table_sort);
47
51
static uint32_t suffix_length(uint32_t string_length);
48
 
static uint32_t sortlength(THD *thd, SORT_FIELD *sortorder, uint32_t s_length,
 
52
static uint32_t sortlength(Session *session, SORT_FIELD *sortorder, uint32_t s_length,
49
53
                       bool *multi_byte_charset);
50
 
static SORT_ADDON_FIELD *get_addon_fields(THD *thd, Field **ptabfield,
 
54
static SORT_ADDON_FIELD *get_addon_fields(Session *session, Field **ptabfield,
51
55
                                          uint32_t sortlength, uint32_t *plength);
52
56
static void unpack_addon_fields(struct st_sort_addon_field *addon_field,
53
57
                                unsigned char *buff);
63
67
  The result set is stored in table->io_cache or
64
68
  table->record_pointers.
65
69
 
66
 
  @param thd           Current thread
 
70
  @param session           Current thread
67
71
  @param table          Table to sort
68
72
  @param sortorder      How to sort the table
69
73
  @param s_length       Number of elements in sortorder
87
91
    examined_rows       will be set to number of examined rows
88
92
*/
89
93
 
90
 
ha_rows filesort(THD *thd, Table *table, SORT_FIELD *sortorder, uint32_t s_length,
 
94
ha_rows filesort(Session *session, Table *table, SORT_FIELD *sortorder, uint32_t s_length,
91
95
                 SQL_SELECT *select, ha_rows max_rows,
92
96
                 bool sort_positions, ha_rows *examined_rows)
93
97
{
97
101
  BUFFPEK *buffpek;
98
102
  ha_rows records= HA_POS_ERROR;
99
103
  unsigned char **sort_keys= 0;
100
 
  IO_CACHE tempfile, buffpek_pointers, *selected_records_file, *outfile; 
 
104
  IO_CACHE tempfile, buffpek_pointers, *selected_records_file, *outfile;
101
105
  SORTPARAM param;
102
106
  bool multi_byte_charset;
103
107
 
111
115
   Release InnoDB's adaptive hash index latch (if holding) before
112
116
   running a sort.
113
117
  */
114
 
  ha_release_temporary_latches(thd);
 
118
  ha_release_temporary_latches(session);
115
119
 
116
 
  /* 
117
 
    Don't use table->sort in filesort as it is also used by 
118
 
    QUICK_INDEX_MERGE_SELECT. Work with a copy and put it back at the end 
 
120
  /*
 
121
    Don't use table->sort in filesort as it is also used by
 
122
    QUICK_INDEX_MERGE_SELECT. Work with a copy and put it back at the end
119
123
    when index_merge select has finished with it.
120
124
  */
121
125
  memcpy(&table_sort, &table->sort, sizeof(filesort_info_st));
122
126
  table->sort.io_cache= NULL;
123
 
  
 
127
 
124
128
  outfile= table_sort.io_cache;
125
129
  my_b_clear(&tempfile);
126
130
  my_b_clear(&buffpek_pointers);
127
131
  buffpek=0;
128
132
  error= 1;
129
133
  memset(&param, 0, sizeof(param));
130
 
  param.sort_length= sortlength(thd, sortorder, s_length, &multi_byte_charset);
 
134
  param.sort_length= sortlength(session, sortorder, s_length, &multi_byte_charset);
131
135
  param.ref_length= table->file->ref_length;
132
136
  param.addon_field= 0;
133
137
  param.addon_length= 0;
134
138
  if (!(table->file->ha_table_flags() & HA_FAST_KEY_READ) && !sort_positions)
135
139
  {
136
 
    /* 
137
 
      Get the descriptors of all fields whose values are appended 
 
140
    /*
 
141
      Get the descriptors of all fields whose values are appended
138
142
      to sorted fields and get its total length in param.spack_length.
139
143
    */
140
 
    param.addon_field= get_addon_fields(thd, table->field, 
 
144
    param.addon_field= get_addon_fields(session, table->field,
141
145
                                        param.sort_length,
142
146
                                        &param.addon_length);
143
147
  }
149
153
  if (param.addon_field)
150
154
  {
151
155
    param.res_length= param.addon_length;
152
 
    if (!(table_sort.addon_buf= (unsigned char *) my_malloc(param.addon_length,
153
 
                                                    MYF(MY_WME))))
 
156
    if (!(table_sort.addon_buf= (unsigned char *) malloc(param.addon_length)))
154
157
      goto err;
155
158
  }
156
159
  else
157
160
  {
158
161
    param.res_length= param.ref_length;
159
 
    /* 
160
 
      The reference to the record is considered 
 
162
    /*
 
163
      The reference to the record is considered
161
164
      as an additional sorted field
162
165
    */
163
166
    param.sort_length+= param.ref_length;
167
170
 
168
171
  if (select && select->quick)
169
172
  {
170
 
    status_var_increment(thd->status_var.filesort_range_count);
 
173
    status_var_increment(session->status_var.filesort_range_count);
171
174
  }
172
175
  else
173
176
  {
174
 
    status_var_increment(thd->status_var.filesort_scan_count);
 
177
    status_var_increment(session->status_var.filesort_scan_count);
175
178
  }
176
179
#ifdef CAN_TRUST_RANGE
177
180
  if (select && select->quick && select->quick->records > 0L)
185
188
  {
186
189
    records= table->file->estimate_rows_upper_bound();
187
190
    /*
188
 
      If number of records is not known, use as much of sort buffer 
189
 
      as possible. 
 
191
      If number of records is not known, use as much of sort buffer
 
192
      as possible.
190
193
    */
191
194
    if (records == HA_POS_ERROR)
192
195
      records--;  // we use 'records+1' below.
194
197
  }
195
198
 
196
199
  if (multi_byte_charset &&
197
 
      !(param.tmp_buffer= (char*) my_malloc(param.sort_length,MYF(MY_WME))))
 
200
      !(param.tmp_buffer= (char*) malloc(param.sort_length)))
198
201
    goto err;
199
202
 
200
 
  memavl= thd->variables.sortbuff_size;
 
203
  memavl= session->variables.sortbuff_size;
201
204
  min_sort_memory= cmax((uint32_t)MIN_SORT_MEMORY, param.sort_length*MERGEBUFF2);
202
205
  while (memavl >= min_sort_memory)
203
206
  {
206
209
    param.keys=(uint32_t) cmin(records+1, keys);
207
210
    if ((table_sort.sort_keys=
208
211
         (unsigned char **) make_char_array((char **) table_sort.sort_keys,
209
 
                                    param.keys, param.rec_length, MYF(0))))
 
212
                                            param.keys, param.rec_length)))
210
213
      break;
211
214
    old_memavl=memavl;
212
215
    if ((memavl=memavl/4*3) < min_sort_memory && old_memavl > min_sort_memory)
218
221
    my_error(ER_OUT_OF_SORTMEMORY,MYF(ME_ERROR+ME_WAITTANG));
219
222
    goto err;
220
223
  }
221
 
  if (open_cached_file(&buffpek_pointers,mysql_tmpdir,TEMP_PREFIX,
 
224
  if (open_cached_file(&buffpek_pointers,drizzle_tmpdir,TEMP_PREFIX,
222
225
                       DISK_BUFFER_SIZE, MYF(MY_WME)))
223
226
    goto err;
224
227
 
253
256
    close_cached_file(&buffpek_pointers);
254
257
        /* Open cached file if it isn't open */
255
258
    if (! my_b_inited(outfile) &&
256
 
        open_cached_file(outfile,mysql_tmpdir,TEMP_PREFIX,READ_RECORD_BUFFER,
 
259
        open_cached_file(outfile,drizzle_tmpdir,TEMP_PREFIX,READ_RECORD_BUFFER,
257
260
                          MYF(MY_WME)))
258
261
      goto err;
259
262
    if (reinit_io_cache(outfile,WRITE_CACHE,0L,0,0))
312
315
    my_message(ER_FILSORT_ABORT, ER(ER_FILSORT_ABORT),
313
316
               MYF(ME_ERROR+ME_WAITTANG));
314
317
  else
315
 
    statistic_add(thd->status_var.filesort_rows,
 
318
    statistic_add(session->status_var.filesort_rows,
316
319
                  (uint32_t) records, &LOCK_status);
317
320
  *examined_rows= param.examined_rows;
318
321
  memcpy(&table->sort, &table_sort, sizeof(filesort_info_st));
356
359
/** Make a array of string pointers. */
357
360
 
358
361
static char **make_char_array(char **old_pos, register uint32_t fields,
359
 
                              uint32_t length, myf my_flag)
 
362
                              uint32_t length)
360
363
{
361
364
  register char **pos;
362
365
  char *char_pos;
363
366
 
364
367
  if (old_pos ||
365
 
      (old_pos= (char**) my_malloc((uint32_t) fields*(length+sizeof(char*)),
366
 
                                   my_flag)))
 
368
      (old_pos= (char**) malloc((uint32_t) fields*(length+sizeof(char*)))))
367
369
  {
368
370
    pos=old_pos; char_pos=((char*) (pos+fields)) -length;
369
371
    while (fields--) *(pos++) = (char_pos+= length);
383
385
  if (count > UINT_MAX/sizeof(BUFFPEK))
384
386
    return 0; /* sizeof(BUFFPEK)*count will overflow */
385
387
  if (!tmp)
386
 
    tmp= (unsigned char *)my_malloc(length, MYF(MY_WME));
 
388
    tmp= (unsigned char *)malloc(length);
387
389
  if (tmp)
388
390
  {
389
391
    if (reinit_io_cache(buffpek_pointers,READ_CACHE,0L,0,0) ||
444
446
  unsigned char *ref_pos,*next_pos,ref_buff[MAX_REFLENGTH];
445
447
  my_off_t record;
446
448
  Table *sort_form;
447
 
  THD *thd= current_thd;
448
 
  volatile THD::killed_state *killed= &thd->killed;
 
449
  Session *session= current_session;
 
450
  volatile Session::killed_state *killed= &session->killed;
449
451
  handler *file;
450
452
  MY_BITMAP *save_read_set, *save_write_set;
451
453
 
467
469
    next_pos=(unsigned char*) 0;                        /* Find records in sequence */
468
470
    file->ha_rnd_init(1);
469
471
    file->extra_opt(HA_EXTRA_CACHE,
470
 
                    current_thd->variables.read_buff_size);
 
472
                    current_session->variables.read_buff_size);
471
473
  }
472
474
 
473
475
  READ_RECORD read_record_info;
475
477
  {
476
478
    if (select->quick->reset())
477
479
      return(HA_POS_ERROR);
478
 
    init_read_record(&read_record_info, current_thd, select->quick->head,
 
480
    init_read_record(&read_record_info, current_session, select->quick->head,
479
481
                     select, 1, 1);
480
482
  }
481
483
 
517
519
      else
518
520
      {
519
521
        error=file->rnd_next(sort_form->record[0]);
 
522
        if (!error)
 
523
          update_virtual_fields_marked_for_write(sort_form);
 
524
 
520
525
        if (!flag)
521
526
        {
522
527
          my_store_ptr(ref_pos,ref_length,record); // Position to row
554
559
    else
555
560
      file->unlock_row();
556
561
    /* It does not make sense to read more keys in case of a fatal error */
557
 
    if (thd->is_error())
 
562
    if (session->is_error())
558
563
      break;
559
564
  }
560
565
  if (quick_select)
572
577
      file->ha_rnd_end();
573
578
  }
574
579
 
575
 
  if (thd->is_error())
 
580
  if (session->is_error())
576
581
    return(HA_POS_ERROR);
577
 
  
 
582
 
578
583
  /* Signal we should use orignal column read and write maps */
579
584
  sort_form->column_bitmaps_set(save_read_set, save_write_set);
580
585
 
626
631
  rec_length= param->rec_length;
627
632
  my_string_ptr_sort((unsigned char*) sort_keys, (uint32_t) count, sort_length);
628
633
  if (!my_b_inited(tempfile) &&
629
 
      open_cached_file(tempfile, mysql_tmpdir, TEMP_PREFIX, DISK_BUFFER_SIZE,
 
634
      open_cached_file(tempfile, drizzle_tmpdir, TEMP_PREFIX, DISK_BUFFER_SIZE,
630
635
                       MYF(MY_WME)))
631
636
    goto err;                                   /* purecov: inspected */
632
637
  /* check we won't have more buffpeks than we can possibly keep in memory */
790
795
              break;
791
796
            }
792
797
          }
793
 
#if SIZEOF_LONG_LONG > 4
794
798
          to[7]= (unsigned char) value;
795
799
          to[6]= (unsigned char) (value >> 8);
796
800
          to[5]= (unsigned char) (value >> 16);
802
806
            to[0]= (unsigned char) (value >> 56);
803
807
          else
804
808
            to[0]= (unsigned char) (value >> 56) ^ 128; /* Reverse signbit */
805
 
#else
806
 
          to[3]= (unsigned char) value;
807
 
          to[2]= (unsigned char) (value >> 8);
808
 
          to[1]= (unsigned char) (value >> 16);
809
 
          if (item->unsigned_flag)                    /* Fix sign */
810
 
            to[0]= (unsigned char) (value >> 24);
811
 
          else
812
 
            to[0]= (unsigned char) (value >> 24) ^ 128; /* Reverse signbit */
813
 
#endif
814
809
          break;
815
810
        }
816
811
      case DECIMAL_RESULT:
819
814
          if (maybe_null)
820
815
          {
821
816
            if (item->null_value)
822
 
            { 
 
817
            {
823
818
              memset(to, 0, sort_field->length+1);
824
819
              to++;
825
820
              break;
848
843
          break;
849
844
        }
850
845
      case ROW_RESULT:
851
 
      default: 
 
846
      default:
852
847
        // This case should never be choosen
853
848
        assert(0);
854
849
        break;
871
866
 
872
867
  if (param->addon_field)
873
868
  {
874
 
    /* 
 
869
    /*
875
870
      Save field values appended to sorted fields.
876
871
      First null bit indicators are appended then field values follow.
877
872
      In this implementation we use fixed layout for field values -
957
952
}
958
953
 
959
954
 
960
 
static bool save_index(SORTPARAM *param, unsigned char **sort_keys, uint32_t count, 
 
955
static bool save_index(SORTPARAM *param, unsigned char **sort_keys, uint32_t count,
961
956
                       filesort_info_st *table_sort)
962
957
{
963
958
  uint32_t offset,res_length;
968
963
  offset= param->rec_length-res_length;
969
964
  if ((ha_rows) count > param->max_rows)
970
965
    count=(uint32_t) param->max_rows;
971
 
  if (!(to= table_sort->record_pointers= 
972
 
        (unsigned char*) my_malloc(res_length*count, MYF(MY_WME))))
 
966
  if (!(to= table_sort->record_pointers=
 
967
        (unsigned char*) malloc(res_length*count)))
973
968
    return(1);                 /* purecov: inspected */
974
969
  for (unsigned char **end= sort_keys+count ; sort_keys != end ; sort_keys++)
975
970
  {
992
987
  if (*maxbuffer < MERGEBUFF2)
993
988
    return(0);                          /* purecov: inspected */
994
989
  if (flush_io_cache(t_file) ||
995
 
      open_cached_file(&t_file2,mysql_tmpdir,TEMP_PREFIX,DISK_BUFFER_SIZE,
 
990
      open_cached_file(&t_file2,drizzle_tmpdir,TEMP_PREFIX,DISK_BUFFER_SIZE,
996
991
                        MYF(MY_WME)))
997
992
    return(1);                          /* purecov: inspected */
998
993
 
1125
1120
  QUEUE queue;
1126
1121
  qsort2_cmp cmp;
1127
1122
  void *first_cmp_arg;
1128
 
  volatile THD::killed_state *killed= &current_thd->killed;
1129
 
  THD::killed_state not_killable;
 
1123
  volatile Session::killed_state *killed= &current_session->killed;
 
1124
  Session::killed_state not_killable;
1130
1125
 
1131
 
  status_var_increment(current_thd->status_var.filesort_merge_passes);
 
1126
  status_var_increment(current_session->status_var.filesort_merge_passes);
1132
1127
  if (param->not_killable)
1133
1128
  {
1134
1129
    killed= &not_killable;
1135
 
    not_killable= THD::NOT_KILLED;
 
1130
    not_killable= Session::NOT_KILLED;
1136
1131
  }
1137
1132
 
1138
1133
  error=0;
1147
1142
 
1148
1143
  /* The following will fire if there is not enough space in sort_buffer */
1149
1144
  assert(maxcount!=0);
1150
 
  
 
1145
 
1151
1146
  if (param->unique_buff)
1152
1147
  {
1153
1148
    cmp= param->compare;
1175
1170
 
1176
1171
  if (param->unique_buff)
1177
1172
  {
1178
 
    /* 
 
1173
    /*
1179
1174
       Called by Unique::get()
1180
1175
       Copy the first argument to param->unique_buff for unique removal.
1181
1176
       Store it also in 'to_file'.
1294
1289
      for (end= strpos+buffpek->mem_count*rec_length ;
1295
1290
           strpos != end ;
1296
1291
           strpos+= rec_length)
1297
 
      {     
 
1292
      {
1298
1293
        if (my_b_write(to_file, (unsigned char *) strpos, res_length))
1299
1294
        {
1300
 
          error=1; goto err;                        
 
1295
          error=1; goto err;
1301
1296
        }
1302
1297
      }
1303
1298
    }
1343
1338
/**
1344
1339
  Calculate length of sort key.
1345
1340
 
1346
 
  @param thd                      Thread handler
 
1341
  @param session                          Thread handler
1347
1342
  @param sortorder                Order of items to sort
1348
1343
  @param s_length                 Number of items to sort
1349
1344
  @param[out] multi_byte_charset Set to 1 if we are using multi-byte charset
1359
1354
*/
1360
1355
 
1361
1356
static uint32_t
1362
 
sortlength(THD *thd, SORT_FIELD *sortorder, uint32_t s_length,
 
1357
sortlength(Session *session, SORT_FIELD *sortorder, uint32_t s_length,
1363
1358
           bool *multi_byte_charset)
1364
1359
{
1365
1360
  register uint32_t length;
1393
1388
      switch (sortorder->result_type) {
1394
1389
      case STRING_RESULT:
1395
1390
        sortorder->length=sortorder->item->max_length;
1396
 
        set_if_smaller(sortorder->length, thd->variables.max_sort_length);
 
1391
        set_if_smaller(sortorder->length, session->variables.max_sort_length);
1397
1392
        if (use_strnxfrm((cs=sortorder->item->collation.collation)))
1398
 
        { 
 
1393
        {
1399
1394
          sortorder->length= cs->coll->strnxfrmlen(cs, sortorder->length);
1400
1395
          sortorder->need_strxnfrm= 1;
1401
1396
          *multi_byte_charset= 1;
1408
1403
        }
1409
1404
        break;
1410
1405
      case INT_RESULT:
1411
 
#if SIZEOF_LONG_LONG > 4
1412
1406
        sortorder->length=8;                    // Size of intern int64_t
1413
 
#else
1414
 
        sortorder->length=4;
1415
 
#endif
1416
1407
        break;
1417
1408
      case DECIMAL_RESULT:
1418
1409
        sortorder->length=
1419
 
          my_decimal_get_binary_size(sortorder->item->max_length - 
 
1410
          my_decimal_get_binary_size(sortorder->item->max_length -
1420
1411
                                     (sortorder->item->decimals ? 1 : 0),
1421
1412
                                     sortorder->item->decimals);
1422
1413
        break;
1424
1415
        sortorder->length=sizeof(double);
1425
1416
        break;
1426
1417
      case ROW_RESULT:
1427
 
      default: 
 
1418
      default:
1428
1419
        // This case should never be choosen
1429
1420
        assert(0);
1430
1421
        break;
1432
1423
      if (sortorder->item->maybe_null)
1433
1424
        length++;                               // Place for NULL marker
1434
1425
    }
1435
 
    set_if_smaller(sortorder->length, thd->variables.max_sort_length);
 
1426
    set_if_smaller(sortorder->length, session->variables.max_sort_length);
1436
1427
    length+=sortorder->length;
1437
1428
  }
1438
1429
  sortorder->field= (Field*) 0;                 // end marker
1446
1437
 
1447
1438
  The function first finds out what fields are used in the result set.
1448
1439
  Then it calculates the length of the buffer to store the values of
1449
 
  these fields together with the value of sort values. 
 
1440
  these fields together with the value of sort values.
1450
1441
  If the calculated length is not greater than max_length_for_sort_data
1451
1442
  the function allocates memory for an array of descriptors containing
1452
1443
  layouts for the values of the non-sorted fields in the buffer and
1453
1444
  fills them.
1454
1445
 
1455
 
  @param thd                 Current thread
 
1446
  @param session                 Current thread
1456
1447
  @param ptabfield           Array of references to the table fields
1457
1448
  @param sortlength          Total length of sorted fields
1458
1449
  @param[out] plength        Total length of appended fields
1468
1459
*/
1469
1460
 
1470
1461
static SORT_ADDON_FIELD *
1471
 
get_addon_fields(THD *thd, Field **ptabfield, uint32_t sortlength, uint32_t *plength)
 
1462
get_addon_fields(Session *session, Field **ptabfield, uint32_t sortlength, uint32_t *plength)
1472
1463
{
1473
1464
  Field **pfield;
1474
1465
  Field *field;
1484
1475
    Note for future refinement:
1485
1476
    This this a too strong condition.
1486
1477
    Actually we need only the fields referred in the
1487
 
    result set. And for some of them it makes sense to use 
 
1478
    result set. And for some of them it makes sense to use
1488
1479
    the values directly from sorted fields.
1489
1480
  */
1490
1481
  *plength= 0;
1499
1490
    if (field->maybe_null())
1500
1491
      null_fields++;
1501
1492
    fields++;
1502
 
  } 
 
1493
  }
1503
1494
  if (!fields)
1504
1495
    return 0;
1505
1496
  length+= (null_fields+7)/8;
1506
1497
 
1507
 
  if (length+sortlength > thd->variables.max_length_for_sort_data ||
1508
 
      !(addonf= (SORT_ADDON_FIELD *) my_malloc(sizeof(SORT_ADDON_FIELD)*
1509
 
                                               (fields+1), MYF(MY_WME))))
 
1498
  if (length+sortlength > session->variables.max_length_for_sort_data ||
 
1499
      !(addonf= (SORT_ADDON_FIELD *) malloc(sizeof(SORT_ADDON_FIELD)*
 
1500
                                            (fields+1))))
1510
1501
    return 0;
1511
1502
 
1512
1503
  *plength= length;
1534
1525
    addonf++;
1535
1526
  }
1536
1527
  addonf->field= 0;     // Put end marker
1537
 
  
 
1528
 
1538
1529
  return (addonf-fields);
1539
1530
}
1540
1531
 
1554
1545
    void.
1555
1546
*/
1556
1547
 
1557
 
static void 
 
1548
static void
1558
1549
unpack_addon_fields(struct st_sort_addon_field *addon_field, unsigned char *buff)
1559
1550
{
1560
1551
  Field *field;