mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +03: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:
@ -110,6 +110,11 @@ execute stmt1 using @string;
|
|||||||
deallocate prepare stmt1;
|
deallocate prepare stmt1;
|
||||||
insert into t1 values(concat("for",UUID()));
|
insert into t1 values(concat("for",UUID()));
|
||||||
insert into t1 select "yesterday";
|
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()
|
create procedure foo()
|
||||||
begin
|
begin
|
||||||
insert into t1 values("work");
|
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
|
ERROR HY000: Cannot change the binary logging format inside a stored function or trigger
|
||||||
select * from t1 where a="alarm";
|
select * from t1 where a="alarm";
|
||||||
a
|
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;
|
show binlog events from 102;
|
||||||
Log_name Pos Event_type Server_id End_log_pos Info
|
Log_name Pos Event_type Server_id End_log_pos Info
|
||||||
master-bin.000001 # Query 1 # drop database if exists mysqltest1
|
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 values("for")
|
||||||
master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 select "yesterday"
|
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 # 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 # 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 # 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 # 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 # 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 # 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`; 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 # 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 # 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 # 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 # 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`; 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()
|
master-bin.000001 # Query 1 # use `mysqltest1`; CREATE DEFINER=`root`@`localhost` procedure foo()
|
||||||
begin
|
begin
|
||||||
insert into t1 values("work");
|
insert into t1 values("work");
|
||||||
@ -212,10 +259,13 @@ insert into t1 values("alarm");
|
|||||||
return 100;
|
return 100;
|
||||||
end
|
end
|
||||||
master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 values("work")
|
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 # 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`; 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 # Write_rows 1 # table_id: # flags: STMT_END_F
|
||||||
master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 values("work")
|
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 # Write_rows 1 # table_id: # flags: STMT_END_F
|
||||||
master-bin.000001 # Table_map 1 # table_id: # (mysqltest1.t1)
|
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 # 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 values(concat("for",UUID()));
|
||||||
insert into t1 select "yesterday";
|
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
|
# inside a stored procedure (inside a function or trigger won't
|
||||||
# work)
|
# work)
|
||||||
|
|
||||||
@ -140,20 +149,60 @@ delimiter ;|
|
|||||||
call foo();
|
call foo();
|
||||||
call foo2();
|
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
|
--error ER_STORED_FUNCTION_PREVENTS_SWITCH_BINLOG_FORMAT
|
||||||
select foo3();
|
select foo3();
|
||||||
select * from t1 where a="alarm";
|
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:
|
# 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_column 2 # 5 #
|
||||||
--replace_regex /table_id: [0-9]+/table_id: #/
|
--replace_regex /table_id: [0-9]+/table_id: #/
|
||||||
show binlog events from 102;
|
show binlog events from 102;
|
||||||
sync_slave_with_master;
|
sync_slave_with_master;
|
||||||
# as we're using UUID we don't SELECT but use "diff" like in rpl_row_UUID
|
# 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 --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_row_UDF_slave.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;
|
connection master;
|
||||||
drop database mysqltest1;
|
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
|
# 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
|
# 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)
|
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)
|
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));
|
u_d->name.str, ER(ER_UNKNOWN_ERROR));
|
||||||
DBUG_RETURN(TRUE);
|
DBUG_RETURN(TRUE);
|
||||||
}
|
}
|
||||||
thd->set_current_stmt_binlog_row_based_if_mixed();
|
|
||||||
DBUG_RETURN(FALSE);
|
DBUG_RETURN(FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3002,7 +3002,6 @@ String *Item_func_uuid::val_str(String *str)
|
|||||||
char *s;
|
char *s;
|
||||||
THD *thd= current_thd;
|
THD *thd= current_thd;
|
||||||
|
|
||||||
thd->set_current_stmt_binlog_row_based_if_mixed();
|
|
||||||
pthread_mutex_lock(&LOCK_uuid_generator);
|
pthread_mutex_lock(&LOCK_uuid_generator);
|
||||||
if (! uuid_time) /* first UUID() call. initializing data */
|
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)
|
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));
|
my_error(ER_STORED_FUNCTION_PREVENTS_SWITCH_BINLOG_FORMAT, MYF(0));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -191,6 +191,7 @@ void lex_start(THD *thd, const uchar *buf, uint length)
|
|||||||
lex->nest_level=0 ;
|
lex->nest_level=0 ;
|
||||||
lex->allow_sum_func= 0;
|
lex->allow_sum_func= 0;
|
||||||
lex->in_sum_func= NULL;
|
lex->in_sum_func= NULL;
|
||||||
|
lex->binlog_row_based_if_mixed= 0;
|
||||||
DBUG_VOID_RETURN;
|
DBUG_VOID_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -880,7 +880,11 @@ typedef struct st_lex
|
|||||||
uint8 create_view_check;
|
uint8 create_view_check;
|
||||||
bool drop_if_exists, drop_temporary, local_file, one_shot_set;
|
bool drop_if_exists, drop_temporary, local_file, one_shot_set;
|
||||||
bool in_comment, ignore_space, verbose, no_write_to_binlog;
|
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.
|
Special JOIN::prepare mode: changing of query is prohibited.
|
||||||
When creating a view, we need to just check its syntax omitting
|
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],
|
statistic_increment(thd->status_var.com_stat[lex->sql_command],
|
||||||
&LOCK_status);
|
&LOCK_status);
|
||||||
|
|
||||||
|
if (lex->binlog_row_based_if_mixed)
|
||||||
|
thd->set_current_stmt_binlog_row_based_if_mixed();
|
||||||
|
|
||||||
switch (lex->sql_command) {
|
switch (lex->sql_command) {
|
||||||
case SQLCOM_SELECT:
|
case SQLCOM_SELECT:
|
||||||
{
|
{
|
||||||
@ -5065,6 +5068,8 @@ end_with_restore_list:
|
|||||||
send_ok(thd);
|
send_ok(thd);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
end:
|
||||||
thd->proc_info="query end";
|
thd->proc_info="query end";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -5095,7 +5100,8 @@ end_with_restore_list:
|
|||||||
DBUG_RETURN(res || thd->net.report_error);
|
DBUG_RETURN(res || thd->net.report_error);
|
||||||
|
|
||||||
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)
|
if (udf->type == UDFTYPE_AGGREGATE)
|
||||||
Select->in_sum_expr--;
|
Select->in_sum_expr--;
|
||||||
|
|
||||||
|
Lex->binlog_row_based_if_mixed= 1;
|
||||||
|
|
||||||
switch (udf->returns) {
|
switch (udf->returns) {
|
||||||
case STRING_RESULT:
|
case STRING_RESULT:
|
||||||
if (udf->type == UDFTYPE_FUNCTION)
|
if (udf->type == UDFTYPE_FUNCTION)
|
||||||
|
Reference in New Issue
Block a user