mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 20:12:31 +01:00
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.
This commit is contained in:
parent
91574a1dc6
commit
e485f8e12c
10 changed files with 121 additions and 10 deletions
|
@ -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)
|
||||
|
|
Loading…
Reference in a new issue