Commit ab0fa111 authored by unknown's avatar unknown

Fixed bug in restoring auto-increment value in case of duplicate key with insert or update

Fixed bug when calculating max_key_length that caused some ALTER TABLE to fail if MAX_ROWS was used.
Use maria_block_size instead of MARIA_MIN_KEY_BLOCK_LENGTH
Fixed bug when scanning table with BLOCK format for repair; If table was > bitmap coverage one page block was read twice which caused a lot of duplicate key errors
Could not repeat Bug#34106 "auto_increment is reset to 1 when table is recovered from crash" after this patch.

NOTE: This is an incompatible change, so one must do maria_chk -r on ones old Maria tables!
Sorry, but this was needed to fix the bug with max_key_length and to be able to handle bigger key files with smaller key references


cmd-line-utils/readline/readline.c:
  Fixed compiler warnings
mysql-test/r/maria.result:
  Added more test of auto-increment handling
mysql-test/t/maria.test:
  Added more test of auto-increment handling
mysys/my_pread.c:
  Fixed wrong test
  Removed not needed tests (error is always 1 if readbytes != Count)
mysys/my_read.c:
  Fixed wrong test
storage/maria/ha_maria.cc:
  Disable LOAD INDEX until I got Sanja's extension to pagecache interface
storage/maria/ma_blockrec.c:
  Ensure that info->last_auto_increment is reset properly
storage/maria/ma_check.c:
  Fixed wrong printing of row number in case of duplicate key for --safe-repair
  Safety fix in recreate table so that Column numbers are given to maria_create() in original order
  Added missing HA_OPEN_FOR_REPAIR to maria_open()
  Fixed bug when scanning table with BLOCK format for repair; If table was > bitmap coverage one page block was read twice which caused a lot of duplicate key errors
storage/maria/ma_create.c:
  Use correct value for how much free space there is on a key page
  Remember some missing table option when doing re-create.
  Removed optimization where last packed fields is unpacked; Caused problems for re-create.
storage/maria/ma_delete.c:
  Ensure that info->last_auto_increment is reset properly
  Fix for update to restore autoincrement value on duplicate key
storage/maria/ma_key_recover.c:
  Moved handling of restoring value of auto-increment in case of duplicate key from clr to undo
  This ensures the restoring works both for insert and update and also that this is symetrical to how the auto_increment value is stored
storage/maria/ma_key_recover.h:
  Added new prototype
storage/maria/ma_loghandler.c:
  Added hook to write_hook_for_undo_key_delete()
storage/maria/ma_open.c:
  Fixed wrong calculation of max_key_file_length
storage/maria/ma_page.c:
  Use maria_block_size instead of MARIA_MIN_KEY_BLOCK_LENGTH
  Increase internal buffer (safety fix)
storage/maria/ma_search.c:
  Use maria_block_size instead of MARIA_MIN_KEY_BLOCK_LENGTH
  Note that this is an incompatible change, so one must do maria_chk -r on ones old Maria tables (sorry)
storage/maria/ma_update.c:
  Ensure that info->last_auto_increment is reset properly
storage/maria/ma_write.c:
  Ensure that info->last_auto_increment is reset properly
  Fix for update to restore autoincrement value on duplicate key
storage/maria/maria_chk.c:
  Allow small page_buffer_size
  Fixed printing for --describe to better fit into 80 characters
storage/maria/maria_def.h:
  Added comments
parent b40a6348
...@@ -90,7 +90,6 @@ static void bind_arrow_keys_internal PARAMS((Keymap)); ...@@ -90,7 +90,6 @@ static void bind_arrow_keys_internal PARAMS((Keymap));
static void bind_arrow_keys PARAMS((void)); static void bind_arrow_keys PARAMS((void));
static void readline_default_bindings PARAMS((void)); static void readline_default_bindings PARAMS((void));
static void reset_default_bindings PARAMS((void));
static int _rl_subseq_result PARAMS((int, Keymap, int, int)); static int _rl_subseq_result PARAMS((int, Keymap, int, int));
static int _rl_subseq_getchar PARAMS((int)); static int _rl_subseq_getchar PARAMS((int));
...@@ -287,7 +286,7 @@ rl_set_prompt (prompt) ...@@ -287,7 +286,7 @@ rl_set_prompt (prompt)
{ {
FREE (rl_prompt); FREE (rl_prompt);
rl_prompt = prompt ? savestring (prompt) : (char *)NULL; rl_prompt = prompt ? savestring (prompt) : (char *)NULL;
rl_display_prompt = rl_prompt ? rl_prompt : ""; rl_display_prompt = rl_prompt ? rl_prompt : (char*) "";
rl_visible_prompt_length = rl_expand_prompt (rl_prompt); rl_visible_prompt_length = rl_expand_prompt (rl_prompt);
return 0; return 0;
...@@ -1072,18 +1071,6 @@ readline_default_bindings () ...@@ -1072,18 +1071,6 @@ readline_default_bindings ()
rl_tty_set_default_bindings (_rl_keymap); rl_tty_set_default_bindings (_rl_keymap);
} }
/* Reset the default bindings for the terminal special characters we're
interested in back to rl_insert and read the new ones. */
static void
reset_default_bindings ()
{
if (_rl_bind_stty_chars)
{
rl_tty_unset_default_bindings (_rl_keymap);
rl_tty_set_default_bindings (_rl_keymap);
}
}
/* Bind some common arrow key sequences in MAP. */ /* Bind some common arrow key sequences in MAP. */
static void static void
bind_arrow_keys_internal (map) bind_arrow_keys_internal (map)
......
...@@ -2200,3 +2200,45 @@ id f1 ...@@ -2200,3 +2200,45 @@ id f1
2 test2 2 test2
drop table t1; drop table t1;
SET SQL_MODE = 'TRADITIONAL'; SET SQL_MODE = 'TRADITIONAL';
create table t1 (n int not null primary key auto_increment, c char(1), unique(c));
insert into t1 values(100, "a");
insert into t1 values(300, "b");
insert into t1 values(50, "a");
ERROR 23000: Duplicate entry 'a' for key 'c'
insert into t1 values(null, "c");
select * from t1;
n c
100 a
300 b
301 c
update t1 set n=400,c='a' where n=301;
ERROR 23000: Duplicate entry 'a' for key 'c'
insert into t1 values(null, "d");
select * from t1;
n c
100 a
300 b
301 c
302 d
drop table t1;
create table t1 (n int not null primary key auto_increment, c char(1), unique(c)) transactional=0 row_format=dynamic;
insert into t1 values(100, "a");
insert into t1 values(300, "b");
insert into t1 values(50, "a");
ERROR 23000: Duplicate entry 'a' for key 'c'
insert into t1 values(null, "c");
select * from t1;
n c
100 a
300 b
301 c
update t1 set n=400,c='a' where n=301;
ERROR 23000: Duplicate entry 'a' for key 'c'
insert into t1 values(null, "d");
select * from t1;
n c
100 a
300 b
301 c
302 d
drop table t1;
...@@ -1426,6 +1426,33 @@ SELECT * FROM t1; ...@@ -1426,6 +1426,33 @@ SELECT * FROM t1;
drop table t1; drop table t1;
SET SQL_MODE = 'TRADITIONAL'; SET SQL_MODE = 'TRADITIONAL';
create table t1 (n int not null primary key auto_increment, c char(1), unique(c));
insert into t1 values(100, "a");
insert into t1 values(300, "b");
--error 1062
insert into t1 values(50, "a");
insert into t1 values(null, "c");
select * from t1;
--error 1062
update t1 set n=400,c='a' where n=301;
insert into t1 values(null, "d");
select * from t1;
drop table t1;
create table t1 (n int not null primary key auto_increment, c char(1), unique(c)) transactional=0 row_format=dynamic;
insert into t1 values(100, "a");
insert into t1 values(300, "b");
--error 1062
insert into t1 values(50, "a");
insert into t1 values(null, "c");
select * from t1;
--error 1062
update t1 set n=400,c='a' where n=301;
insert into t1 values(null, "d");
select * from t1;
drop table t1;
# End of 5.2 tests # End of 5.2 tests
--disable_result_log --disable_result_log
......
...@@ -66,11 +66,12 @@ size_t my_pread(File Filedes, uchar *Buffer, size_t Count, my_off_t offset, ...@@ -66,11 +66,12 @@ size_t my_pread(File Filedes, uchar *Buffer, size_t Count, my_off_t offset,
if ((error= ((readbytes= pread(Filedes, Buffer, Count, offset)) != Count))) if ((error= ((readbytes= pread(Filedes, Buffer, Count, offset)) != Count)))
{ {
my_errno= errno; my_errno= errno;
if (errno == 0 || (errno == -1 && (MyFlags & (MY_NABP | MY_FNABP)))) if (errno == 0 || (readbytes == (size_t) -1 &&
(MyFlags & (MY_NABP | MY_FNABP))))
my_errno= HA_ERR_FILE_TOO_SHORT; my_errno= HA_ERR_FILE_TOO_SHORT;
} }
#endif #endif
if (error || readbytes != Count) if (error)
{ {
DBUG_PRINT("warning",("Read only %d bytes off %u from %d, errno: %d", DBUG_PRINT("warning",("Read only %d bytes off %u from %d, errno: %d",
(int) readbytes, (uint) Count,Filedes,my_errno)); (int) readbytes, (uint) Count,Filedes,my_errno));
......
...@@ -47,7 +47,8 @@ size_t my_read(File Filedes, uchar *Buffer, size_t Count, myf MyFlags) ...@@ -47,7 +47,8 @@ size_t my_read(File Filedes, uchar *Buffer, size_t Count, myf MyFlags)
if ((readbytes= read(Filedes, Buffer, Count)) != Count) if ((readbytes= read(Filedes, Buffer, Count)) != Count)
{ {
my_errno= errno; my_errno= errno;
if (errno == 0 || (errno == -1 && (MyFlags & (MY_NABP | MY_FNABP)))) if (errno == 0 || (readbytes == (size_t) -1 &&
(MyFlags & (MY_NABP | MY_FNABP))))
my_errno= HA_ERR_FILE_TOO_SHORT; my_errno= HA_ERR_FILE_TOO_SHORT;
DBUG_PRINT("warning",("Read only %d bytes off %lu from %d, errno: %d", DBUG_PRINT("warning",("Read only %d bytes off %lu from %d, errno: %d",
(int) readbytes, (ulong) Count, Filedes, (int) readbytes, (ulong) Count, Filedes,
......
...@@ -1491,6 +1491,7 @@ int ha_maria::preload_keys(THD * thd, HA_CHECK_OPT *check_opt) ...@@ -1491,6 +1491,7 @@ int ha_maria::preload_keys(THD * thd, HA_CHECK_OPT *check_opt)
maria_extra(file, HA_EXTRA_PRELOAD_BUFFER_SIZE, maria_extra(file, HA_EXTRA_PRELOAD_BUFFER_SIZE,
(void*) &thd->variables.preload_buff_size); (void*) &thd->variables.preload_buff_size);
#ifndef NOT_YET
if ((error= maria_preload(file, map, ignore_leaves))) if ((error= maria_preload(file, map, ignore_leaves)))
{ {
switch (error) { switch (error) {
...@@ -1508,7 +1509,7 @@ int ha_maria::preload_keys(THD * thd, HA_CHECK_OPT *check_opt) ...@@ -1508,7 +1509,7 @@ int ha_maria::preload_keys(THD * thd, HA_CHECK_OPT *check_opt)
error= HA_ADMIN_FAILED; error= HA_ADMIN_FAILED;
goto err; goto err;
} }
#endif
DBUG_RETURN(HA_ADMIN_OK); DBUG_RETURN(HA_ADMIN_OK);
err: err:
......
...@@ -6415,6 +6415,7 @@ my_bool _ma_apply_undo_row_insert(MARIA_HA *info, LSN undo_lsn, ...@@ -6415,6 +6415,7 @@ my_bool _ma_apply_undo_row_insert(MARIA_HA *info, LSN undo_lsn,
checksum= 0; checksum= 0;
if (share->calc_checksum) if (share->calc_checksum)
checksum= (ha_checksum) 0 - ha_checksum_korr(header); checksum= (ha_checksum) 0 - ha_checksum_korr(header);
info->last_auto_increment= ~ (ulonglong) 0;
if (_ma_write_clr(info, undo_lsn, LOGREC_UNDO_ROW_INSERT, if (_ma_write_clr(info, undo_lsn, LOGREC_UNDO_ROW_INSERT,
share->calc_checksum != 0, checksum, &lsn, (void*) 0)) share->calc_checksum != 0, checksum, &lsn, (void*) 0))
goto err; goto err;
...@@ -6815,6 +6816,7 @@ my_bool _ma_apply_undo_row_update(MARIA_HA *info, LSN undo_lsn, ...@@ -6815,6 +6816,7 @@ my_bool _ma_apply_undo_row_update(MARIA_HA *info, LSN undo_lsn,
(*share->calc_checksum)(info, current_record)); (*share->calc_checksum)(info, current_record));
} }
info->last_auto_increment= ~ (ulonglong) 0;
/* Now records are up to date, execute the update to original values */ /* Now records are up to date, execute the update to original values */
if (_ma_update_at_original_place(info, page, rownr, length_on_head_page, if (_ma_update_at_original_place(info, page, rownr, length_on_head_page,
extent_count, extent_info, extent_count, extent_info,
......
...@@ -2361,10 +2361,10 @@ int maria_repair(HA_CHECK *param, register MARIA_HA *info, ...@@ -2361,10 +2361,10 @@ int maria_repair(HA_CHECK *param, register MARIA_HA *info,
if (my_errno != HA_ERR_FOUND_DUPP_KEY) if (my_errno != HA_ERR_FOUND_DUPP_KEY)
goto err; goto err;
DBUG_DUMP("record",(uchar*) sort_param.record,share->base.pack_reclength); DBUG_DUMP("record",(uchar*) sort_param.record,share->base.pack_reclength);
_ma_check_print_info(param, _ma_check_print_warning(param,
"Duplicate key %2d for record at %10s against new record at %10s", "Duplicate key %2d for record at %10s against new record at %10s",
info->errkey+1, info->errkey+1,
llstr(sort_param.start_recpos,llbuff), llstr(sort_param.current_filepos, llbuff),
llstr(info->dup_key_pos,llbuff2)); llstr(info->dup_key_pos,llbuff2));
if (param->testflag & T_VERBOSE) if (param->testflag & T_VERBOSE)
{ {
...@@ -4972,7 +4972,8 @@ static int sort_key_write(MARIA_SORT_PARAM *sort_param, const uchar *a) ...@@ -4972,7 +4972,8 @@ static int sort_key_write(MARIA_SORT_PARAM *sort_param, const uchar *a)
sort_param->keyinfo, sort_param->keyinfo,
a); a);
_ma_check_print_warning(param, _ma_check_print_warning(param,
"Duplicate key for record at %10s against record at %10s", "Duplicate key %2u for record at %10s against record at %10s",
sort_param->key + 1,
llstr(sort_info->info->cur_row.lastpos, llbuff), llstr(sort_info->info->cur_row.lastpos, llbuff),
llstr(get_record_for_key(sort_info->info, llstr(get_record_for_key(sort_info->info,
sort_param->keyinfo, sort_param->keyinfo,
...@@ -5409,7 +5410,8 @@ int maria_test_if_almost_full(MARIA_HA *info) ...@@ -5409,7 +5410,8 @@ int maria_test_if_almost_full(MARIA_HA *info)
(my_off_t) share->base.max_data_file_length; (my_off_t) share->base.max_data_file_length;
} }
/* Recreate table with bigger more alloced record-data */
/* Recreate table with bigger more alloced record-data */
int maria_recreate_table(HA_CHECK *param, MARIA_HA **org_info, char *filename) int maria_recreate_table(HA_CHECK *param, MARIA_HA **org_info, char *filename)
{ {
...@@ -5432,8 +5434,8 @@ int maria_recreate_table(HA_CHECK *param, MARIA_HA **org_info, char *filename) ...@@ -5432,8 +5434,8 @@ int maria_recreate_table(HA_CHECK *param, MARIA_HA **org_info, char *filename)
status_info= (*org_info)->state[0]; status_info= (*org_info)->state[0];
info.state= &status_info; info.state= &status_info;
share= *(*org_info)->s; share= *(*org_info)->s;
unpack= (share.options & HA_OPTION_COMPRESS_RECORD) && unpack= ((share.data_file_type == COMPRESSED_RECORD) &&
(param->testflag & T_UNPACK); (param->testflag & T_UNPACK));
if (!(keyinfo=(MARIA_KEYDEF*) my_alloca(sizeof(MARIA_KEYDEF) * if (!(keyinfo=(MARIA_KEYDEF*) my_alloca(sizeof(MARIA_KEYDEF) *
share.base.keys))) share.base.keys)))
DBUG_RETURN(0); DBUG_RETURN(0);
...@@ -5463,19 +5465,11 @@ int maria_recreate_table(HA_CHECK *param, MARIA_HA **org_info, char *filename) ...@@ -5463,19 +5465,11 @@ int maria_recreate_table(HA_CHECK *param, MARIA_HA **org_info, char *filename)
DBUG_RETURN(1); DBUG_RETURN(1);
} }
/* Copy the column definitions */ /* Copy the column definitions in their original order */
memcpy((uchar*) columndef,(uchar*) share.columndef, for (column= share.columndef, end= share.columndef+share.base.fields;
(size_t) (sizeof(MARIA_COLUMNDEF)*(share.base.fields+1)));
for (column=columndef, end= columndef+share.base.fields;
column != end ; column != end ;
column++) column++)
{ columndef[column->column_nr]= *column;
if (unpack && !(share.options & HA_OPTION_PACK_RECORD) &&
column->type != FIELD_BLOB &&
column->type != FIELD_VARCHAR &&
column->type != FIELD_CHECK)
column->type=(int) FIELD_NORMAL;
}
/* Change the new key to point at the saved key segments */ /* Change the new key to point at the saved key segments */
memcpy((uchar*) keysegs,(uchar*) share.keyparts, memcpy((uchar*) keysegs,(uchar*) share.keyparts,
...@@ -5505,25 +5499,23 @@ int maria_recreate_table(HA_CHECK *param, MARIA_HA **org_info, char *filename) ...@@ -5505,25 +5499,23 @@ int maria_recreate_table(HA_CHECK *param, MARIA_HA **org_info, char *filename)
u_ptr->seg=keyseg; u_ptr->seg=keyseg;
keyseg+=u_ptr->keysegs+1; keyseg+=u_ptr->keysegs+1;
} }
file_length=(ulonglong) my_seek(info.dfile.file, 0L, MY_SEEK_END, MYF(0));
if (share.options & HA_OPTION_COMPRESS_RECORD) if (share.options & HA_OPTION_COMPRESS_RECORD)
share.base.records=max_records=info.state->records; share.base.records=max_records=info.state->records;
else if (share.base.min_pack_length) else if (share.base.min_pack_length)
max_records=(ha_rows) (my_seek(info.dfile.file, 0L, MY_SEEK_END, max_records=(ha_rows) (file_length / share.base.min_pack_length);
MYF(0)) /
(ulong) share.base.min_pack_length);
else else
max_records=0; max_records=0;
unpack= (share.data_file_type == COMPRESSED_RECORD) &&
(param->testflag & T_UNPACK);
share.options&= ~HA_OPTION_TEMP_COMPRESS_RECORD; share.options&= ~HA_OPTION_TEMP_COMPRESS_RECORD;
file_length=(ulonglong) my_seek(info.dfile.file, 0L, MY_SEEK_END, MYF(0));
tmp_length= file_length+file_length/10; tmp_length= file_length+file_length/10;
set_if_bigger(file_length,param->max_data_file_length); set_if_bigger(file_length,param->max_data_file_length);
set_if_bigger(file_length,tmp_length); set_if_bigger(file_length,tmp_length);
set_if_bigger(file_length,(ulonglong) share.base.max_data_file_length); set_if_bigger(file_length,(ulonglong) share.base.max_data_file_length);
VOID(maria_close(*org_info)); VOID(maria_close(*org_info));
bzero((char*) &create_info,sizeof(create_info)); bzero((char*) &create_info,sizeof(create_info));
create_info.max_rows=max(max_records,share.base.records); create_info.max_rows=max(max_records,share.base.records);
create_info.reloc_rows=share.base.reloc; create_info.reloc_rows=share.base.reloc;
...@@ -5544,6 +5536,8 @@ int maria_recreate_table(HA_CHECK *param, MARIA_HA **org_info, char *filename) ...@@ -5544,6 +5536,8 @@ int maria_recreate_table(HA_CHECK *param, MARIA_HA **org_info, char *filename)
*/ */
create_info.with_auto_increment= TRUE; create_info.with_auto_increment= TRUE;
create_info.null_bytes= share.base.null_bytes; create_info.null_bytes= share.base.null_bytes;
create_info.transactional= share.base.born_transactional;
/* /*
We don't have to handle symlinks here because we are using We don't have to handle symlinks here because we are using
HA_DONT_TOUCH_DATA HA_DONT_TOUCH_DATA
...@@ -5560,10 +5554,13 @@ int maria_recreate_table(HA_CHECK *param, MARIA_HA **org_info, char *filename) ...@@ -5560,10 +5554,13 @@ int maria_recreate_table(HA_CHECK *param, MARIA_HA **org_info, char *filename)
my_errno); my_errno);
goto end; goto end;
} }
*org_info=maria_open(filename,O_RDWR, *org_info= maria_open(filename,O_RDWR,
(param->testflag & T_WAIT_FOREVER) ? HA_OPEN_WAIT_IF_LOCKED : (HA_OPEN_FOR_REPAIR |
(param->testflag & T_DESCRIPT) ? HA_OPEN_IGNORE_IF_LOCKED : ((param->testflag & T_WAIT_FOREVER) ?
HA_OPEN_ABORT_IF_LOCKED); HA_OPEN_WAIT_IF_LOCKED :
(param->testflag & T_DESCRIPT) ?
HA_OPEN_IGNORE_IF_LOCKED :
HA_OPEN_ABORT_IF_LOCKED)));
if (!*org_info) if (!*org_info)
{ {
_ma_check_print_error(param, _ma_check_print_error(param,
...@@ -6143,7 +6140,11 @@ read_next_page: ...@@ -6143,7 +6140,11 @@ read_next_page:
sort_info->page++; /* In case of errors */ sort_info->page++; /* In case of errors */
page++; page++;
if (!(page % share->bitmap.pages_covered)) if (!(page % share->bitmap.pages_covered))
page++; /* Skip bitmap */ {
/* Skip bitmap */
page++;
sort_info->page++;
}
if ((my_off_t) (page + 1) * share->block_size > sort_info->filelength) if ((my_off_t) (page + 1) * share->block_size > sort_info->filelength)
DBUG_RETURN(HA_ERR_END_OF_FILE); DBUG_RETURN(HA_ERR_END_OF_FILE);
if (!(pagecache_read(share->pagecache, if (!(pagecache_read(share->pagecache,
......
...@@ -97,15 +97,18 @@ int maria_create(const char *name, enum data_file_type datafile_type, ...@@ -97,15 +97,18 @@ int maria_create(const char *name, enum data_file_type datafile_type,
{ {
org_datafile_type= ci->org_data_file_type; org_datafile_type= ci->org_data_file_type;
if (!(ci->old_options & HA_OPTION_TEMP_COMPRESS_RECORD)) if (!(ci->old_options & HA_OPTION_TEMP_COMPRESS_RECORD))
options=ci->old_options & options= (ci->old_options &
(HA_OPTION_COMPRESS_RECORD | HA_OPTION_PACK_RECORD | (HA_OPTION_COMPRESS_RECORD | HA_OPTION_PACK_RECORD |
HA_OPTION_READ_ONLY_DATA | HA_OPTION_CHECKSUM | HA_OPTION_READ_ONLY_DATA | HA_OPTION_CHECKSUM |
HA_OPTION_TMP_TABLE | HA_OPTION_DELAY_KEY_WRITE); HA_OPTION_TMP_TABLE | HA_OPTION_DELAY_KEY_WRITE |
HA_OPTION_LONG_BLOB_PTR | HA_OPTION_PAGE_CHECKSUM));
else else
{ {
/* Uncompressing rows */ /* Uncompressing rows */
options=ci->old_options & options= (ci->old_options &
(HA_OPTION_CHECKSUM | HA_OPTION_TMP_TABLE | HA_OPTION_DELAY_KEY_WRITE); (HA_OPTION_CHECKSUM | HA_OPTION_TMP_TABLE |
HA_OPTION_DELAY_KEY_WRITE | HA_OPTION_LONG_BLOB_PTR |
HA_OPTION_PAGE_CHECKSUM));
} }
} }
...@@ -257,31 +260,6 @@ int maria_create(const char *name, enum data_file_type datafile_type, ...@@ -257,31 +260,6 @@ int maria_create(const char *name, enum data_file_type datafile_type,
else else
min_pack_length+= 5; /* Min row overhead */ min_pack_length+= 5; /* Min row overhead */
if ((packed & 7) == 1)
{
/*
Not optimal packing, try to remove a 1 uchar length zero-field as
this will get same record length, but smaller pack overhead
*/
while (column != columndef)
{
column--;
if (column->type == (int) FIELD_SKIP_ZERO && column->length == 1)
{
/*
NOTE1: here we change a field type FIELD_SKIP_ZERO ->
FIELD_NORMAL
*/
column->type=(int) FIELD_NORMAL;
column->empty_pos= 0;
column->empty_bit= 0;
packed--;
min_pack_length++;
break;
}
}
}
if (flags & HA_CREATE_TMP_TABLE) if (flags & HA_CREATE_TMP_TABLE)
{ {
options|= HA_OPTION_TMP_TABLE; options|= HA_OPTION_TMP_TABLE;
...@@ -641,7 +619,9 @@ int maria_create(const char *name, enum data_file_type datafile_type, ...@@ -641,7 +619,9 @@ int maria_create(const char *name, enum data_file_type datafile_type,
if (length > max_key_length) if (length > max_key_length)
max_key_length= length; max_key_length= length;
tot_length+= ((max_rows/(ulong) (((uint) maria_block_size-5)/ tot_length+= ((max_rows/(ulong) (((uint) maria_block_size -
MAX_KEYPAGE_HEADER_SIZE -
KEYPAGE_CHECKSUM_SIZE)/
(length*2))) * (length*2))) *
maria_block_size); maria_block_size);
} }
...@@ -652,7 +632,9 @@ int maria_create(const char *name, enum data_file_type datafile_type, ...@@ -652,7 +632,9 @@ int maria_create(const char *name, enum data_file_type datafile_type,
uniquedef->key=keys+i; uniquedef->key=keys+i;
unique_key_parts+=uniquedef->keysegs; unique_key_parts+=uniquedef->keysegs;
share.state.key_root[keys+i]= HA_OFFSET_ERROR; share.state.key_root[keys+i]= HA_OFFSET_ERROR;
tot_length+= (max_rows/(ulong) (((uint) maria_block_size-5)/ tot_length+= (max_rows/(ulong) (((uint) maria_block_size -
MAX_KEYPAGE_HEADER_SIZE -
KEYPAGE_CHECKSUM_SIZE) /
((MARIA_UNIQUE_HASH_LENGTH + pointer)*2)))* ((MARIA_UNIQUE_HASH_LENGTH + pointer)*2)))*
(ulong) maria_block_size; (ulong) maria_block_size;
} }
...@@ -704,12 +686,16 @@ int maria_create(const char *name, enum data_file_type datafile_type, ...@@ -704,12 +686,16 @@ int maria_create(const char *name, enum data_file_type datafile_type,
share.base.rec_reflength=pointer; share.base.rec_reflength=pointer;
share.base.block_size= maria_block_size; share.base.block_size= maria_block_size;
/* Get estimate for index file length (this may be wrong for FT keys) */ /*
Get estimate for index file length (this may be wrong for FT keys)
This is used for pointers to other key pages.
*/
tmp= (tot_length + maria_block_size * keys * tmp= (tot_length + maria_block_size * keys *
MARIA_INDEX_BLOCK_MARGIN) / maria_block_size; MARIA_INDEX_BLOCK_MARGIN) / maria_block_size;
/* /*
use maximum of key_file_length we calculated and key_file_length value we use maximum of key_file_length we calculated and key_file_length value we
got from MYI file header (see also mariapack.c:save_state) got from MAI file header (see also mariapack.c:save_state)
*/ */
share.base.key_reflength= share.base.key_reflength=
maria_get_pointer_length(max(ci->key_file_length,tmp),3); maria_get_pointer_length(max(ci->key_file_length,tmp),3);
......
...@@ -71,6 +71,8 @@ int maria_delete(MARIA_HA *info,const uchar *record) ...@@ -71,6 +71,8 @@ int maria_delete(MARIA_HA *info,const uchar *record)
if (_ma_mark_file_changed(info)) if (_ma_mark_file_changed(info))
goto err; goto err;
/* Ensure we don't change the autoincrement value */
info->last_auto_increment= ~(ulonglong) 0;
/* Remove all keys from the index file */ /* Remove all keys from the index file */
old_key= info->lastkey2; old_key= info->lastkey2;
...@@ -212,6 +214,11 @@ int _ma_ck_delete(register MARIA_HA *info, uint keynr, uchar *key, ...@@ -212,6 +214,11 @@ int _ma_ck_delete(register MARIA_HA *info, uint keynr, uchar *key,
msg.root= &share->state.key_root[keynr]; msg.root= &share->state.key_root[keynr];
msg.value= new_root; msg.value= new_root;
/*
set autoincrement to 1 if this is an auto_increment key
This is only used if we are now in a rollback of a duplicate key
*/
msg.auto_increment= share->base.auto_key == keynr + 1;
if (translog_write_record(&lsn, log_type, if (translog_write_record(&lsn, log_type,
info->trn, info, info->trn, info,
......
...@@ -159,10 +159,6 @@ my_bool write_hook_for_clr_end(enum translog_record_type type ...@@ -159,10 +159,6 @@ my_bool write_hook_for_clr_end(enum translog_record_type type
case LOGREC_UNDO_ROW_INSERT: case LOGREC_UNDO_ROW_INSERT:
share->state.state.records--; share->state.state.records--;
share->state.state.checksum+= msg->checksum_delta; share->state.state.checksum+= msg->checksum_delta;
/* Restore auto increment if no one has changed it in between */
if (share->last_auto_increment == tbl_info->last_auto_increment)
share->state.auto_increment= tbl_info->last_auto_increment;
break;
break; break;
case LOGREC_UNDO_ROW_UPDATE: case LOGREC_UNDO_ROW_UPDATE:
share->state.state.checksum+= msg->checksum_delta; share->state.state.checksum+= msg->checksum_delta;
...@@ -212,7 +208,7 @@ my_bool write_hook_for_undo_key(enum translog_record_type type, ...@@ -212,7 +208,7 @@ my_bool write_hook_for_undo_key(enum translog_record_type type,
/** /**
Upates "auto_increment" and calls the generic UNDO_KEY hook Updates "auto_increment" and calls the generic UNDO_KEY hook
@return Operation status, always 0 (success) @return Operation status, always 0 (success)
*/ */
...@@ -264,6 +260,32 @@ my_bool write_hook_for_undo_key_insert(enum translog_record_type type, ...@@ -264,6 +260,32 @@ my_bool write_hook_for_undo_key_insert(enum translog_record_type type,
} }
/**
@brief Updates "share->auto_increment" in case of abort and calls
generic UNDO_KEY hook
@return Operation status, always 0 (success)
*/
my_bool write_hook_for_undo_key_delete(enum translog_record_type type,
TRN *trn, MARIA_HA *tbl_info,
LSN *lsn, void *hook_arg)
{
struct st_msg_to_write_hook_for_undo_key *msg=
(struct st_msg_to_write_hook_for_undo_key *) hook_arg;
MARIA_SHARE *share= tbl_info->s;
if (msg->auto_increment > 0) /* If auto increment key */
{
/* Restore auto increment if no one has changed it in between */
if (share->last_auto_increment == tbl_info->last_auto_increment &&
tbl_info->last_auto_increment != ~(ulonglong) 0)
share->state.auto_increment= tbl_info->last_auto_increment;
}
return write_hook_for_undo_key(type, trn, tbl_info, lsn, hook_arg);
}
/***************************************************************************** /*****************************************************************************
Functions for logging of key page changes Functions for logging of key page changes
*****************************************************************************/ *****************************************************************************/
......
...@@ -55,6 +55,9 @@ extern my_bool write_hook_for_undo_key(enum translog_record_type type, ...@@ -55,6 +55,9 @@ extern my_bool write_hook_for_undo_key(enum translog_record_type type,
extern my_bool write_hook_for_undo_key_insert(enum translog_record_type type, extern my_bool write_hook_for_undo_key_insert(enum translog_record_type type,
TRN *trn, MARIA_HA *tbl_info, TRN *trn, MARIA_HA *tbl_info,
LSN *lsn, void *hook_arg); LSN *lsn, void *hook_arg);
extern my_bool write_hook_for_undo_key_delete(enum translog_record_type type,
TRN *trn, MARIA_HA *tbl_info,
LSN *lsn, void *hook_arg);
void _ma_unpin_all_pages(MARIA_HA *info, LSN undo_lsn); void _ma_unpin_all_pages(MARIA_HA *info, LSN undo_lsn);
my_bool _ma_log_prefix(MARIA_HA *info, my_off_t page, my_bool _ma_log_prefix(MARIA_HA *info, my_off_t page,
......
...@@ -543,13 +543,13 @@ static LOG_DESC INIT_LOGREC_UNDO_KEY_INSERT_WITH_ROOT= ...@@ -543,13 +543,13 @@ static LOG_DESC INIT_LOGREC_UNDO_KEY_INSERT_WITH_ROOT=
static LOG_DESC INIT_LOGREC_UNDO_KEY_DELETE= static LOG_DESC INIT_LOGREC_UNDO_KEY_DELETE=
{LOGRECTYPE_VARIABLE_LENGTH, 0, {LOGRECTYPE_VARIABLE_LENGTH, 0,
LSN_STORE_SIZE + FILEID_STORE_SIZE + KEY_NR_STORE_SIZE, LSN_STORE_SIZE + FILEID_STORE_SIZE + KEY_NR_STORE_SIZE,
NULL, write_hook_for_undo_key, NULL, 1, NULL, write_hook_for_undo_key_delete, NULL, 1,
"undo_key_delete", LOGREC_LAST_IN_GROUP, NULL, NULL}; "undo_key_delete", LOGREC_LAST_IN_GROUP, NULL, NULL};
static LOG_DESC INIT_LOGREC_UNDO_KEY_DELETE_WITH_ROOT= static LOG_DESC INIT_LOGREC_UNDO_KEY_DELETE_WITH_ROOT=
{LOGRECTYPE_VARIABLE_LENGTH, 0, {LOGRECTYPE_VARIABLE_LENGTH, 0,
LSN_STORE_SIZE + FILEID_STORE_SIZE + KEY_NR_STORE_SIZE + PAGE_STORE_SIZE, LSN_STORE_SIZE + FILEID_STORE_SIZE + KEY_NR_STORE_SIZE + PAGE_STORE_SIZE,
NULL, write_hook_for_undo_key, NULL, 1, NULL, write_hook_for_undo_key_delete, NULL, 1,
"undo_key_delete_with_root", LOGREC_LAST_IN_GROUP, NULL, NULL}; "undo_key_delete_with_root", LOGREC_LAST_IN_GROUP, NULL, NULL};
static LOG_DESC INIT_LOGREC_PREPARE= static LOG_DESC INIT_LOGREC_PREPARE=
......
...@@ -449,7 +449,7 @@ MARIA_HA *maria_open(const char *name, int mode, uint open_flags) ...@@ -449,7 +449,7 @@ MARIA_HA *maria_open(const char *name, int mode, uint open_flags)
(ulonglong) 1 << (share->base.rec_reflength*8))-1); (ulonglong) 1 << (share->base.rec_reflength*8))-1);
max_key_file_length= max_key_file_length=
_ma_safe_mul(MARIA_MIN_KEY_BLOCK_LENGTH, _ma_safe_mul(maria_block_size,
((ulonglong) 1 << (share->base.key_reflength*8))-1); ((ulonglong) 1 << (share->base.key_reflength*8))-1);
#if SIZEOF_OFF_T == 4 #if SIZEOF_OFF_T == 4
set_if_smaller(max_data_file_length, INT_MAX32); set_if_smaller(max_data_file_length, INT_MAX32);
......
...@@ -101,7 +101,7 @@ int _ma_write_keypage(register MARIA_HA *info, ...@@ -101,7 +101,7 @@ int _ma_write_keypage(register MARIA_HA *info,
_ma_get_used_and_nod(share, buff, page_length, nod); _ma_get_used_and_nod(share, buff, page_length, nod);
if (pos < share->base.keystart || if (pos < share->base.keystart ||
pos+block_size > info->state->key_file_length || pos+block_size > info->state->key_file_length ||
(pos & (MARIA_MIN_KEY_BLOCK_LENGTH-1))) (pos & (maria_block_size-1)))
{ {
DBUG_PRINT("error",("Trying to write inside key status region: " DBUG_PRINT("error",("Trying to write inside key status region: "
"key_start: %lu length: %lu page: %lu", "key_start: %lu length: %lu page: %lu",
...@@ -182,7 +182,7 @@ int _ma_write_keypage(register MARIA_HA *info, ...@@ -182,7 +182,7 @@ int _ma_write_keypage(register MARIA_HA *info,
int _ma_dispose(register MARIA_HA *info, my_off_t pos, my_bool page_not_read) int _ma_dispose(register MARIA_HA *info, my_off_t pos, my_bool page_not_read)
{ {
my_off_t old_link; my_off_t old_link;
uchar buff[MAX_KEYPAGE_HEADER_SIZE+8]; uchar buff[MAX_KEYPAGE_HEADER_SIZE+ 8 + 2];
ulonglong page_no; ulonglong page_no;
MARIA_SHARE *share= info->s; MARIA_SHARE *share= info->s;
MARIA_PINNED_PAGE page_link; MARIA_PINNED_PAGE page_link;
......
...@@ -590,11 +590,11 @@ my_off_t _ma_kpos(uint nod_flag, uchar *after_key) ...@@ -590,11 +590,11 @@ my_off_t _ma_kpos(uint nod_flag, uchar *after_key)
switch (nod_flag) { switch (nod_flag) {
#if SIZEOF_OFF_T > 4 #if SIZEOF_OFF_T > 4
case 7: case 7:
return mi_uint7korr(after_key)*MARIA_MIN_KEY_BLOCK_LENGTH; return mi_uint7korr(after_key)*maria_block_size;
case 6: case 6:
return mi_uint6korr(after_key)*MARIA_MIN_KEY_BLOCK_LENGTH; return mi_uint6korr(after_key)*maria_block_size;
case 5: case 5:
return mi_uint5korr(after_key)*MARIA_MIN_KEY_BLOCK_LENGTH; return mi_uint5korr(after_key)*maria_block_size;
#else #else
case 7: case 7:
after_key++; after_key++;
...@@ -604,13 +604,13 @@ my_off_t _ma_kpos(uint nod_flag, uchar *after_key) ...@@ -604,13 +604,13 @@ my_off_t _ma_kpos(uint nod_flag, uchar *after_key)
after_key++; after_key++;
#endif #endif
case 4: case 4:
return ((my_off_t) mi_uint4korr(after_key))*MARIA_MIN_KEY_BLOCK_LENGTH; return ((my_off_t) mi_uint4korr(after_key))*maria_block_size;
case 3: case 3:
return ((my_off_t) mi_uint3korr(after_key))*MARIA_MIN_KEY_BLOCK_LENGTH; return ((my_off_t) mi_uint3korr(after_key))*maria_block_size;
case 2: case 2:
return (my_off_t) (mi_uint2korr(after_key)*MARIA_MIN_KEY_BLOCK_LENGTH); return (my_off_t) (mi_uint2korr(after_key)*maria_block_size);
case 1: case 1:
return (uint) (*after_key)*MARIA_MIN_KEY_BLOCK_LENGTH; return (uint) (*after_key)*maria_block_size;
case 0: /* At leaf page */ case 0: /* At leaf page */
default: /* Impossible */ default: /* Impossible */
return(HA_OFFSET_ERROR); return(HA_OFFSET_ERROR);
...@@ -622,7 +622,7 @@ my_off_t _ma_kpos(uint nod_flag, uchar *after_key) ...@@ -622,7 +622,7 @@ my_off_t _ma_kpos(uint nod_flag, uchar *after_key)
void _ma_kpointer(register MARIA_HA *info, register uchar *buff, my_off_t pos) void _ma_kpointer(register MARIA_HA *info, register uchar *buff, my_off_t pos)
{ {
pos/=MARIA_MIN_KEY_BLOCK_LENGTH; pos/=maria_block_size;
switch (info->s->base.key_reflength) { switch (info->s->base.key_reflength) {
#if SIZEOF_OFF_T > 4 #if SIZEOF_OFF_T > 4
case 7: mi_int7store(buff,pos); break; case 7: mi_int7store(buff,pos); break;
......
...@@ -76,6 +76,9 @@ int maria_update(register MARIA_HA *info, const uchar *oldrec, uchar *newrec) ...@@ -76,6 +76,9 @@ int maria_update(register MARIA_HA *info, const uchar *oldrec, uchar *newrec)
goto err_end; goto err_end;
} }
/* Ensure we don't try to restore auto_increment if it doesn't change */
info->last_auto_increment= ~(ulonglong) 0;
/* Check which keys changed from the original row */ /* Check which keys changed from the original row */
new_key= info->lastkey2; new_key= info->lastkey2;
......
...@@ -138,6 +138,9 @@ int maria_write(MARIA_HA *info, uchar *record) ...@@ -138,6 +138,9 @@ int maria_write(MARIA_HA *info, uchar *record)
goto err2; goto err2;
} }
/* Ensure we don't try to restore auto_increment if it doesn't change */
info->last_auto_increment= ~(ulonglong) 0;
if ((info->opt_flag & OPT_NO_ROWS)) if ((info->opt_flag & OPT_NO_ROWS))
filepos= HA_OFFSET_ERROR; filepos= HA_OFFSET_ERROR;
else else
......
...@@ -332,7 +332,7 @@ static struct my_option my_long_options[] = ...@@ -332,7 +332,7 @@ static struct my_option my_long_options[] =
{ "page_buffer_size", OPT_PAGE_BUFFER_SIZE, { "page_buffer_size", OPT_PAGE_BUFFER_SIZE,
"Size of page buffer. Used by --safe-repair", "Size of page buffer. Used by --safe-repair",
(uchar**) &check_param.use_buffers, (uchar**) &check_param.use_buffers, 0, (uchar**) &check_param.use_buffers, (uchar**) &check_param.use_buffers, 0,
GET_ULONG, REQUIRED_ARG, (long) USE_BUFFER_INIT, (long) USE_BUFFER_INIT, GET_ULONG, REQUIRED_ARG, (long) USE_BUFFER_INIT, 1024L*1024L,
(long) ~0L, (long) MALLOC_OVERHEAD, (long) IO_SIZE, 0}, (long) ~0L, (long) MALLOC_OVERHEAD, (long) IO_SIZE, 0},
{ "read_buffer_size", OPT_READ_BUFFER_SIZE, "", { "read_buffer_size", OPT_READ_BUFFER_SIZE, "",
(uchar**) &check_param.read_buffer_length, (uchar**) &check_param.read_buffer_length,
...@@ -1466,14 +1466,14 @@ static void descript(HA_CHECK *param, register MARIA_HA *info, char *name) ...@@ -1466,14 +1466,14 @@ static void descript(HA_CHECK *param, register MARIA_HA *info, char *name)
pos=strmov(pos,null_txt); pos=strmov(pos,null_txt);
*pos=0; *pos=0;
printf("%-4d%-6ld%-3d %-8s%-21s", printf("%-4d%-6ld%-3d %-8s%-23s",
key+1,(long) keyseg->start+1,keyseg->length,text,buff); key+1,(long) keyseg->start+1,keyseg->length,text,buff);
if (share->state.key_root[key] != HA_OFFSET_ERROR) if (share->state.key_root[key] != HA_OFFSET_ERROR)
llstr(share->state.key_root[key],buff); llstr(share->state.key_root[key],buff);
else else
buff[0]=0; buff[0]=0;
if (param->testflag & T_VERBOSE) if (param->testflag & T_VERBOSE)
printf("%11.0f %12s %10d", printf("%9.0f %12s %10d",
share->state.rec_per_key_part[keyseg_nr++], share->state.rec_per_key_part[keyseg_nr++],
buff,keyinfo->block_length); buff,keyinfo->block_length);
VOID(putchar('\n')); VOID(putchar('\n'));
......
...@@ -65,7 +65,7 @@ typedef struct st_maria_status_info ...@@ -65,7 +65,7 @@ typedef struct st_maria_status_info
typedef struct st_maria_state_info typedef struct st_maria_state_info
{ {
struct struct
{ /* Fileheader */ { /* Fileheader (24 bytes) */
uchar file_version[4]; uchar file_version[4];
uchar options[2]; uchar options[2];
uchar header_length[2]; uchar header_length[2];
...@@ -285,6 +285,10 @@ typedef struct st_maria_share ...@@ -285,6 +285,10 @@ typedef struct st_maria_share
uchar *file_map; /* mem-map of file if possible */ uchar *file_map; /* mem-map of file if possible */
PAGECACHE *pagecache; /* ref to the current key cache */ PAGECACHE *pagecache; /* ref to the current key cache */
MARIA_DECODE_TREE *decode_trees; MARIA_DECODE_TREE *decode_trees;
/*
Previous auto-increment value. Used to verify if we can restore the
auto-increment counter if we have to abort an insert (duplicate key).
*/
ulonglong last_auto_increment; ulonglong last_auto_increment;
uint16 *decode_tables; uint16 *decode_tables;
uint16 id; /**< 2-byte id by which log records refer to the table */ uint16 id; /**< 2-byte id by which log records refer to the table */
...@@ -485,7 +489,7 @@ struct st_maria_handler ...@@ -485,7 +489,7 @@ struct st_maria_handler
uint32 int_keytree_version; /* -""- */ uint32 int_keytree_version; /* -""- */
int (*read_record)(MARIA_HA *, uchar*, MARIA_RECORD_POS); int (*read_record)(MARIA_HA *, uchar*, MARIA_RECORD_POS);
invalidator_by_filename invalidator; /* query cache invalidator */ invalidator_by_filename invalidator; /* query cache invalidator */
ulonglong last_auto_increment; ulonglong last_auto_increment; /* auto value at start of statement */
ulong this_unique; /* uniq filenumber or thread */ ulong this_unique; /* uniq filenumber or thread */
ulong last_unique; /* last unique number */ ulong last_unique; /* last unique number */
ulong this_loop; /* counter for this open */ ulong this_loop; /* counter for this open */
......
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