mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +03:00
Fix for BUG#20524 "auto_increment_* not observed when inserting
a too large value": the bug was that if MySQL generated a value for an auto_increment column, based on auto_increment_* variables, and this value was bigger than the column's max possible value, then that max possible value was inserted (after issuing a warning). But this didn't honour auto_increment_* variables (and so could cause conflicts in a master-master replication where one master is supposed to generated only even numbers, and the other only odd numbers), so now we "round down" this max possible value to honour auto_increment_* variables, before inserting it. mysql-test/r/rpl_auto_increment.result: result update. Before the fix, the result was that master inserted 127 in t1 (which didn't honour auto_increment_* variables!), instead of failing with "duplicate key 125" like now. mysql-test/t/rpl_auto_increment.test: Test for BUG#20524 "auto_increment_* not observed when inserting a too large value". We also check the pathological case (table t2) where it's impossible to "round down". The fixer of BUG#20573 will be able to use table t2 for testing his fix. sql/handler.cc: If handler::update_auto_increment() generates a value larger than the field's max possible value, we used to simply insert this max possible value (after pushing a warning). Now we "round down" this max possible value to honour auto_increment_* variables (if at all possible), before trying the insertion.
This commit is contained in:
@ -183,3 +183,47 @@ a
|
|||||||
32
|
32
|
||||||
42
|
42
|
||||||
drop table t1;
|
drop table t1;
|
||||||
|
create table t1 (a tinyint not null auto_increment primary key) engine=myisam;
|
||||||
|
insert into t1 values(103);
|
||||||
|
set auto_increment_increment=11;
|
||||||
|
set auto_increment_offset=4;
|
||||||
|
insert into t1 values(null);
|
||||||
|
insert into t1 values(null);
|
||||||
|
insert into t1 values(null);
|
||||||
|
ERROR 23000: Duplicate entry '125' for key 1
|
||||||
|
select a, mod(a-@@auto_increment_offset,@@auto_increment_increment) from t1 order by a;
|
||||||
|
a mod(a-@@auto_increment_offset,@@auto_increment_increment)
|
||||||
|
103 0
|
||||||
|
114 0
|
||||||
|
125 0
|
||||||
|
create table t2 (a tinyint unsigned not null auto_increment primary key) engine=myisam;
|
||||||
|
set auto_increment_increment=10;
|
||||||
|
set auto_increment_offset=1;
|
||||||
|
set insert_id=1000;
|
||||||
|
insert into t2 values(null);
|
||||||
|
Warnings:
|
||||||
|
Warning 1264 Out of range value adjusted for column 'a' at row 1
|
||||||
|
select a, mod(a-@@auto_increment_offset,@@auto_increment_increment) from t2 order by a;
|
||||||
|
a mod(a-@@auto_increment_offset,@@auto_increment_increment)
|
||||||
|
251 0
|
||||||
|
create table t3 like t1;
|
||||||
|
set auto_increment_increment=1000;
|
||||||
|
set auto_increment_offset=700;
|
||||||
|
insert into t3 values(null);
|
||||||
|
Warnings:
|
||||||
|
Warning 1264 Out of range value adjusted for column 'a' at row 1
|
||||||
|
select * from t3 order by a;
|
||||||
|
a
|
||||||
|
127
|
||||||
|
select * from t1 order by a;
|
||||||
|
a
|
||||||
|
103
|
||||||
|
114
|
||||||
|
125
|
||||||
|
select * from t2 order by a;
|
||||||
|
a
|
||||||
|
251
|
||||||
|
select * from t3 order by a;
|
||||||
|
a
|
||||||
|
127
|
||||||
|
drop table t1,t2,t3;
|
||||||
|
@ -96,9 +96,47 @@ select * from t1;
|
|||||||
|
|
||||||
sync_slave_with_master;
|
sync_slave_with_master;
|
||||||
select * from t1;
|
select * from t1;
|
||||||
|
|
||||||
|
# Test for BUG#20524 "auto_increment_* not observed when inserting
|
||||||
|
# a too large value". When an autogenerated value was bigger than the
|
||||||
|
# maximum possible value of the field, it was truncated to that max
|
||||||
|
# possible value, without being "rounded down" to still honour
|
||||||
|
# auto_increment_* variables.
|
||||||
|
|
||||||
|
connection master;
|
||||||
|
drop table t1;
|
||||||
|
create table t1 (a tinyint not null auto_increment primary key) engine=myisam;
|
||||||
|
insert into t1 values(103);
|
||||||
|
set auto_increment_increment=11;
|
||||||
|
set auto_increment_offset=4;
|
||||||
|
insert into t1 values(null);
|
||||||
|
insert into t1 values(null);
|
||||||
|
--error 1062
|
||||||
|
insert into t1 values(null);
|
||||||
|
select a, mod(a-@@auto_increment_offset,@@auto_increment_increment) from t1 order by a;
|
||||||
|
|
||||||
|
# same but with a larger value
|
||||||
|
create table t2 (a tinyint unsigned not null auto_increment primary key) engine=myisam;
|
||||||
|
set auto_increment_increment=10;
|
||||||
|
set auto_increment_offset=1;
|
||||||
|
set insert_id=1000;
|
||||||
|
insert into t2 values(null);
|
||||||
|
select a, mod(a-@@auto_increment_offset,@@auto_increment_increment) from t2 order by a;
|
||||||
|
|
||||||
|
# An offset so big that even first value does not fit
|
||||||
|
create table t3 like t1;
|
||||||
|
set auto_increment_increment=1000;
|
||||||
|
set auto_increment_offset=700;
|
||||||
|
insert into t3 values(null);
|
||||||
|
select * from t3 order by a;
|
||||||
|
sync_slave_with_master;
|
||||||
|
select * from t1 order by a;
|
||||||
|
select * from t2 order by a;
|
||||||
|
select * from t3 order by a;
|
||||||
|
|
||||||
connection master;
|
connection master;
|
||||||
|
|
||||||
drop table t1;
|
drop table t1,t2,t3;
|
||||||
|
|
||||||
# End cleanup
|
# End cleanup
|
||||||
sync_slave_with_master;
|
sync_slave_with_master;
|
||||||
|
@ -1471,6 +1471,46 @@ next_insert_id(ulonglong nr,struct system_variables *variables)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Computes the largest number X:
|
||||||
|
- smaller than or equal to "nr"
|
||||||
|
- of the form: auto_increment_offset + N * auto_increment_increment
|
||||||
|
where N>=0.
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
prev_insert_id
|
||||||
|
nr Number to "round down"
|
||||||
|
variables variables struct containing auto_increment_increment and
|
||||||
|
auto_increment_offset
|
||||||
|
|
||||||
|
RETURN
|
||||||
|
The number X if it exists, "nr" otherwise.
|
||||||
|
*/
|
||||||
|
|
||||||
|
inline ulonglong
|
||||||
|
prev_insert_id(ulonglong nr, struct system_variables *variables)
|
||||||
|
{
|
||||||
|
if (unlikely(nr < variables->auto_increment_offset))
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
There's nothing good we can do here. That is a pathological case, where
|
||||||
|
the offset is larger than the column's max possible value, i.e. not even
|
||||||
|
the first sequence value may be inserted. User will receive warning.
|
||||||
|
*/
|
||||||
|
DBUG_PRINT("info",("auto_increment: nr: %lu cannot honour "
|
||||||
|
"auto_increment_offset: %lu",
|
||||||
|
nr, variables->auto_increment_offset));
|
||||||
|
return nr;
|
||||||
|
}
|
||||||
|
if (variables->auto_increment_increment == 1)
|
||||||
|
return nr; // optimization of the formula below
|
||||||
|
nr= (((nr - variables->auto_increment_offset)) /
|
||||||
|
(ulonglong) variables->auto_increment_increment);
|
||||||
|
return (nr * (ulonglong) variables->auto_increment_increment +
|
||||||
|
variables->auto_increment_offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Update the auto_increment field if necessary
|
Update the auto_increment field if necessary
|
||||||
|
|
||||||
@ -1580,10 +1620,19 @@ bool handler::update_auto_increment()
|
|||||||
/* Mark that we should clear next_insert_id before next stmt */
|
/* Mark that we should clear next_insert_id before next stmt */
|
||||||
thd->clear_next_insert_id= 1;
|
thd->clear_next_insert_id= 1;
|
||||||
|
|
||||||
if (!table->next_number_field->store((longlong) nr, TRUE))
|
if (likely(!table->next_number_field->store((longlong) nr, TRUE)))
|
||||||
thd->insert_id((ulonglong) nr);
|
thd->insert_id((ulonglong) nr);
|
||||||
else
|
else
|
||||||
thd->insert_id(table->next_number_field->val_int());
|
{
|
||||||
|
/*
|
||||||
|
overflow of the field; we'll use the max value, however we try to
|
||||||
|
decrease it to honour auto_increment_* variables:
|
||||||
|
*/
|
||||||
|
nr= prev_insert_id(table->next_number_field->val_int(), variables);
|
||||||
|
thd->insert_id(nr);
|
||||||
|
if (unlikely(table->next_number_field->store((longlong) nr, TRUE)))
|
||||||
|
thd->insert_id(nr= table->next_number_field->val_int());
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
We can't set next_insert_id if the auto-increment key is not the
|
We can't set next_insert_id if the auto-increment key is not the
|
||||||
|
Reference in New Issue
Block a user