Commit 6345502b authored by ingo@mysql.com's avatar ingo@mysql.com

Bug#19604 - CHECK TABLE with concurrent INSERT can reset auto_increment

CHECK TABLE did temporarily clear the auto_increment value.
It runs with a read lock, allowing other readers and
conurrent INSERTs. The latter could grab the wrong value
in this moment.

CHECK TABLE does no longer modify the auto_increment value.
Not even for a short moment.
parent 91031fc2
...@@ -453,25 +453,24 @@ int chk_key(MI_CHECK *param, register MI_INFO *info) ...@@ -453,25 +453,24 @@ int chk_key(MI_CHECK *param, register MI_INFO *info)
if ((uint) share->base.auto_key -1 == key) if ((uint) share->base.auto_key -1 == key)
{ {
/* Check that auto_increment key is bigger than max key value */ /* Check that auto_increment key is bigger than max key value */
ulonglong save_auto_value=info->s->state.auto_increment; ulonglong auto_increment;
info->s->state.auto_increment=0;
info->lastinx=key; info->lastinx=key;
_mi_read_key_record(info, 0L, info->rec_buff); _mi_read_key_record(info, 0L, info->rec_buff);
update_auto_increment(info, info->rec_buff); auto_increment= retrieve_auto_increment(info, info->rec_buff);
if (info->s->state.auto_increment > save_auto_value) if (auto_increment > info->s->state.auto_increment)
{ {
mi_check_print_warning(param, mi_check_print_warning(param, "Auto-increment value: %s is smaller "
"Auto-increment value: %s is smaller than max used value: %s", "than max used value: %s",
llstr(save_auto_value,buff2), llstr(info->s->state.auto_increment,buff2),
llstr(info->s->state.auto_increment, buff)); llstr(auto_increment, buff));
} }
if (param->testflag & T_AUTO_INC) if (param->testflag & T_AUTO_INC)
{ {
set_if_bigger(info->s->state.auto_increment, set_if_bigger(info->s->state.auto_increment,
param->auto_increment_value); auto_increment);
set_if_bigger(info->s->state.auto_increment,
param->auto_increment_value);
} }
else
info->s->state.auto_increment=save_auto_value;
/* Check that there isn't a row with auto_increment = 0 in the table */ /* Check that there isn't a row with auto_increment = 0 in the table */
mi_extra(info,HA_EXTRA_KEYREAD,0); mi_extra(info,HA_EXTRA_KEYREAD,0);
...@@ -481,8 +480,8 @@ int chk_key(MI_CHECK *param, register MI_INFO *info) ...@@ -481,8 +480,8 @@ int chk_key(MI_CHECK *param, register MI_INFO *info)
{ {
/* Don't count this as a real warning, as myisamchk can't correct it */ /* Don't count this as a real warning, as myisamchk can't correct it */
uint save=param->warning_printed; uint save=param->warning_printed;
mi_check_print_warning(param, mi_check_print_warning(param, "Found row where the auto_increment "
"Found row where the auto_increment column has the value 0"); "column has the value 0");
param->warning_printed=save; param->warning_printed=save;
} }
mi_extra(info,HA_EXTRA_NO_KEYREAD,0); mi_extra(info,HA_EXTRA_NO_KEYREAD,0);
...@@ -4099,11 +4098,10 @@ void update_auto_increment_key(MI_CHECK *param, MI_INFO *info, ...@@ -4099,11 +4098,10 @@ void update_auto_increment_key(MI_CHECK *param, MI_INFO *info,
} }
else else
{ {
ulonglong auto_increment= (repair_only ? info->s->state.auto_increment : ulonglong auto_increment= retrieve_auto_increment(info, record);
param->auto_increment_value);
info->s->state.auto_increment=0;
update_auto_increment(info, record);
set_if_bigger(info->s->state.auto_increment,auto_increment); set_if_bigger(info->s->state.auto_increment,auto_increment);
if (!repair_only)
set_if_bigger(info->s->state.auto_increment, param->auto_increment_value);
} }
mi_extra(info,HA_EXTRA_NO_KEYREAD,0); mi_extra(info,HA_EXTRA_NO_KEYREAD,0);
my_free((char*) record, MYF(0)); my_free((char*) record, MYF(0));
......
...@@ -507,22 +507,21 @@ int _mi_read_key_record(MI_INFO *info, my_off_t filepos, byte *buf) ...@@ -507,22 +507,21 @@ int _mi_read_key_record(MI_INFO *info, my_off_t filepos, byte *buf)
return(-1); /* Wrong data to read */ return(-1); /* Wrong data to read */
} }
/* /*
Update auto_increment info Retrieve auto_increment info
SYNOPSIS SYNOPSIS
update_auto_increment() retrieve_auto_increment()
info MyISAM handler info MyISAM handler
record Row to update record Row to update
IMPLEMENTATION IMPLEMENTATION
Only replace the auto_increment value if it is higher than the previous For signed columns we don't retrieve the auto increment value if it's
one. For signed columns we don't update the auto increment value if it's
less than zero. less than zero.
*/ */
void update_auto_increment(MI_INFO *info,const byte *record) ulonglong retrieve_auto_increment(MI_INFO *info,const byte *record)
{ {
ulonglong value= 0; /* Store unsigned values here */ ulonglong value= 0; /* Store unsigned values here */
longlong s_value= 0; /* Store signed values here */ longlong s_value= 0; /* Store signed values here */
...@@ -587,6 +586,5 @@ void update_auto_increment(MI_INFO *info,const byte *record) ...@@ -587,6 +586,5 @@ void update_auto_increment(MI_INFO *info,const byte *record)
and if s_value == 0 then value will contain either s_value or the and if s_value == 0 then value will contain either s_value or the
correct value. correct value.
*/ */
set_if_bigger(info->s->state.auto_increment, return (s_value > 0) ? (ulonglong) s_value : value;
(s_value > 0) ? (ulonglong) s_value : value);
} }
...@@ -164,7 +164,8 @@ int mi_update(register MI_INFO *info, const byte *oldrec, byte *newrec) ...@@ -164,7 +164,8 @@ int mi_update(register MI_INFO *info, const byte *oldrec, byte *newrec)
key_changed|= HA_STATE_CHANGED; /* Must update index file */ key_changed|= HA_STATE_CHANGED; /* Must update index file */
} }
if (auto_key_changed) if (auto_key_changed)
update_auto_increment(info,newrec); set_if_bigger(info->s->state.auto_increment,
retrieve_auto_increment(info, newrec));
if (share->calc_checksum) if (share->calc_checksum)
info->state->checksum+=(info->checksum - old_checksum); info->state->checksum+=(info->checksum - old_checksum);
......
...@@ -149,7 +149,8 @@ int mi_write(MI_INFO *info, byte *record) ...@@ -149,7 +149,8 @@ int mi_write(MI_INFO *info, byte *record)
info->state->checksum+=info->checksum; info->state->checksum+=info->checksum;
} }
if (share->base.auto_key) if (share->base.auto_key)
update_auto_increment(info,record); set_if_bigger(info->s->state.auto_increment,
retrieve_auto_increment(info, record));
info->update= (HA_STATE_CHANGED | HA_STATE_AKTIV | HA_STATE_WRITTEN | info->update= (HA_STATE_CHANGED | HA_STATE_AKTIV | HA_STATE_WRITTEN |
HA_STATE_ROW_CHANGED); HA_STATE_ROW_CHANGED);
info->state->records++; info->state->records++;
......
...@@ -582,7 +582,7 @@ extern uint _mi_pack_key(MI_INFO *info,uint keynr,uchar *key,uchar *old, ...@@ -582,7 +582,7 @@ extern uint _mi_pack_key(MI_INFO *info,uint keynr,uchar *key,uchar *old,
extern int _mi_read_key_record(MI_INFO *info,my_off_t filepos,byte *buf); extern int _mi_read_key_record(MI_INFO *info,my_off_t filepos,byte *buf);
extern int _mi_read_cache(IO_CACHE *info,byte *buff,my_off_t pos, extern int _mi_read_cache(IO_CACHE *info,byte *buff,my_off_t pos,
uint length,int re_read_if_possibly); uint length,int re_read_if_possibly);
extern void update_auto_increment(MI_INFO *info,const byte *record); extern ulonglong retrieve_auto_increment(MI_INFO *info,const byte *record);
extern byte *mi_alloc_rec_buff(MI_INFO *,ulong, byte**); extern byte *mi_alloc_rec_buff(MI_INFO *,ulong, byte**);
#define mi_get_rec_buff_ptr(info,buf) \ #define mi_get_rec_buff_ptr(info,buf) \
......
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