Commit e9b5cafa authored by unknown's avatar unknown

Bug#19995 (Extreneous table maps generated for statements that do not generate rows):

Switched to writing out table maps for tables that are locked when
the first row in a statement is seen.


mysql-test/include/master-slave.inc:
  Moved code to reset master and slave into separate file.
mysql-test/r/binlog_row_blackhole.result:
  Result change
mysql-test/r/binlog_row_mix_innodb_myisam.result:
  Result change
mysql-test/r/ndb_binlog_ignore_db.result:
  Result change
mysql-test/r/rpl_ndb_charset.result:
  Result change
mysql-test/r/rpl_row_basic_11bugs.result:
  Result change
mysql-test/r/rpl_row_charset.result:
  Result change
mysql-test/r/rpl_row_create_table.result:
  Result change
mysql-test/t/rpl_row_basic_11bugs.test:
  Added test to check that no events are generated when no rows are changed.
mysql-test/t/rpl_row_create_table.test:
  Master log position changed
sql/handler.cc:
  Adding function write_locked_table_maps() that will write table maps for all
  tables locked for write.
  Using "table->in_use" instead of "current_thd" since tables are now locked
  when the function is called.
  Removing old code to write table map.
sql/log_event.cc:
  Added assertion
sql/sql_class.cc:
  Removing code to write "dummy termination event".
sql/sql_class.h:
  Adding getter for binlog_table_maps.
sql/sql_insert.cc:
  Setting thd->lock before calling write_record for the execution of
  CREATE-SELECT and INSERT-SELECT since they keep multiple locks in the
  air at the same time.
mysql-test/include/master-slave-reset.inc:
  New BitKeeper file ``mysql-test/include/master-slave-reset.inc''
parent 39b6d186
connection slave;
#we expect STOP SLAVE to produce a warning as the slave is stopped
#(the server was started with skip-slave-start)
--disable_warnings
stop slave;
--wait_for_slave_to_stop
--enable_warnings
connection master;
--disable_warnings
--disable_query_log
use test;
--enable_query_log
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
--enable_warnings
reset master;
connection slave;
reset slave;
# Clean up old test tables
--disable_warnings
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
--enable_warnings
start slave;
......@@ -2,28 +2,8 @@ connect (master,127.0.0.1,root,,test,$MASTER_MYPORT,);
connect (master1,127.0.0.1,root,,test,$MASTER_MYPORT,);
connect (slave,127.0.0.1,root,,test,$SLAVE_MYPORT,);
connect (slave1,127.0.0.1,root,,test,$SLAVE_MYPORT,);
connection slave;
#we expect STOP SLAVE to produce a warning as the slave is stopped
#(the server was started with skip-slave-start)
--disable_warnings
stop slave;
--enable_warnings
--require r/slave-stopped.result
show status like 'Slave_running';
connection master;
--disable_warnings
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
--enable_warnings
reset master;
connection slave;
reset slave;
# Clean up old test tables
--disable_warnings
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
--enable_warnings
start slave;
--require r/slave-running.result
show status like 'Slave_running';
-- source include/master-slave-reset.inc
# Set the default connection to 'master'
connection master;
......@@ -118,12 +118,6 @@ master-bin.000001 # Query 1 # use `test`; COMMIT
master-bin.000001 # Table_map 1 # table_id: # (test.t1)
master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F
master-bin.000001 # Query 1 # use `test`; COMMIT
master-bin.000001 # Table_map 1 # table_id: # (test.t1)
master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F
master-bin.000001 # Query 1 # use `test`; COMMIT
master-bin.000001 # Table_map 1 # table_id: # (test.t1)
master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F
master-bin.000001 # Query 1 # use `test`; COMMIT
master-bin.000001 # Query 1 # use `test`; create table t2 (a varchar(200)) engine=blackhole
master-bin.000001 # Table_map 1 # table_id: # (test.t2)
master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F
......@@ -131,12 +125,6 @@ master-bin.000001 # Query 1 # use `test`; COMMIT
master-bin.000001 # Query 1 # use `test`; alter table t1 add b int
master-bin.000001 # Query 1 # use `test`; alter table t1 drop b
master-bin.000001 # Query 1 # use `test`; create table t3 like t1
master-bin.000001 # Table_map 1 # table_id: # (test.t1)
master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F
master-bin.000001 # Query 1 # use `test`; COMMIT
master-bin.000001 # Table_map 1 # table_id: # (test.t1)
master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F
master-bin.000001 # Query 1 # use `test`; COMMIT
drop table t1,t2,t3;
reset master;
create table t1 (a int) engine=blackhole;
......
......@@ -262,27 +262,23 @@ master-bin.000001 209 Write_rows 1 # table_id: # flags: STMT_END_F
master-bin.000001 243 Table_map 1 # table_id: # (test.t1)
master-bin.000001 282 Write_rows 1 # table_id: # flags: STMT_END_F
master-bin.000001 316 Xid 1 # COMMIT /* xid= */
master-bin.000001 343 Table_map 1 # table_id: # (test.t1)
master-bin.000001 382 Query 1 # use `test`; delete from t1
master-bin.000001 459 Xid 1 # COMMIT /* xid= */
master-bin.000001 486 Table_map 1 # table_id: # (test.t2)
master-bin.000001 525 Query 1 # use `test`; delete from t2
master-bin.000001 602 Xid 1 # COMMIT /* xid= */
master-bin.000001 629 Query 1 # use `test`; alter table t2 engine=MyISAM
master-bin.000001 720 Table_map 1 # table_id: # (test.t1)
master-bin.000001 759 Write_rows 1 # table_id: # flags: STMT_END_F
master-bin.000001 793 Xid 1 # COMMIT /* xid= */
master-bin.000001 820 Query 1 # use `test`; BEGIN
master-bin.000001 888 Table_map 1 # table_id: # (test.t1)
master-bin.000001 927 Write_rows 1 # table_id: # flags: STMT_END_F
master-bin.000001 956 Xid 1 # COMMIT /* xid= */
master-bin.000001 983 Query 1 # use `test`; drop table t1,t2
master-bin.000001 1062 Query 1 # use `test`; create table t0 (n int)
master-bin.000001 1148 Table_map 1 # table_id: # (test.t0)
master-bin.000001 1187 Write_rows 1 # table_id: # flags: STMT_END_F
master-bin.000001 1221 Table_map 1 # table_id: # (test.t0)
master-bin.000001 1260 Write_rows 1 # table_id: # flags: STMT_END_F
master-bin.000001 1294 Query 1 # use `test`; create table t2 (n int) engine=innodb
master-bin.000001 343 Query 1 # use `test`; delete from t1
master-bin.000001 420 Xid 1 # COMMIT /* xid= */
master-bin.000001 447 Query 1 # use `test`; delete from t2
master-bin.000001 524 Xid 1 # COMMIT /* xid= */
master-bin.000001 551 Query 1 # use `test`; alter table t2 engine=MyISAM
master-bin.000001 642 Table_map 1 # table_id: # (test.t1)
master-bin.000001 681 Write_rows 1 # table_id: # flags: STMT_END_F
master-bin.000001 715 Xid 1 # COMMIT /* xid= */
master-bin.000001 742 Table_map 1 # table_id: # (test.t2)
master-bin.000001 781 Write_rows 1 # table_id: # flags: STMT_END_F
master-bin.000001 815 Query 1 # use `test`; drop table t1,t2
master-bin.000001 894 Query 1 # use `test`; create table t0 (n int)
master-bin.000001 980 Table_map 1 # table_id: # (test.t0)
master-bin.000001 1019 Write_rows 1 # table_id: # flags: STMT_END_F
master-bin.000001 1053 Table_map 1 # table_id: # (test.t0)
master-bin.000001 1092 Write_rows 1 # table_id: # flags: STMT_END_F
master-bin.000001 1126 Query 1 # use `test`; create table t2 (n int) engine=innodb
do release_lock("lock1");
drop table t0,t2;
reset master;
......
......@@ -7,6 +7,4 @@ insert into t1 values (1, 1);
show binlog events from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Query # # use `test`; drop table if exists t1
master-bin.000001 # Table_map # # table_id: # (mysql.proc)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
drop database mysqltest;
......@@ -112,16 +112,10 @@ drop database mysqltest3;
show binlog events from 102;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Query 1 # drop database if exists mysqltest2
master-bin.000001 # Table_map 1 # table_id: # (mysql.proc)
master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F
master-bin.000001 # Query 1 # drop database if exists mysqltest3
master-bin.000001 # Table_map 1 # table_id: # (mysql.proc)
master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F
master-bin.000001 # Query 1 # create database mysqltest2 character set latin2
master-bin.000001 # Query 1 # create database mysqltest3
master-bin.000001 # Query 1 # drop database mysqltest3
master-bin.000001 # Table_map 1 # table_id: # (mysql.proc)
master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F
master-bin.000001 # Query 1 # create database mysqltest3
master-bin.000001 # Query 1 # use `mysqltest2`; create table t1 (a int auto_increment primary key, b varchar(100))
master-bin.000001 # Table_map 1 # table_id: # (mysqltest2.t1)
......@@ -147,11 +141,7 @@ master-bin.000001 # Query 1 # use `mysqltest2`; truncate table t1
master-bin.000001 # Table_map 1 # table_id: # (mysqltest2.t1)
master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F
master-bin.000001 # Query 1 # drop database mysqltest2
master-bin.000001 # Table_map 1 # table_id: # (mysql.proc)
master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F
master-bin.000001 # Query 1 # drop database mysqltest3
master-bin.000001 # Table_map 1 # table_id: # (mysql.proc)
master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F
select "--- --global--" as "";
--- --global--
......
......@@ -44,3 +44,20 @@ t1
USE test_ignore;
ERROR 42000: Unknown database 'test_ignore'
DROP DATABASE test_ignore;
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
reset master;
reset slave;
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
start slave;
CREATE TABLE t1 (a INT);
DELETE FROM t1;
INSERT INTO t1 VALUES (1),(2);
DELETE FROM t1 WHERE a = 0;
UPDATE t1 SET a=99 WHERE a = 0;
SHOW BINLOG EVENTS;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 4 Format_desc 1 102 Server ver: 5.1.11-beta-debug-log, Binlog ver: 4
master-bin.000001 102 Query 1 188 use `test`; CREATE TABLE t1 (a INT)
master-bin.000001 188 Query 1 265 use `test`; DELETE FROM t1
master-bin.000001 265 Table_map 1 304 table_id: # (test.t1)
master-bin.000001 304 Write_rows 1 343 table_id: # flags: STMT_END_F
......@@ -112,16 +112,10 @@ drop database mysqltest3;
show binlog events from 102;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Query 1 # drop database if exists mysqltest2
master-bin.000001 # Table_map 1 # table_id: # (mysql.proc)
master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F
master-bin.000001 # Query 1 # drop database if exists mysqltest3
master-bin.000001 # Table_map 1 # table_id: # (mysql.proc)
master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F
master-bin.000001 # Query 1 # create database mysqltest2 character set latin2
master-bin.000001 # Query 1 # create database mysqltest3
master-bin.000001 # Query 1 # drop database mysqltest3
master-bin.000001 # Table_map 1 # table_id: # (mysql.proc)
master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F
master-bin.000001 # Query 1 # create database mysqltest3
master-bin.000001 # Query 1 # use `mysqltest2`; create table t1 (a int auto_increment primary key, b varchar(100))
master-bin.000001 # Table_map 1 # table_id: # (mysqltest2.t1)
......@@ -147,11 +141,7 @@ master-bin.000001 # Query 1 # use `mysqltest2`; truncate table t1
master-bin.000001 # Table_map 1 # table_id: # (mysqltest2.t1)
master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F
master-bin.000001 # Query 1 # drop database mysqltest2
master-bin.000001 # Table_map 1 # table_id: # (mysql.proc)
master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F
master-bin.000001 # Query 1 # drop database mysqltest3
master-bin.000001 # Table_map 1 # table_id: # (mysql.proc)
master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F
select "--- --global--" as "";
--- --global--
......
......@@ -127,7 +127,7 @@ NULL 5 10
NULL 6 12
CREATE TABLE t7 (UNIQUE(b)) SELECT a,b FROM tt3;
ERROR 23000: Duplicate entry '2' for key 'b'
SHOW BINLOG EVENTS FROM 1326;
SHOW BINLOG EVENTS FROM 1256;
Log_name Pos Event_type Server_id End_log_pos Info
CREATE TABLE t7 (a INT, b INT UNIQUE);
INSERT INTO t7 SELECT a,b FROM tt3;
......@@ -137,11 +137,11 @@ a b
1 2
2 4
3 6
SHOW BINLOG EVENTS FROM 1326;
SHOW BINLOG EVENTS FROM 1256;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 1326 Query 1 1426 use `test`; CREATE TABLE t7 (a INT, b INT UNIQUE)
master-bin.000001 1426 Table_map 1 1466 table_id: # (test.t7)
master-bin.000001 1466 Write_rows 1 1522 table_id: # flags: STMT_END_F
master-bin.000001 1256 Query 1 1356 use `test`; CREATE TABLE t7 (a INT, b INT UNIQUE)
master-bin.000001 1356 Table_map 1 1396 table_id: # (test.t7)
master-bin.000001 1396 Write_rows 1 1452 table_id: # flags: STMT_END_F
SELECT * FROM t7 ORDER BY a,b;
a b
1 2
......@@ -154,10 +154,10 @@ INSERT INTO t7 SELECT a,b FROM tt4;
ROLLBACK;
Warnings:
Warning 1196 Some non-transactional changed tables couldn't be rolled back
SHOW BINLOG EVENTS FROM 1522;
SHOW BINLOG EVENTS FROM 1452;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 1522 Table_map 1 1562 table_id: # (test.t7)
master-bin.000001 1562 Write_rows 1 1618 table_id: # flags: STMT_END_F
master-bin.000001 1452 Table_map 1 1492 table_id: # (test.t7)
master-bin.000001 1492 Write_rows 1 1548 table_id: # flags: STMT_END_F
SELECT * FROM t7 ORDER BY a,b;
a b
1 2
......@@ -191,10 +191,10 @@ Create Table CREATE TABLE `t9` (
`a` int(11) DEFAULT NULL,
`b` int(11) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
SHOW BINLOG EVENTS FROM 1618;
SHOW BINLOG EVENTS FROM 1548;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 1618 Query 1 1704 use `test`; CREATE TABLE t8 LIKE t4
master-bin.000001 1704 Query 1 1843 use `test`; CREATE TABLE `t9` (
master-bin.000001 1548 Query 1 1634 use `test`; CREATE TABLE t8 LIKE t4
master-bin.000001 1634 Query 1 1773 use `test`; CREATE TABLE `t9` (
`a` int(11) DEFAULT NULL,
`b` int(11) DEFAULT NULL
)
......
......@@ -36,3 +36,18 @@ USE test_ignore;
connection master;
DROP DATABASE test_ignore;
sync_slave_with_master;
# Bug#19995: Extreneous table maps generated for statements that does
# not generate rows
--disable_query_log
--source include/master-slave-reset.inc
--enable_query_log
connection master;
CREATE TABLE t1 (a INT);
DELETE FROM t1;
INSERT INTO t1 VALUES (1),(2);
DELETE FROM t1 WHERE a = 0;
UPDATE t1 SET a=99 WHERE a = 0;
--replace_regex /table_id: [0-9]+/table_id: #/
SHOW BINLOG EVENTS;
......@@ -67,7 +67,7 @@ connection master;
CREATE TABLE t7 (UNIQUE(b)) SELECT a,b FROM tt3;
# Shouldn't be written to the binary log
--replace_regex /table_id: [0-9]+/table_id: #/
SHOW BINLOG EVENTS FROM 1326;
SHOW BINLOG EVENTS FROM 1256;
# Test that INSERT-SELECT works the same way as for SBR.
CREATE TABLE t7 (a INT, b INT UNIQUE);
......@@ -76,7 +76,7 @@ INSERT INTO t7 SELECT a,b FROM tt3;
SELECT * FROM t7 ORDER BY a,b;
# Should be written to the binary log
--replace_regex /table_id: [0-9]+/table_id: #/
SHOW BINLOG EVENTS FROM 1326;
SHOW BINLOG EVENTS FROM 1256;
sync_slave_with_master;
SELECT * FROM t7 ORDER BY a,b;
......@@ -87,7 +87,7 @@ BEGIN;
INSERT INTO t7 SELECT a,b FROM tt4;
ROLLBACK;
--replace_regex /table_id: [0-9]+/table_id: #/
SHOW BINLOG EVENTS FROM 1522;
SHOW BINLOG EVENTS FROM 1452;
SELECT * FROM t7 ORDER BY a,b;
sync_slave_with_master;
SELECT * FROM t7 ORDER BY a,b;
......@@ -101,7 +101,7 @@ CREATE TEMPORARY TABLE tt6 LIKE tt4;
--query_vertical SHOW CREATE TABLE t8
--query_vertical SHOW CREATE TABLE t9
--replace_regex /table_id: [0-9]+/table_id: #/
SHOW BINLOG EVENTS FROM 1618;
SHOW BINLOG EVENTS FROM 1548;
sync_slave_with_master;
--echo **** On Slave ****
--query_vertical SHOW CREATE TABLE t8
......
......@@ -3199,6 +3199,58 @@ namespace {
}
}
/**
Write table maps for all (manually or automatically) locked tables
to the binary log.
This function will generate and write table maps for all tables
that are locked by the thread 'thd'. Either manually locked
(stored in THD::locked_tables) and automatically locked (stored in
THD::lock) are considered.
See THD::lock and THD::locked_tables for more information.
*/
static int
write_locked_table_maps(THD *thd)
{
DBUG_ENTER("write_locked_table_maps");
DBUG_PRINT("enter", ("thd=%p, thd->lock=%p, thd->locked_tables=%p",
thd, thd->lock, thd->locked_tables));
if (thd->get_binlog_table_maps() == 0)
{
/*
Exactly one table has to be locked, otherwise this code is not
guaranteed to work.
*/
DBUG_ASSERT((thd->lock != NULL) + (thd->locked_tables != NULL) == 1);
MYSQL_LOCK *lock= thd->lock ? thd->lock : thd->locked_tables;
DBUG_ASSERT(lock->table_count > 0);
TABLE **const end_ptr= lock->table + lock->table_count;
for (TABLE **table_ptr= lock->table ;
table_ptr != end_ptr ;
++table_ptr)
{
TABLE *const table= *table_ptr;
DBUG_PRINT("info", ("Checking table %s", table->s->table_name));
if (table->current_lock == F_WRLCK &&
check_table_binlog_row_based(thd, table))
{
int const has_trans= table->file->has_transactions();
int const error= thd->binlog_write_table_map(table, has_trans);
/*
If an error occurs, it is the responsibility of the caller to
roll back the transaction.
*/
if (unlikely(error))
DBUG_RETURN(1);
}
}
}
DBUG_RETURN(0);
}
template<class RowsEventT> int binlog_log_row(TABLE* table,
const byte *before_record,
const byte *after_record)
......@@ -3206,7 +3258,7 @@ template<class RowsEventT> int binlog_log_row(TABLE* table,
if (table->file->is_injective())
return 0;
bool error= 0;
THD *const thd= current_thd;
THD *const thd= table->in_use;
if (check_table_binlog_row_based(thd, table))
{
......@@ -3215,17 +3267,26 @@ template<class RowsEventT> int binlog_log_row(TABLE* table,
uint32 bitbuf[BITMAP_STACKBUF_SIZE/sizeof(uint32)];
uint n_fields= table->s->fields;
my_bool use_bitbuf= n_fields <= sizeof(bitbuf)*8;
/*
If there are no table maps written to the binary log, this is
the first row handled in this statement. In that case, we need
to write table maps for all locked tables to the binary log.
*/
if (likely(!(error= bitmap_init(&cols,
use_bitbuf ? bitbuf : NULL,
(n_fields + 7) & ~7UL,
false))))
{
bitmap_set_all(&cols);
error=
RowsEventT::binlog_row_logging_function(thd, table,
table->file->has_transactions(),
&cols, table->s->fields,
before_record, after_record);
if (likely(!(error= write_locked_table_maps(thd))))
{
error=
RowsEventT::binlog_row_logging_function(thd, table,
table->file->has_transactions(),
&cols, table->s->fields,
before_record, after_record);
}
if (!use_bitbuf)
bitmap_free(&cols);
}
......@@ -3251,41 +3312,6 @@ int handler::ha_external_lock(THD *thd, int lock_type)
int error;
if (unlikely(error= external_lock(thd, lock_type)))
DBUG_RETURN(error);
#ifdef HAVE_ROW_BASED_REPLICATION
if (table->file->is_injective())
DBUG_RETURN(0);
/*
There is a number of statements that are logged statement-based
but call external lock. For these, we do not need to generate a
table map.
TODO: The need for this switch is an indication that the model for
locking combined with row-based replication needs to be looked
over. Ideally, no such special handling should be needed.
*/
switch (thd->lex->sql_command) {
case SQLCOM_TRUNCATE:
case SQLCOM_ALTER_TABLE:
case SQLCOM_OPTIMIZE:
case SQLCOM_REPAIR:
DBUG_RETURN(0);
default:
break;
}
/*
If we are locking a table for writing, we generate a table map.
For all other kinds of locks, we don't do anything.
*/
if (lock_type == F_WRLCK && check_table_binlog_row_based(thd, table))
{
int const has_trans= table->file->has_transactions();
error= thd->binlog_write_table_map(table, has_trans);
if (unlikely(error))
DBUG_RETURN(error);
}
#endif
DBUG_RETURN(0);
}
......
......@@ -5602,6 +5602,7 @@ int Rows_log_event::exec_event(st_relay_log_info *rli)
bool Rows_log_event::write_data_header(IO_CACHE *file)
{
byte buf[ROWS_HEADER_LEN]; // No need to init the buffer
DBUG_ASSERT(m_table_id != ~0UL);
DBUG_EXECUTE_IF("old_row_based_repl_4_byte_map_id_master",
{
int4store(buf + 0, m_table_id);
......
......@@ -2624,31 +2624,6 @@ int THD::binlog_flush_pending_rows_event(bool stmt_end)
error= mysql_bin_log.flush_and_set_pending_rows_event(this, 0);
}
else if (stmt_end && binlog_table_maps > 0)
{ /* there is no pending event at this point */
/*
If pending is null and we are going to end the statement, we
have to write an extra, empty, binrow event so that the slave
knows to discard the tables it has received. Otherwise, the
table maps written this far will be included in the table maps
for the following statement.
TODO: Remove the need for a dummy event altogether. It can be
fixed if we can write table maps to a memory buffer before
writing the first binrow event. We can then flush and clear the
memory buffer with table map events before writing the first
binrow event. In the event of a crash, nothing is lost since
the table maps are only needed if there are binrow events.
*/
Rows_log_event *ev=
new Write_rows_log_event(this, 0, ~0UL, 0, FALSE);
ev->set_flags(Rows_log_event::STMT_END_F);
binlog_set_pending_rows_event(ev);
error= mysql_bin_log.flush_and_set_pending_rows_event(this, 0);
binlog_table_maps= 0;
}
DBUG_RETURN(error);
}
......
......@@ -941,16 +941,18 @@ class THD :public Statement,
int binlog_flush_pending_rows_event(bool stmt_end);
void binlog_delete_pending_rows_event();
private:
#ifdef HAVE_ROW_BASED_REPLICATION
private:
uint binlog_table_maps; // Number of table maps currently in the binlog
#endif /* HAVE_ROW_BASED_REPLICATION */
public:
uint get_binlog_table_maps() const {
return binlog_table_maps;
}
#endif /* HAVE_ROW_BASED_REPLICATION */
#endif /* MYSQL_CLIENT */
#ifndef MYSQL_CLIENT
public:
enum enum_binlog_query_type {
/*
The query can be logged row-based or statement-based
......@@ -1572,6 +1574,9 @@ class select_insert :public select_result_interceptor {
bool send_eof();
/* not implemented: select_insert is never re-used in prepared statements */
void cleanup();
protected:
MYSQL_LOCK *lock;
};
......@@ -1581,7 +1586,6 @@ class select_create: public select_insert {
List<create_field> *extra_fields;
List<Key> *keys;
HA_CREATE_INFO *create_info;
MYSQL_LOCK *lock;
Field **field;
public:
select_create (TABLE_LIST *table,
......@@ -1590,8 +1594,7 @@ class select_create: public select_insert {
List<Key> &keys_par,
List<Item> &select_fields,enum_duplicates duplic, bool ignore)
:select_insert (NULL, NULL, &select_fields, 0, 0, duplic, ignore), create_table(table),
extra_fields(&fields_par),keys(&keys_par), create_info(create_info_par),
lock(0)
extra_fields(&fields_par),keys(&keys_par), create_info(create_info_par)
{}
int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
......
......@@ -2152,6 +2152,7 @@ select_insert::select_insert(TABLE_LIST *table_list_par, TABLE *table_par,
bool ignore_check_option_errors)
:table_list(table_list_par), table(table_par), fields(fields_par),
last_insert_id(0),
lock(0),
insert_into_view(table_list_par && table_list_par->view != 0)
{
bzero((char*) &info,sizeof(info));
......@@ -2348,7 +2349,36 @@ bool select_insert::send_data(List<Item> &values)
DBUG_RETURN(1);
}
}
if (!(error= write_record(thd, table, &info)))
/*
The thd->lock lock contain the locks for the select part of the
statement and the 'lock' variable contain the write lock for the
currently locked table that is being created or inserted
into. However, the row-based replication will investigate the
thd->lock to decide what table maps are to be written, so this one
has to contain the tables locked for writing. To be able to write
table map for the table being created, we temporarily set
THD::lock to select_insert::lock while writing the record to the
storage engine. We cannot set this elsewhere, since the execution
of a stored function inside the select expression might cause the
lock structures to be NULL.
*/
{
MYSQL_LOCK *saved_lock= NULL;
if (lock)
{
saved_lock= thd->lock;
thd->lock= lock;
}
error= write_record(thd, table, &info);
if (lock)
thd->lock= saved_lock;
}
if (!error)
{
if (table->triggers || info.handle_duplicates == DUP_UPDATE)
{
......
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