Commit e485f8e1 authored by guilhem@mysql.com's avatar guilhem@mysql.com

Fixes to the replication mixed mode (patch approved by Monty):

- detect the need for row-based binlogging not at execution stage but earlier at parsing stage; needed for example for CREATE TABLE SELECT UUID().
- more tests of this mixed mode.
parent 91574a1d
......@@ -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
......
......@@ -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;
......@@ -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)
......
......@@ -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);
}
......
......@@ -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 */
{
......
......@@ -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;
}
......
......@@ -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;
}
......
......@@ -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
......
......@@ -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;
}
......
......@@ -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)
......
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