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