~drizzle-trunk/drizzle/development

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