~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/myisam/mi_dynrec.cc

  • Committer: Brian Aker
  • Date: 2009-05-23 17:13:03 UTC
  • mfrom: (1034.1.8 merge)
  • Revision ID: brian@gaz-20090523171303-d28xhutqic0xe2b4
Merge Brian

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* Copyright (C) 2000-2006 MySQL AB
2
 
 
3
 
   This program is free software; you can redistribute it and/or modify
4
 
   it under the terms of the GNU General Public License as published by
5
 
   the Free Software Foundation; version 2 of the License.
6
 
 
7
 
   This program is distributed in the hope that it will be useful,
8
 
   but WITHOUT ANY WARRANTY; without even the implied warranty of
9
 
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
 
   GNU General Public License for more details.
11
 
 
12
 
   You should have received a copy of the GNU General Public License
13
 
   along with this program; if not, write to the Free Software
14
 
   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */
15
 
 
16
 
/*
17
 
  Functions to handle space-packed-records and blobs
18
 
 
19
 
  A row may be stored in one or more linked blocks.
20
 
  The block size is between MI_MIN_BLOCK_LENGTH and MI_MAX_BLOCK_LENGTH.
21
 
  Each block is aligned on MI_DYN_ALIGN_SIZE.
22
 
  The reson for the max block size is to not have too many different types
23
 
  of blocks.  For the differnet block types, look at _mi_get_block_info()
24
 
*/
25
 
 
26
 
#include "myisam_priv.h"
27
 
 
28
 
#ifdef HAVE_SYS_TYPES
29
 
#include <sys/types.h>
30
 
#endif
31
 
#ifdef HAVE_SYS_MMAN_H
32
 
#include <sys/mman.h>
33
 
#endif
34
 
#include <drizzled/util/test.h>
35
 
#include "drizzled/error.h"
36
 
 
37
 
#include <cassert>
38
 
#include <algorithm>
39
 
 
40
 
using namespace drizzled;
41
 
using namespace std;
42
 
 
43
 
/* Enough for comparing if number is zero */
44
 
static char zero_string[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
45
 
 
46
 
static int write_dynamic_record(MI_INFO *info,const unsigned char *record,
47
 
                                ulong reclength);
48
 
static int _mi_find_writepos(MI_INFO *info,ulong reclength,internal::my_off_t *filepos,
49
 
                             ulong *length);
50
 
static int update_dynamic_record(MI_INFO *info,internal::my_off_t filepos,unsigned char *record,
51
 
                                 ulong reclength);
52
 
static int delete_dynamic_record(MI_INFO *info,internal::my_off_t filepos,
53
 
                                 uint32_t second_read);
54
 
static int _mi_cmp_buffer(int file, const unsigned char *buff, internal::my_off_t filepos,
55
 
                          uint32_t length);
56
 
 
57
 
        /* Interface function from MI_INFO */
58
 
 
59
 
 
60
 
/*
61
 
  Create mmaped area for MyISAM handler
62
 
 
63
 
  SYNOPSIS
64
 
    mi_dynmap_file()
65
 
    info                MyISAM handler
66
 
 
67
 
  RETURN
68
 
    0  ok
69
 
    1  error.
70
 
*/
71
 
 
72
 
bool mi_dynmap_file(MI_INFO *info, internal::my_off_t size)
73
 
{
74
 
  if (size > (internal::my_off_t) (~((size_t) 0)) - MEMMAP_EXTRA_MARGIN)
75
 
  {
76
 
    return(1);
77
 
  }
78
 
  /*
79
 
    I wonder if it is good to use MAP_NORESERVE. From the Linux man page:
80
 
    MAP_NORESERVE
81
 
      Do not reserve swap space for this mapping. When swap space is
82
 
      reserved, one has the guarantee that it is possible to modify the
83
 
      mapping. When swap space is not reserved one might get SIGSEGV
84
 
      upon a write if no physical memory is available.
85
 
  */
86
 
  info->s->file_map= (unsigned char*)
87
 
                  mmap(NULL, (size_t)(size + MEMMAP_EXTRA_MARGIN),
88
 
                       info->s->mode==O_RDONLY ? PROT_READ :
89
 
                       PROT_READ | PROT_WRITE,
90
 
                       MAP_SHARED | MAP_NORESERVE,
91
 
                       info->dfile, 0L);
92
 
  if (info->s->file_map == (unsigned char*) MAP_FAILED)
93
 
  {
94
 
    info->s->file_map= NULL;
95
 
    return(1);
96
 
  }
97
 
/* per krow we should look at removing the following code */
98
 
#if !defined(TARGET_OS_SOLARIS)
99
 
  madvise((char*) info->s->file_map, size, MADV_RANDOM);
100
 
#endif
101
 
  info->s->mmaped_length= size;
102
 
  return(0);
103
 
}
104
 
 
105
 
 
106
 
/*
107
 
  Resize mmaped area for MyISAM handler
108
 
 
109
 
  SYNOPSIS
110
 
    mi_remap_file()
111
 
    info                MyISAM handler
112
 
 
113
 
  RETURN
114
 
*/
115
 
 
116
 
void mi_remap_file(MI_INFO *info, internal::my_off_t size)
117
 
{
118
 
  if (info->s->file_map)
119
 
  {
120
 
    munmap((char*) info->s->file_map,
121
 
           (size_t) info->s->mmaped_length + MEMMAP_EXTRA_MARGIN);
122
 
    mi_dynmap_file(info, size);
123
 
  }
124
 
}
125
 
 
126
 
 
127
 
/*
128
 
  Read bytes from MySAM handler, using mmap or pread
129
 
 
130
 
  SYNOPSIS
131
 
    mi_mmap_pread()
132
 
    info                MyISAM handler
133
 
    Buffer              Input buffer
134
 
    Count               Count of bytes for read
135
 
    offset              Start position
136
 
    MyFlags
137
 
 
138
 
  RETURN
139
 
    0  ok
140
 
*/
141
 
 
142
 
size_t mi_mmap_pread(MI_INFO *info, unsigned char *Buffer,
143
 
                    size_t Count, internal::my_off_t offset, myf MyFlags)
144
 
{
145
 
  /*
146
 
    The following test may fail in the following cases:
147
 
    - We failed to remap a memory area (fragmented memory?)
148
 
    - This thread has done some writes, but not yet extended the
149
 
    memory mapped area.
150
 
  */
151
 
 
152
 
  if (info->s->mmaped_length >= offset + Count)
153
 
  {
154
 
    memcpy(Buffer, info->s->file_map + offset, Count);
155
 
    return 0;
156
 
  }
157
 
  else
158
 
  {
159
 
    return my_pread(info->dfile, Buffer, Count, offset, MyFlags);
160
 
  }
161
 
}
162
 
 
163
 
 
164
 
        /* wrapper for my_pread in case if mmap isn't used */
165
 
 
166
 
size_t mi_nommap_pread(MI_INFO *info, unsigned char *Buffer,
167
 
                       size_t Count, internal::my_off_t offset, myf MyFlags)
168
 
{
169
 
  return my_pread(info->dfile, Buffer, Count, offset, MyFlags);
170
 
}
171
 
 
172
 
 
173
 
/*
174
 
  Write bytes to MySAM handler, using mmap or pwrite
175
 
 
176
 
  SYNOPSIS
177
 
    mi_mmap_pwrite()
178
 
    info                MyISAM handler
179
 
    Buffer              Output buffer
180
 
    Count               Count of bytes for write
181
 
    offset              Start position
182
 
    MyFlags
183
 
 
184
 
  RETURN
185
 
    0  ok
186
 
    !=0  error.  In this case return error from pwrite
187
 
*/
188
 
 
189
 
size_t mi_mmap_pwrite(MI_INFO *info, const unsigned char *Buffer,
190
 
                      size_t Count, internal::my_off_t offset, myf MyFlags)
191
 
{
192
 
 
193
 
  /*
194
 
    The following test may fail in the following cases:
195
 
    - We failed to remap a memory area (fragmented memory?)
196
 
    - This thread has done some writes, but not yet extended the
197
 
    memory mapped area.
198
 
  */
199
 
 
200
 
  if (info->s->mmaped_length >= offset + Count)
201
 
  {
202
 
    memcpy(info->s->file_map + offset, Buffer, Count);
203
 
    return 0;
204
 
  }
205
 
  else
206
 
  {
207
 
    info->s->nonmmaped_inserts++;
208
 
    return my_pwrite(info->dfile, Buffer, Count, offset, MyFlags);
209
 
  }
210
 
 
211
 
}
212
 
 
213
 
 
214
 
        /* wrapper for my_pwrite in case if mmap isn't used */
215
 
 
216
 
size_t mi_nommap_pwrite(MI_INFO *info, const unsigned char *Buffer,
217
 
                      size_t Count, internal::my_off_t offset, myf MyFlags)
218
 
{
219
 
  return my_pwrite(info->dfile, Buffer, Count, offset, MyFlags);
220
 
}
221
 
 
222
 
 
223
 
int _mi_write_dynamic_record(MI_INFO *info, const unsigned char *record)
224
 
{
225
 
  ulong reclength=_mi_rec_pack(info,info->rec_buff,record);
226
 
  return (write_dynamic_record(info,info->rec_buff,reclength));
227
 
}
228
 
 
229
 
int _mi_update_dynamic_record(MI_INFO *info, internal::my_off_t pos, const unsigned char *record)
230
 
{
231
 
  uint32_t length=_mi_rec_pack(info,info->rec_buff,record);
232
 
  return (update_dynamic_record(info,pos,info->rec_buff,length));
233
 
}
234
 
 
235
 
int _mi_write_blob_record(MI_INFO *info, const unsigned char *record)
236
 
{
237
 
  unsigned char *rec_buff;
238
 
  int error;
239
 
  ulong reclength,reclength2,extra;
240
 
 
241
 
  extra= (ALIGN_SIZE(MI_MAX_DYN_BLOCK_HEADER)+MI_SPLIT_LENGTH+
242
 
          MI_DYN_DELETE_BLOCK_HEADER+1);
243
 
  reclength= (info->s->base.pack_reclength +
244
 
              _my_calc_total_blob_length(info,record)+ extra);
245
 
#ifdef NOT_USED                                 /* We now support big rows */
246
 
  if (reclength > MI_DYN_MAX_ROW_LENGTH)
247
 
  {
248
 
    errno=HA_ERR_TO_BIG_ROW;
249
 
    return -1;
250
 
  }
251
 
#endif
252
 
  if (!(rec_buff=(unsigned char*) malloc(reclength)))
253
 
  {
254
 
    errno= HA_ERR_OUT_OF_MEM;
255
 
    return(-1);
256
 
  }
257
 
  reclength2= _mi_rec_pack(info,rec_buff+ALIGN_SIZE(MI_MAX_DYN_BLOCK_HEADER),
258
 
                           record);
259
 
  assert(reclength2 <= reclength);
260
 
  error=write_dynamic_record(info,rec_buff+ALIGN_SIZE(MI_MAX_DYN_BLOCK_HEADER),
261
 
                             reclength2);
262
 
  free(rec_buff);
263
 
  return(error);
264
 
}
265
 
 
266
 
 
267
 
int _mi_update_blob_record(MI_INFO *info, internal::my_off_t pos, const unsigned char *record)
268
 
{
269
 
  unsigned char *rec_buff;
270
 
  int error;
271
 
  ulong reclength,extra;
272
 
 
273
 
  extra= (ALIGN_SIZE(MI_MAX_DYN_BLOCK_HEADER)+MI_SPLIT_LENGTH+
274
 
          MI_DYN_DELETE_BLOCK_HEADER);
275
 
  reclength= (info->s->base.pack_reclength+
276
 
              _my_calc_total_blob_length(info,record)+ extra);
277
 
#ifdef NOT_USED                                 /* We now support big rows */
278
 
  if (reclength > MI_DYN_MAX_ROW_LENGTH)
279
 
  {
280
 
    errno=HA_ERR_TO_BIG_ROW;
281
 
    return -1;
282
 
  }
283
 
#endif
284
 
  if (!(rec_buff=(unsigned char*) malloc(reclength)))
285
 
  {
286
 
    errno= HA_ERR_OUT_OF_MEM;
287
 
    return(-1);
288
 
  }
289
 
  reclength=_mi_rec_pack(info,rec_buff+ALIGN_SIZE(MI_MAX_DYN_BLOCK_HEADER),
290
 
                         record);
291
 
  error=update_dynamic_record(info,pos,
292
 
                              rec_buff+ALIGN_SIZE(MI_MAX_DYN_BLOCK_HEADER),
293
 
                              reclength);
294
 
  free(rec_buff);
295
 
  return(error);
296
 
}
297
 
 
298
 
 
299
 
int _mi_delete_dynamic_record(MI_INFO *info)
300
 
{
301
 
  return delete_dynamic_record(info,info->lastpos,0);
302
 
}
303
 
 
304
 
 
305
 
        /* Write record to data-file */
306
 
 
307
 
static int write_dynamic_record(MI_INFO *info, const unsigned char *record,
308
 
                                ulong reclength)
309
 
{
310
 
  int flag;
311
 
  ulong length;
312
 
  internal::my_off_t filepos;
313
 
 
314
 
  flag=0;
315
 
 
316
 
  /*
317
 
    Check if we have enough room for the new record.
318
 
    First we do simplified check to make usual case faster.
319
 
    Then we do more precise check for the space left.
320
 
    Though it still is not absolutely precise, as
321
 
    we always use MI_MAX_DYN_BLOCK_HEADER while it can be
322
 
    less in the most of the cases.
323
 
  */
324
 
 
325
 
  if (unlikely(info->s->base.max_data_file_length -
326
 
               info->state->data_file_length <
327
 
               reclength + MI_MAX_DYN_BLOCK_HEADER))
328
 
  {
329
 
    if (info->s->base.max_data_file_length - info->state->data_file_length +
330
 
        info->state->empty - info->state->del * MI_MAX_DYN_BLOCK_HEADER <
331
 
        reclength + MI_MAX_DYN_BLOCK_HEADER)
332
 
    {
333
 
      errno=HA_ERR_RECORD_FILE_FULL;
334
 
      return(1);
335
 
    }
336
 
  }
337
 
 
338
 
  do
339
 
  {
340
 
    if (_mi_find_writepos(info,reclength,&filepos,&length))
341
 
      goto err;
342
 
    if (_mi_write_part_record(info,filepos,length,
343
 
                              (info->append_insert_at_end ?
344
 
                               HA_OFFSET_ERROR : info->s->state.dellink),
345
 
                              (unsigned char**) &record,&reclength,&flag))
346
 
      goto err;
347
 
  } while (reclength);
348
 
 
349
 
  return(0);
350
 
err:
351
 
  return(1);
352
 
}
353
 
 
354
 
 
355
 
        /* Get a block for data ; The given data-area must be used !! */
356
 
 
357
 
static int _mi_find_writepos(MI_INFO *info,
358
 
                             ulong reclength, /* record length */
359
 
                             internal::my_off_t *filepos, /* Return file pos */
360
 
                             ulong *length)   /* length of block at filepos */
361
 
{
362
 
  MI_BLOCK_INFO block_info;
363
 
  ulong tmp;
364
 
 
365
 
  if (info->s->state.dellink != HA_OFFSET_ERROR &&
366
 
      !info->append_insert_at_end)
367
 
  {
368
 
    /* Deleted blocks exists;  Get last used block */
369
 
    *filepos=info->s->state.dellink;
370
 
    block_info.second_read=0;
371
 
    info->rec_cache.seek_not_done=1;
372
 
    if (!(_mi_get_block_info(&block_info,info->dfile,info->s->state.dellink) &
373
 
           BLOCK_DELETED))
374
 
    {
375
 
      errno=HA_ERR_WRONG_IN_RECORD;
376
 
      return(-1);
377
 
    }
378
 
    info->s->state.dellink=block_info.next_filepos;
379
 
    info->state->del--;
380
 
    info->state->empty-= block_info.block_len;
381
 
    *length= block_info.block_len;
382
 
  }
383
 
  else
384
 
  {
385
 
    /* No deleted blocks;  Allocate a new block */
386
 
    *filepos=info->state->data_file_length;
387
 
    if ((tmp=reclength+3 + test(reclength >= (65520-3))) <
388
 
        info->s->base.min_block_length)
389
 
      tmp= info->s->base.min_block_length;
390
 
    else
391
 
      tmp= ((tmp+MI_DYN_ALIGN_SIZE-1) &
392
 
            (~ (ulong) (MI_DYN_ALIGN_SIZE-1)));
393
 
    if (info->state->data_file_length >
394
 
        (info->s->base.max_data_file_length - tmp))
395
 
    {
396
 
      errno=HA_ERR_RECORD_FILE_FULL;
397
 
      return(-1);
398
 
    }
399
 
    if (tmp > MI_MAX_BLOCK_LENGTH)
400
 
      tmp=MI_MAX_BLOCK_LENGTH;
401
 
    *length= tmp;
402
 
    info->state->data_file_length+= tmp;
403
 
    info->s->state.split++;
404
 
    info->update|=HA_STATE_WRITE_AT_END;
405
 
  }
406
 
  return(0);
407
 
} /* _mi_find_writepos */
408
 
 
409
 
 
410
 
 
411
 
/*
412
 
  Unlink a deleted block from the deleted list.
413
 
  This block will be combined with the preceding or next block to form
414
 
  a big block.
415
 
*/
416
 
 
417
 
static bool unlink_deleted_block(MI_INFO *info, MI_BLOCK_INFO *block_info)
418
 
{
419
 
  if (block_info->filepos == info->s->state.dellink)
420
 
  {
421
 
    /* First deleted block;  We can just use this ! */
422
 
    info->s->state.dellink=block_info->next_filepos;
423
 
  }
424
 
  else
425
 
  {
426
 
    MI_BLOCK_INFO tmp;
427
 
    tmp.second_read=0;
428
 
    /* Unlink block from the previous block */
429
 
    if (!(_mi_get_block_info(&tmp,info->dfile,block_info->prev_filepos)
430
 
          & BLOCK_DELETED))
431
 
      return(1);                                /* Something is wrong */
432
 
    mi_sizestore(tmp.header+4,block_info->next_filepos);
433
 
    if (info->s->file_write(info, tmp.header+4,8,
434
 
                  block_info->prev_filepos+4, MYF(MY_NABP)))
435
 
      return(1);
436
 
    /* Unlink block from next block */
437
 
    if (block_info->next_filepos != HA_OFFSET_ERROR)
438
 
    {
439
 
      if (!(_mi_get_block_info(&tmp,info->dfile,block_info->next_filepos)
440
 
            & BLOCK_DELETED))
441
 
        return(1);                              /* Something is wrong */
442
 
      mi_sizestore(tmp.header+12,block_info->prev_filepos);
443
 
      if (info->s->file_write(info, tmp.header+12,8,
444
 
                    block_info->next_filepos+12,
445
 
                    MYF(MY_NABP)))
446
 
        return(1);
447
 
    }
448
 
  }
449
 
  /* We now have one less deleted block */
450
 
  info->state->del--;
451
 
  info->state->empty-= block_info->block_len;
452
 
  info->s->state.split--;
453
 
 
454
 
  /*
455
 
    If this was a block that we where accessing through table scan
456
 
    (mi_rrnd() or mi_scan(), then ensure that we skip over this block
457
 
    when doing next mi_rrnd() or mi_scan().
458
 
  */
459
 
  if (info->nextpos == block_info->filepos)
460
 
    info->nextpos+=block_info->block_len;
461
 
  return(0);
462
 
}
463
 
 
464
 
 
465
 
/*
466
 
  Add a backward link to delete block
467
 
 
468
 
  SYNOPSIS
469
 
    update_backward_delete_link()
470
 
    info                MyISAM handler
471
 
    delete_block        Position to delete block to update.
472
 
                        If this is 'HA_OFFSET_ERROR', nothing will be done
473
 
    filepos             Position to block that 'delete_block' should point to
474
 
 
475
 
  RETURN
476
 
    0  ok
477
 
    1  error.  In this case my_error is set.
478
 
*/
479
 
 
480
 
static int update_backward_delete_link(MI_INFO *info, internal::my_off_t delete_block,
481
 
                                       internal::my_off_t filepos)
482
 
{
483
 
  MI_BLOCK_INFO block_info;
484
 
 
485
 
  if (delete_block != HA_OFFSET_ERROR)
486
 
  {
487
 
    block_info.second_read=0;
488
 
    if (_mi_get_block_info(&block_info,info->dfile,delete_block)
489
 
        & BLOCK_DELETED)
490
 
    {
491
 
      unsigned char buff[8];
492
 
      mi_sizestore(buff,filepos);
493
 
      if (info->s->file_write(info,buff, 8, delete_block+12, MYF(MY_NABP)))
494
 
        return(1);                              /* Error on write */
495
 
    }
496
 
    else
497
 
    {
498
 
      errno=HA_ERR_WRONG_IN_RECORD;
499
 
      return(1);                                /* Wrong delete link */
500
 
    }
501
 
  }
502
 
  return(0);
503
 
}
504
 
 
505
 
        /* Delete datarecord from database */
506
 
        /* info->rec_cache.seek_not_done is updated in cmp_record */
507
 
 
508
 
static int delete_dynamic_record(MI_INFO *info, internal::my_off_t filepos,
509
 
                                 uint32_t second_read)
510
 
{
511
 
  uint32_t length,b_type;
512
 
  MI_BLOCK_INFO block_info,del_block;
513
 
  int error;
514
 
  bool remove_next_block;
515
 
 
516
 
  /* First add a link from the last block to the new one */
517
 
  error= update_backward_delete_link(info, info->s->state.dellink, filepos);
518
 
 
519
 
  block_info.second_read=second_read;
520
 
  do
521
 
  {
522
 
    /* Remove block at 'filepos' */
523
 
    if ((b_type=_mi_get_block_info(&block_info,info->dfile,filepos))
524
 
        & (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR |
525
 
           BLOCK_FATAL_ERROR) ||
526
 
        (length=(uint) (block_info.filepos-filepos) +block_info.block_len) <
527
 
        MI_MIN_BLOCK_LENGTH)
528
 
    {
529
 
      errno=HA_ERR_WRONG_IN_RECORD;
530
 
      return(1);
531
 
    }
532
 
    /* Check if next block is a delete block */
533
 
    del_block.second_read=0;
534
 
    remove_next_block=0;
535
 
    if (_mi_get_block_info(&del_block,info->dfile,filepos+length) &
536
 
        BLOCK_DELETED && del_block.block_len+length < MI_DYN_MAX_BLOCK_LENGTH)
537
 
    {
538
 
      /* We can't remove this yet as this block may be the head block */
539
 
      remove_next_block=1;
540
 
      length+=del_block.block_len;
541
 
    }
542
 
 
543
 
    block_info.header[0]=0;
544
 
    mi_int3store(block_info.header+1,length);
545
 
    mi_sizestore(block_info.header+4,info->s->state.dellink);
546
 
    if (b_type & BLOCK_LAST)
547
 
      memset(block_info.header+12, 255, 8);
548
 
    else
549
 
      mi_sizestore(block_info.header+12,block_info.next_filepos);
550
 
    if (info->s->file_write(info,(unsigned char*) block_info.header,20,filepos,
551
 
                  MYF(MY_NABP)))
552
 
      return(1);
553
 
    info->s->state.dellink = filepos;
554
 
    info->state->del++;
555
 
    info->state->empty+=length;
556
 
    filepos=block_info.next_filepos;
557
 
 
558
 
    /* Now it's safe to unlink the deleted block directly after this one */
559
 
    if (remove_next_block && unlink_deleted_block(info,&del_block))
560
 
      error=1;
561
 
  } while (!(b_type & BLOCK_LAST));
562
 
 
563
 
  return(error);
564
 
}
565
 
 
566
 
 
567
 
        /* Write a block to datafile */
568
 
 
569
 
int _mi_write_part_record(MI_INFO *info,
570
 
                          internal::my_off_t filepos,   /* points at empty block */
571
 
                          ulong length,         /* length of block */
572
 
                          internal::my_off_t next_filepos,/* Next empty block */
573
 
                          unsigned char **record,       /* pointer to record ptr */
574
 
                          ulong *reclength,     /* length of *record */
575
 
                          int *flag)            /* *flag == 0 if header */
576
 
{
577
 
  ulong head_length,res_length,extra_length,long_block,del_length;
578
 
  unsigned char *pos,*record_end;
579
 
  internal::my_off_t  next_delete_block;
580
 
  unsigned char temp[MI_SPLIT_LENGTH+MI_DYN_DELETE_BLOCK_HEADER];
581
 
 
582
 
  next_delete_block=HA_OFFSET_ERROR;
583
 
 
584
 
  res_length=extra_length=0;
585
 
  if (length > *reclength + MI_SPLIT_LENGTH)
586
 
  {                                             /* Splitt big block */
587
 
    res_length=MY_ALIGN(length- *reclength - MI_EXTEND_BLOCK_LENGTH,
588
 
                        MI_DYN_ALIGN_SIZE);
589
 
    length-= res_length;                        /* Use this for first part */
590
 
  }
591
 
  long_block= (length < 65520L && *reclength < 65520L) ? 0 : 1;
592
 
  if (length == *reclength+ 3 + long_block)
593
 
  {
594
 
    /* Block is exactly of the right length */
595
 
    temp[0]=(unsigned char) (1+ *flag)+(unsigned char) long_block;      /* Flag is 0 or 6 */
596
 
    if (long_block)
597
 
    {
598
 
      mi_int3store(temp+1,*reclength);
599
 
      head_length=4;
600
 
    }
601
 
    else
602
 
    {
603
 
      mi_int2store(temp+1,*reclength);
604
 
      head_length=3;
605
 
    }
606
 
  }
607
 
  else if (length-long_block < *reclength+4)
608
 
  {                                             /* To short block */
609
 
    if (next_filepos == HA_OFFSET_ERROR)
610
 
      next_filepos= (info->s->state.dellink != HA_OFFSET_ERROR &&
611
 
                     !info->append_insert_at_end ?
612
 
                     info->s->state.dellink : info->state->data_file_length);
613
 
    if (*flag == 0)                             /* First block */
614
 
    {
615
 
      if (*reclength > MI_MAX_BLOCK_LENGTH)
616
 
      {
617
 
        head_length= 16;
618
 
        temp[0]=13;
619
 
        mi_int4store(temp+1,*reclength);
620
 
        mi_int3store(temp+5,length-head_length);
621
 
        mi_sizestore((unsigned char*) temp+8,next_filepos);
622
 
      }
623
 
      else
624
 
      {
625
 
        head_length=5+8+long_block*2;
626
 
        temp[0]=5+(unsigned char) long_block;
627
 
        if (long_block)
628
 
        {
629
 
          mi_int3store(temp+1,*reclength);
630
 
          mi_int3store(temp+4,length-head_length);
631
 
          mi_sizestore((unsigned char*) temp+7,next_filepos);
632
 
        }
633
 
        else
634
 
        {
635
 
          mi_int2store(temp+1,*reclength);
636
 
          mi_int2store(temp+3,length-head_length);
637
 
          mi_sizestore((unsigned char*) temp+5,next_filepos);
638
 
        }
639
 
      }
640
 
    }
641
 
    else
642
 
    {
643
 
      head_length=3+8+long_block;
644
 
      temp[0]=11+(unsigned char) long_block;
645
 
      if (long_block)
646
 
      {
647
 
        mi_int3store(temp+1,length-head_length);
648
 
        mi_sizestore((unsigned char*) temp+4,next_filepos);
649
 
      }
650
 
      else
651
 
      {
652
 
        mi_int2store(temp+1,length-head_length);
653
 
        mi_sizestore((unsigned char*) temp+3,next_filepos);
654
 
      }
655
 
    }
656
 
  }
657
 
  else
658
 
  {                                     /* Block with empty info last */
659
 
    head_length=4+long_block;
660
 
    extra_length= length- *reclength-head_length;
661
 
    temp[0]= (unsigned char) (3+ *flag)+(unsigned char) long_block; /* 3,4 or 9,10 */
662
 
    if (long_block)
663
 
    {
664
 
      mi_int3store(temp+1,*reclength);
665
 
      temp[4]= (unsigned char) (extra_length);
666
 
    }
667
 
    else
668
 
    {
669
 
      mi_int2store(temp+1,*reclength);
670
 
      temp[3]= (unsigned char) (extra_length);
671
 
    }
672
 
    length=       *reclength+head_length;       /* Write only what is needed */
673
 
  }
674
 
 
675
 
        /* Make a long block for one write */
676
 
  record_end= *record+length-head_length;
677
 
  del_length=(res_length ? MI_DYN_DELETE_BLOCK_HEADER : 0);
678
 
  memmove(*record - head_length, temp, head_length);
679
 
  memcpy(temp,record_end,(size_t) (extra_length+del_length));
680
 
  memset(record_end, 0, extra_length);
681
 
 
682
 
  if (res_length)
683
 
  {
684
 
    /* Check first if we can join this block with the next one */
685
 
    MI_BLOCK_INFO del_block;
686
 
    internal::my_off_t next_block=filepos+length+extra_length+res_length;
687
 
 
688
 
    del_block.second_read=0;
689
 
    if (next_block < info->state->data_file_length &&
690
 
        info->s->state.dellink != HA_OFFSET_ERROR)
691
 
    {
692
 
      if ((_mi_get_block_info(&del_block,info->dfile,next_block)
693
 
           & BLOCK_DELETED) &&
694
 
          res_length + del_block.block_len < MI_DYN_MAX_BLOCK_LENGTH)
695
 
      {
696
 
        if (unlink_deleted_block(info,&del_block))
697
 
          goto err;
698
 
        res_length+=del_block.block_len;
699
 
      }
700
 
    }
701
 
 
702
 
    /* Create a delete link of the last part of the block */
703
 
    pos=record_end+extra_length;
704
 
    pos[0]= '\0';
705
 
    mi_int3store(pos+1,res_length);
706
 
    mi_sizestore(pos+4,info->s->state.dellink);
707
 
    memset(pos+12, 255, 8);                     /* End link */
708
 
    next_delete_block=info->s->state.dellink;
709
 
    info->s->state.dellink= filepos+length+extra_length;
710
 
    info->state->del++;
711
 
    info->state->empty+=res_length;
712
 
    info->s->state.split++;
713
 
  }
714
 
  if (info->opt_flag & WRITE_CACHE_USED &&
715
 
      info->update & HA_STATE_WRITE_AT_END)
716
 
  {
717
 
    if (info->update & HA_STATE_EXTEND_BLOCK)
718
 
    {
719
 
      info->update&= ~HA_STATE_EXTEND_BLOCK;
720
 
      if (my_block_write(&info->rec_cache,(unsigned char*) *record-head_length,
721
 
                         length+extra_length+del_length,filepos))
722
 
      goto err;
723
 
    }
724
 
    else if (my_b_write(&info->rec_cache,(unsigned char*) *record-head_length,
725
 
                        length+extra_length+del_length))
726
 
      goto err;
727
 
  }
728
 
  else
729
 
  {
730
 
    info->rec_cache.seek_not_done=1;
731
 
    if (info->s->file_write(info,(unsigned char*) *record-head_length,length+extra_length+
732
 
                  del_length,filepos,info->s->write_flag))
733
 
      goto err;
734
 
  }
735
 
  memcpy(record_end, temp, extra_length + del_length);
736
 
  *record=record_end;
737
 
  *reclength-=(length-head_length);
738
 
  *flag=6;
739
 
 
740
 
  if (del_length)
741
 
  {
742
 
    /* link the next delete block to this */
743
 
    if (update_backward_delete_link(info, next_delete_block,
744
 
                                    info->s->state.dellink))
745
 
      goto err;
746
 
  }
747
 
 
748
 
  return(0);
749
 
err:
750
 
  return(1);
751
 
} /*_mi_write_part_record */
752
 
 
753
 
 
754
 
        /* update record from datafile */
755
 
 
756
 
static int update_dynamic_record(MI_INFO *info, internal::my_off_t filepos, unsigned char *record,
757
 
                                 ulong reclength)
758
 
{
759
 
  int flag;
760
 
  uint32_t error;
761
 
  ulong length;
762
 
  MI_BLOCK_INFO block_info;
763
 
 
764
 
  flag=block_info.second_read=0;
765
 
  /*
766
 
     Check if we have enough room for the record.
767
 
     First we do simplified check to make usual case faster.
768
 
     Then we do more precise check for the space left.
769
 
     Though it still is not absolutely precise, as
770
 
     we always use MI_MAX_DYN_BLOCK_HEADER while it can be
771
 
     less in the most of the cases.
772
 
  */
773
 
 
774
 
  /*
775
 
    compare with just the reclength as we're going
776
 
    to get some space from the old replaced record
777
 
  */
778
 
  if (unlikely(info->s->base.max_data_file_length -
779
 
        info->state->data_file_length < reclength))
780
 
  {
781
 
    /*
782
 
       let's read the old record's block to find out the length of the
783
 
       old record
784
 
    */
785
 
    if ((error=_mi_get_block_info(&block_info,info->dfile,filepos))
786
 
        & (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR | BLOCK_FATAL_ERROR))
787
 
    {
788
 
      if (!(error & BLOCK_FATAL_ERROR))
789
 
        errno=HA_ERR_WRONG_IN_RECORD;
790
 
      goto err;
791
 
    }
792
 
 
793
 
    /*
794
 
      if new record isn't longer, we can go on safely
795
 
    */
796
 
    if (block_info.rec_len < reclength)
797
 
    {
798
 
      if (info->s->base.max_data_file_length - info->state->data_file_length +
799
 
          info->state->empty - info->state->del * MI_MAX_DYN_BLOCK_HEADER <
800
 
          reclength - block_info.rec_len + MI_MAX_DYN_BLOCK_HEADER)
801
 
      {
802
 
        errno=HA_ERR_RECORD_FILE_FULL;
803
 
        goto err;
804
 
      }
805
 
    }
806
 
    block_info.second_read=0;
807
 
  }
808
 
 
809
 
  while (reclength > 0)
810
 
  {
811
 
    if (filepos != info->s->state.dellink)
812
 
    {
813
 
      block_info.next_filepos= HA_OFFSET_ERROR;
814
 
      if ((error=_mi_get_block_info(&block_info,info->dfile,filepos))
815
 
          & (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR |
816
 
             BLOCK_FATAL_ERROR))
817
 
      {
818
 
        if (!(error & BLOCK_FATAL_ERROR))
819
 
          errno=HA_ERR_WRONG_IN_RECORD;
820
 
        goto err;
821
 
      }
822
 
      length=(ulong) (block_info.filepos-filepos) + block_info.block_len;
823
 
      if (length < reclength)
824
 
      {
825
 
        uint32_t tmp=MY_ALIGN(reclength - length + 3 +
826
 
                          test(reclength >= 65520L),MI_DYN_ALIGN_SIZE);
827
 
        /* Don't create a block bigger than MI_MAX_BLOCK_LENGTH */
828
 
        tmp= min(length+tmp, MI_MAX_BLOCK_LENGTH)-length;
829
 
        /* Check if we can extend this block */
830
 
        if (block_info.filepos + block_info.block_len ==
831
 
            info->state->data_file_length &&
832
 
            info->state->data_file_length <
833
 
            info->s->base.max_data_file_length-tmp)
834
 
        {
835
 
          /* extend file */
836
 
          if (info->nextpos == info->state->data_file_length)
837
 
            info->nextpos+= tmp;
838
 
          info->state->data_file_length+= tmp;
839
 
          info->update|= HA_STATE_WRITE_AT_END | HA_STATE_EXTEND_BLOCK;
840
 
          length+=tmp;
841
 
        }
842
 
        else if (length < MI_MAX_BLOCK_LENGTH - MI_MIN_BLOCK_LENGTH)
843
 
        {
844
 
          /*
845
 
            Check if next block is a deleted block
846
 
            Above we have MI_MIN_BLOCK_LENGTH to avoid the problem where
847
 
            the next block is so small it can't be splited which could
848
 
            casue problems
849
 
          */
850
 
 
851
 
          MI_BLOCK_INFO del_block;
852
 
          del_block.second_read=0;
853
 
          if (_mi_get_block_info(&del_block,info->dfile,
854
 
                                 block_info.filepos + block_info.block_len) &
855
 
              BLOCK_DELETED)
856
 
          {
857
 
            /* Use; Unlink it and extend the current block */
858
 
            if (unlink_deleted_block(info,&del_block))
859
 
              goto err;
860
 
            if ((length+=del_block.block_len) > MI_MAX_BLOCK_LENGTH)
861
 
            {
862
 
              /*
863
 
                New block was too big, link overflow part back to
864
 
                delete list
865
 
              */
866
 
              internal::my_off_t next_pos;
867
 
              ulong rest_length= length-MI_MAX_BLOCK_LENGTH;
868
 
              set_if_bigger(rest_length, (ulong)MI_MIN_BLOCK_LENGTH);
869
 
              next_pos= del_block.filepos+ del_block.block_len - rest_length;
870
 
 
871
 
              if (update_backward_delete_link(info, info->s->state.dellink,
872
 
                                              next_pos))
873
 
                return(1);
874
 
 
875
 
              /* create delete link for data that didn't fit into the page */
876
 
              del_block.header[0]=0;
877
 
              mi_int3store(del_block.header+1, rest_length);
878
 
              mi_sizestore(del_block.header+4,info->s->state.dellink);
879
 
              memset(del_block.header+12, 255, 8);
880
 
              if (info->s->file_write(info,(unsigned char*) del_block.header,20, next_pos,
881
 
                            MYF(MY_NABP)))
882
 
                return(1);
883
 
              info->s->state.dellink= next_pos;
884
 
              info->s->state.split++;
885
 
              info->state->del++;
886
 
              info->state->empty+= rest_length;
887
 
              length-= rest_length;
888
 
            }
889
 
          }
890
 
        }
891
 
      }
892
 
    }
893
 
    else
894
 
    {
895
 
      if (_mi_find_writepos(info,reclength,&filepos,&length))
896
 
        goto err;
897
 
    }
898
 
    if (_mi_write_part_record(info,filepos,length,block_info.next_filepos,
899
 
                              &record,&reclength,&flag))
900
 
      goto err;
901
 
    if ((filepos=block_info.next_filepos) == HA_OFFSET_ERROR)
902
 
    {
903
 
      /* Start writing data on deleted blocks */
904
 
      filepos=info->s->state.dellink;
905
 
    }
906
 
  }
907
 
 
908
 
  if (block_info.next_filepos != HA_OFFSET_ERROR)
909
 
    if (delete_dynamic_record(info,block_info.next_filepos,1))
910
 
      goto err;
911
 
  return(0);
912
 
err:
913
 
  return(1);
914
 
}
915
 
 
916
 
 
917
 
        /* Pack a record. Return new reclength */
918
 
 
919
 
uint32_t _mi_rec_pack(MI_INFO *info, register unsigned char *to,
920
 
                  register const unsigned char *from)
921
 
{
922
 
  uint          length,new_length,flag,bit,i;
923
 
  unsigned char         *pos,*end,*startpos,*packpos;
924
 
  enum en_fieldtype type;
925
 
  register MI_COLUMNDEF *rec;
926
 
  MI_BLOB       *blob;
927
 
 
928
 
  flag=0 ; bit=1;
929
 
  startpos=packpos=to; to+= info->s->base.pack_bits; blob=info->blobs;
930
 
  rec=info->s->rec;
931
 
 
932
 
  for (i=info->s->base.fields ; i-- > 0; from+= length,rec++)
933
 
  {
934
 
    length=(uint) rec->length;
935
 
    if ((type = (enum en_fieldtype) rec->type) != FIELD_NORMAL)
936
 
    {
937
 
      if (type == FIELD_BLOB)
938
 
      {
939
 
        if (!blob->length)
940
 
          flag|=bit;
941
 
        else
942
 
        {
943
 
          char *temp_pos;
944
 
          size_t tmp_length=length-portable_sizeof_char_ptr;
945
 
          memcpy(to,from,tmp_length);
946
 
          memcpy(&temp_pos,from+tmp_length,sizeof(char*));
947
 
          memcpy(to + tmp_length, temp_pos, blob->length);
948
 
          to+=tmp_length+blob->length;
949
 
        }
950
 
        blob++;
951
 
      }
952
 
      else if (type == FIELD_SKIP_ZERO)
953
 
      {
954
 
        if (memcmp(from,zero_string,length) == 0)
955
 
          flag|=bit;
956
 
        else
957
 
        {
958
 
          memcpy(to, from, length);
959
 
          to+=length;
960
 
        }
961
 
      }
962
 
      else if (type == FIELD_SKIP_ENDSPACE ||
963
 
               type == FIELD_SKIP_PRESPACE)
964
 
      {
965
 
        pos= (unsigned char*) from; end= (unsigned char*) from + length;
966
 
        if (type == FIELD_SKIP_ENDSPACE)
967
 
        {                                       /* Pack trailing spaces */
968
 
          while (end > from && *(end-1) == ' ')
969
 
            end--;
970
 
        }
971
 
        else
972
 
        {                                       /* Pack pref-spaces */
973
 
          while (pos < end && *pos == ' ')
974
 
            pos++;
975
 
        }
976
 
        new_length=(uint) (end-pos);
977
 
        if (new_length +1 + test(rec->length > 255 && new_length > 127)
978
 
            < length)
979
 
        {
980
 
          if (rec->length > 255 && new_length > 127)
981
 
          {
982
 
            to[0]= (unsigned char) ((new_length & 127) + 128);
983
 
            to[1]= (unsigned char) (new_length >> 7);
984
 
            to+=2;
985
 
          }
986
 
          else
987
 
            *to++= (unsigned char) new_length;
988
 
          memcpy(to, pos, new_length);
989
 
          to+=new_length;
990
 
          flag|=bit;
991
 
        }
992
 
        else
993
 
        {
994
 
          memcpy(to, from, length);
995
 
          to+=length;
996
 
        }
997
 
      }
998
 
      else if (type == FIELD_VARCHAR)
999
 
      {
1000
 
        uint32_t pack_length= ha_varchar_packlength(rec->length -1);
1001
 
        uint32_t tmp_length;
1002
 
        if (pack_length == 1)
1003
 
        {
1004
 
          tmp_length= (uint) *(unsigned char*) from;
1005
 
          *to++= *from;
1006
 
        }
1007
 
        else
1008
 
        {
1009
 
          tmp_length= uint2korr(from);
1010
 
          store_key_length_inc(to,tmp_length);
1011
 
        }
1012
 
        memcpy(to, from+pack_length, tmp_length);
1013
 
        to+= tmp_length;
1014
 
        continue;
1015
 
      }
1016
 
      else
1017
 
      {
1018
 
        memcpy(to, from, length);
1019
 
        to+=length;
1020
 
        continue;                               /* Normal field */
1021
 
      }
1022
 
      if ((bit= bit << 1) >= 256)
1023
 
      {
1024
 
        *packpos++= (unsigned char) flag;
1025
 
        bit=1; flag=0;
1026
 
      }
1027
 
    }
1028
 
    else
1029
 
    {
1030
 
      memcpy(to, from, length);
1031
 
      to+=length;
1032
 
    }
1033
 
  }
1034
 
  if (bit != 1)
1035
 
    *packpos= (unsigned char) flag;
1036
 
  if (info->s->calc_checksum)
1037
 
    *to++= (unsigned char) info->checksum;
1038
 
  return((uint) (to-startpos));
1039
 
} /* _mi_rec_pack */
1040
 
 
1041
 
 
1042
 
 
1043
 
/*
1044
 
  Check if a record was correctly packed. Used only by myisamchk
1045
 
  Returns 0 if record is ok.
1046
 
*/
1047
 
 
1048
 
bool _mi_rec_check(MI_INFO *info,const unsigned char *record, unsigned char *rec_buff,
1049
 
                      ulong packed_length, bool with_checksum)
1050
 
{
1051
 
  uint          length,new_length,flag,bit,i;
1052
 
  unsigned char         *pos,*end,*packpos,*to;
1053
 
  enum en_fieldtype type;
1054
 
  register MI_COLUMNDEF *rec;
1055
 
 
1056
 
  packpos=rec_buff; to= rec_buff+info->s->base.pack_bits;
1057
 
  rec=info->s->rec;
1058
 
  flag= *packpos; bit=1;
1059
 
 
1060
 
  for (i=info->s->base.fields ; i-- > 0; record+= length, rec++)
1061
 
  {
1062
 
    length=(uint) rec->length;
1063
 
    if ((type = (enum en_fieldtype) rec->type) != FIELD_NORMAL)
1064
 
    {
1065
 
      if (type == FIELD_BLOB)
1066
 
      {
1067
 
        uint32_t blob_length=
1068
 
          _mi_calc_blob_length(length-portable_sizeof_char_ptr,record);
1069
 
        if (!blob_length && !(flag & bit))
1070
 
          goto err;
1071
 
        if (blob_length)
1072
 
          to+=length - portable_sizeof_char_ptr+ blob_length;
1073
 
      }
1074
 
      else if (type == FIELD_SKIP_ZERO)
1075
 
      {
1076
 
        if (memcmp(record,zero_string,length) == 0)
1077
 
        {
1078
 
          if (!(flag & bit))
1079
 
            goto err;
1080
 
        }
1081
 
        else
1082
 
          to+=length;
1083
 
      }
1084
 
      else if (type == FIELD_SKIP_ENDSPACE ||
1085
 
               type == FIELD_SKIP_PRESPACE)
1086
 
      {
1087
 
        pos= (unsigned char*) record; end= (unsigned char*) record + length;
1088
 
        if (type == FIELD_SKIP_ENDSPACE)
1089
 
        {                                       /* Pack trailing spaces */
1090
 
          while (end > record && *(end-1) == ' ')
1091
 
            end--;
1092
 
        }
1093
 
        else
1094
 
        {                                       /* Pack pre-spaces */
1095
 
          while (pos < end && *pos == ' ')
1096
 
            pos++;
1097
 
        }
1098
 
        new_length=(uint) (end-pos);
1099
 
        if (new_length +1 + test(rec->length > 255 && new_length > 127)
1100
 
            < length)
1101
 
        {
1102
 
          if (!(flag & bit))
1103
 
            goto err;
1104
 
          if (rec->length > 255 && new_length > 127)
1105
 
          {
1106
 
            if (to[0] != (unsigned char) ((new_length & 127) + 128) ||
1107
 
                to[1] != (unsigned char) (new_length >> 7))
1108
 
              goto err;
1109
 
            to+=2;
1110
 
          }
1111
 
          else if (*to++ != (unsigned char) new_length)
1112
 
            goto err;
1113
 
          to+=new_length;
1114
 
        }
1115
 
        else
1116
 
          to+=length;
1117
 
      }
1118
 
      else if (type == FIELD_VARCHAR)
1119
 
      {
1120
 
        uint32_t pack_length= ha_varchar_packlength(rec->length -1);
1121
 
        uint32_t tmp_length;
1122
 
        if (pack_length == 1)
1123
 
        {
1124
 
          tmp_length= (uint) *(unsigned char*) record;
1125
 
          to+= 1+ tmp_length;
1126
 
          continue;
1127
 
        }
1128
 
        else
1129
 
        {
1130
 
          tmp_length= uint2korr(record);
1131
 
          to+= get_pack_length(tmp_length)+tmp_length;
1132
 
        }
1133
 
        continue;
1134
 
      }
1135
 
      else
1136
 
      {
1137
 
        to+=length;
1138
 
        continue;                               /* Normal field */
1139
 
      }
1140
 
      if ((bit= bit << 1) >= 256)
1141
 
      {
1142
 
        flag= *++packpos;
1143
 
        bit=1;
1144
 
      }
1145
 
    }
1146
 
    else
1147
 
      to+= length;
1148
 
  }
1149
 
  if (packed_length != (uint) (to - rec_buff) + test(info->s->calc_checksum) ||
1150
 
      (bit != 1 && (flag & ~(bit - 1))))
1151
 
    goto err;
1152
 
  if (with_checksum && ((unsigned char) info->checksum != (unsigned char) *to))
1153
 
  {
1154
 
    goto err;
1155
 
  }
1156
 
  return(0);
1157
 
 
1158
 
err:
1159
 
  return(1);
1160
 
}
1161
 
 
1162
 
 
1163
 
 
1164
 
        /* Unpacks a record */
1165
 
        /* Returns -1 and errno =HA_ERR_RECORD_DELETED if reclength isn't */
1166
 
        /* right. Returns reclength (>0) if ok */
1167
 
 
1168
 
ulong _mi_rec_unpack(register MI_INFO *info, register unsigned char *to, unsigned char *from,
1169
 
                     ulong found_length)
1170
 
{
1171
 
  uint32_t flag,bit,length,rec_length,min_pack_length;
1172
 
  enum en_fieldtype type;
1173
 
  unsigned char *from_end,*to_end,*packpos;
1174
 
  register MI_COLUMNDEF *rec,*end_field;
1175
 
 
1176
 
  to_end=to + info->s->base.reclength;
1177
 
  from_end=from+found_length;
1178
 
  flag= (unsigned char) *from; bit=1; packpos=from;
1179
 
  if (found_length < info->s->base.min_pack_length)
1180
 
    goto err;
1181
 
  from+= info->s->base.pack_bits;
1182
 
  min_pack_length=info->s->base.min_pack_length - info->s->base.pack_bits;
1183
 
 
1184
 
  for (rec=info->s->rec , end_field=rec+info->s->base.fields ;
1185
 
       rec < end_field ; to+= rec_length, rec++)
1186
 
  {
1187
 
    rec_length=rec->length;
1188
 
    if ((type = (enum en_fieldtype) rec->type) != FIELD_NORMAL &&
1189
 
        (type != FIELD_CHECK))
1190
 
    {
1191
 
      if (type == FIELD_VARCHAR)
1192
 
      {
1193
 
        uint32_t pack_length= ha_varchar_packlength(rec_length-1);
1194
 
        if (pack_length == 1)
1195
 
        {
1196
 
          length= (uint) *(unsigned char*) from;
1197
 
          if (length > rec_length-1)
1198
 
            goto err;
1199
 
          *to= *from++;
1200
 
        }
1201
 
        else
1202
 
        {
1203
 
          get_key_length(length, from);
1204
 
          if (length > rec_length-2)
1205
 
            goto err;
1206
 
          int2store(to,length);
1207
 
        }
1208
 
        if (from+length > from_end)
1209
 
          goto err;
1210
 
        memcpy(to+pack_length, from, length);
1211
 
        from+= length;
1212
 
        min_pack_length--;
1213
 
        continue;
1214
 
      }
1215
 
      if (flag & bit)
1216
 
      {
1217
 
        if (type == FIELD_BLOB || type == FIELD_SKIP_ZERO)
1218
 
          memset(to, 0, rec_length);
1219
 
        else if (type == FIELD_SKIP_ENDSPACE ||
1220
 
                 type == FIELD_SKIP_PRESPACE)
1221
 
        {
1222
 
          if (rec->length > 255 && *from & 128)
1223
 
          {
1224
 
            if (from + 1 >= from_end)
1225
 
              goto err;
1226
 
            length= (*from & 127)+ ((uint) (unsigned char) *(from+1) << 7); from+=2;
1227
 
          }
1228
 
          else
1229
 
          {
1230
 
            if (from == from_end)
1231
 
              goto err;
1232
 
            length= (unsigned char) *from++;
1233
 
          }
1234
 
          min_pack_length--;
1235
 
          if (length >= rec_length ||
1236
 
              min_pack_length + length > (uint) (from_end - from))
1237
 
            goto err;
1238
 
          if (type == FIELD_SKIP_ENDSPACE)
1239
 
          {
1240
 
            memcpy(to, from, length);
1241
 
            memset(to+length, ' ', rec_length-length);
1242
 
          }
1243
 
          else
1244
 
          {
1245
 
            memset(to, ' ', rec_length-length);
1246
 
            memcpy(to + rec_length - length, from, length);
1247
 
          }
1248
 
          from+=length;
1249
 
        }
1250
 
      }
1251
 
      else if (type == FIELD_BLOB)
1252
 
      {
1253
 
        uint32_t size_length=rec_length- portable_sizeof_char_ptr;
1254
 
        ulong blob_length=_mi_calc_blob_length(size_length,from);
1255
 
        ulong from_left= (ulong) (from_end - from);
1256
 
        if (from_left < size_length ||
1257
 
            from_left - size_length < blob_length ||
1258
 
            from_left - size_length - blob_length < min_pack_length)
1259
 
          goto err;
1260
 
        memcpy(to, from, size_length);
1261
 
        from+=size_length;
1262
 
        memcpy(to+size_length, &from, sizeof(char*));
1263
 
        from+=blob_length;
1264
 
      }
1265
 
      else
1266
 
      {
1267
 
        if (type == FIELD_SKIP_ENDSPACE || type == FIELD_SKIP_PRESPACE)
1268
 
          min_pack_length--;
1269
 
        if (min_pack_length + rec_length > (uint) (from_end - from))
1270
 
          goto err;
1271
 
        memcpy(to, from, rec_length);
1272
 
        from+=rec_length;
1273
 
      }
1274
 
      if ((bit= bit << 1) >= 256)
1275
 
      {
1276
 
        flag= (unsigned char) *++packpos; bit=1;
1277
 
      }
1278
 
    }
1279
 
    else
1280
 
    {
1281
 
      if (min_pack_length > (uint) (from_end - from))
1282
 
        goto err;
1283
 
      min_pack_length-=rec_length;
1284
 
      memcpy(to, from, rec_length);
1285
 
      from+=rec_length;
1286
 
    }
1287
 
  }
1288
 
  if (info->s->calc_checksum)
1289
 
    from++;
1290
 
  if (to == to_end && from == from_end && (bit == 1 || !(flag & ~(bit-1))))
1291
 
    return(found_length);
1292
 
 
1293
 
err:
1294
 
  errno= HA_ERR_WRONG_IN_RECORD;
1295
 
  return(MY_FILE_ERROR);
1296
 
} /* _mi_rec_unpack */
1297
 
 
1298
 
 
1299
 
        /* Calc length of blob. Update info in blobs->length */
1300
 
 
1301
 
ulong _my_calc_total_blob_length(MI_INFO *info, const unsigned char *record)
1302
 
{
1303
 
  ulong length;
1304
 
  MI_BLOB *blob,*end;
1305
 
 
1306
 
  for (length=0, blob= info->blobs, end=blob+info->s->base.blobs ;
1307
 
       blob != end;
1308
 
       blob++)
1309
 
  {
1310
 
    blob->length=_mi_calc_blob_length(blob->pack_length,record + blob->offset);
1311
 
    length+=blob->length;
1312
 
  }
1313
 
  return length;
1314
 
}
1315
 
 
1316
 
 
1317
 
ulong _mi_calc_blob_length(uint32_t length, const unsigned char *pos)
1318
 
{
1319
 
  switch (length) {
1320
 
  case 1:
1321
 
    return (uint) (unsigned char) *pos;
1322
 
  case 2:
1323
 
    return (uint) uint2korr(pos);
1324
 
  case 3:
1325
 
    return uint3korr(pos);
1326
 
  case 4:
1327
 
    return uint4korr(pos);
1328
 
  default:
1329
 
    break;
1330
 
  }
1331
 
  return 0; /* Impossible */
1332
 
}
1333
 
 
1334
 
 
1335
 
void _my_store_blob_length(unsigned char *pos,uint32_t pack_length,uint32_t length)
1336
 
{
1337
 
  switch (pack_length) {
1338
 
  case 1:
1339
 
    *pos= (unsigned char) length;
1340
 
    break;
1341
 
  case 2:
1342
 
    int2store(pos,length);
1343
 
    break;
1344
 
  case 3:
1345
 
    int3store(pos,length);
1346
 
    break;
1347
 
  case 4:
1348
 
    int4store(pos,length);
1349
 
  default:
1350
 
    break;
1351
 
  }
1352
 
  return;
1353
 
}
1354
 
 
1355
 
 
1356
 
/*
1357
 
  Read record from datafile.
1358
 
 
1359
 
  SYNOPSIS
1360
 
    _mi_read_dynamic_record()
1361
 
      info                      MI_INFO pointer to table.
1362
 
      filepos                   From where to read the record.
1363
 
      buf                       Destination for record.
1364
 
 
1365
 
  NOTE
1366
 
 
1367
 
    If a write buffer is active, it needs to be flushed if its contents
1368
 
    intersects with the record to read. We always check if the position
1369
 
    of the first byte of the write buffer is lower than the position
1370
 
    past the last byte to read. In theory this is also true if the write
1371
 
    buffer is completely below the read segment. That is, if there is no
1372
 
    intersection. But this case is unusual. We flush anyway. Only if the
1373
 
    first byte in the write buffer is above the last byte to read, we do
1374
 
    not flush.
1375
 
 
1376
 
    A dynamic record may need several reads. So this check must be done
1377
 
    before every read. Reading a dynamic record starts with reading the
1378
 
    block header. If the record does not fit into the free space of the
1379
 
    header, the block may be longer than the header. In this case a
1380
 
    second read is necessary. These one or two reads repeat for every
1381
 
    part of the record.
1382
 
 
1383
 
  RETURN
1384
 
    0           OK
1385
 
    -1          Error
1386
 
*/
1387
 
 
1388
 
int _mi_read_dynamic_record(MI_INFO *info, internal::my_off_t filepos, unsigned char *buf)
1389
 
{
1390
 
  int block_of_record;
1391
 
  uint32_t b_type, left_length= 0;
1392
 
  unsigned char *to= NULL;
1393
 
  MI_BLOCK_INFO block_info;
1394
 
  int file;
1395
 
 
1396
 
  if (filepos != HA_OFFSET_ERROR)
1397
 
  {
1398
 
    file=info->dfile;
1399
 
    block_of_record= 0;   /* First block of record is numbered as zero. */
1400
 
    block_info.second_read= 0;
1401
 
    do
1402
 
    {
1403
 
      /* A corrupted table can have wrong pointers. (Bug# 19835) */
1404
 
      if (filepos == HA_OFFSET_ERROR)
1405
 
        goto panic;
1406
 
      if (info->opt_flag & WRITE_CACHE_USED &&
1407
 
          info->rec_cache.pos_in_file < filepos + MI_BLOCK_INFO_HEADER_LENGTH &&
1408
 
          flush_io_cache(&info->rec_cache))
1409
 
        goto err;
1410
 
      info->rec_cache.seek_not_done=1;
1411
 
      if ((b_type= _mi_get_block_info(&block_info, file, filepos))
1412
 
          & (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR |
1413
 
             BLOCK_FATAL_ERROR))
1414
 
      {
1415
 
        if (b_type & (BLOCK_SYNC_ERROR | BLOCK_DELETED))
1416
 
          errno=HA_ERR_RECORD_DELETED;
1417
 
        goto err;
1418
 
      }
1419
 
      if (block_of_record++ == 0)                       /* First block */
1420
 
      {
1421
 
        if (block_info.rec_len > (uint) info->s->base.max_pack_length)
1422
 
          goto panic;
1423
 
        if (info->s->base.blobs)
1424
 
        {
1425
 
          if (!(to=mi_alloc_rec_buff(info, block_info.rec_len,
1426
 
                                     &info->rec_buff)))
1427
 
            goto err;
1428
 
        }
1429
 
        else
1430
 
          to= info->rec_buff;
1431
 
        left_length=block_info.rec_len;
1432
 
      }
1433
 
      if (left_length < block_info.data_len || ! block_info.data_len)
1434
 
        goto panic;                     /* Wrong linked record */
1435
 
      /* copy information that is already read */
1436
 
      {
1437
 
        uint32_t offset= (uint) (block_info.filepos - filepos);
1438
 
        uint32_t prefetch_len= (sizeof(block_info.header) - offset);
1439
 
        filepos+= sizeof(block_info.header);
1440
 
 
1441
 
        if (prefetch_len > block_info.data_len)
1442
 
          prefetch_len= block_info.data_len;
1443
 
        if (prefetch_len)
1444
 
        {
1445
 
          memcpy(to, block_info.header + offset, prefetch_len);
1446
 
          block_info.data_len-= prefetch_len;
1447
 
          left_length-= prefetch_len;
1448
 
          to+= prefetch_len;
1449
 
        }
1450
 
      }
1451
 
      /* read rest of record from file */
1452
 
      if (block_info.data_len)
1453
 
      {
1454
 
        if (info->opt_flag & WRITE_CACHE_USED &&
1455
 
            info->rec_cache.pos_in_file < filepos + block_info.data_len &&
1456
 
            flush_io_cache(&info->rec_cache))
1457
 
          goto err;
1458
 
        /*
1459
 
          What a pity that this method is not called 'file_pread' and that
1460
 
          there is no equivalent without seeking. We are at the right
1461
 
          position already. :(
1462
 
        */
1463
 
        if (info->s->file_read(info, (unsigned char*) to, block_info.data_len,
1464
 
                               filepos, MYF(MY_NABP)))
1465
 
          goto panic;
1466
 
        left_length-=block_info.data_len;
1467
 
        to+=block_info.data_len;
1468
 
      }
1469
 
      filepos= block_info.next_filepos;
1470
 
    } while (left_length);
1471
 
 
1472
 
    info->update|= HA_STATE_AKTIV;      /* We have a aktive record */
1473
 
    fast_mi_writeinfo(info);
1474
 
    return(_mi_rec_unpack(info,buf,info->rec_buff,block_info.rec_len) !=
1475
 
                MY_FILE_ERROR ? 0 : -1);
1476
 
  }
1477
 
  fast_mi_writeinfo(info);
1478
 
  return(-1);                   /* Wrong data to read */
1479
 
 
1480
 
panic:
1481
 
  errno=HA_ERR_WRONG_IN_RECORD;
1482
 
err:
1483
 
  _mi_writeinfo(info,0);
1484
 
  return(-1);
1485
 
}
1486
 
 
1487
 
        /* compare unique constraint between stored rows */
1488
 
 
1489
 
int _mi_cmp_dynamic_unique(MI_INFO *info, MI_UNIQUEDEF *def,
1490
 
                           const unsigned char *record, internal::my_off_t pos)
1491
 
{
1492
 
  unsigned char *rec_buff,*old_record;
1493
 
  int error;
1494
 
 
1495
 
  if (!(old_record=(unsigned char *)malloc(info->s->base.reclength)))
1496
 
    return(1);
1497
 
 
1498
 
  /* Don't let the compare destroy blobs that may be in use */
1499
 
  rec_buff=info->rec_buff;
1500
 
  if (info->s->base.blobs)
1501
 
    info->rec_buff=0;
1502
 
  error=_mi_read_dynamic_record(info,pos,old_record);
1503
 
  if (!error)
1504
 
    error=mi_unique_comp(def, record, old_record, def->null_are_equal);
1505
 
  if (info->s->base.blobs)
1506
 
  {
1507
 
    void * rec_buff_ptr= mi_get_rec_buff_ptr(info, info->rec_buff);
1508
 
    if (rec_buff_ptr != NULL)
1509
 
      free(rec_buff_ptr);
1510
 
    info->rec_buff=rec_buff;
1511
 
  }
1512
 
  free(old_record);
1513
 
  return(error);
1514
 
}
1515
 
 
1516
 
 
1517
 
        /* Compare of record one disk with packed record in memory */
1518
 
 
1519
 
int _mi_cmp_dynamic_record(register MI_INFO *info, register const unsigned char *record)
1520
 
{
1521
 
  uint32_t flag,reclength,b_type;
1522
 
  internal::my_off_t filepos;
1523
 
  unsigned char *buffer;
1524
 
  MI_BLOCK_INFO block_info;
1525
 
 
1526
 
  if (info->opt_flag & WRITE_CACHE_USED)
1527
 
  {
1528
 
    info->update&= ~(HA_STATE_WRITE_AT_END | HA_STATE_EXTEND_BLOCK);
1529
 
    if (flush_io_cache(&info->rec_cache))
1530
 
      return(-1);
1531
 
  }
1532
 
  info->rec_cache.seek_not_done=1;
1533
 
 
1534
 
        /* If nobody have touched the database we don't have to test rec */
1535
 
 
1536
 
  buffer=info->rec_buff;
1537
 
  if ((info->opt_flag & READ_CHECK_USED))
1538
 
  {                                             /* If check isn't disabled  */
1539
 
    if (info->s->base.blobs)
1540
 
    {
1541
 
      if (!(buffer=(unsigned char*) malloc(info->s->base.pack_reclength+
1542
 
                                     _my_calc_total_blob_length(info,record))))
1543
 
        return(-1);
1544
 
    }
1545
 
    reclength=_mi_rec_pack(info,buffer,record);
1546
 
    record= buffer;
1547
 
 
1548
 
    filepos=info->lastpos;
1549
 
    flag=block_info.second_read=0;
1550
 
    block_info.next_filepos=filepos;
1551
 
    while (reclength > 0)
1552
 
    {
1553
 
      if ((b_type=_mi_get_block_info(&block_info,info->dfile,
1554
 
                                    block_info.next_filepos))
1555
 
          & (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR |
1556
 
             BLOCK_FATAL_ERROR))
1557
 
      {
1558
 
        if (b_type & (BLOCK_SYNC_ERROR | BLOCK_DELETED))
1559
 
          errno=HA_ERR_RECORD_CHANGED;
1560
 
        goto err;
1561
 
      }
1562
 
      if (flag == 0)                            /* First block */
1563
 
      {
1564
 
        flag=1;
1565
 
        if (reclength != block_info.rec_len)
1566
 
        {
1567
 
          errno=HA_ERR_RECORD_CHANGED;
1568
 
          goto err;
1569
 
        }
1570
 
      } else if (reclength < block_info.data_len)
1571
 
      {
1572
 
        errno=HA_ERR_WRONG_IN_RECORD;
1573
 
        goto err;
1574
 
      }
1575
 
      reclength-=block_info.data_len;
1576
 
      if (_mi_cmp_buffer(info->dfile,record,block_info.filepos,
1577
 
                         block_info.data_len))
1578
 
      {
1579
 
        errno=HA_ERR_RECORD_CHANGED;
1580
 
        goto err;
1581
 
      }
1582
 
      flag=1;
1583
 
      record+=block_info.data_len;
1584
 
    }
1585
 
  }
1586
 
  errno=0;
1587
 
err:
1588
 
  if (buffer != info->rec_buff)
1589
 
    free((unsigned char*) buffer);
1590
 
  return(errno);
1591
 
}
1592
 
 
1593
 
 
1594
 
        /* Compare file to buffert */
1595
 
 
1596
 
static int _mi_cmp_buffer(int file, const unsigned char *buff, internal::my_off_t filepos,
1597
 
                          uint32_t length)
1598
 
{
1599
 
  uint32_t next_length;
1600
 
  unsigned char temp_buff[IO_SIZE*2];
1601
 
 
1602
 
  next_length= IO_SIZE*2 - (uint) (filepos & (IO_SIZE-1));
1603
 
 
1604
 
  while (length > IO_SIZE*2)
1605
 
  {
1606
 
    if (my_pread(file,temp_buff,next_length,filepos, MYF(MY_NABP)) ||
1607
 
        memcmp(buff, temp_buff, next_length))
1608
 
      goto err;
1609
 
    filepos+=next_length;
1610
 
    buff+=next_length;
1611
 
    length-= next_length;
1612
 
    next_length=IO_SIZE*2;
1613
 
  }
1614
 
  if (my_pread(file,temp_buff,length,filepos,MYF(MY_NABP)))
1615
 
    goto err;
1616
 
  return(memcmp(buff,temp_buff,length));
1617
 
err:
1618
 
  return(1);
1619
 
}
1620
 
 
1621
 
 
1622
 
/*
1623
 
  Read record from datafile.
1624
 
 
1625
 
  SYNOPSIS
1626
 
    _mi_read_rnd_dynamic_record()
1627
 
      info                      MI_INFO pointer to table.
1628
 
      buf                       Destination for record.
1629
 
      filepos                   From where to read the record.
1630
 
      skip_deleted_blocks       If to repeat reading until a non-deleted
1631
 
                                record is found.
1632
 
 
1633
 
  NOTE
1634
 
 
1635
 
    If a write buffer is active, it needs to be flushed if its contents
1636
 
    intersects with the record to read. We always check if the position
1637
 
    of the first byte of the write buffer is lower than the position
1638
 
    past the last byte to read. In theory this is also true if the write
1639
 
    buffer is completely below the read segment. That is, if there is no
1640
 
    intersection. But this case is unusual. We flush anyway. Only if the
1641
 
    first byte in the write buffer is above the last byte to read, we do
1642
 
    not flush.
1643
 
 
1644
 
    A dynamic record may need several reads. So this check must be done
1645
 
    before every read. Reading a dynamic record starts with reading the
1646
 
    block header. If the record does not fit into the free space of the
1647
 
    header, the block may be longer than the header. In this case a
1648
 
    second read is necessary. These one or two reads repeat for every
1649
 
    part of the record.
1650
 
 
1651
 
  RETURN
1652
 
    0           OK
1653
 
    != 0        Error
1654
 
*/
1655
 
 
1656
 
int _mi_read_rnd_dynamic_record(MI_INFO *info, unsigned char *buf,
1657
 
                                register internal::my_off_t filepos,
1658
 
                                bool skip_deleted_blocks)
1659
 
{
1660
 
  int block_of_record, info_read, save_errno;
1661
 
  uint32_t left_len,b_type;
1662
 
  unsigned char *to= NULL;
1663
 
  MI_BLOCK_INFO block_info;
1664
 
  MYISAM_SHARE *share=info->s;
1665
 
 
1666
 
  info_read=0;
1667
 
 
1668
 
  if (info->lock_type == F_UNLCK)
1669
 
  {
1670
 
    info->tmp_lock_type=F_RDLCK;
1671
 
  }
1672
 
  else
1673
 
    info_read=1;                                /* memory-keyinfoblock is ok */
1674
 
 
1675
 
  block_of_record= 0;   /* First block of record is numbered as zero. */
1676
 
  block_info.second_read= 0;
1677
 
  left_len=1;
1678
 
  do
1679
 
  {
1680
 
    if (filepos >= info->state->data_file_length)
1681
 
    {
1682
 
      if (!info_read)
1683
 
      {                                         /* Check if changed */
1684
 
        info_read=1;
1685
 
        info->rec_cache.seek_not_done=1;
1686
 
        if (mi_state_info_read_dsk(share->kfile,&share->state,1))
1687
 
          goto panic;
1688
 
      }
1689
 
      if (filepos >= info->state->data_file_length)
1690
 
      {
1691
 
        errno= HA_ERR_END_OF_FILE;
1692
 
        goto err;
1693
 
      }
1694
 
    }
1695
 
    if (info->opt_flag & READ_CACHE_USED)
1696
 
    {
1697
 
      if (_mi_read_cache(&info->rec_cache,(unsigned char*) block_info.header,filepos,
1698
 
                         sizeof(block_info.header),
1699
 
                         (!block_of_record && skip_deleted_blocks ?
1700
 
                          READING_NEXT : 0) | READING_HEADER))
1701
 
        goto panic;
1702
 
      b_type=_mi_get_block_info(&block_info,-1,filepos);
1703
 
    }
1704
 
    else
1705
 
    {
1706
 
      if (info->opt_flag & WRITE_CACHE_USED &&
1707
 
          info->rec_cache.pos_in_file < filepos + MI_BLOCK_INFO_HEADER_LENGTH &&
1708
 
          flush_io_cache(&info->rec_cache))
1709
 
        return(errno);
1710
 
      info->rec_cache.seek_not_done=1;
1711
 
      b_type=_mi_get_block_info(&block_info,info->dfile,filepos);
1712
 
    }
1713
 
 
1714
 
    if (b_type & (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR |
1715
 
                  BLOCK_FATAL_ERROR))
1716
 
    {
1717
 
      if ((b_type & (BLOCK_DELETED | BLOCK_SYNC_ERROR))
1718
 
          && skip_deleted_blocks)
1719
 
      {
1720
 
        filepos=block_info.filepos+block_info.block_len;
1721
 
        block_info.second_read=0;
1722
 
        continue;               /* Search after next_record */
1723
 
      }
1724
 
      if (b_type & (BLOCK_DELETED | BLOCK_SYNC_ERROR))
1725
 
      {
1726
 
        errno=HA_ERR_RECORD_DELETED;
1727
 
        info->lastpos=block_info.filepos;
1728
 
        info->nextpos=block_info.filepos+block_info.block_len;
1729
 
      }
1730
 
      goto err;
1731
 
    }
1732
 
    if (block_of_record == 0)                           /* First block */
1733
 
    {
1734
 
      if (block_info.rec_len > (uint) share->base.max_pack_length)
1735
 
        goto panic;
1736
 
      info->lastpos=filepos;
1737
 
      if (share->base.blobs)
1738
 
      {
1739
 
        if (!(to= mi_alloc_rec_buff(info, block_info.rec_len,
1740
 
                                    &info->rec_buff)))
1741
 
          goto err;
1742
 
      }
1743
 
      else
1744
 
        to= info->rec_buff;
1745
 
      left_len=block_info.rec_len;
1746
 
    }
1747
 
    if (left_len < block_info.data_len)
1748
 
      goto panic;                               /* Wrong linked record */
1749
 
 
1750
 
    /* copy information that is already read */
1751
 
    {
1752
 
      uint32_t offset=(uint) (block_info.filepos - filepos);
1753
 
      uint32_t tmp_length= (sizeof(block_info.header) - offset);
1754
 
      filepos=block_info.filepos;
1755
 
 
1756
 
      if (tmp_length > block_info.data_len)
1757
 
        tmp_length= block_info.data_len;
1758
 
      if (tmp_length)
1759
 
      {
1760
 
        memcpy(to, block_info.header+offset,tmp_length);
1761
 
        block_info.data_len-=tmp_length;
1762
 
        left_len-=tmp_length;
1763
 
        to+=tmp_length;
1764
 
        filepos+=tmp_length;
1765
 
      }
1766
 
    }
1767
 
    /* read rest of record from file */
1768
 
    if (block_info.data_len)
1769
 
    {
1770
 
      if (info->opt_flag & READ_CACHE_USED)
1771
 
      {
1772
 
        if (_mi_read_cache(&info->rec_cache,(unsigned char*) to,filepos,
1773
 
                           block_info.data_len,
1774
 
                           (!block_of_record && skip_deleted_blocks) ?
1775
 
                           READING_NEXT : 0))
1776
 
          goto panic;
1777
 
      }
1778
 
      else
1779
 
      {
1780
 
        if (info->opt_flag & WRITE_CACHE_USED &&
1781
 
            info->rec_cache.pos_in_file <
1782
 
            block_info.filepos + block_info.data_len &&
1783
 
            flush_io_cache(&info->rec_cache))
1784
 
          goto err;
1785
 
        /* lseek(info->dfile,filepos,SEEK_SET); */
1786
 
        if (internal::my_read(info->dfile,(unsigned char*) to,block_info.data_len,MYF(MY_NABP)))
1787
 
        {
1788
 
          if (errno == -1)
1789
 
            errno= HA_ERR_WRONG_IN_RECORD;      /* Unexpected end of file */
1790
 
          goto err;
1791
 
        }
1792
 
      }
1793
 
    }
1794
 
    /*
1795
 
      Increment block-of-record counter. If it was the first block,
1796
 
      remember the position behind the block for the next call.
1797
 
    */
1798
 
    if (block_of_record++ == 0)
1799
 
    {
1800
 
      info->nextpos= block_info.filepos + block_info.block_len;
1801
 
      skip_deleted_blocks= 0;
1802
 
    }
1803
 
    left_len-=block_info.data_len;
1804
 
    to+=block_info.data_len;
1805
 
    filepos=block_info.next_filepos;
1806
 
  } while (left_len);
1807
 
 
1808
 
  info->update|= HA_STATE_AKTIV | HA_STATE_KEY_CHANGED;
1809
 
  fast_mi_writeinfo(info);
1810
 
  if (_mi_rec_unpack(info,buf,info->rec_buff,block_info.rec_len) !=
1811
 
      MY_FILE_ERROR)
1812
 
    return(0);
1813
 
  return(errno);                        /* Wrong record */
1814
 
 
1815
 
panic:
1816
 
  errno=HA_ERR_WRONG_IN_RECORD;         /* Something is fatal wrong */
1817
 
err:
1818
 
  save_errno=errno;
1819
 
  _mi_writeinfo(info,0);
1820
 
  return(errno=save_errno);
1821
 
}
1822
 
 
1823
 
 
1824
 
        /* Read and process header from a dynamic-record-file */
1825
 
 
1826
 
uint32_t _mi_get_block_info(MI_BLOCK_INFO *info, int file, internal::my_off_t filepos)
1827
 
{
1828
 
  uint32_t return_val=0;
1829
 
  unsigned char *header=info->header;
1830
 
 
1831
 
  if (file >= 0)
1832
 
  {
1833
 
    /*
1834
 
      We do not use my_pread() here because we want to have the file
1835
 
      pointer set to the end of the header after this function.
1836
 
      my_pread() may leave the file pointer untouched.
1837
 
    */
1838
 
    lseek(file,filepos,SEEK_SET);
1839
 
    if (internal::my_read(file, header, sizeof(info->header),MYF(0)) !=
1840
 
        sizeof(info->header))
1841
 
      goto err;
1842
 
  }
1843
 
  if (info->second_read)
1844
 
  {
1845
 
    if (info->header[0] <= 6 || info->header[0] == 13)
1846
 
      return_val=BLOCK_SYNC_ERROR;
1847
 
  }
1848
 
  else
1849
 
  {
1850
 
    if (info->header[0] > 6 && info->header[0] != 13)
1851
 
      return_val=BLOCK_SYNC_ERROR;
1852
 
  }
1853
 
  info->next_filepos= HA_OFFSET_ERROR; /* Dummy if no next block */
1854
 
 
1855
 
  switch (info->header[0]) {
1856
 
  case 0:
1857
 
    if ((info->block_len=(uint) mi_uint3korr(header+1)) <
1858
 
        MI_MIN_BLOCK_LENGTH ||
1859
 
        (info->block_len & (MI_DYN_ALIGN_SIZE -1)))
1860
 
      goto err;
1861
 
    info->filepos=filepos;
1862
 
    info->next_filepos=mi_sizekorr(header+4);
1863
 
    info->prev_filepos=mi_sizekorr(header+12);
1864
 
#if SIZEOF_OFF_T == 4
1865
 
    if ((mi_uint4korr(header+4) != 0 &&
1866
 
         (mi_uint4korr(header+4) != UINT32_MAX ||
1867
 
          info->next_filepos != UINT32_MAX) ||
1868
 
        (mi_uint4korr(header+12) != 0 &&
1869
 
         (mi_uint4korr(header+12) != UINT32_MAX ||
1870
 
          info->prev_filepos != UINT32_MAX))
1871
 
      goto err;
1872
 
#endif
1873
 
    return return_val | BLOCK_DELETED;          /* Deleted block */
1874
 
 
1875
 
  case 1:
1876
 
    info->rec_len=info->data_len=info->block_len=mi_uint2korr(header+1);
1877
 
    info->filepos=filepos+3;
1878
 
    return return_val | BLOCK_FIRST | BLOCK_LAST;
1879
 
  case 2:
1880
 
    info->rec_len=info->data_len=info->block_len=mi_uint3korr(header+1);
1881
 
    info->filepos=filepos+4;
1882
 
    return return_val | BLOCK_FIRST | BLOCK_LAST;
1883
 
 
1884
 
  case 13:
1885
 
    info->rec_len=mi_uint4korr(header+1);
1886
 
    info->block_len=info->data_len=mi_uint3korr(header+5);
1887
 
    info->next_filepos=mi_sizekorr(header+8);
1888
 
    info->second_read=1;
1889
 
    info->filepos=filepos+16;
1890
 
    return return_val | BLOCK_FIRST;
1891
 
 
1892
 
  case 3:
1893
 
    info->rec_len=info->data_len=mi_uint2korr(header+1);
1894
 
    info->block_len=info->rec_len+ (uint) header[3];
1895
 
    info->filepos=filepos+4;
1896
 
    return return_val | BLOCK_FIRST | BLOCK_LAST;
1897
 
  case 4:
1898
 
    info->rec_len=info->data_len=mi_uint3korr(header+1);
1899
 
    info->block_len=info->rec_len+ (uint) header[4];
1900
 
    info->filepos=filepos+5;
1901
 
    return return_val | BLOCK_FIRST | BLOCK_LAST;
1902
 
 
1903
 
  case 5:
1904
 
    info->rec_len=mi_uint2korr(header+1);
1905
 
    info->block_len=info->data_len=mi_uint2korr(header+3);
1906
 
    info->next_filepos=mi_sizekorr(header+5);
1907
 
    info->second_read=1;
1908
 
    info->filepos=filepos+13;
1909
 
    return return_val | BLOCK_FIRST;
1910
 
  case 6:
1911
 
    info->rec_len=mi_uint3korr(header+1);
1912
 
    info->block_len=info->data_len=mi_uint3korr(header+4);
1913
 
    info->next_filepos=mi_sizekorr(header+7);
1914
 
    info->second_read=1;
1915
 
    info->filepos=filepos+15;
1916
 
    return return_val | BLOCK_FIRST;
1917
 
 
1918
 
    /* The following blocks are identical to 1-6 without rec_len */
1919
 
  case 7:
1920
 
    info->data_len=info->block_len=mi_uint2korr(header+1);
1921
 
    info->filepos=filepos+3;
1922
 
    return return_val | BLOCK_LAST;
1923
 
  case 8:
1924
 
    info->data_len=info->block_len=mi_uint3korr(header+1);
1925
 
    info->filepos=filepos+4;
1926
 
    return return_val | BLOCK_LAST;
1927
 
 
1928
 
  case 9:
1929
 
    info->data_len=mi_uint2korr(header+1);
1930
 
    info->block_len=info->data_len+ (uint) header[3];
1931
 
    info->filepos=filepos+4;
1932
 
    return return_val | BLOCK_LAST;
1933
 
  case 10:
1934
 
    info->data_len=mi_uint3korr(header+1);
1935
 
    info->block_len=info->data_len+ (uint) header[4];
1936
 
    info->filepos=filepos+5;
1937
 
    return return_val | BLOCK_LAST;
1938
 
 
1939
 
  case 11:
1940
 
    info->data_len=info->block_len=mi_uint2korr(header+1);
1941
 
    info->next_filepos=mi_sizekorr(header+3);
1942
 
    info->second_read=1;
1943
 
    info->filepos=filepos+11;
1944
 
    return return_val;
1945
 
  case 12:
1946
 
    info->data_len=info->block_len=mi_uint3korr(header+1);
1947
 
    info->next_filepos=mi_sizekorr(header+4);
1948
 
    info->second_read=1;
1949
 
    info->filepos=filepos+12;
1950
 
    return return_val;
1951
 
  }
1952
 
 
1953
 
err:
1954
 
  errno=HA_ERR_WRONG_IN_RECORD;  /* Garbage */
1955
 
  return BLOCK_ERROR;
1956
 
}