diff --git a/mysql-test/r/rpl_switch_stm_row_mixed.result b/mysql-test/r/rpl_switch_stm_row_mixed.result index 762a21a4370..313037bb9dc 100644 --- a/mysql-test/r/rpl_switch_stm_row_mixed.result +++ b/mysql-test/r/rpl_switch_stm_row_mixed.result @@ -110,6 +110,11 @@ execute stmt1 using @string; deallocate prepare stmt1; insert into t1 values(concat("for",UUID())); insert into t1 select "yesterday"; +create table t2 select UUID(); +create table t3 select 1 union select UUID(); +create table t4 select * from t1 where 3 in (select 1 union select 2 union select UUID() union select 3); +create table t5 select * from t1 where 3 in (select 1 union select 2 union select curdate() union select 3); +insert into t5 select UUID() from t1 where 3 in (select 1 union select 2 union select 3 union select * from t4); create procedure foo() begin insert into t1 values("work"); @@ -137,6 +142,21 @@ select foo3(); ERROR HY000: Cannot change the binary logging format inside a stored function or trigger select * from t1 where a="alarm"; a +select count(*) from t1; +count(*) +36 +select count(*) from t2; +count(*) +1 +select count(*) from t3; +count(*) +2 +select count(*) from t4; +count(*) +29 +select count(*) from t5; +count(*) +58 show binlog events from 102; Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Query 1 # drop database if exists mysqltest1 @@ -179,17 +199,44 @@ master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 select @'string' master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 values("for") master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 select "yesterday" master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 values("work") +master-bin.000001 # Table_map 1 # table_id: # (mysqltest1.t1) master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F +master-bin.000001 # Table_map 1 # table_id: # (mysqltest1.t1) master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F master-bin.000001 # User var 1 # @`string`=_latin1 0x656D657267656E6379 COLLATE latin1_swedish_ci master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 select @'string' +master-bin.000001 # Table_map 1 # table_id: # (mysqltest1.t1) master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 select "yesterday" +master-bin.000001 # Table_map 1 # table_id: # (mysqltest1.t1) master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F master-bin.000001 # User var 1 # @`string`=_latin1 0x656D657267656E6379 COLLATE latin1_swedish_ci master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 select @'string' +master-bin.000001 # Table_map 1 # table_id: # (mysqltest1.t1) master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 select "yesterday" +master-bin.000001 # Query 1 # use `mysqltest1`; CREATE TABLE `t2` ( + `UUID()` varchar(36) CHARACTER SET utf8 NOT NULL DEFAULT '' +) +master-bin.000001 # Table_map 1 # table_id: # (mysqltest1.t2) +master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F +master-bin.000001 # Query 1 # use `mysqltest1`; COMMIT +master-bin.000001 # Query 1 # use `mysqltest1`; CREATE TABLE `t3` ( + `1` varbinary(108) NOT NULL DEFAULT '' +) +master-bin.000001 # Table_map 1 # table_id: # (mysqltest1.t3) +master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F +master-bin.000001 # Query 1 # use `mysqltest1`; COMMIT +master-bin.000001 # Query 1 # use `mysqltest1`; CREATE TABLE `t4` ( + `a` varchar(100) DEFAULT NULL +) +master-bin.000001 # Table_map 1 # table_id: # (mysqltest1.t4) +master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F +master-bin.000001 # Query 1 # use `mysqltest1`; COMMIT +master-bin.000001 # Query 1 # use `mysqltest1`; create table t5 select * from t1 where 3 in (select 1 union select 2 union select curdate() union select 3) +master-bin.000001 # Table_map 1 # table_id: # (mysqltest1.t5) +master-bin.000001 # Write_rows 1 # table_id: # +master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F master-bin.000001 # Query 1 # use `mysqltest1`; CREATE DEFINER=`root`@`localhost` procedure foo() begin insert into t1 values("work"); @@ -212,10 +259,13 @@ insert into t1 values("alarm"); return 100; end master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 values("work") +master-bin.000001 # Table_map 1 # table_id: # (mysqltest1.t1) master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 select "yesterday" +master-bin.000001 # Table_map 1 # table_id: # (mysqltest1.t1) master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 values("work") +master-bin.000001 # Table_map 1 # table_id: # (mysqltest1.t1) master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F master-bin.000001 # Table_map 1 # table_id: # (mysqltest1.t1) master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F diff --git a/mysql-test/t/rpl_switch_stm_row_mixed.test b/mysql-test/t/rpl_switch_stm_row_mixed.test index ef4eef6cc7b..4a79b3995c4 100644 --- a/mysql-test/t/rpl_switch_stm_row_mixed.test +++ b/mysql-test/t/rpl_switch_stm_row_mixed.test @@ -111,6 +111,15 @@ deallocate prepare stmt1; insert into t1 values(concat("for",UUID())); insert into t1 select "yesterday"; +# Test of CREATE TABLE SELECT + +create table t2 select UUID(); +create table t3 select 1 union select UUID(); +create table t4 select * from t1 where 3 in (select 1 union select 2 union select UUID() union select 3); +create table t5 select * from t1 where 3 in (select 1 union select 2 union select curdate() union select 3); +# what if UUID() is first: +insert into t5 select UUID() from t1 where 3 in (select 1 union select 2 union select 3 union select * from t4); + # inside a stored procedure (inside a function or trigger won't # work) @@ -140,20 +149,60 @@ delimiter ;| call foo(); call foo2(); -# test that can't SET in a stored function if not in row-based mode +# test that can't SET in a stored function --error ER_STORED_FUNCTION_PREVENTS_SWITCH_BINLOG_FORMAT select foo3(); select * from t1 where a="alarm"; +# If you want to do manual testing of the mixed mode regarding UDFs (not +# testable automatically as quite platform- and compiler-dependent), +# you just need to set the variable below to 1, and to +# "make udf_example.so" in sql/, and to copy sql/udf_example.so to +# MYSQL_TEST_DIR/lib/mysql. +let $you_want_to_test_UDF=0; +if ($you_want_to_test_UDF) +{ + CREATE FUNCTION metaphon RETURNS STRING SONAME 'udf_example.so'; + prepare stmt1 from 'insert into t1 select metaphon(?)'; + set @string="emergency"; + insert into t1 values("work"); + execute stmt1 using @string; + deallocate prepare stmt1; + prepare stmt1 from 'insert into t1 select ?'; + insert into t1 values(metaphon("work")); + execute stmt1 using @string; + deallocate prepare stmt1; + insert into t1 values(metaphon("for")); + insert into t1 select "yesterday"; + create table t6 select metaphon("for"); + create table t7 select 1 union select metaphon("for"); + create table t8 select * from t1 where 3 in (select 1 union select 2 union select metaphon("for") union select 3); + create table t9 select * from t1 where 3 in (select 1 union select 2 union select curdate() union select 3); +} + # and now compare: +# first check that data on master is sensible +select count(*) from t1; +select count(*) from t2; +select count(*) from t3; +select count(*) from t4; +select count(*) from t5; +if ($you_want_to_test_UDF) +{ + select count(*) from t6; + select count(*) from t7; + select count(*) from t8; + select count(*) from t9; +} + --replace_column 2 # 5 # --replace_regex /table_id: [0-9]+/table_id: #/ show binlog events from 102; sync_slave_with_master; # as we're using UUID we don't SELECT but use "diff" like in rpl_row_UUID ---exec $MYSQL_DUMP --compact --order-by-primary --skip-extended-insert --no-create-info mysqltest1 > $MYSQLTEST_VARDIR/tmp/rpl_row_UDF_master.sql ---exec $MYSQL_DUMP_SLAVE --compact --order-by-primary --skip-extended-insert --no-create-info mysqltest1 > $MYSQLTEST_VARDIR/tmp/rpl_row_UDF_slave.sql +--exec $MYSQL_DUMP --compact --order-by-primary --skip-extended-insert --no-create-info mysqltest1 > $MYSQLTEST_VARDIR/tmp/rpl_switch_stm_row_mixed_master.sql +--exec $MYSQL_DUMP_SLAVE --compact --order-by-primary --skip-extended-insert --no-create-info mysqltest1 > $MYSQLTEST_VARDIR/tmp/rpl_switch_stm_row_mixed_slave.sql connection master; drop database mysqltest1; @@ -164,4 +213,4 @@ sync_slave_with_master; # will be created. You will need to go to the mysql-test dir and diff # the files your self to see what is not matching -#--exec diff $MYSQLTEST_VARDIR/tmp/rpl_row_UDF_master.sql $MYSQLTEST_VARDIR/tmp/rpl_row_UDF_slave.sql; +--exec diff $MYSQLTEST_VARDIR/tmp/rpl_switch_stm_row_mixed_master.sql $MYSQLTEST_VARDIR/tmp/rpl_switch_stm_row_mixed_slave.sql; diff --git a/sql/item_create.cc b/sql/item_create.cc index 17f1fbca471..fb1ef0ee9bc 100644 --- a/sql/item_create.cc +++ b/sql/item_create.cc @@ -431,7 +431,9 @@ Item *create_func_unhex(Item* a) Item *create_func_uuid(void) { - return new Item_func_uuid(); + THD *thd= current_thd; + thd->lex->binlog_row_based_if_mixed= 1; + return new(thd->mem_root) Item_func_uuid(); } Item *create_func_version(void) diff --git a/sql/item_func.cc b/sql/item_func.cc index 0277ac96a4e..34fd07e5a16 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -2657,7 +2657,6 @@ udf_handler::fix_fields(THD *thd, Item_result_field *func, u_d->name.str, ER(ER_UNKNOWN_ERROR)); DBUG_RETURN(TRUE); } - thd->set_current_stmt_binlog_row_based_if_mixed(); DBUG_RETURN(FALSE); } diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index eb89eb7708c..a3e47154bc3 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -3002,7 +3002,6 @@ String *Item_func_uuid::val_str(String *str) char *s; THD *thd= current_thd; - thd->set_current_stmt_binlog_row_based_if_mixed(); pthread_mutex_lock(&LOCK_uuid_generator); if (! uuid_time) /* first UUID() call. initializing data */ { diff --git a/sql/set_var.cc b/sql/set_var.cc index 443a11736b5..899bb8543df 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -1271,7 +1271,6 @@ bool sys_var_thd_binlog_format::is_readonly() const */ if (thd->spcont && thd->prelocked_mode) { - DBUG_ASSERT(thd->variables.binlog_format != BINLOG_FORMAT_ROW); my_error(ER_STORED_FUNCTION_PREVENTS_SWITCH_BINLOG_FORMAT, MYF(0)); return 1; } diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index b5c1d943339..e1a519060aa 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -191,6 +191,7 @@ void lex_start(THD *thd, const uchar *buf, uint length) lex->nest_level=0 ; lex->allow_sum_func= 0; lex->in_sum_func= NULL; + lex->binlog_row_based_if_mixed= 0; DBUG_VOID_RETURN; } diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 66f097a101c..59ebdd2a1cc 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -880,7 +880,11 @@ typedef struct st_lex uint8 create_view_check; bool drop_if_exists, drop_temporary, local_file, one_shot_set; bool in_comment, ignore_space, verbose, no_write_to_binlog; - bool tx_chain, tx_release; + /* + binlog_row_based_if_mixed tells if the parsing stage detected that some + items require row-based binlogging to give a reliable binlog/replication. + */ + bool tx_chain, tx_release, binlog_row_based_if_mixed; /* Special JOIN::prepare mode: changing of query is prohibited. When creating a view, we need to just check its syntax omitting diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 112d2e3440a..871c8bdff9f 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2446,6 +2446,9 @@ mysql_execute_command(THD *thd) statistic_increment(thd->status_var.com_stat[lex->sql_command], &LOCK_status); + if (lex->binlog_row_based_if_mixed) + thd->set_current_stmt_binlog_row_based_if_mixed(); + switch (lex->sql_command) { case SQLCOM_SELECT: { @@ -5065,6 +5068,8 @@ end_with_restore_list: send_ok(thd); break; } + +end: thd->proc_info="query end"; /* @@ -5095,7 +5100,8 @@ end_with_restore_list: DBUG_RETURN(res || thd->net.report_error); error: - DBUG_RETURN(1); + res= 1; // would be better to set res=1 before "goto error" + goto end; } diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 47852212b84..f53748e3df4 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -6415,6 +6415,8 @@ simple_expr: if (udf->type == UDFTYPE_AGGREGATE) Select->in_sum_expr--; + Lex->binlog_row_based_if_mixed= 1; + switch (udf->returns) { case STRING_RESULT: if (udf->type == UDFTYPE_FUNCTION)