diff options
27 files changed, 619 insertions, 215 deletions
diff --git a/mysql-test/r/binlog_innodb.result b/mysql-test/r/binlog_innodb.result new file mode 100644 index 00000000000..61f5ad19f0d --- /dev/null +++ b/mysql-test/r/binlog_innodb.result @@ -0,0 +1,114 @@ +SET BINLOG_FORMAT=MIXED; +RESET MASTER; +CREATE TABLE t1 (a INT PRIMARY KEY, b INT) ENGINE=INNODB; +INSERT INTO t1 VALUES (1,1),(2,2),(3,3),(4,4),(5,5),(6,6); +BEGIN; +SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ; +UPDATE t1 SET b = 2*a WHERE a > 1; +COMMIT; +BEGIN; +SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; +UPDATE t1 SET b = a * a WHERE a > 3; +COMMIT; +SET BINLOG_FORMAT=STATEMENT; +BEGIN; +SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; +UPDATE t1 SET b = 1*a WHERE a > 1; +ERROR HY000: Logging not possible. Message: InnoDB: Transaction level 'READ-UNCOMMITTED' is not safe for binlog mode 'STATEMENT' +COMMIT; +BEGIN; +SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; +UPDATE t1 SET b = 2*a WHERE a > 2; +ERROR HY000: Logging not possible. Message: InnoDB: Transaction level 'READ-COMMITTED' is not safe for binlog mode 'STATEMENT' +COMMIT; +BEGIN; +SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ; +UPDATE t1 SET b = 3*a WHERE a > 3; +COMMIT; +BEGIN; +SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE; +UPDATE t1 SET b = 4*a WHERE a > 4; +COMMIT; +SET BINLOG_FORMAT=MIXED; +BEGIN; +SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; +UPDATE t1 SET b = 1*a WHERE a > 1; +COMMIT; +BEGIN; +SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; +UPDATE t1 SET b = 2*a WHERE a > 2; +COMMIT; +BEGIN; +SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ; +UPDATE t1 SET b = 3*a WHERE a > 3; +COMMIT; +BEGIN; +SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE; +UPDATE t1 SET b = 4*a WHERE a > 4; +COMMIT; +SET BINLOG_FORMAT=ROW; +BEGIN; +SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; +UPDATE t1 SET b = 1*a WHERE a > 1; +COMMIT; +BEGIN; +SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; +UPDATE t1 SET b = 2*a WHERE a > 2; +COMMIT; +BEGIN; +SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ; +UPDATE t1 SET b = 3*a WHERE a > 3; +COMMIT; +BEGIN; +SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE; +UPDATE t1 SET b = 4*a WHERE a > 4; +COMMIT; +show binlog events from <binlog_start>; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a INT PRIMARY KEY, b INT) ENGINE=INNODB +master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (1,1),(2,2),(3,3),(4,4),(5,5),(6,6) +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # use `test`; BEGIN +master-bin.000001 # Query # # use `test`; UPDATE t1 SET b = 2*a WHERE a > 1 +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # use `test`; BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Update_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # use `test`; BEGIN +master-bin.000001 # Query # # use `test`; UPDATE t1 SET b = 3*a WHERE a > 3 +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # use `test`; BEGIN +master-bin.000001 # Query # # use `test`; UPDATE t1 SET b = 4*a WHERE a > 4 +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # use `test`; BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Update_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # use `test`; BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Update_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # use `test`; BEGIN +master-bin.000001 # Query # # use `test`; UPDATE t1 SET b = 3*a WHERE a > 3 +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # use `test`; BEGIN +master-bin.000001 # Query # # use `test`; UPDATE t1 SET b = 4*a WHERE a > 4 +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # use `test`; BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Update_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # use `test`; BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Update_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # use `test`; BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Update_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # use `test`; BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Update_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ +DROP TABLE t1; diff --git a/mysql-test/r/binlog_multi_engine.result b/mysql-test/r/binlog_multi_engine.result new file mode 100644 index 00000000000..7af4525d887 --- /dev/null +++ b/mysql-test/r/binlog_multi_engine.result @@ -0,0 +1,86 @@ +CREATE TABLE t1m (m INT, n INT) ENGINE=MYISAM; +CREATE TABLE t1b (b INT, c INT) ENGINE=BLACKHOLE; +CREATE TABLE t1n (e INT, f INT) ENGINE=NDB; +SET SESSION BINLOG_FORMAT=STATEMENT; +INSERT INTO t1m VALUES (1,1), (1,2), (2,1), (2,2); +INSERT INTO t1b VALUES (1,1), (1,2), (2,1), (2,2); +INSERT INTO t1n VALUES (1,1), (1,2), (2,1), (2,2); +ERROR HY000: Attempting to log statement in in statement format, but statement format is not possible with this combination of engines +UPDATE t1m, t1b SET m = 2, b = 3 WHERE n = c; +UPDATE t1m, t1n SET m = 2, e = 3 WHERE n = f; +ERROR HY000: Attempting to log statement in in statement format, but statement format is not possible with this combination of engines +UPDATE t1n, t1b SET e = 2, b = 3 WHERE f = c; +ERROR HY000: It is not possible to log anything with this combination of engines +TRUNCATE t1m; +TRUNCATE t1b; +TRUNCATE t1n; +SET SESSION BINLOG_FORMAT=MIXED; +INSERT INTO t1m VALUES (1,1), (1,2), (2,1), (2,2); +INSERT INTO t1b VALUES (1,1), (1,2), (2,1), (2,2); +INSERT INTO t1n VALUES (1,1), (1,2), (2,1), (2,2); +UPDATE t1m, t1b SET m = 2, b = 3 WHERE n = c; +UPDATE t1m, t1n SET m = 2, e = 3 WHERE n = f; +UPDATE t1n, t1b SET e = 2, b = 3 WHERE f = c; +ERROR HY000: It is not possible to log anything with this combination of engines +TRUNCATE t1m; +TRUNCATE t1b; +TRUNCATE t1n; +SET SESSION BINLOG_FORMAT=ROW; +INSERT INTO t1m VALUES (1,1), (1,2), (2,1), (2,2); +INSERT INTO t1b VALUES (1,1), (1,2), (2,1), (2,2); +ERROR HY000: Attempting to log statement in in row format, but row format is not possible with this combination of engines +INSERT INTO t1n VALUES (1,1), (1,2), (2,1), (2,2); +UPDATE t1m, t1b SET m = 2, b = 3 WHERE n = c; +ERROR HY000: Attempting to log statement in in row format, but row format is not possible with this combination of engines +UPDATE t1m, t1n SET m = 2, e = 3 WHERE n = f; +UPDATE t1n, t1b SET e = 2, b = 3 WHERE f = c; +ERROR HY000: It is not possible to log anything with this combination of engines +TRUNCATE t1m; +TRUNCATE t1b; +TRUNCATE t1n; +show binlog events from <binlog_start>; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # use `test`; CREATE TABLE t1m (m INT, n INT) ENGINE=MYISAM +master-bin.000001 # Query # # use `test`; CREATE TABLE t1b (b INT, c INT) ENGINE=BLACKHOLE +master-bin.000001 # Query # # use `test`; CREATE TABLE t1n (e INT, f INT) ENGINE=NDB +master-bin.000001 # Query # # use `test`; INSERT INTO t1m VALUES (1,1), (1,2), (2,1), (2,2) +master-bin.000001 # Query # # use `test`; INSERT INTO t1b VALUES (1,1), (1,2), (2,1), (2,2) +master-bin.000001 # Query # # use `test`; UPDATE t1m, t1b SET m = 2, b = 3 WHERE n = c +master-bin.000001 # Query # # use `test`; TRUNCATE t1m +master-bin.000001 # Query # # use `test`; TRUNCATE t1b +master-bin.000001 # Query # # use `test`; TRUNCATE t1n +master-bin.000001 # Query # # use `test`; INSERT INTO t1m VALUES (1,1), (1,2), (2,1), (2,2) +master-bin.000001 # Query # # use `test`; INSERT INTO t1b VALUES (1,1), (1,2), (2,1), (2,2) +master-bin.000001 # Query # # use `test`; INSERT INTO t1n VALUES (1,1), (1,2), (2,1), (2,2) +master-bin.000001 # Query # # use `test`; UPDATE t1m, t1b SET m = 2, b = 3 WHERE n = c +master-bin.000001 # Query # # use `test`; UPDATE t1m, t1n SET m = 2, e = 3 WHERE n = f +master-bin.000001 # Query # # use `test`; TRUNCATE t1m +master-bin.000001 # Query # # use `test`; TRUNCATE t1b +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t1n) +master-bin.000001 # Table_map # # table_id: # (mysql.ndb_apply_status) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Update_rows # # table_id: # +master-bin.000001 # Update_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Query # # use `test`; TRUNCATE t1n +master-bin.000001 # Table_map # # table_id: # (test.t1m) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Table_map # # table_id: # (test.t1m) +master-bin.000001 # Table_map # # table_id: # (test.t1n) +master-bin.000001 # Update_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # use `test`; TRUNCATE t1m +master-bin.000001 # Query # # use `test`; TRUNCATE t1b +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t1n) +master-bin.000001 # Table_map # # table_id: # (mysql.ndb_apply_status) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Update_rows # # table_id: # +master-bin.000001 # Update_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Query # # use `test`; TRUNCATE t1n +DROP TABLE t1m, t1b, t1n; diff --git a/mysql-test/r/binlog_row_blackhole.result b/mysql-test/r/binlog_row_blackhole.result deleted file mode 100644 index e58f4648470..00000000000 --- a/mysql-test/r/binlog_row_blackhole.result +++ /dev/null @@ -1,155 +0,0 @@ -drop table if exists t1,t2; -CREATE TABLE t1 ( -Period smallint(4) unsigned zerofill DEFAULT '0000' NOT NULL, -Varor_period smallint(4) unsigned DEFAULT '0' NOT NULL -) ENGINE=blackhole; -INSERT INTO t1 VALUES (9410,9412); -select period from t1; -period -select * from t1; -Period Varor_period -select t1.* from t1; -Period Varor_period -CREATE TABLE t2 ( -auto int NOT NULL auto_increment, -fld1 int(6) unsigned zerofill DEFAULT '000000' NOT NULL, -companynr tinyint(2) unsigned zerofill DEFAULT '00' NOT NULL, -fld3 char(30) DEFAULT '' NOT NULL, -fld4 char(35) DEFAULT '' NOT NULL, -fld5 char(35) DEFAULT '' NOT NULL, -fld6 char(4) DEFAULT '' NOT NULL, -primary key (auto) -) ENGINE=blackhole; -INSERT INTO t2 VALUES (1192,068305,00,'Colombo','hardware','colicky',''); -INSERT INTO t2 VALUES (1193,000000,00,'nondecreasing','implant','thrillingly',''); -select t2.fld3 from t2 where companynr = 58 and fld3 like "%imaginable%"; -fld3 -select fld3 from t2 where fld3 like "%cultivation" ; -fld3 -select t2.fld3,companynr from t2 where companynr = 57+1 order by fld3; -fld3 companynr -select fld3,companynr from t2 where companynr = 58 order by fld3; -fld3 companynr -select fld3 from t2 order by fld3 desc limit 10; -fld3 -select fld3 from t2 order by fld3 desc limit 5; -fld3 -select fld3 from t2 order by fld3 desc limit 5,5; -fld3 -select t2.fld3 from t2 where fld3 = 'honeysuckle'; -fld3 -select t2.fld3 from t2 where fld3 LIKE 'honeysuckl_'; -fld3 -select t2.fld3 from t2 where fld3 LIKE 'hon_ysuckl_'; -fld3 -select t2.fld3 from t2 where fld3 LIKE 'honeysuckle%'; -fld3 -select t2.fld3 from t2 where fld3 LIKE 'h%le'; -fld3 -select t2.fld3 from t2 where fld3 LIKE 'honeysuckle_'; -fld3 -select t2.fld3 from t2 where fld3 LIKE 'don_t_find_me_please%'; -fld3 -select t2.fld3 from t2 where fld3 >= 'honeysuckle' and fld3 <= 'honoring' order by fld3; -fld3 -select fld1,fld3 from t2 where fld3="Colombo" or fld3 = "nondecreasing" order by fld3; -fld1 fld3 -DROP TABLE t1; -CREATE TABLE t1 (a VARCHAR(200), b TEXT, FULLTEXT (a,b)); -INSERT INTO t1 VALUES('MySQL has now support', 'for full-text search'), -('Full-text indexes', 'are called collections'), -('Only MyISAM tables','support collections'), -('Function MATCH ... AGAINST()','is used to do a search'), -('Full-text search in MySQL', 'implements vector space model'); -SHOW INDEX FROM t1; -Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment -t1 1 a 1 a NULL NULL NULL NULL YES FULLTEXT -t1 1 a 2 b NULL NULL NULL NULL YES FULLTEXT -select * from t1 where MATCH(a,b) AGAINST ("collections"); -a b -Only MyISAM tables support collections -Full-text indexes are called collections -explain extended select * from t1 where MATCH(a,b) AGAINST ("collections"); -id select_type table type possible_keys key key_len ref rows filtered Extra -1 SIMPLE t1 fulltext a a 0 1 100.00 Using where -Warnings: -Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` where (match `test`.`t1`.`a`,`test`.`t1`.`b` against (_latin1'collections')) -select * from t1 where MATCH(a,b) AGAINST ("indexes"); -a b -Full-text indexes are called collections -select * from t1 where MATCH(a,b) AGAINST ("indexes collections"); -a b -Full-text indexes are called collections -Only MyISAM tables support collections -select * from t1 where MATCH(a,b) AGAINST ("only"); -a b -reset master; -drop table t1,t2; -create table t1 (a int) engine=blackhole; -delete from t1 where a=10; -update t1 set a=11 where a=15; -insert into t1 values(1); -insert ignore into t1 values(1); -replace into t1 values(100); -create table t2 (a varchar(200)) engine=blackhole; -load data infile '../std_data_ln/words.dat' into table t2; -alter table t1 add b int; -alter table t1 drop b; -create table t3 like t1; -insert into t1 select * from t3; -replace into t1 select * from t3; -select * from t1; -a -select * from t2; -a -select * from t3; -a -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 t1,t2 -master-bin.000001 # Query # # use `test`; create table t1 (a int) engine=blackhole -master-bin.000001 # Table_map # # table_id: # (test.t1) -master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F -master-bin.000001 # Table_map # # table_id: # (test.t1) -master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F -master-bin.000001 # Table_map # # table_id: # (test.t1) -master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F -master-bin.000001 # Query # # use `test`; create table t2 (a varchar(200)) engine=blackhole -master-bin.000001 # Table_map # # table_id: # (test.t2) -master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F -master-bin.000001 # Query # # use `test`; alter table t1 add b int -master-bin.000001 # Query # # use `test`; alter table t1 drop b -master-bin.000001 # Query # # use `test`; create table t3 like t1 -drop table t1,t2,t3; -CREATE TABLE t1(a INT) ENGINE=BLACKHOLE; -INSERT DELAYED INTO t1 VALUES(1); -DROP TABLE t1; -CREATE TABLE t1(a INT, b INT) ENGINE=BLACKHOLE; -DELETE FROM t1 WHERE a=10; -ALTER TABLE t1 ADD INDEX(a); -DELETE FROM t1 WHERE a=10; -ALTER TABLE t1 DROP INDEX a; -ALTER TABLE t1 ADD UNIQUE INDEX(a); -DELETE FROM t1 WHERE a=10; -ALTER TABLE t1 DROP INDEX a; -ALTER TABLE t1 ADD PRIMARY KEY(a); -DELETE FROM t1 WHERE a=10; -DROP TABLE t1; -reset master; -create table t1 (a int) engine=blackhole; -set autocommit=0; -start transaction; -insert into t1 values(1); -commit; -start transaction; -insert into t1 values(2); -rollback; -set autocommit=1; -show binlog events from <binlog_start>; -Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 # Query # # use `test`; create table t1 (a int) engine=blackhole -master-bin.000001 # Query # # use `test`; BEGIN -master-bin.000001 # Table_map # # table_id: # (test.t1) -master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F -master-bin.000001 # Query # # use `test`; COMMIT -drop table if exists t1; diff --git a/mysql-test/t/binlog_innodb.test b/mysql-test/t/binlog_innodb.test new file mode 100644 index 00000000000..712708100f5 --- /dev/null +++ b/mysql-test/t/binlog_innodb.test @@ -0,0 +1,95 @@ +source include/have_innodb.inc; + +SET BINLOG_FORMAT=MIXED; + +RESET MASTER; + +CREATE TABLE t1 (a INT PRIMARY KEY, b INT) ENGINE=INNODB; +INSERT INTO t1 VALUES (1,1),(2,2),(3,3),(4,4),(5,5),(6,6); + +BEGIN; +SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ; +# Should be logged as statement +UPDATE t1 SET b = 2*a WHERE a > 1; +COMMIT; + +BEGIN; +SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; +# Should be logged as rows +UPDATE t1 SET b = a * a WHERE a > 3; +COMMIT; + +# Check that errors are generated when trying to use READ COMMITTED +# transaction isolation level in STATEMENT binlog mode. + +SET BINLOG_FORMAT=STATEMENT; + +BEGIN; +SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; +error ER_BINLOG_LOGGING_IMPOSSIBLE; +UPDATE t1 SET b = 1*a WHERE a > 1; +COMMIT; + +BEGIN; +SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; +error ER_BINLOG_LOGGING_IMPOSSIBLE; +UPDATE t1 SET b = 2*a WHERE a > 2; +COMMIT; + +BEGIN; +SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ; +UPDATE t1 SET b = 3*a WHERE a > 3; +COMMIT; + +BEGIN; +SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE; +UPDATE t1 SET b = 4*a WHERE a > 4; +COMMIT; + +SET BINLOG_FORMAT=MIXED; + +BEGIN; +SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; +UPDATE t1 SET b = 1*a WHERE a > 1; +COMMIT; + +BEGIN; +SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; +UPDATE t1 SET b = 2*a WHERE a > 2; +COMMIT; + +BEGIN; +SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ; +UPDATE t1 SET b = 3*a WHERE a > 3; +COMMIT; + +BEGIN; +SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE; +UPDATE t1 SET b = 4*a WHERE a > 4; +COMMIT; + +SET BINLOG_FORMAT=ROW; + +BEGIN; +SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; +UPDATE t1 SET b = 1*a WHERE a > 1; +COMMIT; + +BEGIN; +SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; +UPDATE t1 SET b = 2*a WHERE a > 2; +COMMIT; + +BEGIN; +SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ; +UPDATE t1 SET b = 3*a WHERE a > 3; +COMMIT; + +BEGIN; +SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE; +UPDATE t1 SET b = 4*a WHERE a > 4; +COMMIT; + +source include/show_binlog_events.inc; + +DROP TABLE t1; diff --git a/mysql-test/t/binlog_multi_engine.test b/mysql-test/t/binlog_multi_engine.test new file mode 100644 index 00000000000..25c99ff6ca8 --- /dev/null +++ b/mysql-test/t/binlog_multi_engine.test @@ -0,0 +1,59 @@ +source include/have_blackhole.inc; +source include/have_ndb.inc; + +CREATE TABLE t1m (m INT, n INT) ENGINE=MYISAM; +CREATE TABLE t1b (b INT, c INT) ENGINE=BLACKHOLE; +CREATE TABLE t1n (e INT, f INT) ENGINE=NDB; + +SET SESSION BINLOG_FORMAT=STATEMENT; + +INSERT INTO t1m VALUES (1,1), (1,2), (2,1), (2,2); +INSERT INTO t1b VALUES (1,1), (1,2), (2,1), (2,2); +error ER_BINLOG_STMT_FORMAT_FORBIDDEN; +INSERT INTO t1n VALUES (1,1), (1,2), (2,1), (2,2); + +UPDATE t1m, t1b SET m = 2, b = 3 WHERE n = c; +error ER_BINLOG_STMT_FORMAT_FORBIDDEN; +UPDATE t1m, t1n SET m = 2, e = 3 WHERE n = f; +error ER_BINLOG_ENGINES_INCOMPATIBLE; +UPDATE t1n, t1b SET e = 2, b = 3 WHERE f = c; + +TRUNCATE t1m; +TRUNCATE t1b; +TRUNCATE t1n; + +SET SESSION BINLOG_FORMAT=MIXED; + +INSERT INTO t1m VALUES (1,1), (1,2), (2,1), (2,2); +INSERT INTO t1b VALUES (1,1), (1,2), (2,1), (2,2); +INSERT INTO t1n VALUES (1,1), (1,2), (2,1), (2,2); + +UPDATE t1m, t1b SET m = 2, b = 3 WHERE n = c; +UPDATE t1m, t1n SET m = 2, e = 3 WHERE n = f; +error ER_BINLOG_ENGINES_INCOMPATIBLE; +UPDATE t1n, t1b SET e = 2, b = 3 WHERE f = c; + +TRUNCATE t1m; +TRUNCATE t1b; +TRUNCATE t1n; + +SET SESSION BINLOG_FORMAT=ROW; + +INSERT INTO t1m VALUES (1,1), (1,2), (2,1), (2,2); +error ER_BINLOG_ROW_FORMAT_FORBIDDEN; +INSERT INTO t1b VALUES (1,1), (1,2), (2,1), (2,2); +INSERT INTO t1n VALUES (1,1), (1,2), (2,1), (2,2); + +error ER_BINLOG_ROW_FORMAT_FORBIDDEN; +UPDATE t1m, t1b SET m = 2, b = 3 WHERE n = c; +UPDATE t1m, t1n SET m = 2, e = 3 WHERE n = f; +error ER_BINLOG_ENGINES_INCOMPATIBLE; +UPDATE t1n, t1b SET e = 2, b = 3 WHERE f = c; + +TRUNCATE t1m; +TRUNCATE t1b; +TRUNCATE t1n; + +source include/show_binlog_events.inc; + +DROP TABLE t1m, t1b, t1n; diff --git a/mysql-test/t/binlog_row_blackhole.test b/mysql-test/t/binlog_row_blackhole.test deleted file mode 100644 index d5355ad1ff0..00000000000 --- a/mysql-test/t/binlog_row_blackhole.test +++ /dev/null @@ -1,11 +0,0 @@ -# This is a wrapper for binlog.test so that the same test case can be used -# For both statement and row based bin logs 9/19/2005 [jbm] - --- source include/have_binlog_format_row.inc - -# Bug#18326: Do not lock table for writing during prepare of statement -# The use of the ps protocol causes extra table maps in the binlog, so -# we disable the ps-protocol for this statement. ---disable_ps_protocol --- source extra/binlog_tests/blackhole.test ---enable_ps_protocol diff --git a/mysql-test/t/partition_hash.test b/mysql-test/t/partition_hash.test index dc527cad2b7..26a563cd8cc 100644 --- a/mysql-test/t/partition_hash.test +++ b/mysql-test/t/partition_hash.test @@ -134,6 +134,7 @@ drop table t1; --disable_warnings CREATE TABLE t1 (s1 int) ENGINE=BLACKHOLE PARTITION BY HASH (s1); --enable_warnings +--error 0,ER_BINLOG_ROW_FORMAT_FORBIDDEN INSERT INTO t1 VALUES (0); DROP TABLE t1; diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index 2eb3826ebee..abf415ecb15 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -4488,7 +4488,6 @@ int ha_ndbcluster::external_lock(THD *thd, int lock_type) DBUG_PRINT("warning", ("ops_pending != 0L")); m_ops_pending= 0; } - thd->set_current_stmt_binlog_row_based_if_mixed(); DBUG_RETURN(error); } @@ -4538,7 +4537,6 @@ int ha_ndbcluster::start_stmt(THD *thd, thr_lock_type lock_type) m_active_trans= trans; // Start of statement m_ops_pending= 0; - thd->set_current_stmt_binlog_row_based_if_mixed(); DBUG_RETURN(error); } @@ -6099,6 +6097,7 @@ void ha_ndbcluster::get_auto_increment(ulonglong offset, ulonglong increment, HA_PRIMARY_KEY_REQUIRED_FOR_DELETE | \ HA_PARTIAL_COLUMN_READ | \ HA_HAS_OWN_BINLOGGING | \ + HA_BINLOG_ROW_CAPABLE | \ HA_HAS_RECORDS ha_ndbcluster::ha_ndbcluster(handlerton *hton, TABLE_SHARE *table_arg): @@ -8906,7 +8905,6 @@ pthread_handler_t ndb_util_thread_func(void *arg __attribute__((unused))) my_net_init(&thd->net, 0); thd->main_security_ctx.master_access= ~0; thd->main_security_ctx.priv_user = 0; - thd->current_stmt_binlog_row_based= TRUE; // If in mixed mode /* Signal successful initialization */ ndb_util_thread_running= 1; diff --git a/sql/handler.cc b/sql/handler.cc index afb88dc962d..e557a55aa45 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -3639,7 +3639,15 @@ int handler::ha_external_lock(THD *thd, int lock_type) taken a table lock), ha_release_auto_increment() was too. */ DBUG_ASSERT(next_insert_id == 0); - DBUG_RETURN(external_lock(thd, lock_type)); + + /* + We cache the table flags if the locking succeeded. Otherwise, we + keep them as they were when they were fetched in ha_open(). + */ + int error= external_lock(thd, lock_type); + if (error == 0) + cached_table_flags= table_flags(); + DBUG_RETURN(error); } diff --git a/sql/handler.h b/sql/handler.h index 6a16dd96f49..e80b62c1250 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -117,6 +117,18 @@ #define HA_HAS_RECORDS (LL(1) << 32) /* records() gives exact count*/ /* Has it's own method of binlog logging */ #define HA_HAS_OWN_BINLOGGING (LL(1) << 33) +/* + Engine is capable of row-format and statement-format logging, + respectively +*/ +#define HA_BINLOG_ROW_CAPABLE (LL(1) << 34) +#define HA_BINLOG_STMT_CAPABLE (LL(1) << 35) + +/* + Set of all binlog flags. Currently only contain the capabilities + flags. + */ +#define HA_BINLOG_FLAGS (HA_BINLOG_ROW_CAPABLE | HA_BINLOG_STMT_CAPABLE) /* bits in index_flags(index_number) for what you can do with index */ #define HA_READ_NEXT 1 /* TODO really use this flag */ @@ -688,7 +700,7 @@ struct handlerton }; -/* Possible flags of a handlerton */ +/* Possible flags of a handlerton (there can be 32 of them) */ #define HTON_NO_FLAGS 0 #define HTON_CLOSE_CURSORS_AT_COMMIT (1 << 0) #define HTON_ALTER_NOT_SUPPORTED (1 << 1) //Engine does not support alter @@ -793,19 +805,37 @@ typedef struct st_key_create_information class TABLEOP_HOOKS { public: + TABLEOP_HOOKS() {} + virtual ~TABLEOP_HOOKS() {} + inline void prelock(TABLE **tables, uint count) { do_prelock(tables, count); } - virtual ~TABLEOP_HOOKS() {} - TABLEOP_HOOKS() {} + inline int postlock(TABLE **tables, uint count) + { + return do_postlock(tables, count); + } private: /* Function primitive that is called prior to locking tables */ virtual void do_prelock(TABLE **tables, uint count) { /* Default is to do nothing */ } + + /** + Primitive called after tables are locked. + + If an error is returned, the tables will be unlocked and error + handling start. + + @return Error code or zero. + */ + virtual int do_postlock(TABLE **tables, uint count) + { + return 0; /* Default is to do nothing */ + } }; typedef struct st_savepoint SAVEPOINT; @@ -900,10 +930,13 @@ class handler :public Sql_alloc friend int ha_delete_table(THD*,handlerton*,const char*,const char*, const char*,bool); +public: + typedef ulonglong Table_flags; + protected: struct st_table_share *table_share; /* The table definition */ struct st_table *table; /* The current open table */ - ulonglong cached_table_flags; /* Set on init() and open() */ + Table_flags cached_table_flags; /* Set on init() and open() */ virtual int index_init(uint idx, bool sorted) { active_index=idx; return 0; } virtual int index_end() { active_index=MAX_KEY; return 0; } @@ -916,7 +949,7 @@ class handler :public Sql_alloc */ virtual int rnd_init(bool scan) =0; virtual int rnd_end() { return 0; } - virtual ulonglong table_flags(void) const =0; + virtual Table_flags table_flags(void) const =0; void ha_statistic_increment(ulong SSV::*offset) const; void **ha_data(THD *) const; @@ -1130,7 +1163,7 @@ public: { return inited == INDEX ? ha_index_end() : inited == RND ? ha_rnd_end() : 0; } - longlong ha_table_flags() { return cached_table_flags; } + Table_flags ha_table_flags() const { return cached_table_flags; } /* Signal that the table->read_set and table->write_set table maps changed @@ -1694,6 +1727,8 @@ private: /* Some extern variables used with handlers */ extern const char *ha_row_type[]; +extern const char *tx_isolation_names[]; +extern const char *binlog_format_names[]; extern TYPELIB tx_isolation_typelib; extern TYPELIB myisam_stats_method_typelib; extern ulong total_ha, total_ha_2pc; diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 7fb4d95f1f6..950577380e7 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1273,6 +1273,7 @@ int simple_open_n_lock_tables(THD *thd,TABLE_LIST *tables); bool open_and_lock_tables(THD *thd,TABLE_LIST *tables); bool open_normal_and_derived_tables(THD *thd, TABLE_LIST *tables, uint flags); int lock_tables(THD *thd, TABLE_LIST *tables, uint counter, bool *need_reopen); +int decide_logging_format(THD *thd, TABLE_LIST *tables); TABLE *open_temporary_table(THD *thd, const char *path, const char *db, const char *table_name, bool link_in_list); bool rm_temporary_table(handlerton *base, char *path); diff --git a/sql/set_var.cc b/sql/set_var.cc index 46dfbc7c7f9..281f3e60d55 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -1011,17 +1011,6 @@ bool sys_var_thd_binlog_format::is_readonly() const my_error(ER_STORED_FUNCTION_PREVENTS_SWITCH_BINLOG_FORMAT, MYF(0)); return 1; } -#ifdef HAVE_NDB_BINLOG - /* - Cluster does not support changing the binlog format on the fly yet. - */ - LEX_STRING ndb_name= {(char*)STRING_WITH_LEN("ndbcluster")}; - if (opt_bin_log && plugin_is_ready(&ndb_name, MYSQL_STORAGE_ENGINE_PLUGIN)) - { - my_error(ER_NDB_CANT_SWITCH_BINLOG_FORMAT, MYF(0)); - return 1; - } -#endif /* HAVE_NDB_BINLOG */ return sys_var_thd_enum::is_readonly(); } diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index b5bfe8a691c..a8deec9c668 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -6072,3 +6072,5 @@ ER_SLAVE_CREATE_EVENT_FAILURE eng "Failed to create %s" ER_SLAVE_MASTER_COM_FAILURE eng "Master command %s failed: %s" +ER_BINLOG_LOGGING_IMPOSSIBLE + eng "Binary logging not possible. Message: %s" diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 7c8b1f724d8..8de3beb2a24 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -3955,6 +3955,121 @@ static void mark_real_tables_as_free_for_reuse(TABLE_LIST *table) } +/** + Decide on logging format to use for the statement. + + Compute the capabilities vector for the involved storage engines + and mask out the flags for the binary log. Right now, the binlog + flags only include the capabilities of the storage engines, so this + is safe. + + We now have three alternatives that prevent the statement from + being loggable: + + 1. If there are no capabilities left (all flags are clear) it is + not possible to log the statement at all, so we roll back the + statement and report an error. + + 2. Statement mode is set, but the capabilities indicate that + statement format is not possible. + + 3. Row mode is set, but the capabilities indicate that row + format is not possible. + + 4. Statement is unsafe, but the capabilities indicate that row + format is not possible. + + If we are in MIXED mode, we then decide what logging format to use: + + 1. If the statement is unsafe, row-based logging is used. + + 2. If statement-based logging is not possible, row-based logging is + used. + + 3. Otherwise, statement-based logging is used. + + @param thd Client thread + @param tables Tables involved in the query + */ + +int decide_logging_format(THD *thd, TABLE_LIST *tables) +{ + if (mysql_bin_log.is_open() && (thd->options & OPTION_BIN_LOG)) + { + handler::Table_flags binlog_flags= ~handler::Table_flags(); + for (TABLE_LIST *table= tables; table; table= table->next_global) + if (!table->placeholder() && table->lock_type >= TL_WRITE_ALLOW_WRITE) + { +#define FLAGSTR(S,F) ((S) & (F) ? #F " " : "") +#ifndef DBUG_OFF + ulonglong flags= table->table->file->ha_table_flags(); + DBUG_PRINT("info", ("table: %s; ha_table_flags: %s%s", + table->table_name, + FLAGSTR(flags, HA_BINLOG_STMT_CAPABLE), + FLAGSTR(flags, HA_BINLOG_ROW_CAPABLE))); +#endif + binlog_flags &= table->table->file->ha_table_flags(); + } + binlog_flags&= HA_BINLOG_FLAGS; + DBUG_PRINT("info", ("binlog_flags: %s%s", + FLAGSTR(binlog_flags, HA_BINLOG_STMT_CAPABLE), + FLAGSTR(binlog_flags, HA_BINLOG_ROW_CAPABLE))); + DBUG_PRINT("info", ("thd->variables.binlog_format: %ld", + thd->variables.binlog_format)); + + int error= 0; + if (binlog_flags == 0) + { + my_error((error= ER_BINLOG_LOGGING_IMPOSSIBLE), MYF(0), + "Statement cannot be logged to the binary log in" + " row-based nor statement-based format"); + } + else if (thd->variables.binlog_format == BINLOG_FORMAT_STMT && + (binlog_flags & HA_BINLOG_STMT_CAPABLE) == 0) + { + my_error((error= ER_BINLOG_LOGGING_IMPOSSIBLE), MYF(0), + "Statement-based format required for this statement," + " but not allowed by this combination of engines"); + } + else if ((thd->variables.binlog_format == BINLOG_FORMAT_ROW || + thd->lex->is_stmt_unsafe()) && + (binlog_flags & HA_BINLOG_ROW_CAPABLE) == 0) + { + my_error((error= ER_BINLOG_LOGGING_IMPOSSIBLE), MYF(0), + "Row-based format required for this statement," + " but not allowed by this combination of engines"); + } + + DBUG_PRINT("info", ("error: %d", error)); + + if (error) + { + ha_rollback_stmt(thd); + return -1; + } + + /* + We switch to row-based format if we are in mixed mode and one of + the following are true: + + 1. If the statement is unsafe + 2. If statement format cannot be used + + Observe that point to cannot be decided before the tables + involved in a statement has been checked, i.e., we cannot put + this code in reset_current_stmt_binlog_row_based(), it has to be + here. + */ + if (thd->lex->is_stmt_unsafe() || + (binlog_flags & HA_BINLOG_STMT_CAPABLE) == 0) + { + thd->set_current_stmt_binlog_row_based_if_mixed(); + } + } + + return 0; +} + /* Lock all tables in list @@ -3993,17 +4108,10 @@ int lock_tables(THD *thd, TABLE_LIST *tables, uint count, bool *need_reopen) in prelocked mode. */ DBUG_ASSERT(!thd->prelocked_mode || !thd->lex->requires_prelocking()); - *need_reopen= FALSE; - /* - CREATE ... SELECT UUID() locks no tables, we have to test here. - */ - if (thd->lex->is_stmt_unsafe()) - thd->set_current_stmt_binlog_row_based_if_mixed(); - if (!tables && !thd->lex->requires_prelocking()) - DBUG_RETURN(0); + DBUG_RETURN(decide_logging_format(thd, tables)); /* We need this extra check for thd->prelocked_mode because we want to avoid @@ -4056,6 +4164,7 @@ int lock_tables(THD *thd, TABLE_LIST *tables, uint count, bool *need_reopen) } DBUG_RETURN(-1); } + if (thd->lex->requires_prelocking() && thd->lex->sql_command != SQLCOM_LOCK_TABLES) { @@ -4122,7 +4231,8 @@ int lock_tables(THD *thd, TABLE_LIST *tables, uint count, bool *need_reopen) thd->prelocked_mode= PRELOCKED_UNDER_LOCK_TABLES; } } - DBUG_RETURN(0); + + DBUG_RETURN(decide_logging_format(thd, tables)); } diff --git a/sql/sql_class.h b/sql/sql_class.h index 0be437fd5c1..87b73594e78 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1991,20 +1991,21 @@ class select_insert :public select_result_interceptor { class select_create: public select_insert { ORDER *group; TABLE_LIST *create_table; + TABLE_LIST *select_tables; HA_CREATE_INFO *create_info; Alter_info *alter_info; Field **field; public: - select_create(TABLE_LIST *table_arg, - HA_CREATE_INFO *create_info_arg, - Alter_info *alter_info_arg, - List<Item> &select_fields, - enum_duplicates duplic, bool ignore) - :select_insert(NULL, NULL, &select_fields, 0, 0, duplic, ignore), + select_create (TABLE_LIST *table_arg, + HA_CREATE_INFO *create_info_par, + List<create_field> &fields_par, + List<Key> &keys_par, + List<Item> &select_fields,enum_duplicates duplic, bool ignore, + TABLE_LIST *select_tables_arg) + :select_insert (NULL, NULL, &select_fields, 0, 0, duplic, ignore), create_table(table_arg), - create_info(create_info_arg), - alter_info(alter_info_arg) - {} + create_info(create_info_par), select_tables(select_tables_arg) + {} int prepare(List<Item> &list, SELECT_LEX_UNIT *u); void binlog_show_create_table(TABLE **tables, uint count); diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index b0c96530548..95d31b371d6 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -3341,8 +3341,15 @@ static TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info, table->reginfo.lock_type=TL_WRITE; hooks->prelock(&table, 1); // Call prelock hooks if (! ((*lock)= mysql_lock_tables(thd, &table, 1, - MYSQL_LOCK_IGNORE_FLUSH, ¬_used))) + MYSQL_LOCK_IGNORE_FLUSH, ¬_used)) || + hooks->postlock(&table, 1)) { + if (*lock) + { + mysql_unlock_tables(thd, *lock); + *lock= 0; + } + if (!create_info->table_existed) drop_open_table(thd, table, create_table->db, create_table->table_name); DBUG_RETURN(0); @@ -3377,24 +3384,35 @@ select_create::prepare(List<Item> &values, SELECT_LEX_UNIT *u) */ class MY_HOOKS : public TABLEOP_HOOKS { public: - MY_HOOKS(select_create *x) : ptr(x) { } + MY_HOOKS(select_create *x, TABLE_LIST *create_table, + TABLE_LIST *select_tables) + : ptr(x), all_tables(*create_table) + { + all_tables.next_global= select_tables; + } private: - virtual void do_prelock(TABLE **tables, uint count) + virtual int do_postlock(TABLE **tables, uint count) { + THD *thd= const_cast<THD*>(ptr->get_thd()); + if (int error= decide_logging_format(thd, &all_tables)) + return error; + TABLE const *const table = *tables; - if (ptr->get_thd()->current_stmt_binlog_row_based && + if (thd->current_stmt_binlog_row_based && !table->s->tmp_table && !ptr->get_create_info()->table_existed) { ptr->binlog_show_create_table(tables, count); } + return 0; } select_create *ptr; + TABLE_LIST all_tables; }; - MY_HOOKS hooks(this); + MY_HOOKS hooks(this, create_table, select_tables); hook_ptr= &hooks; unit= u; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index f5b0220a46c..480f6c9a6e3 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2228,7 +2228,8 @@ mysql_execute_command(THD *thd) &alter_info, select_lex->item_list, lex->duplicates, - lex->ignore))) + lex->ignore, + select_tables))) { /* CREATE from SELECT give its SELECT_LEX for SELECT, diff --git a/storage/archive/ha_archive.h b/storage/archive/ha_archive.h index 936bb6e253d..22fb57b0cc7 100644 --- a/storage/archive/ha_archive.h +++ b/storage/archive/ha_archive.h @@ -87,6 +87,7 @@ public: ulonglong table_flags() const { return (HA_NO_TRANSACTIONS | HA_REC_NOT_IN_SEQ | HA_CAN_BIT_FIELD | + HA_BINLOG_ROW_CAPABLE | HA_BINLOG_STMT_CAPABLE | HA_FILE_BASED | HA_CAN_INSERT_DELAYED | HA_CAN_GEOMETRY); } ulong index_flags(uint idx, uint part, bool all_parts) const diff --git a/storage/blackhole/ha_blackhole.h b/storage/blackhole/ha_blackhole.h index 9b511fc2e0c..f51159b768e 100644 --- a/storage/blackhole/ha_blackhole.h +++ b/storage/blackhole/ha_blackhole.h @@ -53,6 +53,7 @@ public: ulonglong table_flags() const { return(HA_NULL_IN_KEY | HA_CAN_FULLTEXT | HA_CAN_SQL_HANDLER | + HA_BINLOG_STMT_CAPABLE | HA_CAN_INDEX_BLOBS | HA_AUTO_PART_KEY | HA_FILE_BASED | HA_CAN_GEOMETRY | HA_CAN_INSERT_DELAYED); } diff --git a/storage/csv/ha_tina.h b/storage/csv/ha_tina.h index ecb7f006cc4..8d2c6855b84 100644 --- a/storage/csv/ha_tina.h +++ b/storage/csv/ha_tina.h @@ -99,7 +99,8 @@ public: const char **bas_ext() const; ulonglong table_flags() const { - return (HA_NO_TRANSACTIONS | HA_REC_NOT_IN_SEQ | HA_NO_AUTO_INCREMENT); + return (HA_NO_TRANSACTIONS | HA_REC_NOT_IN_SEQ | HA_NO_AUTO_INCREMENT | + HA_BINLOG_ROW_CAPABLE | HA_BINLOG_STMT_CAPABLE); } ulong index_flags(uint idx, uint part, bool all_parts) const { diff --git a/storage/example/ha_example.h b/storage/example/ha_example.h index 69b7cf4d336..25a22cc94c5 100644 --- a/storage/example/ha_example.h +++ b/storage/example/ha_example.h @@ -82,7 +82,12 @@ public: */ ulonglong table_flags() const { - return 0; + /* + We are saying that this engine is just row capable to have an + engine that can only handle row-based logging. This is used in + testing. + */ + return HA_BINLOG_ROW_CAPABLE; } /** @brief diff --git a/storage/federated/ha_federated.h b/storage/federated/ha_federated.h index 94f61af96c3..861f50fad06 100644 --- a/storage/federated/ha_federated.h +++ b/storage/federated/ha_federated.h @@ -128,6 +128,7 @@ public: /* fix server to be able to get remote server table flags */ return (HA_PRIMARY_KEY_IN_READ_INDEX | HA_FILE_BASED | HA_REC_NOT_IN_SEQ | HA_AUTO_PART_KEY | HA_CAN_INDEX_BLOBS | + HA_BINLOG_ROW_CAPABLE | HA_BINLOG_STMT_CAPABLE | HA_NO_PREFIX_CHAR_KEYS | HA_PRIMARY_KEY_REQUIRED_FOR_DELETE | HA_PARTIAL_COLUMN_READ | HA_NULL_IN_KEY); } diff --git a/storage/heap/ha_heap.h b/storage/heap/ha_heap.h index c93a33b524b..f41c710716d 100644 --- a/storage/heap/ha_heap.h +++ b/storage/heap/ha_heap.h @@ -48,6 +48,7 @@ public: ulonglong table_flags() const { return (HA_FAST_KEY_READ | HA_NO_BLOBS | HA_NULL_IN_KEY | + HA_BINLOG_ROW_CAPABLE | HA_BINLOG_STMT_CAPABLE | HA_REC_NOT_IN_SEQ | HA_CAN_INSERT_DELAYED | HA_NO_TRANSACTIONS | HA_HAS_RECORDS | HA_STATS_RECORDS_IS_EXACT); } diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 86cd7a758a9..3ec729fe3f8 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -958,6 +958,7 @@ ha_innobase::ha_innobase(handlerton *hton, TABLE_SHARE *table_arg) HA_CAN_SQL_HANDLER | HA_PRIMARY_KEY_REQUIRED_FOR_POSITION | HA_PRIMARY_KEY_IN_READ_INDEX | + HA_BINLOG_ROW_CAPABLE | HA_CAN_GEOMETRY | HA_PARTIAL_COLUMN_READ | HA_TABLE_SCAN_ON_INDEX), start_of_scan(0), @@ -2268,6 +2269,45 @@ ha_innobase::get_row_type() const return(ROW_TYPE_NOT_USED); } + + +/******************************************************************** +Get the table flags to use for the statement. */ +handler::Table_flags +ha_innobase::table_flags() const +{ + THD *const thd= current_thd; + /* We are using thd->variables.tx_isolation here instead of + trx->isolation_level since store_lock() has not been called + yet. + + The trx->isolation_level is set inside store_lock() (which + is called from mysql_lock_tables()) until after this + function has been called (which is called in lock_tables() + before that function calls mysql_lock_tables()). */ + ulong const tx_isolation= thd->variables.tx_isolation; + if (tx_isolation <= ISO_READ_COMMITTED) + { + ulong const binlog_format= thd->variables.binlog_format; + /* Statement based binlogging does not work in these + isolation levels since the necessary locks cannot + be taken */ + if (binlog_format == BINLOG_FORMAT_STMT) + { + char buf[256]; + my_snprintf(buf, sizeof(buf), + "Transaction level '%s' in InnoDB is" + " not safe for binlog mode '%s'", + tx_isolation_names[tx_isolation], + binlog_format_names[binlog_format]); + my_error(ER_BINLOG_LOGGING_IMPOSSIBLE, MYF(0), buf); + } + return int_table_flags; + } + + return int_table_flags | HA_BINLOG_STMT_CAPABLE; +} + /******************************************************************** Gives the file extension of an InnoDB single-table tablespace. */ static const char* ha_innobase_exts[] = { diff --git a/storage/innobase/handler/ha_innodb.h b/storage/innobase/handler/ha_innodb.h index 1c864445ac0..c727243bfd3 100644 --- a/storage/innobase/handler/ha_innodb.h +++ b/storage/innobase/handler/ha_innodb.h @@ -54,7 +54,7 @@ class ha_innobase: public handler ulong upd_and_key_val_buff_len; /* the length of each of the previous two buffers */ - ulong int_table_flags; + Table_flags int_table_flags; uint primary_key; ulong start_of_scan; /* this is set to 1 when we are starting a table scan but have not @@ -84,7 +84,7 @@ class ha_innobase: public handler const char* table_type() const { return("InnoDB");} const char *index_type(uint key_number) { return "BTREE"; } const char** bas_ext() const; - ulonglong table_flags() const { return int_table_flags; } + Table_flags table_flags() const; ulong index_flags(uint idx, uint part, bool all_parts) const { return (HA_READ_NEXT | diff --git a/storage/myisam/ha_myisam.cc b/storage/myisam/ha_myisam.cc index 8b95cdb30fd..01458a3d689 100644 --- a/storage/myisam/ha_myisam.cc +++ b/storage/myisam/ha_myisam.cc @@ -474,6 +474,7 @@ void mi_check_print_warning(MI_CHECK *param, const char *fmt,...) ha_myisam::ha_myisam(handlerton *hton, TABLE_SHARE *table_arg) :handler(hton, table_arg), file(0), int_table_flags(HA_NULL_IN_KEY | HA_CAN_FULLTEXT | HA_CAN_SQL_HANDLER | + HA_BINLOG_ROW_CAPABLE | HA_BINLOG_STMT_CAPABLE | HA_DUPLICATE_POS | HA_CAN_INDEX_BLOBS | HA_AUTO_PART_KEY | HA_FILE_BASED | HA_CAN_GEOMETRY | HA_NO_TRANSACTIONS | HA_CAN_INSERT_DELAYED | HA_CAN_BIT_FIELD | HA_CAN_RTREEKEYS | diff --git a/storage/myisammrg/ha_myisammrg.h b/storage/myisammrg/ha_myisammrg.h index 88bb5dd2e21..0b9a497bc22 100644 --- a/storage/myisammrg/ha_myisammrg.h +++ b/storage/myisammrg/ha_myisammrg.h @@ -35,6 +35,7 @@ class ha_myisammrg: public handler ulonglong table_flags() const { return (HA_REC_NOT_IN_SEQ | HA_AUTO_PART_KEY | HA_NO_TRANSACTIONS | + HA_BINLOG_ROW_CAPABLE | HA_BINLOG_STMT_CAPABLE | HA_NULL_IN_KEY | HA_CAN_INDEX_BLOBS | HA_FILE_BASED | HA_ANY_INDEX_MAY_BE_UNIQUE | HA_CAN_BIT_FIELD | HA_NO_COPY_ON_ALTER); |