2006-09-21 13:19:52 +02:00
|
|
|
--echo #
|
|
|
|
--echo # Setup
|
|
|
|
--echo #
|
2003-05-26 14:08:17 +02:00
|
|
|
|
2003-01-28 05:48:26 +01:00
|
|
|
source include/master-slave.inc;
|
2005-07-15 17:51:43 +02:00
|
|
|
source include/have_innodb.inc;
|
2006-09-21 13:19:52 +02:00
|
|
|
use test;
|
|
|
|
--disable_warnings
|
|
|
|
drop table if exists t1, t2, t3;
|
|
|
|
--enable_warnings
|
|
|
|
|
|
|
|
--echo #
|
|
|
|
--echo # See if queries that use both auto_increment and LAST_INSERT_ID()
|
|
|
|
--echo # are replicated well
|
|
|
|
--echo #
|
|
|
|
--echo # We also check how the foreign_key_check variable is replicated
|
|
|
|
--echo #
|
|
|
|
|
2003-01-28 05:48:26 +01:00
|
|
|
connection master;
|
|
|
|
create table t1(a int auto_increment, key(a));
|
|
|
|
create table t2(b int auto_increment, c int, key(b));
|
|
|
|
insert into t1 values (1),(2),(3);
|
|
|
|
insert into t1 values (null);
|
|
|
|
insert into t2 values (null,last_insert_id());
|
|
|
|
save_master_pos;
|
|
|
|
connection slave;
|
|
|
|
sync_with_master;
|
|
|
|
select * from t1;
|
|
|
|
select * from t2;
|
|
|
|
connection master;
|
|
|
|
#check if multi-line inserts,
|
|
|
|
#which set last_insert_id to the first id inserted,
|
|
|
|
#are replicated the same way
|
|
|
|
drop table t1;
|
|
|
|
drop table t2;
|
2003-07-26 17:59:05 +02:00
|
|
|
--disable_warnings
|
2003-12-10 05:31:42 +01:00
|
|
|
create table t1(a int auto_increment, key(a)) engine=innodb;
|
|
|
|
create table t2(b int auto_increment, c int, key(b), foreign key(b) references t1(a)) engine=innodb;
|
2003-07-26 17:59:05 +02:00
|
|
|
--enable_warnings
|
2003-05-26 14:08:17 +02:00
|
|
|
SET FOREIGN_KEY_CHECKS=0;
|
2003-01-28 05:48:26 +01:00
|
|
|
insert into t1 values (10);
|
|
|
|
insert into t1 values (null),(null),(null);
|
|
|
|
insert into t2 values (5,0);
|
|
|
|
insert into t2 values (null,last_insert_id());
|
2003-05-26 14:08:17 +02:00
|
|
|
SET FOREIGN_KEY_CHECKS=1;
|
2003-01-28 05:48:26 +01:00
|
|
|
save_master_pos;
|
|
|
|
connection slave;
|
|
|
|
sync_with_master;
|
|
|
|
select * from t1;
|
|
|
|
select * from t2;
|
|
|
|
connection master;
|
2003-05-24 16:43:53 +02:00
|
|
|
|
2006-09-21 13:19:52 +02:00
|
|
|
--echo #
|
|
|
|
--echo # check if INSERT SELECT in auto_increment is well replicated (bug #490)
|
|
|
|
--echo #
|
2003-05-24 16:43:53 +02:00
|
|
|
|
|
|
|
drop table t2;
|
2004-02-02 00:41:35 +01:00
|
|
|
drop table t1;
|
2003-05-24 16:43:53 +02:00
|
|
|
create table t1(a int auto_increment, key(a));
|
|
|
|
create table t2(b int auto_increment, c int, key(b));
|
|
|
|
insert into t1 values (10);
|
|
|
|
insert into t1 values (null),(null),(null);
|
|
|
|
insert into t2 values (5,0);
|
|
|
|
insert into t2 (c) select * from t1;
|
|
|
|
select * from t2;
|
2003-01-28 05:48:26 +01:00
|
|
|
save_master_pos;
|
|
|
|
connection slave;
|
|
|
|
sync_with_master;
|
|
|
|
select * from t1;
|
|
|
|
select * from t2;
|
|
|
|
connection master;
|
|
|
|
drop table t1;
|
|
|
|
drop table t2;
|
|
|
|
save_master_pos;
|
|
|
|
connection slave;
|
|
|
|
sync_with_master;
|
2005-02-14 18:39:33 +01:00
|
|
|
|
2006-09-21 13:19:52 +02:00
|
|
|
--echo #
|
|
|
|
--echo # Bug#8412: Error codes reported in binary log for CHARACTER SET,
|
|
|
|
--echo # FOREIGN_KEY_CHECKS
|
|
|
|
--echo #
|
|
|
|
|
2005-02-14 18:39:33 +01:00
|
|
|
connection master;
|
|
|
|
SET TIMESTAMP=1000000000;
|
|
|
|
CREATE TABLE t1 ( a INT UNIQUE );
|
|
|
|
SET FOREIGN_KEY_CHECKS=0;
|
|
|
|
--error 1062
|
|
|
|
INSERT INTO t1 VALUES (1),(1);
|
|
|
|
sync_slave_with_master;
|
|
|
|
|
Add new option "check-testcases" to mysql-test-run.pl
Cleanup the sideeffects from most of the testcases with sideeffects.
mysql-test/mysql-test-run.pl:
Add option "check-testcases" to mysql-test-run.pl
Will execute "include/check-testcase.test" once before each tescase and record the output into "var/tmp/check-testcase.result"
After the teastcase it will run again and this time compare the output with previously recorded file.
mysql-test/r/analyze.result:
Drop table t1 at end of test
mysql-test/r/create_select_tmp.result:
Drop table t1 at end of test
mysql-test/r/ctype_cp932.result:
Drop table t1 at end of test
mysql-test/r/ctype_recoding.result:
Drop table t1 at end of test
mysql-test/r/grant2.result:
Drop user mysqltest_2 and mysqltest_A@'%'
mysql-test/r/join_outer.result:
Drop view v1 to cleanup
mysql-test/r/ps_1general.result:
Drop table t1 at end of test
mysql-test/r/query_cache.result:
Drop function "f1"
mysql-test/r/read_only.result:
Reset the "read_only" flag
mysql-test/r/rpl000001.result:
Remove user "blafasel2"
mysql-test/r/rpl000017.result:
Remove user "replicate"
mysql-test/r/rpl_failed_optimize.result:
Drop table t1 to cleanup
mysql-test/r/rpl_flush_tables.result:
Drop tables t3, t4, t5
mysql-test/r/rpl_ignore_revoke.result:
Delete user "user_foo"
mysql-test/r/rpl_insert_id.result:
Drop table t1 to cleanup
mysql-test/r/rpl_loaddata.result:
Drop tyable t1 to cleanup
mysql-test/r/rpl_loaddata_rule_m.result:
Drop tyable t1 to cleanup
mysql-test/r/rpl_loaddata_rule_s.result:
Drop tyable t1 to cleanup
mysql-test/r/rpl_misc_functions.result:
Drop tyable t1 to cleanup
mysql-test/r/rpl_multi_update3.result:
Drop tyable t1 and t2 to cleanup
mysql-test/r/rpl_replicate_do.result:
Drop tyable t1 to cleanup
mysql-test/r/rpl_skip_error.result:
Drop tyable t1 to cleanup
mysql-test/r/rpl_slave_status.result:
Drop tyable t1 to cleanup
mysql-test/r/sp-prelocking.result:
Drop view v1 and tables t1, t2, t3 and t4 to cleanup
mysql-test/r/sp-security.result:
Delete users to cleanup
Delete remaining traces in tables_priv and procs_priv
mysql-test/r/subselect_innodb.result:
Drop procedure p1 to cleanup
mysql-test/r/trigger-compat.result:
Drop trigger wl2818_trg1 and wl2818_trg2.
Drop table t1, t2
Drop database mysqltest_db1
And the users "mysqltest_dfn@localhost" and "mysqltest_inv@localhost"
mysql-test/r/type_bit.result:
Drop tables t1 and t2 to cleanup
mysql-test/r/variables.result:
Set GLOBAL max_join_size to 10 as it originally was in variables-master.opt
mysql-test/r/view_grant.result:
Dop user "test@localhost" to cleanup
mysql-test/t/analyze.test:
Drop table t1 to cleanup
mysql-test/t/create_select_tmp.test:
Drop table t1 to cleanup
mysql-test/t/ctype_cp932.test:
Drop table t1 to cleanup
mysql-test/t/ctype_recoding.test:
Drop table t1 to cleanup
mysql-test/t/fulltext_var.test:
Restore the original ft_boolean_syntax
mysql-test/t/grant2.test:
Drop users "mysqltest_2" and "mysqltest_A@'%'" to cleanup
mysql-test/t/innodb_cache.test:
Reset query_cache_size to original value
mysql-test/t/join_outer.test:
Drop view v1 to cleanup
mysql-test/t/ps_1general.test:
Drop table t1 to cleanup
mysql-test/t/query_cache.test:
Drop function "f1" to cleanup
mysql-test/t/read_only.test:
Reset the readonly flag
mysql-test/t/rpl000001.test:
Delete user "blafasel2" to cleanup
mysql-test/t/rpl000017.test:
Delete user "replicate" to cleanup
mysql-test/t/rpl_failed_optimize.test:
Drop table t1 to cleanup
mysql-test/t/rpl_flush_tables.test:
Droip table t3, t4 and t5 to cleanup
mysql-test/t/rpl_ignore_revoke.test:
Delet user "user_foo" to cleanup
mysql-test/t/rpl_insert_id.test:
drop table t1 to cleanup
mysql-test/t/rpl_loaddata.test:
Drop table t1 to cleanup
mysql-test/t/rpl_loaddata_rule_m.test:
Drop table t1 to cleanup
mysql-test/t/rpl_loaddata_rule_s.test:
Drop table t1 to cleanup
mysql-test/t/rpl_misc_functions.test:
Drop table t1 to cleanup
mysql-test/t/rpl_multi_update3.test:
Drop table t1 and t2 to cleanup
mysql-test/t/rpl_replicate_do.test:
Drop table t1 to cleanup
mysql-test/t/rpl_skip_error.test:
Drop table t1 to cleanup
mysql-test/t/rpl_slave_status.test:
Drop table t1 to cleanup
mysql-test/t/sp-prelocking.test:
Drop table t1, t2 t3 and t4 to cleanup
Drop view v1
mysql-test/t/sp-security.test:
Delete test users from mysql.user, mysql.db, mysql.procs_priv and mysql.tables_priv
Drop table t1 to cleanup
mysql-test/t/subselect_innodb.test:
Drop procedure p1 to cleanup
mysql-test/t/trigger-compat.test:
Drop trigger wl2818_trg1 and wl2818_trg2 to cleanup
Drop table t1, t2
Drop users
drop database mysqltest_db1
mysql-test/t/type_bit.test:
drop table t1 and t2 to cleanup
mysql-test/t/variables-master.opt:
Increase max_join_size to 100.
mysql-test/t/variables.test:
Set max_join_size to 10, which was the original value in variables-master.opt
mysql-test/t/view_grant.test:
Drop the user "test@localhost"
mysql-test/include/check-testcase.test:
New BitKeeper file ``mysql-test/include/check-testcase.test''
2006-01-26 17:54:34 +01:00
|
|
|
connection master;
|
|
|
|
drop table t1;
|
|
|
|
sync_slave_with_master;
|
2006-07-10 15:27:03 +02:00
|
|
|
|
2006-09-21 13:19:52 +02:00
|
|
|
--echo #
|
|
|
|
--echo # Bug#14553: NULL in WHERE resets LAST_INSERT_ID
|
|
|
|
--echo #
|
|
|
|
|
2006-07-10 15:27:03 +02:00
|
|
|
connection master;
|
|
|
|
create table t1(a int auto_increment, key(a));
|
|
|
|
create table t2(a int);
|
|
|
|
insert into t1 (a) values (null);
|
|
|
|
insert into t2 (a) select a from t1 where a is null;
|
|
|
|
insert into t2 (a) select a from t1 where a is null;
|
|
|
|
select * from t2;
|
|
|
|
sync_slave_with_master;
|
|
|
|
connection slave;
|
|
|
|
select * from t2;
|
|
|
|
connection master;
|
|
|
|
drop table t1;
|
|
|
|
drop table t2;
|
|
|
|
sync_slave_with_master;
|
2006-04-21 16:55:04 +02:00
|
|
|
|
2006-09-21 13:19:52 +02:00
|
|
|
--echo #
|
|
|
|
--echo # End of 4.1 tests
|
|
|
|
--echo #
|
2006-04-21 16:55:04 +02:00
|
|
|
|
|
|
|
#
|
|
|
|
# BUG#15728: LAST_INSERT_ID function inside a stored function returns 0
|
|
|
|
#
|
|
|
|
# The solution is not to reset last_insert_id on enter to sub-statement.
|
|
|
|
#
|
|
|
|
connection master;
|
|
|
|
--disable_warnings
|
|
|
|
drop function if exists bug15728;
|
|
|
|
drop function if exists bug15728_insert;
|
|
|
|
drop table if exists t1, t2;
|
|
|
|
--enable_warnings
|
|
|
|
|
|
|
|
create table t1 (
|
|
|
|
id int not null auto_increment,
|
|
|
|
last_id int,
|
|
|
|
primary key (id)
|
|
|
|
);
|
|
|
|
create function bug15728() returns int(11)
|
|
|
|
return last_insert_id();
|
|
|
|
|
|
|
|
insert into t1 (last_id) values (0);
|
|
|
|
insert into t1 (last_id) values (last_insert_id());
|
|
|
|
insert into t1 (last_id) values (bug15728());
|
|
|
|
|
|
|
|
# Check that nested call replicates too.
|
|
|
|
create table t2 (
|
|
|
|
id int not null auto_increment,
|
|
|
|
last_id int,
|
|
|
|
primary key (id)
|
|
|
|
);
|
|
|
|
delimiter |;
|
|
|
|
create function bug15728_insert() returns int(11) modifies sql data
|
|
|
|
begin
|
|
|
|
insert into t2 (last_id) values (bug15728());
|
|
|
|
return bug15728();
|
|
|
|
end|
|
|
|
|
create trigger t1_bi before insert on t1 for each row
|
|
|
|
begin
|
|
|
|
declare res int;
|
|
|
|
select bug15728_insert() into res;
|
|
|
|
set NEW.last_id = res;
|
|
|
|
end|
|
|
|
|
delimiter ;|
|
|
|
|
|
|
|
|
insert into t1 (last_id) values (0);
|
|
|
|
|
|
|
|
drop trigger t1_bi;
|
|
|
|
|
|
|
|
# Check that nested call doesn't affect outer context.
|
|
|
|
select last_insert_id();
|
|
|
|
select bug15728_insert();
|
|
|
|
select last_insert_id();
|
|
|
|
insert into t1 (last_id) values (bug15728());
|
|
|
|
# This should be exactly one greater than in the previous call.
|
|
|
|
select last_insert_id();
|
|
|
|
|
|
|
|
save_master_pos;
|
|
|
|
connection slave;
|
|
|
|
sync_with_master;
|
|
|
|
select * from t1;
|
|
|
|
select * from t2;
|
|
|
|
connection master;
|
|
|
|
|
|
|
|
drop function bug15728;
|
|
|
|
drop function bug15728_insert;
|
|
|
|
drop table t1, t2;
|
|
|
|
|
Fix for BUG#20188 "REPLACE or ON DUPLICATE KEY UPDATE in
auto_increment breaks binlog":
if slave's table had a higher auto_increment counter than master's (even
though all rows of the two tables were identical), then in some cases,
REPLACE and INSERT ON DUPLICATE KEY UPDATE failed to replicate
statement-based (it inserted different values on slave from on master).
write_record() contained a "thd->next_insert_id=0" to force an adjustment
of thd->next_insert_id after the update or replacement. But it is this
assigment introduced indeterminism of the statement on the slave, thus
the bug. For ON DUPLICATE, we replace that assignment by a call to
handler::adjust_next_insert_id_after_explicit_value() which is deterministic
(does not depend on slave table's autoinc counter). For REPLACE, this
assignment can simply be removed (as REPLACE can't insert a number larger
than thd->next_insert_id).
We also move a too early restore_auto_increment() down to when we really know
that we can restore the value.
mysql-test/r/rpl_insert_id.result:
result update, without the bugfix, slave's "3 350" were "4 350".
mysql-test/t/rpl_insert_id.test:
test for BUG#20188 "REPLACE or ON DUPLICATE KEY UPDATE in
auto_increment breaks binlog".
There is, in this order:
- a test of the bug for the case of REPLACE
- a test of basic ON DUPLICATE KEY UPDATE functionality which was not
tested before
- a test of the bug for the case of ON DUPLICATE KEY UPDATE
sql/handler.cc:
the adjustment of next_insert_id if inserting a big explicit value, is
moved to a separate method to be used elsewhere.
sql/handler.h:
see handler.cc
sql/sql_insert.cc:
restore_auto_increment() means "I know I won't use this autogenerated
autoincrement value, you are free to reuse it for next row". But we were
calling restore_auto_increment() in the case of REPLACE: if write_row() fails
inserting the row, we don't know that we won't use the value, as we are going to
try again by doing internally an UPDATE of the existing row, or a DELETE
of the existing row and then an INSERT. So I move restore_auto_increment()
further down, when we know for sure we failed all possibilities for the row.
Additionally, in case of REPLACE, we don't need to reset THD::next_insert_id:
the value of thd->next_insert_id will be suitable for the next row.
In case of ON DUPLICATE KEY UPDATE, resetting thd->next_insert_id is also
wrong (breaks statement-based binlog), but cannot simply be removed, as
thd->next_insert_id must be adjusted if the explicit value exceeds it.
We now do the adjustment by calling
handler::adjust_next_insert_id_after_explicit_value() (which, contrary to
thd->next_insert_id=0, does not depend on the slave table's autoinc counter,
and so is deterministic).
2006-07-05 14:41:35 +02:00
|
|
|
# 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;
|
BUG#21726: Incorrect result with multiple invocations of LAST_INSERT_ID
Non-upper-level INSERTs (the ones in the body of stored procedure,
stored function, or trigger) into a table that have AUTO_INCREMENT
column didn't affected the result of LAST_INSERT_ID() on this level.
The problem was introduced with the fix of bug 6880, which in turn was
introduced with the fix of bug 3117, where current insert_id value was
remembered on the first call to LAST_INSERT_ID() (bug 3117) and was
returned from that function until it was reset before the next
_upper-level_ statement (bug 6880).
The fix for bug#21726 brings back the behaviour of version 4.0, and
implements the following: remember insert_id value at the beginning
of the statement or expression (which at that point equals to
the first insert_id value generated by the previous statement), and
return that remembered value from LAST_INSERT_ID() or @@LAST_INSERT_ID.
Thus, the value returned by LAST_INSERT_ID() is not affected by values
generated by current statement, nor by LAST_INSERT_ID(expr) calls in
this statement.
Version 5.1 does not have this bug (it was fixed by WL 3146).
mysql-test/r/rpl_insert_id.result:
Add results for bug#21726: Incorrect result with multiple invocations
of LAST_INSERT_ID, and bug#20339: stored procedure using LAST_INSERT_ID()
does not replicate statement-based.
mysql-test/t/rpl_insert_id.test:
Add test cases for bug#21726: Incorrect result with multiple invocations
of LAST_INSERT_ID, and bug#20339: stored procedure using LAST_INSERT_ID()
does not replicate statement-based.
sql/item_func.cc:
Add implementation of Item_func_last_insert_id::fix_fields(), where we
remember in THD::current_insert_id the first value generated during
execution of the previous statement, which is returned then from
Item_func_last_insert_id::val_int().
sql/item_func.h:
Add declaration of Item_func_last_insert_id::fix_fields().
sql/log_event.cc:
Do not set THD::last_insert_id_used on LAST_INSERT_ID_EVENT. Though we
know the statement will call LAST_INSERT_ID(), it wasn't called yet.
sql/set_var.cc:
In sys_var_last_insert_id::value_ptr() remember in
THD::current_insert_id the first value generated during execution of the
previous statement, and return this value for @@LAST_INSERT_ID.
sql/sql_class.cc:
Reset THD::last_insert_id_used after each statement execution.
sql/sql_class.h:
Rather then remember current insert_id value on first invocation of
THD::insert_id(), remember it in Item_func_last_insert_id::fix_fields(),
sys_var_last_insert_id::value_ptr(), or mysql_execute_command().
Remove THD::insert_id(), as it lost its value now.
sql/sql_insert.cc:
THD::insert_id() is removed, use THD::last_insert_id directly.
sql/sql_load.cc:
THD::insert_id() is removed, using THD::last_insert_id directly is OK.
sql/sql_parse.cc:
Remember in THD::current_insert_id first generated insert id value of
the previous statement in mysql_execute_command().
No need to reset THD::last_insert_id_used in
mysql_reset_thd_for_next_command(), it will be reset after each
statement.
sql/sql_select.cc:
If "IS NULL" is replaced with "= <LAST_INSERT_ID>", use right value,
which is THD::current_insert_id, and also set THD::last_insert_id_used
to issue binary log LAST_INSERT_ID_EVENT.
sql/sql_update.cc:
THD::insert_id() is removed, use THD::last_insert_id directly.
tests/mysql_client_test.c:
Add test case for bug#21726: Incorrect result with multiple invocations
of LAST_INSERT_ID.
2006-10-02 12:28:23 +02:00
|
|
|
|
Fix for BUG#24432
"INSERT... ON DUPLICATE KEY UPDATE skips auto_increment values".
When in an INSERT ON DUPLICATE KEY UPDATE, using
an autoincrement column, we inserted some autogenerated values and
also updated some rows, some autogenerated values were not used
(for example, even if 10 was the largest autoinc value in the table
at the start of the statement, 12 could be the first autogenerated
value inserted by the statement, instead of 11). One autogenerated
value was lost per updated row. Led to exhausting the range of the
autoincrement column faster.
Bug introduced by fix of BUG#20188; present since 5.0.24 and 5.1.12.
This bug breaks replication from a pre-5.0.24 master.
But the present bugfix, as it makes INSERT ON DUP KEY UPDATE
behave like pre-5.0.24, breaks replication from a [5.0.24,5.0.34]
master to a fixed (5.0.36) slave! To warn users against this when
they upgrade their slave, as agreed with the support team, we add
code for a fixed slave to detect that it is connected to a buggy
master in a situation (INSERT ON DUP KEY UPDATE into autoinc column)
likely to break replication, in which case it cannot replicate so
stops and prints a message to the slave's error log and to SHOW SLAVE
STATUS.
For 5.0.36->[5.0.24,5.0.34] replication we cannot warn as master
does not know the slave's version (but we always recommended to users
to have slave at least as new as master).
As agreed with support, I'll also ask for an alert to be put into
the MySQL Network Monitoring and Advisory Service.
mysql-test/r/rpl_insert_id.result:
results to check the bugfix; without the bugfix, you would see, in
master and slave:
"3,2" instead of "2,2" for the INSERT VALUES testcase,
"11,6,..." instead of "6,6,..." for the INSERT SELECT testcase.
mysql-test/t/rpl_insert_id.test:
testing that BUG#24432 is fixed
sql/log_event.cc:
A trick to force the master to pretend it is old and features BUG#24432.
To do fast lookups in the list of known bugs by version, we compute
the 3 X.Y.Z numbers from the master's version string and cache that
into a new member Format_description_log_event::server_version_split.
We do this computation in the event's two constructors.
A simple prevention against buffer overrun when reading the master's
version from a binlog event (assume the event is corrupted on disk,
and so the version string on disk is longer than ST_SERVER_VER_LEN
(50), then we would not get a closing 0 at the end of the class member.
sql/log_event.h:
new member to hold the "split server version" (3 numbers X.Y.Z),
and a method to compute this from the version string.
sql/slave.cc:
a function which tells, based on master's version (as found
in the Format_description event in the relay log being executed),
if master can have a certain bug. This function uses a list of
bug_id / first_version_with_bug / first_version_with_fix.
If the test is positive, a short error message is put into SHOW SLAVE
STATUS, and a verbose message is put into the slave's error log.
The caller is expected to stop the slave in this case.
sql/slave.h:
new function to test if the replication master has a bug
sql/sql_insert.cc:
Fix for BUG#24432:t he reason was a misplaced restore_auto_increment()
(misplaced when fixing BUG#20188). Indeed, when updating the row,
it is clear that the autogenerated auto_increment value will not be
used for this row (and if by "chance" the autoinc value present
in the updated row is >= to the not used autogenerated value,
adjust_next_insert_id_after_explicit_value() will fix next_insert_id).
We also add code for a fixed slave to detect that it is connected to
a buggy master (in which case it cannot replicate so stops).
mysql-test/r/rpl_known_bugs_detection.result:
see that SHOW SLAVE STATUS prints information that slave found a bug
in master, and does not execute the dangerous event (table stays
empty).
mysql-test/t/rpl_known_bugs_detection-master.opt:
pass debug symbol to make the master pretend it has BUG#24432
mysql-test/t/rpl_known_bugs_detection.test:
new test to see if bug detection by slave works
2007-02-08 15:53:14 +01:00
|
|
|
#
|
|
|
|
# BUG#24432 "INSERT... ON DUPLICATE KEY UPDATE skips auto_increment values"
|
|
|
|
#
|
|
|
|
|
|
|
|
# testcase with INSERT VALUES
|
|
|
|
CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY AUTO_INCREMENT, b INT,
|
|
|
|
UNIQUE(b));
|
|
|
|
INSERT INTO t1(b) VALUES(1),(1),(2) ON DUPLICATE KEY UPDATE t1.b=10;
|
|
|
|
SELECT * FROM t1;
|
|
|
|
sync_slave_with_master;
|
|
|
|
SELECT * FROM t1;
|
|
|
|
connection master;
|
|
|
|
drop table t1;
|
|
|
|
|
|
|
|
# tescase with INSERT SELECT
|
|
|
|
CREATE TABLE t1 (
|
|
|
|
id bigint(20) unsigned NOT NULL auto_increment,
|
|
|
|
field_1 int(10) unsigned NOT NULL,
|
|
|
|
field_2 varchar(255) NOT NULL,
|
|
|
|
field_3 varchar(255) NOT NULL,
|
|
|
|
PRIMARY KEY (id),
|
|
|
|
UNIQUE KEY field_1 (field_1, field_2)
|
|
|
|
);
|
|
|
|
CREATE TABLE t2 (
|
|
|
|
field_a int(10) unsigned NOT NULL,
|
|
|
|
field_b varchar(255) NOT NULL,
|
|
|
|
field_c varchar(255) NOT NULL
|
|
|
|
);
|
|
|
|
INSERT INTO t2 (field_a, field_b, field_c) VALUES (1, 'a', '1a');
|
|
|
|
INSERT INTO t2 (field_a, field_b, field_c) VALUES (2, 'b', '2b');
|
|
|
|
INSERT INTO t2 (field_a, field_b, field_c) VALUES (3, 'c', '3c');
|
|
|
|
INSERT INTO t2 (field_a, field_b, field_c) VALUES (4, 'd', '4d');
|
|
|
|
INSERT INTO t2 (field_a, field_b, field_c) VALUES (5, 'e', '5e');
|
|
|
|
# Updating table t1 based on values from table t2
|
|
|
|
INSERT INTO t1 (field_1, field_2, field_3)
|
|
|
|
SELECT t2.field_a, t2.field_b, t2.field_c
|
|
|
|
FROM t2
|
|
|
|
ON DUPLICATE KEY UPDATE
|
|
|
|
t1.field_3 = t2.field_c;
|
|
|
|
# Inserting new record into t2
|
|
|
|
INSERT INTO t2 (field_a, field_b, field_c) VALUES (6, 'f', '6f');
|
|
|
|
# Updating t1 again
|
|
|
|
INSERT INTO t1 (field_1, field_2, field_3)
|
|
|
|
SELECT t2.field_a, t2.field_b, t2.field_c
|
|
|
|
FROM t2
|
|
|
|
ON DUPLICATE KEY UPDATE
|
|
|
|
t1.field_3 = t2.field_c;
|
|
|
|
SELECT * FROM t1;
|
|
|
|
sync_slave_with_master;
|
|
|
|
SELECT * FROM t1;
|
|
|
|
connection master;
|
|
|
|
drop table t1, t2;
|
|
|
|
|
BUG#21726: Incorrect result with multiple invocations of LAST_INSERT_ID
Non-upper-level INSERTs (the ones in the body of stored procedure,
stored function, or trigger) into a table that have AUTO_INCREMENT
column didn't affected the result of LAST_INSERT_ID() on this level.
The problem was introduced with the fix of bug 6880, which in turn was
introduced with the fix of bug 3117, where current insert_id value was
remembered on the first call to LAST_INSERT_ID() (bug 3117) and was
returned from that function until it was reset before the next
_upper-level_ statement (bug 6880).
The fix for bug#21726 brings back the behaviour of version 4.0, and
implements the following: remember insert_id value at the beginning
of the statement or expression (which at that point equals to
the first insert_id value generated by the previous statement), and
return that remembered value from LAST_INSERT_ID() or @@LAST_INSERT_ID.
Thus, the value returned by LAST_INSERT_ID() is not affected by values
generated by current statement, nor by LAST_INSERT_ID(expr) calls in
this statement.
Version 5.1 does not have this bug (it was fixed by WL 3146).
mysql-test/r/rpl_insert_id.result:
Add results for bug#21726: Incorrect result with multiple invocations
of LAST_INSERT_ID, and bug#20339: stored procedure using LAST_INSERT_ID()
does not replicate statement-based.
mysql-test/t/rpl_insert_id.test:
Add test cases for bug#21726: Incorrect result with multiple invocations
of LAST_INSERT_ID, and bug#20339: stored procedure using LAST_INSERT_ID()
does not replicate statement-based.
sql/item_func.cc:
Add implementation of Item_func_last_insert_id::fix_fields(), where we
remember in THD::current_insert_id the first value generated during
execution of the previous statement, which is returned then from
Item_func_last_insert_id::val_int().
sql/item_func.h:
Add declaration of Item_func_last_insert_id::fix_fields().
sql/log_event.cc:
Do not set THD::last_insert_id_used on LAST_INSERT_ID_EVENT. Though we
know the statement will call LAST_INSERT_ID(), it wasn't called yet.
sql/set_var.cc:
In sys_var_last_insert_id::value_ptr() remember in
THD::current_insert_id the first value generated during execution of the
previous statement, and return this value for @@LAST_INSERT_ID.
sql/sql_class.cc:
Reset THD::last_insert_id_used after each statement execution.
sql/sql_class.h:
Rather then remember current insert_id value on first invocation of
THD::insert_id(), remember it in Item_func_last_insert_id::fix_fields(),
sys_var_last_insert_id::value_ptr(), or mysql_execute_command().
Remove THD::insert_id(), as it lost its value now.
sql/sql_insert.cc:
THD::insert_id() is removed, use THD::last_insert_id directly.
sql/sql_load.cc:
THD::insert_id() is removed, using THD::last_insert_id directly is OK.
sql/sql_parse.cc:
Remember in THD::current_insert_id first generated insert id value of
the previous statement in mysql_execute_command().
No need to reset THD::last_insert_id_used in
mysql_reset_thd_for_next_command(), it will be reset after each
statement.
sql/sql_select.cc:
If "IS NULL" is replaced with "= <LAST_INSERT_ID>", use right value,
which is THD::current_insert_id, and also set THD::last_insert_id_used
to issue binary log LAST_INSERT_ID_EVENT.
sql/sql_update.cc:
THD::insert_id() is removed, use THD::last_insert_id directly.
tests/mysql_client_test.c:
Add test case for bug#21726: Incorrect result with multiple invocations
of LAST_INSERT_ID.
2006-10-02 12:28:23 +02:00
|
|
|
#
|
|
|
|
# BUG#20339: stored procedure using LAST_INSERT_ID() does not
|
|
|
|
# replicate statement-based
|
|
|
|
#
|
|
|
|
--disable_warnings
|
|
|
|
DROP PROCEDURE IF EXISTS p1;
|
|
|
|
DROP TABLE IF EXISTS t1, t2;
|
|
|
|
--enable_warnings
|
|
|
|
|
|
|
|
# Reset result of LAST_INSERT_ID().
|
|
|
|
SELECT LAST_INSERT_ID(0);
|
|
|
|
|
|
|
|
CREATE TABLE t1 (
|
|
|
|
id INT NOT NULL DEFAULT 0,
|
|
|
|
last_id INT,
|
|
|
|
PRIMARY KEY (id)
|
|
|
|
);
|
|
|
|
|
|
|
|
CREATE TABLE t2 (
|
|
|
|
id INT NOT NULL AUTO_INCREMENT,
|
|
|
|
last_id INT,
|
|
|
|
PRIMARY KEY (id)
|
|
|
|
);
|
|
|
|
|
|
|
|
delimiter |;
|
|
|
|
CREATE PROCEDURE p1()
|
|
|
|
BEGIN
|
|
|
|
INSERT INTO t2 (last_id) VALUES (LAST_INSERT_ID());
|
|
|
|
INSERT INTO t1 (last_id) VALUES (LAST_INSERT_ID());
|
|
|
|
END|
|
|
|
|
delimiter ;|
|
|
|
|
|
|
|
|
CALL p1();
|
|
|
|
SELECT * FROM t1;
|
|
|
|
SELECT * FROM t2;
|
|
|
|
|
|
|
|
sync_slave_with_master;
|
|
|
|
SELECT * FROM t1;
|
|
|
|
SELECT * FROM t2;
|
|
|
|
|
|
|
|
connection master;
|
|
|
|
|
|
|
|
DROP PROCEDURE p1;
|
|
|
|
DROP TABLE t1, t2;
|
|
|
|
|
|
|
|
|
|
|
|
#
|
|
|
|
# BUG#21726: Incorrect result with multiple invocations of
|
|
|
|
# LAST_INSERT_ID
|
|
|
|
#
|
|
|
|
--disable_warnings
|
|
|
|
DROP PROCEDURE IF EXISTS p1;
|
|
|
|
DROP FUNCTION IF EXISTS f1;
|
|
|
|
DROP FUNCTION IF EXISTS f2;
|
2006-10-03 11:38:16 +02:00
|
|
|
DROP FUNCTION IF EXISTS f3;
|
BUG#21726: Incorrect result with multiple invocations of LAST_INSERT_ID
Non-upper-level INSERTs (the ones in the body of stored procedure,
stored function, or trigger) into a table that have AUTO_INCREMENT
column didn't affected the result of LAST_INSERT_ID() on this level.
The problem was introduced with the fix of bug 6880, which in turn was
introduced with the fix of bug 3117, where current insert_id value was
remembered on the first call to LAST_INSERT_ID() (bug 3117) and was
returned from that function until it was reset before the next
_upper-level_ statement (bug 6880).
The fix for bug#21726 brings back the behaviour of version 4.0, and
implements the following: remember insert_id value at the beginning
of the statement or expression (which at that point equals to
the first insert_id value generated by the previous statement), and
return that remembered value from LAST_INSERT_ID() or @@LAST_INSERT_ID.
Thus, the value returned by LAST_INSERT_ID() is not affected by values
generated by current statement, nor by LAST_INSERT_ID(expr) calls in
this statement.
Version 5.1 does not have this bug (it was fixed by WL 3146).
mysql-test/r/rpl_insert_id.result:
Add results for bug#21726: Incorrect result with multiple invocations
of LAST_INSERT_ID, and bug#20339: stored procedure using LAST_INSERT_ID()
does not replicate statement-based.
mysql-test/t/rpl_insert_id.test:
Add test cases for bug#21726: Incorrect result with multiple invocations
of LAST_INSERT_ID, and bug#20339: stored procedure using LAST_INSERT_ID()
does not replicate statement-based.
sql/item_func.cc:
Add implementation of Item_func_last_insert_id::fix_fields(), where we
remember in THD::current_insert_id the first value generated during
execution of the previous statement, which is returned then from
Item_func_last_insert_id::val_int().
sql/item_func.h:
Add declaration of Item_func_last_insert_id::fix_fields().
sql/log_event.cc:
Do not set THD::last_insert_id_used on LAST_INSERT_ID_EVENT. Though we
know the statement will call LAST_INSERT_ID(), it wasn't called yet.
sql/set_var.cc:
In sys_var_last_insert_id::value_ptr() remember in
THD::current_insert_id the first value generated during execution of the
previous statement, and return this value for @@LAST_INSERT_ID.
sql/sql_class.cc:
Reset THD::last_insert_id_used after each statement execution.
sql/sql_class.h:
Rather then remember current insert_id value on first invocation of
THD::insert_id(), remember it in Item_func_last_insert_id::fix_fields(),
sys_var_last_insert_id::value_ptr(), or mysql_execute_command().
Remove THD::insert_id(), as it lost its value now.
sql/sql_insert.cc:
THD::insert_id() is removed, use THD::last_insert_id directly.
sql/sql_load.cc:
THD::insert_id() is removed, using THD::last_insert_id directly is OK.
sql/sql_parse.cc:
Remember in THD::current_insert_id first generated insert id value of
the previous statement in mysql_execute_command().
No need to reset THD::last_insert_id_used in
mysql_reset_thd_for_next_command(), it will be reset after each
statement.
sql/sql_select.cc:
If "IS NULL" is replaced with "= <LAST_INSERT_ID>", use right value,
which is THD::current_insert_id, and also set THD::last_insert_id_used
to issue binary log LAST_INSERT_ID_EVENT.
sql/sql_update.cc:
THD::insert_id() is removed, use THD::last_insert_id directly.
tests/mysql_client_test.c:
Add test case for bug#21726: Incorrect result with multiple invocations
of LAST_INSERT_ID.
2006-10-02 12:28:23 +02:00
|
|
|
DROP TABLE IF EXISTS t1, t2;
|
|
|
|
--enable_warnings
|
|
|
|
|
|
|
|
CREATE TABLE t1 (
|
|
|
|
i INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
|
|
|
j INT DEFAULT 0
|
|
|
|
);
|
|
|
|
CREATE TABLE t2 (i INT);
|
|
|
|
|
|
|
|
delimiter |;
|
|
|
|
CREATE PROCEDURE p1()
|
|
|
|
BEGIN
|
|
|
|
INSERT INTO t1 (i) VALUES (NULL);
|
|
|
|
INSERT INTO t2 (i) VALUES (LAST_INSERT_ID());
|
|
|
|
INSERT INTO t1 (i) VALUES (NULL), (NULL);
|
|
|
|
INSERT INTO t2 (i) VALUES (LAST_INSERT_ID());
|
|
|
|
END |
|
|
|
|
|
|
|
|
CREATE FUNCTION f1() RETURNS INT MODIFIES SQL DATA
|
|
|
|
BEGIN
|
|
|
|
INSERT INTO t1 (i) VALUES (NULL);
|
|
|
|
INSERT INTO t2 (i) VALUES (LAST_INSERT_ID());
|
|
|
|
INSERT INTO t1 (i) VALUES (NULL), (NULL);
|
|
|
|
INSERT INTO t2 (i) VALUES (LAST_INSERT_ID());
|
|
|
|
RETURN 0;
|
|
|
|
END |
|
|
|
|
|
|
|
|
CREATE FUNCTION f2() RETURNS INT NOT DETERMINISTIC
|
|
|
|
RETURN LAST_INSERT_ID() |
|
2006-10-03 11:38:16 +02:00
|
|
|
|
|
|
|
CREATE FUNCTION f3() RETURNS INT MODIFIES SQL DATA
|
|
|
|
BEGIN
|
|
|
|
INSERT INTO t2 (i) VALUES (LAST_INSERT_ID());
|
|
|
|
RETURN 0;
|
|
|
|
END |
|
BUG#21726: Incorrect result with multiple invocations of LAST_INSERT_ID
Non-upper-level INSERTs (the ones in the body of stored procedure,
stored function, or trigger) into a table that have AUTO_INCREMENT
column didn't affected the result of LAST_INSERT_ID() on this level.
The problem was introduced with the fix of bug 6880, which in turn was
introduced with the fix of bug 3117, where current insert_id value was
remembered on the first call to LAST_INSERT_ID() (bug 3117) and was
returned from that function until it was reset before the next
_upper-level_ statement (bug 6880).
The fix for bug#21726 brings back the behaviour of version 4.0, and
implements the following: remember insert_id value at the beginning
of the statement or expression (which at that point equals to
the first insert_id value generated by the previous statement), and
return that remembered value from LAST_INSERT_ID() or @@LAST_INSERT_ID.
Thus, the value returned by LAST_INSERT_ID() is not affected by values
generated by current statement, nor by LAST_INSERT_ID(expr) calls in
this statement.
Version 5.1 does not have this bug (it was fixed by WL 3146).
mysql-test/r/rpl_insert_id.result:
Add results for bug#21726: Incorrect result with multiple invocations
of LAST_INSERT_ID, and bug#20339: stored procedure using LAST_INSERT_ID()
does not replicate statement-based.
mysql-test/t/rpl_insert_id.test:
Add test cases for bug#21726: Incorrect result with multiple invocations
of LAST_INSERT_ID, and bug#20339: stored procedure using LAST_INSERT_ID()
does not replicate statement-based.
sql/item_func.cc:
Add implementation of Item_func_last_insert_id::fix_fields(), where we
remember in THD::current_insert_id the first value generated during
execution of the previous statement, which is returned then from
Item_func_last_insert_id::val_int().
sql/item_func.h:
Add declaration of Item_func_last_insert_id::fix_fields().
sql/log_event.cc:
Do not set THD::last_insert_id_used on LAST_INSERT_ID_EVENT. Though we
know the statement will call LAST_INSERT_ID(), it wasn't called yet.
sql/set_var.cc:
In sys_var_last_insert_id::value_ptr() remember in
THD::current_insert_id the first value generated during execution of the
previous statement, and return this value for @@LAST_INSERT_ID.
sql/sql_class.cc:
Reset THD::last_insert_id_used after each statement execution.
sql/sql_class.h:
Rather then remember current insert_id value on first invocation of
THD::insert_id(), remember it in Item_func_last_insert_id::fix_fields(),
sys_var_last_insert_id::value_ptr(), or mysql_execute_command().
Remove THD::insert_id(), as it lost its value now.
sql/sql_insert.cc:
THD::insert_id() is removed, use THD::last_insert_id directly.
sql/sql_load.cc:
THD::insert_id() is removed, using THD::last_insert_id directly is OK.
sql/sql_parse.cc:
Remember in THD::current_insert_id first generated insert id value of
the previous statement in mysql_execute_command().
No need to reset THD::last_insert_id_used in
mysql_reset_thd_for_next_command(), it will be reset after each
statement.
sql/sql_select.cc:
If "IS NULL" is replaced with "= <LAST_INSERT_ID>", use right value,
which is THD::current_insert_id, and also set THD::last_insert_id_used
to issue binary log LAST_INSERT_ID_EVENT.
sql/sql_update.cc:
THD::insert_id() is removed, use THD::last_insert_id directly.
tests/mysql_client_test.c:
Add test case for bug#21726: Incorrect result with multiple invocations
of LAST_INSERT_ID.
2006-10-02 12:28:23 +02:00
|
|
|
delimiter ;|
|
|
|
|
|
|
|
|
INSERT INTO t1 VALUES (NULL, -1);
|
|
|
|
CALL p1();
|
|
|
|
SELECT f1();
|
|
|
|
INSERT INTO t1 VALUES (NULL, f2()), (NULL, LAST_INSERT_ID()),
|
|
|
|
(NULL, LAST_INSERT_ID()), (NULL, f2()), (NULL, f2());
|
|
|
|
INSERT INTO t1 VALUES (NULL, f2());
|
|
|
|
INSERT INTO t1 VALUES (NULL, LAST_INSERT_ID()), (NULL, LAST_INSERT_ID(5)),
|
|
|
|
(NULL, @@LAST_INSERT_ID);
|
|
|
|
# Test replication of substitution "IS NULL" -> "= LAST_INSERT_ID".
|
|
|
|
INSERT INTO t1 VALUES (NULL, 0), (NULL, LAST_INSERT_ID());
|
|
|
|
UPDATE t1 SET j= -1 WHERE i IS NULL;
|
|
|
|
|
2006-10-03 11:38:16 +02:00
|
|
|
# Test statement-based replication of function calls.
|
|
|
|
INSERT INTO t1 (i) VALUES (NULL);
|
|
|
|
|
|
|
|
connection master1;
|
|
|
|
INSERT INTO t1 (i) VALUES (NULL);
|
|
|
|
|
|
|
|
connection master;
|
|
|
|
SELECT f3();
|
|
|
|
|
BUG#21726: Incorrect result with multiple invocations of LAST_INSERT_ID
Non-upper-level INSERTs (the ones in the body of stored procedure,
stored function, or trigger) into a table that have AUTO_INCREMENT
column didn't affected the result of LAST_INSERT_ID() on this level.
The problem was introduced with the fix of bug 6880, which in turn was
introduced with the fix of bug 3117, where current insert_id value was
remembered on the first call to LAST_INSERT_ID() (bug 3117) and was
returned from that function until it was reset before the next
_upper-level_ statement (bug 6880).
The fix for bug#21726 brings back the behaviour of version 4.0, and
implements the following: remember insert_id value at the beginning
of the statement or expression (which at that point equals to
the first insert_id value generated by the previous statement), and
return that remembered value from LAST_INSERT_ID() or @@LAST_INSERT_ID.
Thus, the value returned by LAST_INSERT_ID() is not affected by values
generated by current statement, nor by LAST_INSERT_ID(expr) calls in
this statement.
Version 5.1 does not have this bug (it was fixed by WL 3146).
mysql-test/r/rpl_insert_id.result:
Add results for bug#21726: Incorrect result with multiple invocations
of LAST_INSERT_ID, and bug#20339: stored procedure using LAST_INSERT_ID()
does not replicate statement-based.
mysql-test/t/rpl_insert_id.test:
Add test cases for bug#21726: Incorrect result with multiple invocations
of LAST_INSERT_ID, and bug#20339: stored procedure using LAST_INSERT_ID()
does not replicate statement-based.
sql/item_func.cc:
Add implementation of Item_func_last_insert_id::fix_fields(), where we
remember in THD::current_insert_id the first value generated during
execution of the previous statement, which is returned then from
Item_func_last_insert_id::val_int().
sql/item_func.h:
Add declaration of Item_func_last_insert_id::fix_fields().
sql/log_event.cc:
Do not set THD::last_insert_id_used on LAST_INSERT_ID_EVENT. Though we
know the statement will call LAST_INSERT_ID(), it wasn't called yet.
sql/set_var.cc:
In sys_var_last_insert_id::value_ptr() remember in
THD::current_insert_id the first value generated during execution of the
previous statement, and return this value for @@LAST_INSERT_ID.
sql/sql_class.cc:
Reset THD::last_insert_id_used after each statement execution.
sql/sql_class.h:
Rather then remember current insert_id value on first invocation of
THD::insert_id(), remember it in Item_func_last_insert_id::fix_fields(),
sys_var_last_insert_id::value_ptr(), or mysql_execute_command().
Remove THD::insert_id(), as it lost its value now.
sql/sql_insert.cc:
THD::insert_id() is removed, use THD::last_insert_id directly.
sql/sql_load.cc:
THD::insert_id() is removed, using THD::last_insert_id directly is OK.
sql/sql_parse.cc:
Remember in THD::current_insert_id first generated insert id value of
the previous statement in mysql_execute_command().
No need to reset THD::last_insert_id_used in
mysql_reset_thd_for_next_command(), it will be reset after each
statement.
sql/sql_select.cc:
If "IS NULL" is replaced with "= <LAST_INSERT_ID>", use right value,
which is THD::current_insert_id, and also set THD::last_insert_id_used
to issue binary log LAST_INSERT_ID_EVENT.
sql/sql_update.cc:
THD::insert_id() is removed, use THD::last_insert_id directly.
tests/mysql_client_test.c:
Add test case for bug#21726: Incorrect result with multiple invocations
of LAST_INSERT_ID.
2006-10-02 12:28:23 +02:00
|
|
|
SELECT * FROM t1;
|
|
|
|
SELECT * FROM t2;
|
|
|
|
|
|
|
|
sync_slave_with_master;
|
|
|
|
SELECT * FROM t1;
|
|
|
|
SELECT * FROM t2;
|
|
|
|
|
|
|
|
connection master;
|
|
|
|
DROP PROCEDURE p1;
|
|
|
|
DROP FUNCTION f1;
|
|
|
|
DROP FUNCTION f2;
|
2006-10-03 11:38:16 +02:00
|
|
|
DROP FUNCTION f3;
|
BUG#21726: Incorrect result with multiple invocations of LAST_INSERT_ID
Non-upper-level INSERTs (the ones in the body of stored procedure,
stored function, or trigger) into a table that have AUTO_INCREMENT
column didn't affected the result of LAST_INSERT_ID() on this level.
The problem was introduced with the fix of bug 6880, which in turn was
introduced with the fix of bug 3117, where current insert_id value was
remembered on the first call to LAST_INSERT_ID() (bug 3117) and was
returned from that function until it was reset before the next
_upper-level_ statement (bug 6880).
The fix for bug#21726 brings back the behaviour of version 4.0, and
implements the following: remember insert_id value at the beginning
of the statement or expression (which at that point equals to
the first insert_id value generated by the previous statement), and
return that remembered value from LAST_INSERT_ID() or @@LAST_INSERT_ID.
Thus, the value returned by LAST_INSERT_ID() is not affected by values
generated by current statement, nor by LAST_INSERT_ID(expr) calls in
this statement.
Version 5.1 does not have this bug (it was fixed by WL 3146).
mysql-test/r/rpl_insert_id.result:
Add results for bug#21726: Incorrect result with multiple invocations
of LAST_INSERT_ID, and bug#20339: stored procedure using LAST_INSERT_ID()
does not replicate statement-based.
mysql-test/t/rpl_insert_id.test:
Add test cases for bug#21726: Incorrect result with multiple invocations
of LAST_INSERT_ID, and bug#20339: stored procedure using LAST_INSERT_ID()
does not replicate statement-based.
sql/item_func.cc:
Add implementation of Item_func_last_insert_id::fix_fields(), where we
remember in THD::current_insert_id the first value generated during
execution of the previous statement, which is returned then from
Item_func_last_insert_id::val_int().
sql/item_func.h:
Add declaration of Item_func_last_insert_id::fix_fields().
sql/log_event.cc:
Do not set THD::last_insert_id_used on LAST_INSERT_ID_EVENT. Though we
know the statement will call LAST_INSERT_ID(), it wasn't called yet.
sql/set_var.cc:
In sys_var_last_insert_id::value_ptr() remember in
THD::current_insert_id the first value generated during execution of the
previous statement, and return this value for @@LAST_INSERT_ID.
sql/sql_class.cc:
Reset THD::last_insert_id_used after each statement execution.
sql/sql_class.h:
Rather then remember current insert_id value on first invocation of
THD::insert_id(), remember it in Item_func_last_insert_id::fix_fields(),
sys_var_last_insert_id::value_ptr(), or mysql_execute_command().
Remove THD::insert_id(), as it lost its value now.
sql/sql_insert.cc:
THD::insert_id() is removed, use THD::last_insert_id directly.
sql/sql_load.cc:
THD::insert_id() is removed, using THD::last_insert_id directly is OK.
sql/sql_parse.cc:
Remember in THD::current_insert_id first generated insert id value of
the previous statement in mysql_execute_command().
No need to reset THD::last_insert_id_used in
mysql_reset_thd_for_next_command(), it will be reset after each
statement.
sql/sql_select.cc:
If "IS NULL" is replaced with "= <LAST_INSERT_ID>", use right value,
which is THD::current_insert_id, and also set THD::last_insert_id_used
to issue binary log LAST_INSERT_ID_EVENT.
sql/sql_update.cc:
THD::insert_id() is removed, use THD::last_insert_id directly.
tests/mysql_client_test.c:
Add test case for bug#21726: Incorrect result with multiple invocations
of LAST_INSERT_ID.
2006-10-02 12:28:23 +02:00
|
|
|
DROP TABLE t1, t2;
|
|
|
|
|
|
|
|
|
2006-09-21 13:28:16 +02:00
|
|
|
sync_slave_with_master;
|
|
|
|
|
|
|
|
--echo
|
|
|
|
--echo # End of 5.0 tests
|
|
|
|
--echo
|
Fix for BUG#20188 "REPLACE or ON DUPLICATE KEY UPDATE in
auto_increment breaks binlog":
if slave's table had a higher auto_increment counter than master's (even
though all rows of the two tables were identical), then in some cases,
REPLACE and INSERT ON DUPLICATE KEY UPDATE failed to replicate
statement-based (it inserted different values on slave from on master).
write_record() contained a "thd->next_insert_id=0" to force an adjustment
of thd->next_insert_id after the update or replacement. But it is this
assigment introduced indeterminism of the statement on the slave, thus
the bug. For ON DUPLICATE, we replace that assignment by a call to
handler::adjust_next_insert_id_after_explicit_value() which is deterministic
(does not depend on slave table's autoinc counter). For REPLACE, this
assignment can simply be removed (as REPLACE can't insert a number larger
than thd->next_insert_id).
We also move a too early restore_auto_increment() down to when we really know
that we can restore the value.
mysql-test/r/rpl_insert_id.result:
result update, without the bugfix, slave's "3 350" were "4 350".
mysql-test/t/rpl_insert_id.test:
test for BUG#20188 "REPLACE or ON DUPLICATE KEY UPDATE in
auto_increment breaks binlog".
There is, in this order:
- a test of the bug for the case of REPLACE
- a test of basic ON DUPLICATE KEY UPDATE functionality which was not
tested before
- a test of the bug for the case of ON DUPLICATE KEY UPDATE
sql/handler.cc:
the adjustment of next_insert_id if inserting a big explicit value, is
moved to a separate method to be used elsewhere.
sql/handler.h:
see handler.cc
sql/sql_insert.cc:
restore_auto_increment() means "I know I won't use this autogenerated
autoincrement value, you are free to reuse it for next row". But we were
calling restore_auto_increment() in the case of REPLACE: if write_row() fails
inserting the row, we don't know that we won't use the value, as we are going to
try again by doing internally an UPDATE of the existing row, or a DELETE
of the existing row and then an INSERT. So I move restore_auto_increment()
further down, when we know for sure we failed all possibilities for the row.
Additionally, in case of REPLACE, we don't need to reset THD::next_insert_id:
the value of thd->next_insert_id will be suitable for the next row.
In case of ON DUPLICATE KEY UPDATE, resetting thd->next_insert_id is also
wrong (breaks statement-based binlog), but cannot simply be removed, as
thd->next_insert_id must be adjusted if the explicit value exceeds it.
We now do the adjustment by calling
handler::adjust_next_insert_id_after_explicit_value() (which, contrary to
thd->next_insert_id=0, does not depend on the slave table's autoinc counter,
and so is deterministic).
2006-07-05 14:41:35 +02:00
|
|
|
|
2006-05-29 12:45:20 +02:00
|
|
|
|