WL#3303 (RBR: Engine-controlled logging format):

Adding support to allow engines to tell what formats they can handle.
The server will generate an error if it is not possible to log the
statement according to the logging mode in effect.

Adding flags to several storage engines to state what they can handle.

Changes to NDB handler removing code that forces row-based mode and
adding flag saying that NDB can only handle row format.

Adding check that binlog flags are only used for real tables that are
opened for writing.
parent 6a7925a2
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;
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, 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;
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;
# 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
...@@ -130,6 +130,7 @@ drop table t1; ...@@ -130,6 +130,7 @@ drop table t1;
# BUG# 14524 Partitions: crash if blackhole # BUG# 14524 Partitions: crash if blackhole
# #
CREATE TABLE t1 (s1 int) ENGINE=BLACKHOLE PARTITION BY HASH (s1); CREATE TABLE t1 (s1 int) ENGINE=BLACKHOLE PARTITION BY HASH (s1);
--error 0,ER_BINLOG_ROW_FORMAT_FORBIDDEN
INSERT INTO t1 VALUES (0); INSERT INTO t1 VALUES (0);
DROP TABLE t1; DROP TABLE t1;
......
...@@ -4444,7 +4444,6 @@ int ha_ndbcluster::external_lock(THD *thd, int lock_type) ...@@ -4444,7 +4444,6 @@ int ha_ndbcluster::external_lock(THD *thd, int lock_type)
DBUG_PRINT("warning", ("ops_pending != 0L")); DBUG_PRINT("warning", ("ops_pending != 0L"));
m_ops_pending= 0; m_ops_pending= 0;
} }
thd->set_current_stmt_binlog_row_based_if_mixed();
DBUG_RETURN(error); DBUG_RETURN(error);
} }
...@@ -4494,7 +4493,6 @@ int ha_ndbcluster::start_stmt(THD *thd, thr_lock_type lock_type) ...@@ -4494,7 +4493,6 @@ int ha_ndbcluster::start_stmt(THD *thd, thr_lock_type lock_type)
m_active_trans= trans; m_active_trans= trans;
// Start of statement // Start of statement
m_ops_pending= 0; m_ops_pending= 0;
thd->set_current_stmt_binlog_row_based_if_mixed();
DBUG_RETURN(error); DBUG_RETURN(error);
} }
...@@ -6000,6 +5998,7 @@ void ha_ndbcluster::get_auto_increment(ulonglong offset, ulonglong increment, ...@@ -6000,6 +5998,7 @@ void ha_ndbcluster::get_auto_increment(ulonglong offset, ulonglong increment,
HA_PRIMARY_KEY_REQUIRED_FOR_DELETE | \ HA_PRIMARY_KEY_REQUIRED_FOR_DELETE | \
HA_PARTIAL_COLUMN_READ | \ HA_PARTIAL_COLUMN_READ | \
HA_HAS_OWN_BINLOGGING | \ HA_HAS_OWN_BINLOGGING | \
HA_BINLOG_ROW_CAPABLE | \
HA_HAS_RECORDS HA_HAS_RECORDS
ha_ndbcluster::ha_ndbcluster(handlerton *hton, TABLE_SHARE *table_arg): ha_ndbcluster::ha_ndbcluster(handlerton *hton, TABLE_SHARE *table_arg):
...@@ -8788,7 +8787,6 @@ pthread_handler_t ndb_util_thread_func(void *arg __attribute__((unused))) ...@@ -8788,7 +8787,6 @@ pthread_handler_t ndb_util_thread_func(void *arg __attribute__((unused)))
my_net_init(&thd->net, 0); my_net_init(&thd->net, 0);
thd->main_security_ctx.master_access= ~0; thd->main_security_ctx.master_access= ~0;
thd->main_security_ctx.priv_user = 0; thd->main_security_ctx.priv_user = 0;
thd->current_stmt_binlog_row_based= TRUE; // If in mixed mode
/* Signal successful initialization */ /* Signal successful initialization */
ndb_util_thread_running= 1; ndb_util_thread_running= 1;
......
...@@ -117,6 +117,18 @@ ...@@ -117,6 +117,18 @@
#define HA_HAS_RECORDS (LL(1) << 32) /* records() gives exact count*/ #define HA_HAS_RECORDS (LL(1) << 32) /* records() gives exact count*/
/* Has it's own method of binlog logging */ /* Has it's own method of binlog logging */
#define HA_HAS_OWN_BINLOGGING (LL(1) << 33) #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 */ /* bits in index_flags(index_number) for what you can do with index */
#define HA_READ_NEXT 1 /* TODO really use this flag */ #define HA_READ_NEXT 1 /* TODO really use this flag */
...@@ -687,7 +699,7 @@ struct handlerton ...@@ -687,7 +699,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_NO_FLAGS 0
#define HTON_CLOSE_CURSORS_AT_COMMIT (1 << 0) #define HTON_CLOSE_CURSORS_AT_COMMIT (1 << 0)
#define HTON_ALTER_NOT_SUPPORTED (1 << 1) //Engine does not support alter #define HTON_ALTER_NOT_SUPPORTED (1 << 1) //Engine does not support alter
...@@ -889,10 +901,13 @@ class handler :public Sql_alloc ...@@ -889,10 +901,13 @@ class handler :public Sql_alloc
{ {
friend class ha_partition; friend class ha_partition;
public:
typedef ulonglong Table_flags;
protected: protected:
struct st_table_share *table_share; /* The table definition */ struct st_table_share *table_share; /* The table definition */
struct st_table *table; /* The current open table */ 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_init(uint idx, bool sorted) { active_index=idx; return 0; }
virtual int index_end() { active_index=MAX_KEY; return 0; } virtual int index_end() { active_index=MAX_KEY; return 0; }
...@@ -905,7 +920,7 @@ class handler :public Sql_alloc ...@@ -905,7 +920,7 @@ class handler :public Sql_alloc
*/ */
virtual int rnd_init(bool scan) =0; virtual int rnd_init(bool scan) =0;
virtual int rnd_end() { return 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_statistic_increment(ulong SSV::*offset) const;
ha_rows estimation_rows_to_insert; ha_rows estimation_rows_to_insert;
...@@ -1115,7 +1130,7 @@ class handler :public Sql_alloc ...@@ -1115,7 +1130,7 @@ class handler :public Sql_alloc
{ {
return inited == INDEX ? ha_index_end() : inited == RND ? ha_rnd_end() : 0; 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 Signal that the table->read_set and table->write_set table maps changed
......
...@@ -1343,16 +1343,6 @@ bool sys_var_thd_binlog_format::is_readonly() const ...@@ -1343,16 +1343,6 @@ bool sys_var_thd_binlog_format::is_readonly() const
my_error(ER_STORED_FUNCTION_PREVENTS_SWITCH_BINLOG_FORMAT, MYF(0)); my_error(ER_STORED_FUNCTION_PREVENTS_SWITCH_BINLOG_FORMAT, MYF(0));
return 1; return 1;
} }
#ifdef HAVE_NDB_BINLOG
/*
Cluster does not support changing the binlog format on the fly yet.
*/
if (opt_bin_log && (have_ndbcluster == SHOW_OPTION_YES))
{
my_error(ER_NDB_CANT_SWITCH_BINLOG_FORMAT, MYF(0));
return 1;
}
#endif /* HAVE_NDB_BINLOG */
return sys_var_thd_enum::is_readonly(); return sys_var_thd_enum::is_readonly();
} }
......
...@@ -6062,3 +6062,9 @@ ER_NO_PARTITION_FOR_GIVEN_VALUE_SILENT ...@@ -6062,3 +6062,9 @@ ER_NO_PARTITION_FOR_GIVEN_VALUE_SILENT
ER_BINLOG_UNSAFE_STATEMENT ER_BINLOG_UNSAFE_STATEMENT
eng "Statement is not safe to log in statement format." eng "Statement is not safe to log in statement format."
swe "Detta r inte skert att logga i statement-format." swe "Detta r inte skert att logga i statement-format."
ER_BINLOG_ENGINES_INCOMPATIBLE
eng "It is not possible to log anything with this combination of engines"
ER_BINLOG_STMT_FORMAT_FORBIDDEN
eng "Attempting to log statement in in statement format, but statement format is not possible with this combination of engines"
ER_BINLOG_ROW_FORMAT_FORBIDDEN
eng "Attempting to log statement in in row format, but row format is not possible with this combination of engines"
...@@ -3585,14 +3585,93 @@ int lock_tables(THD *thd, TABLE_LIST *tables, uint count, bool *need_reopen) ...@@ -3585,14 +3585,93 @@ int lock_tables(THD *thd, TABLE_LIST *tables, uint count, bool *need_reopen)
in prelocked mode. in prelocked mode.
*/ */
DBUG_ASSERT(!thd->prelocked_mode || !thd->lex->requires_prelocking()); DBUG_ASSERT(!thd->prelocked_mode || !thd->lex->requires_prelocking());
*need_reopen= FALSE; *need_reopen= FALSE;
if (mysql_bin_log.is_open() && (thd->options | OPTION_BIN_LOG))
{
/* /*
CREATE ... SELECT UUID() locks no tables, we have to test here. 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.
*/ */
if (thd->lex->is_stmt_unsafe()) handler::Table_flags binlog_flags= ~handler::Table_flags();
DBUG_PRINT("info", ("HA_BINLOG_FLAGS: 0x%0llx",
(ulonglong) HA_BINLOG_FLAGS));
for (table= tables; table; table= table->next_global)
if (!table->placeholder() && table->lock_type >= TL_WRITE_ALLOW_WRITE)
{
DBUG_PRINT("info", ("table: %s; ha_table_flags: 0x%0llx",
table->table_name,
(ulonglong) table->table->file->ha_table_flags()));
binlog_flags &= table->table->file->ha_table_flags();
}
binlog_flags&= HA_BINLOG_FLAGS;
DBUG_PRINT("info", ("binlog_flags: 0x%0llx", (ulonglong) binlog_flags));
DBUG_PRINT("info", ("thd->variables.binlog_format: %ld",
thd->variables.binlog_format));
/*
We 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.
*/
int error= 0;
if (binlog_flags == 0)
{
error= ER_BINLOG_ENGINES_INCOMPATIBLE;
}
else if (thd->variables.binlog_format == BINLOG_FORMAT_STMT &&
(binlog_flags & HA_BINLOG_STMT_CAPABLE) == 0)
{
error= ER_BINLOG_STMT_FORMAT_FORBIDDEN;
}
else if ((thd->variables.binlog_format == BINLOG_FORMAT_ROW ||
thd->lex->is_stmt_unsafe()) &&
(binlog_flags & HA_BINLOG_ROW_CAPABLE) == 0)
{
error= ER_BINLOG_ROW_FORMAT_FORBIDDEN;
}
DBUG_PRINT("info", ("error: %d", error));
if (error)
{
ha_rollback_stmt(thd);
my_error(error, MYF(0));
DBUG_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(); thd->set_current_stmt_binlog_row_based_if_mixed();
}
}
if (!tables && !thd->lex->requires_prelocking()) if (!tables && !thd->lex->requires_prelocking())
DBUG_RETURN(0); DBUG_RETURN(0);
......
...@@ -87,6 +87,7 @@ class ha_archive: public handler ...@@ -87,6 +87,7 @@ class ha_archive: public handler
ulonglong table_flags() const ulonglong table_flags() const
{ {
return (HA_NO_TRANSACTIONS | HA_REC_NOT_IN_SEQ | HA_CAN_BIT_FIELD | 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); HA_FILE_BASED | HA_CAN_INSERT_DELAYED | HA_CAN_GEOMETRY);
} }
ulong index_flags(uint idx, uint part, bool all_parts) const ulong index_flags(uint idx, uint part, bool all_parts) const
......
...@@ -42,6 +42,7 @@ class ha_blackhole: public handler ...@@ -42,6 +42,7 @@ class ha_blackhole: public handler
ulonglong table_flags() const ulonglong table_flags() const
{ {
return(HA_NULL_IN_KEY | HA_CAN_FULLTEXT | HA_CAN_SQL_HANDLER | 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_CAN_INDEX_BLOBS | HA_AUTO_PART_KEY |
HA_FILE_BASED | HA_CAN_GEOMETRY | HA_CAN_INSERT_DELAYED); HA_FILE_BASED | HA_CAN_GEOMETRY | HA_CAN_INSERT_DELAYED);
} }
......
...@@ -99,7 +99,8 @@ class ha_tina: public handler ...@@ -99,7 +99,8 @@ class ha_tina: public handler
const char **bas_ext() const; const char **bas_ext() const;
ulonglong table_flags() 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 ulong index_flags(uint idx, uint part, bool all_parts) const
{ {
......
...@@ -82,7 +82,12 @@ class ha_example: public handler ...@@ -82,7 +82,12 @@ class ha_example: public handler
*/ */
ulonglong table_flags() const 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 /** @brief
......
...@@ -128,6 +128,7 @@ class ha_federated: public handler ...@@ -128,6 +128,7 @@ class ha_federated: public handler
/* fix server to be able to get remote server table flags */ /* fix server to be able to get remote server table flags */
return (HA_PRIMARY_KEY_IN_READ_INDEX | HA_FILE_BASED return (HA_PRIMARY_KEY_IN_READ_INDEX | HA_FILE_BASED
| HA_REC_NOT_IN_SEQ | HA_AUTO_PART_KEY | HA_CAN_INDEX_BLOBS | | 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_NO_PREFIX_CHAR_KEYS | HA_PRIMARY_KEY_REQUIRED_FOR_DELETE |
HA_PARTIAL_COLUMN_READ | HA_NULL_IN_KEY); HA_PARTIAL_COLUMN_READ | HA_NULL_IN_KEY);
} }
......
...@@ -48,6 +48,7 @@ class ha_heap: public handler ...@@ -48,6 +48,7 @@ class ha_heap: public handler
ulonglong table_flags() const ulonglong table_flags() const
{ {
return (HA_FAST_KEY_READ | HA_NO_BLOBS | HA_NULL_IN_KEY | 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_REC_NOT_IN_SEQ | HA_CAN_INSERT_DELAYED | HA_NO_TRANSACTIONS |
HA_HAS_RECORDS | HA_STATS_RECORDS_IS_EXACT); HA_HAS_RECORDS | HA_STATS_RECORDS_IS_EXACT);
} }
......
...@@ -474,6 +474,7 @@ void mi_check_print_warning(MI_CHECK *param, const char *fmt,...) ...@@ -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) ha_myisam::ha_myisam(handlerton *hton, TABLE_SHARE *table_arg)
:handler(hton, table_arg), file(0), :handler(hton, table_arg), file(0),
int_table_flags(HA_NULL_IN_KEY | HA_CAN_FULLTEXT | HA_CAN_SQL_HANDLER | 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_DUPLICATE_POS | HA_CAN_INDEX_BLOBS | HA_AUTO_PART_KEY |
HA_FILE_BASED | HA_CAN_GEOMETRY | HA_NO_TRANSACTIONS | HA_FILE_BASED | HA_CAN_GEOMETRY | HA_NO_TRANSACTIONS |
HA_CAN_INSERT_DELAYED | HA_CAN_BIT_FIELD | HA_CAN_RTREEKEYS | HA_CAN_INSERT_DELAYED | HA_CAN_BIT_FIELD | HA_CAN_RTREEKEYS |
......
...@@ -35,6 +35,7 @@ class ha_myisammrg: public handler ...@@ -35,6 +35,7 @@ class ha_myisammrg: public handler
ulonglong table_flags() const ulonglong table_flags() const
{ {
return (HA_REC_NOT_IN_SEQ | HA_AUTO_PART_KEY | HA_NO_TRANSACTIONS | 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_NULL_IN_KEY | HA_CAN_INDEX_BLOBS | HA_FILE_BASED |
HA_ANY_INDEX_MAY_BE_UNIQUE | HA_CAN_BIT_FIELD | HA_ANY_INDEX_MAY_BE_UNIQUE | HA_CAN_BIT_FIELD |
HA_NO_COPY_ON_ALTER); HA_NO_COPY_ON_ALTER);
......
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