Loading mysql-test/r/rpl_auto_increment.result +44 −0 Original line number Diff line number Diff line Loading @@ -183,3 +183,47 @@ a 32 42 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; mysql-test/r/rpl_insert_id.result +65 −0 Original line number Diff line number Diff line Loading @@ -132,3 +132,68 @@ id last_id drop function bug15728; drop function bug15728_insert; drop table t1, t2; create table t1 (n int primary key auto_increment not null, b int, unique(b)); set sql_log_bin=0; insert into t1 values(null,100); replace into t1 values(null,50),(null,100),(null,150); select * from t1 order by n; n b 2 50 3 100 4 150 truncate table t1; set sql_log_bin=1; insert into t1 values(null,100); select * from t1 order by n; n b 1 100 insert into t1 values(null,200),(null,300); delete from t1 where b <> 100; select * from t1 order by n; n b 1 100 replace into t1 values(null,100),(null,350); select * from t1 order by n; n b 2 100 3 350 select * from t1 order by n; n b 2 100 3 350 insert into t1 values (NULL,400),(3,500),(NULL,600) on duplicate key UPDATE n=1000; select * from t1 order by n; n b 2 100 4 400 1000 350 1001 600 select * from t1 order by n; n b 2 100 4 400 1000 350 1001 600 drop table t1; create table t1 (n int primary key auto_increment not null, b int, unique(b)); insert into t1 values(null,100); select * from t1 order by n; n b 1 100 insert into t1 values(null,200),(null,300); delete from t1 where b <> 100; select * from t1 order by n; n b 1 100 insert into t1 values(null,100),(null,350) on duplicate key update n=2; select * from t1 order by n; n b 2 100 3 350 select * from t1 order by n; n b 2 100 3 350 drop table t1; mysql-test/t/rpl_auto_increment.test +39 −1 Original line number Diff line number Diff line Loading @@ -96,9 +96,47 @@ select * from t1; sync_slave_with_master; select * from t1; connection master; # 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; drop table t1,t2,t3; # End cleanup sync_slave_with_master; mysql-test/t/rpl_insert_id.test +63 −0 Original line number Diff line number Diff line Loading @@ -147,6 +147,69 @@ drop function bug15728; drop function bug15728_insert; drop table t1, t2; # test of BUG#20188 REPLACE or ON DUPLICATE KEY UPDATE in # auto_increment breaks binlog create table t1 (n int primary key auto_increment not null, b int, unique(b)); # First, test that we do not call restore_auto_increment() too early # in write_record(): set sql_log_bin=0; insert into t1 values(null,100); replace into t1 values(null,50),(null,100),(null,150); select * from t1 order by n; truncate table t1; set sql_log_bin=1; insert into t1 values(null,100); select * from t1 order by n; sync_slave_with_master; # make slave's table autoinc counter bigger insert into t1 values(null,200),(null,300); delete from t1 where b <> 100; # check that slave's table content is identical to master select * from t1 order by n; # only the auto_inc counter differs. connection master; replace into t1 values(null,100),(null,350); select * from t1 order by n; sync_slave_with_master; select * from t1 order by n; # Same test as for REPLACE, but for ON DUPLICATE KEY UPDATE # We first check that if we update a row using a value larger than the # table's counter, the counter for next row is bigger than the # after-value of the updated row. connection master; insert into t1 values (NULL,400),(3,500),(NULL,600) on duplicate key UPDATE n=1000; select * from t1 order by n; sync_slave_with_master; select * from t1 order by n; # and now test for the bug: connection master; drop table t1; create table t1 (n int primary key auto_increment not null, b int, unique(b)); insert into t1 values(null,100); select * from t1 order by n; sync_slave_with_master; insert into t1 values(null,200),(null,300); delete from t1 where b <> 100; select * from t1 order by n; connection master; insert into t1 values(null,100),(null,350) on duplicate key update n=2; select * from t1 order by n; sync_slave_with_master; select * from t1 order by n; connection master; drop table t1; # End of 5.0 tests sync_slave_with_master; sql/handler.cc +72 −13 Original line number Diff line number Diff line Loading @@ -1471,6 +1471,66 @@ next_insert_id(ulonglong nr,struct system_variables *variables) } void handler::adjust_next_insert_id_after_explicit_value(ulonglong nr) { /* If we have set THD::next_insert_id previously and plan to insert an explicitely-specified value larger than this, we need to increase THD::next_insert_id to be greater than the explicit value. */ THD *thd= table->in_use; if (thd->clear_next_insert_id && (nr >= thd->next_insert_id)) { if (thd->variables.auto_increment_increment != 1) nr= next_insert_id(nr, &thd->variables); else nr++; thd->next_insert_id= nr; DBUG_PRINT("info",("next_insert_id: %lu", (ulong) nr)); } } /* 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 Loading Loading @@ -1547,17 +1607,7 @@ bool handler::update_auto_increment() /* Clear flag for next row */ /* Mark that we didn't generate a new value **/ auto_increment_column_changed=0; /* Update next_insert_id if we have already generated a value */ if (thd->clear_next_insert_id && nr >= thd->next_insert_id) { if (variables->auto_increment_increment != 1) nr= next_insert_id(nr, variables); else nr++; thd->next_insert_id= nr; DBUG_PRINT("info",("next_insert_id: %lu", (ulong) nr)); } adjust_next_insert_id_after_explicit_value(nr); DBUG_RETURN(0); } if (!(nr= thd->next_insert_id)) Loading @@ -1580,10 +1630,19 @@ bool handler::update_auto_increment() /* Mark that we should clear next_insert_id before next stmt */ 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); 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 Loading Loading
mysql-test/r/rpl_auto_increment.result +44 −0 Original line number Diff line number Diff line Loading @@ -183,3 +183,47 @@ a 32 42 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;
mysql-test/r/rpl_insert_id.result +65 −0 Original line number Diff line number Diff line Loading @@ -132,3 +132,68 @@ id last_id drop function bug15728; drop function bug15728_insert; drop table t1, t2; create table t1 (n int primary key auto_increment not null, b int, unique(b)); set sql_log_bin=0; insert into t1 values(null,100); replace into t1 values(null,50),(null,100),(null,150); select * from t1 order by n; n b 2 50 3 100 4 150 truncate table t1; set sql_log_bin=1; insert into t1 values(null,100); select * from t1 order by n; n b 1 100 insert into t1 values(null,200),(null,300); delete from t1 where b <> 100; select * from t1 order by n; n b 1 100 replace into t1 values(null,100),(null,350); select * from t1 order by n; n b 2 100 3 350 select * from t1 order by n; n b 2 100 3 350 insert into t1 values (NULL,400),(3,500),(NULL,600) on duplicate key UPDATE n=1000; select * from t1 order by n; n b 2 100 4 400 1000 350 1001 600 select * from t1 order by n; n b 2 100 4 400 1000 350 1001 600 drop table t1; create table t1 (n int primary key auto_increment not null, b int, unique(b)); insert into t1 values(null,100); select * from t1 order by n; n b 1 100 insert into t1 values(null,200),(null,300); delete from t1 where b <> 100; select * from t1 order by n; n b 1 100 insert into t1 values(null,100),(null,350) on duplicate key update n=2; select * from t1 order by n; n b 2 100 3 350 select * from t1 order by n; n b 2 100 3 350 drop table t1;
mysql-test/t/rpl_auto_increment.test +39 −1 Original line number Diff line number Diff line Loading @@ -96,9 +96,47 @@ select * from t1; sync_slave_with_master; select * from t1; connection master; # 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; drop table t1,t2,t3; # End cleanup sync_slave_with_master;
mysql-test/t/rpl_insert_id.test +63 −0 Original line number Diff line number Diff line Loading @@ -147,6 +147,69 @@ drop function bug15728; drop function bug15728_insert; drop table t1, t2; # test of BUG#20188 REPLACE or ON DUPLICATE KEY UPDATE in # auto_increment breaks binlog create table t1 (n int primary key auto_increment not null, b int, unique(b)); # First, test that we do not call restore_auto_increment() too early # in write_record(): set sql_log_bin=0; insert into t1 values(null,100); replace into t1 values(null,50),(null,100),(null,150); select * from t1 order by n; truncate table t1; set sql_log_bin=1; insert into t1 values(null,100); select * from t1 order by n; sync_slave_with_master; # make slave's table autoinc counter bigger insert into t1 values(null,200),(null,300); delete from t1 where b <> 100; # check that slave's table content is identical to master select * from t1 order by n; # only the auto_inc counter differs. connection master; replace into t1 values(null,100),(null,350); select * from t1 order by n; sync_slave_with_master; select * from t1 order by n; # Same test as for REPLACE, but for ON DUPLICATE KEY UPDATE # We first check that if we update a row using a value larger than the # table's counter, the counter for next row is bigger than the # after-value of the updated row. connection master; insert into t1 values (NULL,400),(3,500),(NULL,600) on duplicate key UPDATE n=1000; select * from t1 order by n; sync_slave_with_master; select * from t1 order by n; # and now test for the bug: connection master; drop table t1; create table t1 (n int primary key auto_increment not null, b int, unique(b)); insert into t1 values(null,100); select * from t1 order by n; sync_slave_with_master; insert into t1 values(null,200),(null,300); delete from t1 where b <> 100; select * from t1 order by n; connection master; insert into t1 values(null,100),(null,350) on duplicate key update n=2; select * from t1 order by n; sync_slave_with_master; select * from t1 order by n; connection master; drop table t1; # End of 5.0 tests sync_slave_with_master;
sql/handler.cc +72 −13 Original line number Diff line number Diff line Loading @@ -1471,6 +1471,66 @@ next_insert_id(ulonglong nr,struct system_variables *variables) } void handler::adjust_next_insert_id_after_explicit_value(ulonglong nr) { /* If we have set THD::next_insert_id previously and plan to insert an explicitely-specified value larger than this, we need to increase THD::next_insert_id to be greater than the explicit value. */ THD *thd= table->in_use; if (thd->clear_next_insert_id && (nr >= thd->next_insert_id)) { if (thd->variables.auto_increment_increment != 1) nr= next_insert_id(nr, &thd->variables); else nr++; thd->next_insert_id= nr; DBUG_PRINT("info",("next_insert_id: %lu", (ulong) nr)); } } /* 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 Loading Loading @@ -1547,17 +1607,7 @@ bool handler::update_auto_increment() /* Clear flag for next row */ /* Mark that we didn't generate a new value **/ auto_increment_column_changed=0; /* Update next_insert_id if we have already generated a value */ if (thd->clear_next_insert_id && nr >= thd->next_insert_id) { if (variables->auto_increment_increment != 1) nr= next_insert_id(nr, variables); else nr++; thd->next_insert_id= nr; DBUG_PRINT("info",("next_insert_id: %lu", (ulong) nr)); } adjust_next_insert_id_after_explicit_value(nr); DBUG_RETURN(0); } if (!(nr= thd->next_insert_id)) Loading @@ -1580,10 +1630,19 @@ bool handler::update_auto_increment() /* Mark that we should clear next_insert_id before next stmt */ 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); 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 Loading