Commit 3132a4cd authored by unknown's avatar unknown

Fix for bug #490 and #491 (see details below)


mysql-test/r/insert_select.result:
  Result update.
mysql-test/r/rpl_insert_id.result:
  Test update
mysql-test/t/insert_select.test:
  Check if a partly completed INSERT SELECT (failing because of "Duplicate key"
  after successfully inserting other rows) is written to the binlog if the
  table is not transactional and at least one row has been inserted (bug #491)
mysql-test/t/rpl_insert_id.test:
  Test for bug #490 (INSERT SELECT in auto_increment)
sql/sql_insert.cc:
  - In INSERT ... SELECT, if it fails with error but one row has been inserted and
  the table is not transactional, we must write to the binlog (the slave will stop
  because of the error code in the binlog event, this is normal). bug 491.
  - we must set INSERT_ID before writing to the binlog (bug 490
  accidentally introduced by another dev in 4.0.13).
parent 51dacba9
...@@ -66,3 +66,17 @@ INSERT INTO crash1 (numeropost,icone,contenu,pseudo,date,signature,ip) ...@@ -66,3 +66,17 @@ INSERT INTO crash1 (numeropost,icone,contenu,pseudo,date,signature,ip)
SELECT 1718,icone,contenu,pseudo,date,signature,ip FROM crash2 SELECT 1718,icone,contenu,pseudo,date,signature,ip FROM crash2
WHERE numeropost=9 ORDER BY numreponse ASC; WHERE numeropost=9 ORDER BY numreponse ASC;
DROP TABLE IF EXISTS crash1,crash2; DROP TABLE IF EXISTS crash1,crash2;
drop table if exists t1;
drop table if exists t2;
create table t1(a int, unique(a));
insert into t1 values(2);
create table t2(a int);
insert into t2 values(1),(2);
reset master;
insert into t1 select * from t2;
Duplicate entry '2' for key 1
show binlog events;
Log_name Pos Event_type Server_id Orig_log_pos Info
master-bin.001 4 Start 1 4 Server ver: VERSION, Binlog ver: 3
master-bin.001 79 Query 1 79 use test; insert into t1 select * from t2
drop table t1, t2;
...@@ -39,3 +39,31 @@ b c ...@@ -39,3 +39,31 @@ b c
6 11 6 11
drop table t1; drop table t1;
drop table t2; drop table t2;
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;
b c
5 0
6 10
7 11
8 12
9 13
select * from t1;
a
10
11
12
13
select * from t2;
b c
5 0
6 10
7 11
8 12
9 13
drop table t1;
drop table t2;
...@@ -68,3 +68,22 @@ WHERE numeropost=9 ORDER BY numreponse ASC; ...@@ -68,3 +68,22 @@ WHERE numeropost=9 ORDER BY numreponse ASC;
DROP TABLE IF EXISTS crash1,crash2; DROP TABLE IF EXISTS crash1,crash2;
# Addendum by Guilhem:
# Check if a partly-completed INSERT SELECT in a MyISAM table goes
# into the binlog
drop table if exists t1;
drop table if exists t2;
create table t1(a int, unique(a));
insert into t1 values(2);
create table t2(a int);
insert into t2 values(1),(2);
reset master;
--error 1062
insert into t1 select * from t2;
# The above should produce an error, but still be in the binlog;
# verify the binlog :
let $VERSION=`select version()`;
--replace_result $VERSION VERSION
show binlog events;
drop table t1, t2;
#see if queries that use both # see if queries that use both
#auto_increment and LAST_INSERT_ID() # auto_increment and LAST_INSERT_ID()
#are replicated well # are replicated well
source include/master-slave.inc; source include/master-slave.inc;
connection master; connection master;
drop table if exists t1; drop table if exists t1;
...@@ -15,9 +16,11 @@ sync_with_master; ...@@ -15,9 +16,11 @@ sync_with_master;
select * from t1; select * from t1;
select * from t2; select * from t2;
connection master; connection master;
#check if multi-line inserts,
#which set last_insert_id to the first id inserted, # check if multi-line inserts,
#are replicated the same way # which set last_insert_id to the first id inserted,
# are replicated the same way
drop table t1; drop table t1;
drop table t2; drop table t2;
create table t1(a int auto_increment, key(a)); create table t1(a int auto_increment, key(a));
...@@ -32,6 +35,24 @@ sync_with_master; ...@@ -32,6 +35,24 @@ sync_with_master;
select * from t1; select * from t1;
select * from t2; select * from t2;
connection master; connection master;
# check if INSERT SELECT in auto_increment is well replicated (bug #490)
drop table t1;
drop table t2;
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;
save_master_pos;
connection slave;
sync_with_master;
select * from t1;
select * from t2;
connection master;
drop table t1; drop table t1;
drop table t2; drop table t2;
save_master_pos; save_master_pos;
......
...@@ -1350,6 +1350,24 @@ void select_insert::send_error(uint errcode,const char *err) ...@@ -1350,6 +1350,24 @@ void select_insert::send_error(uint errcode,const char *err)
::send_error(&thd->net,errcode,err); ::send_error(&thd->net,errcode,err);
table->file->extra(HA_EXTRA_NO_CACHE); table->file->extra(HA_EXTRA_NO_CACHE);
table->file->activate_all_index(thd); table->file->activate_all_index(thd);
/*
If at least one row has been inserted/modified and will stay in the table
(the table doesn't have transactions) (example: we got a duplicate key
error while inserting into a MyISAM table) we must write to the binlog (and
the error code will make the slave stop).
*/
if ((info.copied || info.deleted) && !table->file->has_transactions())
{
if (last_insert_id)
thd->insert_id(last_insert_id); // For binary log
mysql_update_log.write(thd,thd->query,thd->query_length);
if (mysql_bin_log.is_open())
{
Query_log_event qinfo(thd, thd->query, thd->query_length,
table->file->has_transactions());
mysql_bin_log.write(&qinfo);
}
}
ha_rollback_stmt(thd); ha_rollback_stmt(thd);
if (info.copied || info.deleted) if (info.copied || info.deleted)
{ {
...@@ -1365,7 +1383,10 @@ bool select_insert::send_eof() ...@@ -1365,7 +1383,10 @@ bool select_insert::send_eof()
error=table->file->activate_all_index(thd); error=table->file->activate_all_index(thd);
table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY); table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
if (last_insert_id)
thd->insert_id(last_insert_id); // For binary log
/* Write to binlog before commiting transaction */ /* Write to binlog before commiting transaction */
mysql_update_log.write(thd,thd->query,thd->query_length);
if (mysql_bin_log.is_open()) if (mysql_bin_log.is_open())
{ {
Query_log_event qinfo(thd, thd->query, thd->query_length, Query_log_event qinfo(thd, thd->query, thd->query_length,
...@@ -1393,10 +1414,7 @@ bool select_insert::send_eof() ...@@ -1393,10 +1414,7 @@ bool select_insert::send_eof()
else else
sprintf(buff,ER(ER_INSERT_INFO),info.records,info.deleted, sprintf(buff,ER(ER_INSERT_INFO),info.records,info.deleted,
thd->cuted_fields); thd->cuted_fields);
if (last_insert_id)
thd->insert_id(last_insert_id); // For update log
::send_ok(&thd->net,info.copied+info.deleted,last_insert_id,buff); ::send_ok(&thd->net,info.copied+info.deleted,last_insert_id,buff);
mysql_update_log.write(thd,thd->query,thd->query_length);
return 0; return 0;
} }
} }
......
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