~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/filesort.cc

  • Committer: Brian Aker
  • Date: 2008-10-06 06:47:29 UTC
  • Revision ID: brian@tangent.org-20081006064729-2i9mhjkzyvow9xsm
RemoveĀ uint.

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