summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mysql-test/r/binlog_innodb.result114
-rw-r--r--mysql-test/r/binlog_multi_engine.result86
-rw-r--r--mysql-test/r/binlog_row_blackhole.result155
-rw-r--r--mysql-test/t/binlog_innodb.test95
-rw-r--r--mysql-test/t/binlog_multi_engine.test59
-rw-r--r--mysql-test/t/binlog_row_blackhole.test11
-rw-r--r--mysql-test/t/partition_hash.test1
-rw-r--r--sql/ha_ndbcluster.cc4
-rw-r--r--sql/handler.cc10
-rw-r--r--sql/handler.h47
-rw-r--r--sql/mysql_priv.h1
-rw-r--r--sql/set_var.cc11
-rw-r--r--sql/share/errmsg.txt2
-rw-r--r--sql/sql_base.cc128
-rw-r--r--sql/sql_class.h19
-rw-r--r--sql/sql_insert.cc28
-rw-r--r--sql/sql_parse.cc3
-rw-r--r--storage/archive/ha_archive.h1
-rw-r--r--storage/blackhole/ha_blackhole.h1
-rw-r--r--storage/csv/ha_tina.h3
-rw-r--r--storage/example/ha_example.h7
-rw-r--r--storage/federated/ha_federated.h1
-rw-r--r--storage/heap/ha_heap.h1
-rw-r--r--storage/innobase/handler/ha_innodb.cc40
-rw-r--r--storage/innobase/handler/ha_innodb.h4
-rw-r--r--storage/myisam/ha_myisam.cc1
-rw-r--r--storage/myisammrg/ha_myisammrg.h1
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, &not_used)))
+ MYSQL_LOCK_IGNORE_FLUSH, &not_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);