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