Commit b152b147 authored by Michael Widenius's avatar Michael Widenius

Use _ma_set_fatal_error() in Aria also for HA_ERR_WRONG_IN_RECORD, to be able...

Use _ma_set_fatal_error() in Aria also for HA_ERR_WRONG_IN_RECORD, to be able to get an assert as soon as a failure is detected.
Fixed stack overrun failure when calling maria_chk_data_link().

storage/maria/ma_blockrec.c:
  Use _ma_set_fatal_error() for HA_ERR_WRONG_IN_RECORD
storage/maria/ma_cache.c:
  Use _ma_set_fatal_error() for HA_ERR_WRONG_IN_RECORD.
  Added argument to _ma_read_cache() to be able to call _ma_set_fatal_error()
storage/maria/ma_check.c:
  Use _ma_set_fatal_error() for HA_ERR_WRONG_IN_RECORD.
  Don't allocate data to print bitmap on stack.
  (This fixed stack overrun failure when calling maria_chk_data_link() when gcc had inlined a function)
  Added new parameter to _ma_read_cache() and _ma_get_block_info()
storage/maria/ma_dynrec.c:
  Use _ma_set_fatal_error() for HA_ERR_WRONG_IN_RECORD.
  Added argument to _ma_get_block_info() to be able to call _ma_set_fatal_error()
storage/maria/ma_locking.c:
  Added DBUG_PRINT
storage/maria/ma_packrec.c:
  Use _ma_set_fatal_error() for HA_ERR_WRONG_IN_RECORD
storage/maria/ma_statrec.c:
  Use _ma_set_fatal_error() for HA_ERR_WRONG_IN_RECORD
storage/maria/maria_def.h:
  Updated prototypes.
parent c49762ce
...@@ -891,8 +891,7 @@ static my_bool extend_area_on_page(MARIA_HA *info, ...@@ -891,8 +891,7 @@ static my_bool extend_area_on_page(MARIA_HA *info,
DBUG_PRINT("error", ("Not enough space: " DBUG_PRINT("error", ("Not enough space: "
"length: %u request_length: %u", "length: %u request_length: %u",
length, request_length)); length, request_length));
my_errno= HA_ERR_WRONG_IN_RECORD; /* File crashed */ _ma_set_fatal_error(info->s, HA_ERR_WRONG_IN_RECORD);
DBUG_ASSERT(0); /* For debugging */
DBUG_RETURN(1); /* Error in block */ DBUG_RETURN(1); /* Error in block */
} }
*empty_space= length; /* All space is here */ *empty_space= length; /* All space is here */
...@@ -1777,7 +1776,7 @@ static my_bool get_head_or_tail_page(MARIA_HA *info, ...@@ -1777,7 +1776,7 @@ static my_bool get_head_or_tail_page(MARIA_HA *info,
DBUG_RETURN(0); DBUG_RETURN(0);
crashed: crashed:
my_errno= HA_ERR_WRONG_IN_RECORD; /* File crashed */ _ma_set_fatal_error(share, HA_ERR_WRONG_IN_RECORD); /* File crashed */
DBUG_RETURN(1); DBUG_RETURN(1);
} }
...@@ -1870,7 +1869,7 @@ static my_bool get_rowpos_in_head_or_tail_page(MARIA_HA *info, ...@@ -1870,7 +1869,7 @@ static my_bool get_rowpos_in_head_or_tail_page(MARIA_HA *info,
DBUG_RETURN(0); DBUG_RETURN(0);
err: err:
my_errno= HA_ERR_WRONG_IN_RECORD; /* File crashed */ _ma_set_fatal_error(share, HA_ERR_WRONG_IN_RECORD); /* File crashed */
DBUG_RETURN(1); DBUG_RETURN(1);
} }
...@@ -2094,8 +2093,7 @@ static my_bool write_full_pages(MARIA_HA *info, ...@@ -2094,8 +2093,7 @@ static my_bool write_full_pages(MARIA_HA *info,
{ {
if (!--sub_blocks) if (!--sub_blocks)
{ {
DBUG_ASSERT(0); /* Wrong in bitmap or UNDO */ _ma_set_fatal_error(share, HA_ERR_WRONG_IN_RECORD);
my_errno= HA_ERR_WRONG_IN_RECORD; /* File crashed */
DBUG_RETURN(1); DBUG_RETURN(1);
} }
...@@ -3419,7 +3417,7 @@ static my_bool write_block_record(MARIA_HA *info, ...@@ -3419,7 +3417,7 @@ static my_bool write_block_record(MARIA_HA *info,
crashed: crashed:
/* Something was wrong with data on page */ /* Something was wrong with data on page */
my_errno= HA_ERR_WRONG_IN_RECORD; _ma_set_fatal_error(share, HA_ERR_WRONG_IN_RECORD);
disk_err: disk_err:
/** /**
...@@ -3891,7 +3889,7 @@ static my_bool _ma_update_at_original_place(MARIA_HA *info, ...@@ -3891,7 +3889,7 @@ static my_bool _ma_update_at_original_place(MARIA_HA *info,
("org_empty_size: %u head_length: %u length_on_page: %u", ("org_empty_size: %u head_length: %u length_on_page: %u",
org_empty_size, (uint) cur_row->head_length, org_empty_size, (uint) cur_row->head_length,
length_on_head_page)); length_on_head_page));
my_errno= HA_ERR_WRONG_IN_RECORD; _ma_set_fatal_error(share, HA_ERR_WRONG_IN_RECORD);
goto err; goto err;
} }
...@@ -4523,7 +4521,7 @@ static uchar *read_next_extent(MARIA_HA *info, MARIA_EXTENT_CURSOR *extent, ...@@ -4523,7 +4521,7 @@ static uchar *read_next_extent(MARIA_HA *info, MARIA_EXTENT_CURSOR *extent,
crashed: crashed:
my_errno= HA_ERR_WRONG_IN_RECORD; /* File crashed */ _ma_set_fatal_error(share, HA_ERR_WRONG_IN_RECORD);
DBUG_PRINT("error", ("wrong extent information")); DBUG_PRINT("error", ("wrong extent information"));
DBUG_RETURN(0); DBUG_RETURN(0);
} }
...@@ -4668,7 +4666,11 @@ int _ma_read_block_record2(MARIA_HA *info, uchar *record, ...@@ -4668,7 +4666,11 @@ int _ma_read_block_record2(MARIA_HA *info, uchar *record,
{ {
cur_row->trid= transid_korr(data+1); cur_row->trid= transid_korr(data+1);
if (!info->trn) if (!info->trn)
DBUG_RETURN(my_errno= HA_ERR_WRONG_IN_RECORD); /* File crashed */ {
/* File crashed */
_ma_set_fatal_error(share, HA_ERR_WRONG_IN_RECORD);
DBUG_RETURN(HA_ERR_WRONG_IN_RECORD);
}
if (!trnman_can_read_from(info->trn, cur_row->trid)) if (!trnman_can_read_from(info->trn, cur_row->trid))
DBUG_RETURN(my_errno= HA_ERR_ROW_NOT_VISIBLE); DBUG_RETURN(my_errno= HA_ERR_ROW_NOT_VISIBLE);
} }
...@@ -4949,7 +4951,8 @@ int _ma_read_block_record2(MARIA_HA *info, uchar *record, ...@@ -4949,7 +4951,8 @@ int _ma_read_block_record2(MARIA_HA *info, uchar *record,
err: err:
/* Something was wrong with data on record */ /* Something was wrong with data on record */
DBUG_PRINT("error", ("Found record with wrong data")); DBUG_PRINT("error", ("Found record with wrong data"));
DBUG_RETURN((my_errno= HA_ERR_WRONG_IN_RECORD)); _ma_set_fatal_error(share, HA_ERR_WRONG_IN_RECORD);
DBUG_RETURN(HA_ERR_WRONG_IN_RECORD);
} }
...@@ -5399,7 +5402,8 @@ int _ma_scan_block_record(MARIA_HA *info, uchar *record, ...@@ -5399,7 +5402,8 @@ int _ma_scan_block_record(MARIA_HA *info, uchar *record,
(uint) (uchar) info->scan.page_buff[DIR_COUNT_OFFSET]) == 0) (uint) (uchar) info->scan.page_buff[DIR_COUNT_OFFSET]) == 0)
{ {
DBUG_PRINT("error", ("Wrong page header")); DBUG_PRINT("error", ("Wrong page header"));
DBUG_RETURN((my_errno= HA_ERR_WRONG_IN_RECORD)); _ma_set_fatal_error(share, HA_ERR_WRONG_IN_RECORD);
DBUG_RETURN(HA_ERR_WRONG_IN_RECORD);
} }
DBUG_PRINT("info", ("Page %lu has %u rows", DBUG_PRINT("info", ("Page %lu has %u rows",
(ulong) page, info->scan.number_of_rows)); (ulong) page, info->scan.number_of_rows));
...@@ -5445,7 +5449,8 @@ int _ma_scan_block_record(MARIA_HA *info, uchar *record, ...@@ -5445,7 +5449,8 @@ int _ma_scan_block_record(MARIA_HA *info, uchar *record,
err: err:
DBUG_PRINT("error", ("Wrong data on page")); DBUG_PRINT("error", ("Wrong data on page"));
DBUG_RETURN((my_errno= HA_ERR_WRONG_IN_RECORD)); _ma_set_fatal_error(share, HA_ERR_WRONG_IN_RECORD);
DBUG_RETURN(HA_ERR_WRONG_IN_RECORD);
} }
...@@ -6365,7 +6370,7 @@ uint _ma_apply_redo_insert_row_head_or_tail(MARIA_HA *info, LSN lsn, ...@@ -6365,7 +6370,7 @@ uint _ma_apply_redo_insert_row_head_or_tail(MARIA_HA *info, LSN lsn,
DBUG_RETURN(result); DBUG_RETURN(result);
crashed_file: crashed_file:
my_errno= HA_ERR_WRONG_IN_RECORD; _ma_set_fatal_error(share, HA_ERR_WRONG_IN_RECORD);
err: err:
error= my_errno; error= my_errno;
if (unlock_method == PAGECACHE_LOCK_LEFT_WRITELOCKED) if (unlock_method == PAGECACHE_LOCK_LEFT_WRITELOCKED)
...@@ -6453,7 +6458,7 @@ uint _ma_apply_redo_purge_row_head_or_tail(MARIA_HA *info, LSN lsn, ...@@ -6453,7 +6458,7 @@ uint _ma_apply_redo_purge_row_head_or_tail(MARIA_HA *info, LSN lsn,
if (delete_dir_entry(buff, block_size, rownr, &empty_space) < 0) if (delete_dir_entry(buff, block_size, rownr, &empty_space) < 0)
{ {
my_errno= HA_ERR_WRONG_IN_RECORD; _ma_set_fatal_error(share, HA_ERR_WRONG_IN_RECORD);
goto err; goto err;
} }
......
...@@ -35,8 +35,8 @@ ...@@ -35,8 +35,8 @@
#include "maria_def.h" #include "maria_def.h"
my_bool _ma_read_cache(IO_CACHE *info, uchar *buff, my_off_t pos, my_bool _ma_read_cache(MARIA_HA *handler, IO_CACHE *info, uchar *buff,
size_t length, uint flag) my_off_t pos, size_t length, uint flag)
{ {
size_t read_length,in_buff_length; size_t read_length,in_buff_length;
my_off_t offset; my_off_t offset;
...@@ -98,7 +98,7 @@ my_bool _ma_read_cache(IO_CACHE *info, uchar *buff, my_off_t pos, ...@@ -98,7 +98,7 @@ my_bool _ma_read_cache(IO_CACHE *info, uchar *buff, my_off_t pos,
("Error %d reading next-multi-part block (Got %d bytes)", ("Error %d reading next-multi-part block (Got %d bytes)",
my_errno, (int) read_length)); my_errno, (int) read_length));
if (!my_errno || my_errno == HA_ERR_FILE_TOO_SHORT) if (!my_errno || my_errno == HA_ERR_FILE_TOO_SHORT)
my_errno= HA_ERR_WRONG_IN_RECORD; _ma_set_fatal_error(handler->s, HA_ERR_WRONG_IN_RECORD);
DBUG_RETURN(1); DBUG_RETURN(1);
} }
bzero(buff+read_length,MARIA_BLOCK_INFO_HEADER_LENGTH - in_buff_length - bzero(buff+read_length,MARIA_BLOCK_INFO_HEADER_LENGTH - in_buff_length -
......
...@@ -1247,7 +1247,7 @@ static int check_dynamic_record(HA_CHECK *param, MARIA_HA *info, int extend, ...@@ -1247,7 +1247,7 @@ static int check_dynamic_record(HA_CHECK *param, MARIA_HA *info, int extend,
block_info.next_filepos=pos; block_info.next_filepos=pos;
do do
{ {
if (_ma_read_cache(&param->read_cache, block_info.header, if (_ma_read_cache(info, &param->read_cache, block_info.header,
(start_block=block_info.next_filepos), (start_block=block_info.next_filepos),
sizeof(block_info.header), sizeof(block_info.header),
(flag ? 0 : READING_NEXT) | READING_HEADER)) (flag ? 0 : READING_NEXT) | READING_HEADER))
...@@ -1265,7 +1265,7 @@ static int check_dynamic_record(HA_CHECK *param, MARIA_HA *info, int extend, ...@@ -1265,7 +1265,7 @@ static int check_dynamic_record(HA_CHECK *param, MARIA_HA *info, int extend,
llstr(start_block,llbuff)); llstr(start_block,llbuff));
DBUG_RETURN(1); DBUG_RETURN(1);
} }
b_type= _ma_get_block_info(&block_info,-1,start_block); b_type= _ma_get_block_info(info, &block_info,-1,start_block);
if (b_type & (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR | if (b_type & (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR |
BLOCK_FATAL_ERROR)) BLOCK_FATAL_ERROR))
{ {
...@@ -1361,7 +1361,7 @@ static int check_dynamic_record(HA_CHECK *param, MARIA_HA *info, int extend, ...@@ -1361,7 +1361,7 @@ static int check_dynamic_record(HA_CHECK *param, MARIA_HA *info, int extend,
got_error=1; got_error=1;
break; break;
} }
if (_ma_read_cache(&param->read_cache, to, block_info.filepos, if (_ma_read_cache(info, &param->read_cache, to, block_info.filepos,
(uint) block_info.data_len, (uint) block_info.data_len,
flag == 1 ? READING_NEXT : 0)) flag == 1 ? READING_NEXT : 0))
{ {
...@@ -1464,7 +1464,7 @@ static int check_compressed_record(HA_CHECK *param, MARIA_HA *info, int extend, ...@@ -1464,7 +1464,7 @@ static int check_compressed_record(HA_CHECK *param, MARIA_HA *info, int extend,
if (_ma_killed_ptr(param)) if (_ma_killed_ptr(param))
DBUG_RETURN(-1); DBUG_RETURN(-1);
if (_ma_read_cache(&param->read_cache, block_info.header, pos, if (_ma_read_cache(info, &param->read_cache, block_info.header, pos,
share->pack.ref_length, READING_NEXT)) share->pack.ref_length, READING_NEXT))
{ {
_ma_check_print_error(param, _ma_check_print_error(param,
...@@ -1489,7 +1489,7 @@ static int check_compressed_record(HA_CHECK *param, MARIA_HA *info, int extend, ...@@ -1489,7 +1489,7 @@ static int check_compressed_record(HA_CHECK *param, MARIA_HA *info, int extend,
got_error=1; got_error=1;
goto end; goto end;
} }
if (_ma_read_cache(&param->read_cache, info->rec_buff, if (_ma_read_cache(info, &param->read_cache, info->rec_buff,
block_info.filepos, block_info.rec_len, READING_NEXT)) block_info.filepos, block_info.rec_len, READING_NEXT))
{ {
_ma_check_print_error(param, _ma_check_print_error(param,
...@@ -4850,7 +4850,7 @@ static int sort_get_next_record(MARIA_SORT_PARAM *sort_param) ...@@ -4850,7 +4850,7 @@ static int sort_get_next_record(MARIA_SORT_PARAM *sort_param)
_ma_check_print_info(param,"Block: %s used by record at %s", _ma_check_print_info(param,"Block: %s used by record at %s",
llstr(param->search_after_block,llbuff), llstr(param->search_after_block,llbuff),
llstr(sort_param->start_recpos,llbuff2)); llstr(sort_param->start_recpos,llbuff2));
if (_ma_read_cache(&sort_param->read_cache, if (_ma_read_cache(info, &sort_param->read_cache,
block_info.header, pos, block_info.header, pos,
MARIA_BLOCK_INFO_HEADER_LENGTH, MARIA_BLOCK_INFO_HEADER_LENGTH,
(! found_record ? READING_NEXT : 0) | (! found_record ? READING_NEXT : 0) |
...@@ -4872,7 +4872,7 @@ static int sort_get_next_record(MARIA_SORT_PARAM *sort_param) ...@@ -4872,7 +4872,7 @@ static int sort_get_next_record(MARIA_SORT_PARAM *sort_param)
param->testflag|=T_RETRY_WITHOUT_QUICK; param->testflag|=T_RETRY_WITHOUT_QUICK;
DBUG_RETURN(1); /* Something wrong with data */ DBUG_RETURN(1); /* Something wrong with data */
} }
b_type= _ma_get_block_info(&block_info,-1,pos); b_type= _ma_get_block_info(info, &block_info,-1,pos);
if ((b_type & (BLOCK_ERROR | BLOCK_FATAL_ERROR)) || if ((b_type & (BLOCK_ERROR | BLOCK_FATAL_ERROR)) ||
((b_type & BLOCK_FIRST) && ((b_type & BLOCK_FIRST) &&
(block_info.rec_len < (uint) share->base.min_pack_length || (block_info.rec_len < (uint) share->base.min_pack_length ||
...@@ -5063,7 +5063,7 @@ static int sort_get_next_record(MARIA_SORT_PARAM *sort_param) ...@@ -5063,7 +5063,7 @@ static int sort_get_next_record(MARIA_SORT_PARAM *sort_param)
} }
} }
if (block_info.data_len && if (block_info.data_len &&
_ma_read_cache(&sort_param->read_cache,to,block_info.filepos, _ma_read_cache(info, &sort_param->read_cache,to,block_info.filepos,
block_info.data_len, block_info.data_len,
(found_record == 1 ? READING_NEXT : 0) | (found_record == 1 ? READING_NEXT : 0) |
parallel_flag)) parallel_flag))
...@@ -5133,7 +5133,7 @@ static int sort_get_next_record(MARIA_SORT_PARAM *sort_param) ...@@ -5133,7 +5133,7 @@ static int sort_get_next_record(MARIA_SORT_PARAM *sort_param)
case COMPRESSED_RECORD: case COMPRESSED_RECORD:
for (searching=0 ;; searching=1, sort_param->pos++) for (searching=0 ;; searching=1, sort_param->pos++)
{ {
if (_ma_read_cache(&sort_param->read_cache, block_info.header, if (_ma_read_cache(info, &sort_param->read_cache, block_info.header,
sort_param->pos, sort_param->pos,
share->pack.ref_length,READING_NEXT)) share->pack.ref_length,READING_NEXT))
DBUG_RETURN(-1); DBUG_RETURN(-1);
...@@ -5165,7 +5165,7 @@ static int sort_get_next_record(MARIA_SORT_PARAM *sort_param) ...@@ -5165,7 +5165,7 @@ static int sort_get_next_record(MARIA_SORT_PARAM *sort_param)
llstr(sort_param->pos,llbuff)); llstr(sort_param->pos,llbuff));
continue; continue;
} }
if (_ma_read_cache(&sort_param->read_cache, sort_param->rec_buff, if (_ma_read_cache(info, &sort_param->read_cache, sort_param->rec_buff,
block_info.filepos, block_info.rec_len, block_info.filepos, block_info.rec_len,
READING_NEXT)) READING_NEXT))
{ {
...@@ -6830,7 +6830,10 @@ static void print_bitmap_description(MARIA_SHARE *share, ...@@ -6830,7 +6830,10 @@ static void print_bitmap_description(MARIA_SHARE *share,
pgcache_page_no_t page, pgcache_page_no_t page,
uchar *bitmap_data) uchar *bitmap_data)
{ {
char tmp[MAX_BITMAP_INFO_LENGTH]; char *tmp= my_malloc(MAX_BITMAP_INFO_LENGTH, MYF(MY_WME));
if (!tmp)
return;
_ma_get_bitmap_description(&share->bitmap, bitmap_data, page, tmp); _ma_get_bitmap_description(&share->bitmap, bitmap_data, page, tmp);
printf("Bitmap page %lu\n%s", (ulong) page, tmp); printf("Bitmap page %lu\n%s", (ulong) page, tmp);
my_free(tmp, MYF(0));
} }
...@@ -391,12 +391,12 @@ static int _ma_find_writepos(MARIA_HA *info, ...@@ -391,12 +391,12 @@ static int _ma_find_writepos(MARIA_HA *info,
*filepos=info->s->state.dellink; *filepos=info->s->state.dellink;
block_info.second_read=0; block_info.second_read=0;
info->rec_cache.seek_not_done=1; info->rec_cache.seek_not_done=1;
if (!(_ma_get_block_info(&block_info, info->dfile.file, if (!(_ma_get_block_info(info, &block_info, info->dfile.file,
info->s->state.dellink) & info->s->state.dellink) &
BLOCK_DELETED)) BLOCK_DELETED))
{ {
DBUG_PRINT("error",("Delete link crashed")); DBUG_PRINT("error",("Delete link crashed"));
my_errno=HA_ERR_WRONG_IN_RECORD; _ma_set_fatal_error(info->s, HA_ERR_WRONG_IN_RECORD);
DBUG_RETURN(-1); DBUG_RETURN(-1);
} }
info->s->state.dellink=block_info.next_filepos; info->s->state.dellink=block_info.next_filepos;
...@@ -452,7 +452,8 @@ static my_bool unlink_deleted_block(MARIA_HA *info, ...@@ -452,7 +452,8 @@ static my_bool unlink_deleted_block(MARIA_HA *info,
MARIA_BLOCK_INFO tmp; MARIA_BLOCK_INFO tmp;
tmp.second_read=0; tmp.second_read=0;
/* Unlink block from the previous block */ /* Unlink block from the previous block */
if (!(_ma_get_block_info(&tmp, info->dfile.file, block_info->prev_filepos) if (!(_ma_get_block_info(info, &tmp, info->dfile.file,
block_info->prev_filepos)
& BLOCK_DELETED)) & BLOCK_DELETED))
DBUG_RETURN(1); /* Something is wrong */ DBUG_RETURN(1); /* Something is wrong */
mi_sizestore(tmp.header+4,block_info->next_filepos); mi_sizestore(tmp.header+4,block_info->next_filepos);
...@@ -462,7 +463,7 @@ static my_bool unlink_deleted_block(MARIA_HA *info, ...@@ -462,7 +463,7 @@ static my_bool unlink_deleted_block(MARIA_HA *info,
/* Unlink block from next block */ /* Unlink block from next block */
if (block_info->next_filepos != HA_OFFSET_ERROR) if (block_info->next_filepos != HA_OFFSET_ERROR)
{ {
if (!(_ma_get_block_info(&tmp, info->dfile.file, if (!(_ma_get_block_info(info, &tmp, info->dfile.file,
block_info->next_filepos) block_info->next_filepos)
& BLOCK_DELETED)) & BLOCK_DELETED))
DBUG_RETURN(1); /* Something is wrong */ DBUG_RETURN(1); /* Something is wrong */
...@@ -514,7 +515,7 @@ static my_bool update_backward_delete_link(MARIA_HA *info, ...@@ -514,7 +515,7 @@ static my_bool update_backward_delete_link(MARIA_HA *info,
if (delete_block != HA_OFFSET_ERROR) if (delete_block != HA_OFFSET_ERROR)
{ {
block_info.second_read=0; block_info.second_read=0;
if (_ma_get_block_info(&block_info, info->dfile.file, delete_block) if (_ma_get_block_info(info, &block_info, info->dfile.file, delete_block)
& BLOCK_DELETED) & BLOCK_DELETED)
{ {
uchar buff[8]; uchar buff[8];
...@@ -524,7 +525,7 @@ static my_bool update_backward_delete_link(MARIA_HA *info, ...@@ -524,7 +525,7 @@ static my_bool update_backward_delete_link(MARIA_HA *info,
} }
else else
{ {
my_errno=HA_ERR_WRONG_IN_RECORD; _ma_set_fatal_error(info->s, HA_ERR_WRONG_IN_RECORD);
DBUG_RETURN(1); /* Wrong delete link */ DBUG_RETURN(1); /* Wrong delete link */
} }
} }
...@@ -550,19 +551,21 @@ static my_bool delete_dynamic_record(MARIA_HA *info, MARIA_RECORD_POS filepos, ...@@ -550,19 +551,21 @@ static my_bool delete_dynamic_record(MARIA_HA *info, MARIA_RECORD_POS filepos,
do do
{ {
/* Remove block at 'filepos' */ /* Remove block at 'filepos' */
if ((b_type= _ma_get_block_info(&block_info, info->dfile.file, filepos)) if ((b_type= _ma_get_block_info(info, &block_info, info->dfile.file,
filepos))
& (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR | & (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR |
BLOCK_FATAL_ERROR) || BLOCK_FATAL_ERROR) ||
(length=(uint) (block_info.filepos-filepos) +block_info.block_len) < (length=(uint) (block_info.filepos-filepos) +block_info.block_len) <
MARIA_MIN_BLOCK_LENGTH) MARIA_MIN_BLOCK_LENGTH)
{ {
my_errno=HA_ERR_WRONG_IN_RECORD; _ma_set_fatal_error(info->s, HA_ERR_WRONG_IN_RECORD);
DBUG_RETURN(1); DBUG_RETURN(1);
} }
/* Check if next block is a delete block */ /* Check if next block is a delete block */
del_block.second_read=0; del_block.second_read=0;
remove_next_block=0; remove_next_block=0;
if (_ma_get_block_info(&del_block, info->dfile.file, filepos + length) & if (_ma_get_block_info(info, &del_block, info->dfile.file,
filepos + length) &
BLOCK_DELETED && del_block.block_len+length < BLOCK_DELETED && del_block.block_len+length <
MARIA_DYN_MAX_BLOCK_LENGTH) MARIA_DYN_MAX_BLOCK_LENGTH)
{ {
...@@ -722,7 +725,7 @@ int _ma_write_part_record(MARIA_HA *info, ...@@ -722,7 +725,7 @@ int _ma_write_part_record(MARIA_HA *info,
if (next_block < info->state->data_file_length && if (next_block < info->state->data_file_length &&
info->s->state.dellink != HA_OFFSET_ERROR) info->s->state.dellink != HA_OFFSET_ERROR)
{ {
if ((_ma_get_block_info(&del_block, info->dfile.file, next_block) if ((_ma_get_block_info(info, &del_block, info->dfile.file, next_block)
& BLOCK_DELETED) && & BLOCK_DELETED) &&
res_length + del_block.block_len < MARIA_DYN_MAX_BLOCK_LENGTH) res_length + del_block.block_len < MARIA_DYN_MAX_BLOCK_LENGTH)
{ {
...@@ -834,13 +837,14 @@ static my_bool update_dynamic_record(MARIA_HA *info, MARIA_RECORD_POS filepos, ...@@ -834,13 +837,14 @@ static my_bool update_dynamic_record(MARIA_HA *info, MARIA_RECORD_POS filepos,
if (filepos != info->s->state.dellink) if (filepos != info->s->state.dellink)
{ {
block_info.next_filepos= HA_OFFSET_ERROR; block_info.next_filepos= HA_OFFSET_ERROR;
if ((error= _ma_get_block_info(&block_info, info->dfile.file, filepos)) if ((error= _ma_get_block_info(info, &block_info, info->dfile.file,
filepos))
& (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR | & (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR |
BLOCK_FATAL_ERROR)) BLOCK_FATAL_ERROR))
{ {
DBUG_PRINT("error",("Got wrong block info")); DBUG_PRINT("error",("Got wrong block info"));
if (!(error & BLOCK_FATAL_ERROR)) if (!(error & BLOCK_FATAL_ERROR))
my_errno=HA_ERR_WRONG_IN_RECORD; _ma_set_fatal_error(info->s, HA_ERR_WRONG_IN_RECORD);
goto err; goto err;
} }
length=(ulong) (block_info.filepos-filepos) + block_info.block_len; length=(ulong) (block_info.filepos-filepos) + block_info.block_len;
...@@ -875,7 +879,7 @@ static my_bool update_dynamic_record(MARIA_HA *info, MARIA_RECORD_POS filepos, ...@@ -875,7 +879,7 @@ static my_bool update_dynamic_record(MARIA_HA *info, MARIA_RECORD_POS filepos,
MARIA_BLOCK_INFO del_block; MARIA_BLOCK_INFO del_block;
del_block.second_read=0; del_block.second_read=0;
if (_ma_get_block_info(&del_block, info->dfile.file, if (_ma_get_block_info(info, &del_block, info->dfile.file,
block_info.filepos + block_info.block_len) & block_info.filepos + block_info.block_len) &
BLOCK_DELETED) BLOCK_DELETED)
{ {
...@@ -1346,7 +1350,7 @@ ulong _ma_rec_unpack(register MARIA_HA *info, register uchar *to, uchar *from, ...@@ -1346,7 +1350,7 @@ ulong _ma_rec_unpack(register MARIA_HA *info, register uchar *to, uchar *from,
DBUG_RETURN(found_length); DBUG_RETURN(found_length);
err: err:
my_errno= HA_ERR_WRONG_IN_RECORD; _ma_set_fatal_error(info->s, HA_ERR_WRONG_IN_RECORD);
DBUG_PRINT("error",("to_end: 0x%lx -> 0x%lx from_end: 0x%lx -> 0x%lx", DBUG_PRINT("error",("to_end: 0x%lx -> 0x%lx from_end: 0x%lx -> 0x%lx",
(long) to, (long) to_end, (long) from, (long) from_end)); (long) to, (long) to_end, (long) from, (long) from_end));
DBUG_DUMP("from", info->rec_buff, info->s->base.min_pack_length); DBUG_DUMP("from", info->rec_buff, info->s->base.min_pack_length);
...@@ -1473,7 +1477,7 @@ int _ma_read_dynamic_record(MARIA_HA *info, uchar *buf, ...@@ -1473,7 +1477,7 @@ int _ma_read_dynamic_record(MARIA_HA *info, uchar *buf,
flush_io_cache(&info->rec_cache)) flush_io_cache(&info->rec_cache))
goto err; goto err;
info->rec_cache.seek_not_done=1; info->rec_cache.seek_not_done=1;
if ((b_type= _ma_get_block_info(&block_info, file, filepos)) & if ((b_type= _ma_get_block_info(info, &block_info, file, filepos)) &
(BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR | (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR |
BLOCK_FATAL_ERROR)) BLOCK_FATAL_ERROR))
{ {
...@@ -1545,7 +1549,7 @@ int _ma_read_dynamic_record(MARIA_HA *info, uchar *buf, ...@@ -1545,7 +1549,7 @@ int _ma_read_dynamic_record(MARIA_HA *info, uchar *buf,
DBUG_RETURN(my_errno); DBUG_RETURN(my_errno);
panic: panic:
my_errno=HA_ERR_WRONG_IN_RECORD; _ma_set_fatal_error(info->s, HA_ERR_WRONG_IN_RECORD);
goto err; goto err;
} }
...@@ -1627,7 +1631,7 @@ my_bool _ma_cmp_dynamic_record(register MARIA_HA *info, ...@@ -1627,7 +1631,7 @@ my_bool _ma_cmp_dynamic_record(register MARIA_HA *info,
block_info.next_filepos=filepos; block_info.next_filepos=filepos;
while (reclength > 0) while (reclength > 0)
{ {
if ((b_type= _ma_get_block_info(&block_info, info->dfile.file, if ((b_type= _ma_get_block_info(info, &block_info, info->dfile.file,
block_info.next_filepos)) block_info.next_filepos))
& (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR | & (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR |
BLOCK_FATAL_ERROR)) BLOCK_FATAL_ERROR))
...@@ -1646,7 +1650,7 @@ my_bool _ma_cmp_dynamic_record(register MARIA_HA *info, ...@@ -1646,7 +1650,7 @@ my_bool _ma_cmp_dynamic_record(register MARIA_HA *info,
} }
} else if (reclength < block_info.data_len) } else if (reclength < block_info.data_len)
{ {
my_errno=HA_ERR_WRONG_IN_RECORD; _ma_set_fatal_error(info->s, HA_ERR_WRONG_IN_RECORD);
goto err; goto err;
} }
reclength-= block_info.data_len; reclength-= block_info.data_len;
...@@ -1779,12 +1783,12 @@ int _ma_read_rnd_dynamic_record(MARIA_HA *info, ...@@ -1779,12 +1783,12 @@ int _ma_read_rnd_dynamic_record(MARIA_HA *info,
} }
if (info->opt_flag & READ_CACHE_USED) if (info->opt_flag & READ_CACHE_USED)
{ {
if (_ma_read_cache(&info->rec_cache, block_info.header, filepos, if (_ma_read_cache(info, &info->rec_cache, block_info.header, filepos,
sizeof(block_info.header), sizeof(block_info.header),
(!block_of_record && skip_deleted_blocks ? (!block_of_record && skip_deleted_blocks ?
READING_NEXT : 0) | READING_HEADER)) READING_NEXT : 0) | READING_HEADER))
goto panic; goto panic;
b_type= _ma_get_block_info(&block_info,-1,filepos); b_type= _ma_get_block_info(info, &block_info,-1,filepos);
} }
else else
{ {
...@@ -1793,7 +1797,7 @@ int _ma_read_rnd_dynamic_record(MARIA_HA *info, ...@@ -1793,7 +1797,7 @@ int _ma_read_rnd_dynamic_record(MARIA_HA *info,
flush_io_cache(&info->rec_cache)) flush_io_cache(&info->rec_cache))
DBUG_RETURN(my_errno); DBUG_RETURN(my_errno);
info->rec_cache.seek_not_done=1; info->rec_cache.seek_not_done=1;
b_type= _ma_get_block_info(&block_info, info->dfile.file, filepos); b_type= _ma_get_block_info(info, &block_info, info->dfile.file, filepos);
} }
if (b_type & (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR | if (b_type & (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR |
...@@ -1855,7 +1859,7 @@ int _ma_read_rnd_dynamic_record(MARIA_HA *info, ...@@ -1855,7 +1859,7 @@ int _ma_read_rnd_dynamic_record(MARIA_HA *info,
{ {
if (info->opt_flag & READ_CACHE_USED) if (info->opt_flag & READ_CACHE_USED)
{ {
if (_ma_read_cache(&info->rec_cache, to,filepos, if (_ma_read_cache(info, &info->rec_cache, to,filepos,
block_info.data_len, block_info.data_len,
(!block_of_record && skip_deleted_blocks) ? (!block_of_record && skip_deleted_blocks) ?
READING_NEXT : 0)) READING_NEXT : 0))
...@@ -1872,7 +1876,10 @@ int _ma_read_rnd_dynamic_record(MARIA_HA *info, ...@@ -1872,7 +1876,10 @@ int _ma_read_rnd_dynamic_record(MARIA_HA *info,
if (my_read(info->dfile.file, to, block_info.data_len, MYF(MY_NABP))) if (my_read(info->dfile.file, to, block_info.data_len, MYF(MY_NABP)))
{ {
if (my_errno == HA_ERR_FILE_TOO_SHORT) if (my_errno == HA_ERR_FILE_TOO_SHORT)
my_errno= HA_ERR_WRONG_IN_RECORD; /* Unexpected end of file */ {
/* Unexpected end of file */
_ma_set_fatal_error(share, HA_ERR_WRONG_IN_RECORD);
}
goto err; goto err;
} }
} }
...@@ -1899,7 +1906,8 @@ int _ma_read_rnd_dynamic_record(MARIA_HA *info, ...@@ -1899,7 +1906,8 @@ int _ma_read_rnd_dynamic_record(MARIA_HA *info,
DBUG_RETURN(my_errno); /* Wrong record */ DBUG_RETURN(my_errno); /* Wrong record */
panic: panic:
my_errno=HA_ERR_WRONG_IN_RECORD; /* Something is fatal wrong */ /* Something is fatal wrong */
_ma_set_fatal_error(share, HA_ERR_WRONG_IN_RECORD);
err: err:
fast_ma_writeinfo(info); fast_ma_writeinfo(info);
DBUG_RETURN(my_errno); DBUG_RETURN(my_errno);
...@@ -1908,7 +1916,8 @@ int _ma_read_rnd_dynamic_record(MARIA_HA *info, ...@@ -1908,7 +1916,8 @@ int _ma_read_rnd_dynamic_record(MARIA_HA *info,
/* Read and process header from a dynamic-record-file */ /* Read and process header from a dynamic-record-file */
uint _ma_get_block_info(MARIA_BLOCK_INFO *info, File file, my_off_t filepos) uint _ma_get_block_info(MARIA_HA *handler, MARIA_BLOCK_INFO *info, File file,
my_off_t filepos)
{ {
uint return_val=0; uint return_val=0;
uchar *header=info->header; uchar *header=info->header;
...@@ -1923,7 +1932,14 @@ uint _ma_get_block_info(MARIA_BLOCK_INFO *info, File file, my_off_t filepos) ...@@ -1923,7 +1932,14 @@ uint _ma_get_block_info(MARIA_BLOCK_INFO *info, File file, my_off_t filepos)
VOID(my_seek(file,filepos,MY_SEEK_SET,MYF(0))); VOID(my_seek(file,filepos,MY_SEEK_SET,MYF(0)));
if (my_read(file, header, sizeof(info->header),MYF(0)) != if (my_read(file, header, sizeof(info->header),MYF(0)) !=
sizeof(info->header)) sizeof(info->header))
goto err; {
/*
This is either an error or just reading at end of file.
Don't give a fatal error for this case.
*/
my_errno= HA_ERR_WRONG_IN_RECORD;
return BLOCK_ERROR;
}
} }
DBUG_DUMP("header",header,MARIA_BLOCK_INFO_HEADER_LENGTH); DBUG_DUMP("header",header,MARIA_BLOCK_INFO_HEADER_LENGTH);
if (info->second_read) if (info->second_read)
...@@ -2037,6 +2053,6 @@ uint _ma_get_block_info(MARIA_BLOCK_INFO *info, File file, my_off_t filepos) ...@@ -2037,6 +2053,6 @@ uint _ma_get_block_info(MARIA_BLOCK_INFO *info, File file, my_off_t filepos)
} }
err: err:
my_errno=HA_ERR_WRONG_IN_RECORD; /* Garbage */ _ma_set_fatal_error(handler->s, HA_ERR_WRONG_IN_RECORD);
return BLOCK_ERROR; return BLOCK_ERROR;
} }
...@@ -536,6 +536,7 @@ void _ma_mark_file_crashed(MARIA_SHARE *share) ...@@ -536,6 +536,7 @@ void _ma_mark_file_crashed(MARIA_SHARE *share)
void _ma_set_fatal_error(MARIA_SHARE *share, int error) void _ma_set_fatal_error(MARIA_SHARE *share, int error)
{ {
DBUG_PRINT("error", ("error: %d", error));
maria_mark_crashed_share(share); maria_mark_crashed_share(share);
if (!(share->state.changed & STATE_CRASHED_PRINTED)) if (!(share->state.changed & STATE_CRASHED_PRINTED))
{ {
......
...@@ -193,7 +193,7 @@ static my_bool _ma_read_pack_info(MARIA_SHARE *share, File file, ...@@ -193,7 +193,7 @@ static my_bool _ma_read_pack_info(MARIA_SHARE *share, File file,
/* Only the first three bytes of magic number are independent of version. */ /* Only the first three bytes of magic number are independent of version. */
if (memcmp(header, maria_pack_file_magic, 3)) if (memcmp(header, maria_pack_file_magic, 3))
{ {
my_errno=HA_ERR_WRONG_IN_RECORD; _ma_set_fatal_error(share, HA_ERR_WRONG_IN_RECORD);
goto err0; goto err0;
} }
share->pack.version= header[3]; /* fourth uchar of magic number */ share->pack.version= header[3]; /* fourth uchar of magic number */
...@@ -330,7 +330,7 @@ static my_bool _ma_read_pack_info(MARIA_SHARE *share, File file, ...@@ -330,7 +330,7 @@ static my_bool _ma_read_pack_info(MARIA_SHARE *share, File file,
DBUG_RETURN(0); DBUG_RETURN(0);
err3: err3:
my_errno=HA_ERR_WRONG_IN_RECORD; _ma_set_fatal_error(share, HA_ERR_WRONG_IN_RECORD);
err2: err2:
my_free(share->decode_tables, MYF(0)); my_free(share->decode_tables, MYF(0));
err1: err1:
...@@ -759,7 +759,7 @@ int _ma_read_pack_record(MARIA_HA *info, uchar *buf, MARIA_RECORD_POS filepos) ...@@ -759,7 +759,7 @@ int _ma_read_pack_record(MARIA_HA *info, uchar *buf, MARIA_RECORD_POS filepos)
DBUG_RETURN(_ma_pack_rec_unpack(info,&info->bit_buff, buf, DBUG_RETURN(_ma_pack_rec_unpack(info,&info->bit_buff, buf,
info->rec_buff, block_info.rec_len)); info->rec_buff, block_info.rec_len));
panic: panic:
my_errno=HA_ERR_WRONG_IN_RECORD; _ma_set_fatal_error(info->s, HA_ERR_WRONG_IN_RECORD);
err: err:
DBUG_RETURN(my_errno); DBUG_RETURN(my_errno);
} }
...@@ -794,7 +794,8 @@ int _ma_pack_rec_unpack(register MARIA_HA *info, MARIA_BIT_BUFF *bit_buff, ...@@ -794,7 +794,8 @@ int _ma_pack_rec_unpack(register MARIA_HA *info, MARIA_BIT_BUFF *bit_buff,
bit_buff->pos - bit_buff->bits / 8 == bit_buff->end) bit_buff->pos - bit_buff->bits / 8 == bit_buff->end)
DBUG_RETURN(0); DBUG_RETURN(0);
info->update&= ~HA_STATE_AKTIV; info->update&= ~HA_STATE_AKTIV;
DBUG_RETURN(my_errno=HA_ERR_WRONG_IN_RECORD); _ma_set_fatal_error(share, HA_ERR_WRONG_IN_RECORD);
DBUG_RETURN(HA_ERR_WRONG_IN_RECORD);
} /* _ma_pack_rec_unpack */ } /* _ma_pack_rec_unpack */
...@@ -1359,7 +1360,7 @@ int _ma_read_rnd_pack_record(MARIA_HA *info, ...@@ -1359,7 +1360,7 @@ int _ma_read_rnd_pack_record(MARIA_HA *info,
file= info->dfile.file; file= info->dfile.file;
if (info->opt_flag & READ_CACHE_USED) if (info->opt_flag & READ_CACHE_USED)
{ {
if (_ma_read_cache(&info->rec_cache, block_info.header, if (_ma_read_cache(info, &info->rec_cache, block_info.header,
filepos, share->pack.ref_length, filepos, share->pack.ref_length,
skip_deleted_blocks ? READING_NEXT : 0)) skip_deleted_blocks ? READING_NEXT : 0))
goto err; goto err;
...@@ -1372,14 +1373,14 @@ int _ma_read_rnd_pack_record(MARIA_HA *info, ...@@ -1372,14 +1373,14 @@ int _ma_read_rnd_pack_record(MARIA_HA *info,
#ifndef DBUG_OFF #ifndef DBUG_OFF
if (block_info.rec_len > share->max_pack_length) if (block_info.rec_len > share->max_pack_length)
{ {
my_errno=HA_ERR_WRONG_IN_RECORD; _ma_set_fatal_error(share, HA_ERR_WRONG_IN_RECORD);
goto err; goto err;
} }
#endif #endif
if (info->opt_flag & READ_CACHE_USED) if (info->opt_flag & READ_CACHE_USED)
{ {
if (_ma_read_cache(&info->rec_cache, info->rec_buff, if (_ma_read_cache(info, &info->rec_cache, info->rec_buff,
block_info.filepos, block_info.rec_len, block_info.filepos, block_info.rec_len,
skip_deleted_blocks ? READING_NEXT : 0)) skip_deleted_blocks ? READING_NEXT : 0))
goto err; goto err;
...@@ -1645,7 +1646,7 @@ static int _ma_read_rnd_mempack_record(MARIA_HA *info, ...@@ -1645,7 +1646,7 @@ static int _ma_read_rnd_mempack_record(MARIA_HA *info,
#ifndef DBUG_OFF #ifndef DBUG_OFF
if (block_info.rec_len > info->s->max_pack_length) if (block_info.rec_len > info->s->max_pack_length)
{ {
my_errno=HA_ERR_WRONG_IN_RECORD; _ma_set_fatal_error(share, HA_ERR_WRONG_IN_RECORD);
goto err; goto err;
} }
#endif #endif
......
...@@ -297,6 +297,6 @@ int _ma_read_rnd_static_record(MARIA_HA *info, uchar *buf, ...@@ -297,6 +297,6 @@ int _ma_read_rnd_static_record(MARIA_HA *info, uchar *buf,
} }
/* my_errno should be set if rec_cache.error == -1 */ /* my_errno should be set if rec_cache.error == -1 */
if (info->rec_cache.error != -1 || my_errno == 0) if (info->rec_cache.error != -1 || my_errno == 0)
my_errno=HA_ERR_WRONG_IN_RECORD; _ma_set_fatal_error(share, HA_ERR_WRONG_IN_RECORD);
DBUG_RETURN(my_errno); /* Something wrong (EOF?) */ DBUG_RETURN(my_errno); /* Something wrong (EOF?) */
} }
...@@ -1018,7 +1018,7 @@ extern MARIA_KEY *_ma_pack_key(MARIA_HA *info, MARIA_KEY *int_key, ...@@ -1018,7 +1018,7 @@ extern MARIA_KEY *_ma_pack_key(MARIA_HA *info, MARIA_KEY *int_key,
HA_KEYSEG ** last_used_keyseg); HA_KEYSEG ** last_used_keyseg);
extern void _ma_copy_key(MARIA_KEY *to, const MARIA_KEY *from); extern void _ma_copy_key(MARIA_KEY *to, const MARIA_KEY *from);
extern int _ma_read_key_record(MARIA_HA *info, uchar *buf, MARIA_RECORD_POS); extern int _ma_read_key_record(MARIA_HA *info, uchar *buf, MARIA_RECORD_POS);
extern my_bool _ma_read_cache(IO_CACHE *info, uchar *buff, extern my_bool _ma_read_cache(MARIA_HA *, IO_CACHE *info, uchar *buff,
MARIA_RECORD_POS pos, size_t length, MARIA_RECORD_POS pos, size_t length,
uint re_read_if_possibly); uint re_read_if_possibly);
extern ulonglong ma_retrieve_auto_increment(const uchar *key, uint8 key_type); extern ulonglong ma_retrieve_auto_increment(const uchar *key, uint8 key_type);
...@@ -1100,7 +1100,7 @@ typedef struct st_maria_block_info ...@@ -1100,7 +1100,7 @@ typedef struct st_maria_block_info
#define fast_ma_writeinfo(INFO) if (!(INFO)->s->tot_locks) (void) _ma_writeinfo((INFO),0) #define fast_ma_writeinfo(INFO) if (!(INFO)->s->tot_locks) (void) _ma_writeinfo((INFO),0)
#define fast_ma_readinfo(INFO) ((INFO)->lock_type == F_UNLCK) && _ma_readinfo((INFO),F_RDLCK,1) #define fast_ma_readinfo(INFO) ((INFO)->lock_type == F_UNLCK) && _ma_readinfo((INFO),F_RDLCK,1)
extern uint _ma_get_block_info(MARIA_BLOCK_INFO *, File, my_off_t); extern uint _ma_get_block_info(MARIA_HA *, MARIA_BLOCK_INFO *, File, my_off_t);
extern uint _ma_rec_pack(MARIA_HA *info, uchar *to, const uchar *from); extern uint _ma_rec_pack(MARIA_HA *info, uchar *to, const uchar *from);
extern uint _ma_pack_get_block_info(MARIA_HA *maria, MARIA_BIT_BUFF *bit_buff, extern uint _ma_pack_get_block_info(MARIA_HA *maria, MARIA_BIT_BUFF *bit_buff,
MARIA_BLOCK_INFO *info, uchar **rec_buff_p, MARIA_BLOCK_INFO *info, uchar **rec_buff_p,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment