mirror of
https://github.com/MariaDB/server.git
synced 2025-01-29 02:05:57 +01:00
merged fixes for BUG#39934 to 5.1-rpl+3
Also renamed current_stmt_binlog_row_based to current_stmt_binlog_format_row for consistency
This commit is contained in:
commit
31193a632e
123 changed files with 6016 additions and 6594 deletions
400
mysql-test/extra/rpl_tests/create_recursive_construct.inc
Normal file
400
mysql-test/extra/rpl_tests/create_recursive_construct.inc
Normal file
|
@ -0,0 +1,400 @@
|
|||
# ==== Purpose ====
|
||||
#
|
||||
# Creates a stored routine, stored function, trigger, view, or
|
||||
# prepared statement (commonly referred to as "recursive construct")
|
||||
# that invokes a given unsafe statement.
|
||||
#
|
||||
# Then, it invokes the created recursive construct several times:
|
||||
#
|
||||
# - With SQL_LOG_BIN = 1 and binlog_format = STATEMENT, to verify
|
||||
# that it gives a warning.
|
||||
#
|
||||
# - With SQL_LOG_BIN = 0 and binlog_format = STATEMENT, to verify that
|
||||
# there is no warning and nothing is logged.
|
||||
#
|
||||
# - With SQL_LOG_BIN = 1 and binlog_format = MIXED, to verify that it
|
||||
# writes row events to the binlog.
|
||||
#
|
||||
# - In some cases, the recursive construct can be invoked so that it
|
||||
# has no side-effects but returns a value that may be
|
||||
# nondeterministic. An example is a function that returns UUID().
|
||||
# The function does not have side effects but its a return value
|
||||
# that may differ on slave. Such statements are invoked so that
|
||||
# the return value is discarded (e.g., SELECT func()), with
|
||||
# SQL_LOG_BIN = 1 and binlog_format = STATEMENT. In this case, no
|
||||
# warning should be given and nothing should be written to the
|
||||
# binlog.
|
||||
#
|
||||
# This is an auxiliary file particularly targeted to being used by the
|
||||
# test binlog_unsafe. In this context, the purpose is to check how
|
||||
# warnings for unsafe statements are propagated in recursive
|
||||
# constructs.
|
||||
#
|
||||
# The statement to invoke ("input") is described using mtr variables,
|
||||
# and the resulting recursive construct ("output") is stored in mtr
|
||||
# variables in a similar fashion. To create several levels of nested
|
||||
# recursive constructs, source this file once, then copy the values of
|
||||
# appropriate output variables to the input variables, and then source
|
||||
# this file again.
|
||||
#
|
||||
#
|
||||
# ==== Usage ====
|
||||
#
|
||||
# See binlog_unsafe for an example of how to use this file.
|
||||
#
|
||||
# let $CRC_ARG_level= <level>;
|
||||
# let $CRC_ARG_type= <type>;
|
||||
# let $CRC_ARG_stmt_sidef= <stmt>;
|
||||
# let $CRC_ARG_value= <stmt>;
|
||||
# let $CRC_ARG_sel_retval= <stmt>;
|
||||
# let $CRC_ARG_sel_sidef= <stmt>;
|
||||
# let $CRC_ARG_desc= <desc>;
|
||||
# source extra/rpl_tests/create_recursive_construct.inc;
|
||||
# let $my_stmt_sidef= $CRC_RET_stmt_sidef;
|
||||
# let $my_value= $CRC_RET_value;
|
||||
# let $my_sel_sidef= $CRC_RET_sel_sidef;
|
||||
# let $my_sel_retval= $CRC_RET_sel_retval;
|
||||
# let $my_drop= $CRC_RET_drop;
|
||||
# let $my_is_toplevel= $CRC_RET_top_is_toplevel;
|
||||
# let $my_desc= $CRC_RET_desc;
|
||||
#
|
||||
# $CRC_ARG_* are used as input parameters (arguments) to this file:
|
||||
#
|
||||
# $CRC_ARG_level is the recursion depth: 1 for the innermost
|
||||
# statement created, 2 for a statement that invokes a statement on
|
||||
# level 1, etc.
|
||||
#
|
||||
# $CRC_ARG_type is an integer from 0 to 6, indicating what type of
|
||||
# statement shall be created:
|
||||
# 0 - Create a stored function where the return value depends on
|
||||
# the value of the given statement.
|
||||
# 1 - Create a stored function that invokes the given statement as
|
||||
# a side-effect but may not return a value that depends on it.
|
||||
# 2 - Create a stored routine that invokes the given statement.
|
||||
# 3 - Create a trigger (on table trigger_table_$CRC_ARG_level) that
|
||||
# invokes the given statement.
|
||||
# 4 - Create a view that returns a value that depends on the value
|
||||
# of the given statement.
|
||||
# 5 - Create a view that invokes the given statement but may return
|
||||
# a value that does not depend on it.
|
||||
# 6 - Create a prepared statement that invokes the given statement.
|
||||
#
|
||||
# $CRC_ARG_stmt_sidef is the statement to invoke. It should be a
|
||||
# statement that can be invoked on its own (not sub-statement),
|
||||
# which causes something unsafe to be written to the binlog.
|
||||
#
|
||||
# $CRC_ARG_value is a sub-statement holding the value of the given
|
||||
# statement. Can be empty if the given statement does not have a
|
||||
# value. Typically, this is non-empty if the given statement is a
|
||||
# function call or user variable, but not if it is a stored routine
|
||||
# call, INSERT, SELECT, etc (because none of them has a value).
|
||||
# $CRC_ARG_value is used only when $CRC_ARG_type=6.
|
||||
#
|
||||
# $CRC_ARG_sel_sidef is a SELECT sub-statement that invokes the
|
||||
# statement as a side-effect, but returns a result set that may not
|
||||
# depend on the statement. Can be empty if the statement cannot
|
||||
# produce a result set from a SELECT. $CRC_ARG_sel_sidef is used
|
||||
# only if $CRC_ARG_type=2
|
||||
#
|
||||
# $CRC_ARG_sel_retval is a SELECT sub-statement that does not have
|
||||
# side-effects, but returns a result set that depends on the unsafe
|
||||
# statement. Can be empty if the statement cannot be invoked from a
|
||||
# SELECT. $CRC_ARG_sel_retval is used only if $CRC_ARG_type=3.
|
||||
#
|
||||
# $CRC_ARG_desc is a human-readable description of the statement to
|
||||
# invoke.
|
||||
#
|
||||
# $CRC_RET_* are used as output parameters (return values) of this
|
||||
# file:
|
||||
#
|
||||
# $CRC_RET_stmt_sidef is a statement invoking the resulting recursive
|
||||
# construct.
|
||||
#
|
||||
# $CRC_RET_value is a sub-statement invoking the resulting recursive
|
||||
# construct and returning the value of the recursive construct.
|
||||
# This is the empty string if the resulting recursive construct does
|
||||
# not have a value. In particular, this is non-empty only if
|
||||
# $CRC_ARG_value=7.
|
||||
#
|
||||
# $CRC_RET_sel_sidef is a SELECT sub-statement that invokes the
|
||||
# resulting recursive construct as a side-effect but where the
|
||||
# result set may not depend on the recursive construct. This is the
|
||||
# empty string if the recursive construct cannot be invoked from a
|
||||
# SELECT. In particular, this is non-empty only if $CRC_ARG_value=6
|
||||
# or $CRC_ARG_value=2.
|
||||
#
|
||||
# $CRC_RET_sel_retval is a SELECT sub-statement that does not have
|
||||
# side-effects, but returns a result set depending on the unsafe
|
||||
# statement. This is the empty string if the recursive construct
|
||||
# cannot produce a result set from a SELECT. In particular, this is
|
||||
# non-empty only if $CRC_ARG_value=7 or $CRC_ARG_value=3.
|
||||
#
|
||||
# $CRC_RET_drop is a statement that drops the created object. I.e.,
|
||||
# it is one of 'DROP FUNCTION <func>', 'DROP PROCEDURE <proc>', etc.
|
||||
#
|
||||
# $CRC_RET_top_is_toplevel is 0 normally, or 1 if the resulting
|
||||
# recursive construct can only be called from a top-level statement.
|
||||
# In particular, this is 1 only when $CRC_ARG_value=1, because
|
||||
# prepared statements cannot be invoked from other recursive
|
||||
# constructs.
|
||||
#
|
||||
# $CRC_RET_desc is a text string that describes the invokation of
|
||||
# the recursive construct in a human-readable fashion.
|
||||
#
|
||||
# Assumptions
|
||||
#
|
||||
# Before sourcing this file with $CRC_ARG_level=X, you need to
|
||||
# create three tables: tX, taX and trigger_table_X. These are used
|
||||
# as auxiliary tables.
|
||||
|
||||
|
||||
#--echo debug: >>>>ENTER create_recursive_construct
|
||||
#--echo debug: level=$CRC_ARG_level
|
||||
#--echo debug: type=$CRC_ARG_type
|
||||
#--echo debug: stmt_sidef=$CRC_ARG_stmt_sidef
|
||||
#--echo debug: value=$CRC_ARG_value
|
||||
#--echo debug: sel_retval=$CRC_ARG_sel_retval
|
||||
#--echo debug: sel_sidef=$CRC_ARG_sel_sidef
|
||||
|
||||
--let $CRC_RET_stmt_sidef=
|
||||
--let $CRC_RET_value=
|
||||
--let $CRC_RET_sel_retval=
|
||||
--let $CRC_RET_sel_sidef=
|
||||
--let $CRC_RET_drop=
|
||||
--let $CRC_RET_is_toplevel= 1
|
||||
--let $CRC_RET_desc=
|
||||
--let $CRC_name=
|
||||
--let $CRC_create=
|
||||
|
||||
######## func_retval ########
|
||||
if (`SELECT $CRC_ARG_type = 0 AND '$CRC_ARG_value' != ''`) {
|
||||
# It will be safe to call this function and discard the return
|
||||
# value, but it will be unsafe to use return value (e.g., in
|
||||
# INSERT...SELECT).
|
||||
--let $CRC_name= func_retval_$CRC_ARG_level
|
||||
--let $CRC_create= CREATE FUNCTION $CRC_name() RETURNS VARCHAR(100) BEGIN INSERT INTO ta$CRC_ARG_level VALUES (47); RETURN $CRC_ARG_value; END
|
||||
--let $CRC_RET_stmt_sidef= INSERT INTO t$CRC_ARG_level VALUES ($CRC_name())
|
||||
--let $CRC_RET_value= $CRC_name()
|
||||
--let $CRC_RET_sel_sidef=
|
||||
--let $CRC_RET_sel_retval= SELECT $CRC_name()
|
||||
--let $CRC_RET_drop= DROP FUNCTION $CRC_name
|
||||
--let $CRC_RET_is_toplevel= 0
|
||||
--let $CRC_RET_desc= function $CRC_name returning value from $CRC_ARG_desc
|
||||
}
|
||||
|
||||
######## func_sidef ########
|
||||
if (`SELECT $CRC_ARG_type = 1`) {
|
||||
# It will be unsafe to call func even if you discard return value.
|
||||
--let $CRC_name= func_sidef_$CRC_ARG_level
|
||||
--let $CRC_create= CREATE FUNCTION $CRC_name() RETURNS VARCHAR(100) BEGIN INSERT INTO ta$CRC_ARG_level VALUES (47); $CRC_ARG_stmt_sidef; RETURN 0; END
|
||||
--let $CRC_RET_stmt_sidef= INSERT INTO t$CRC_ARG_level SELECT $CRC_name()
|
||||
--let $CRC_RET_value=
|
||||
--let $CRC_RET_sel_retval=
|
||||
--let $CRC_RET_sel_sidef= SELECT $CRC_name()
|
||||
--let $CRC_RET_drop= DROP FUNCTION $CRC_name
|
||||
--let $CRC_RET_is_toplevel= 0
|
||||
--let $CRC_RET_desc= function $CRC_name invoking $CRC_ARG_desc
|
||||
}
|
||||
|
||||
######## proc ########
|
||||
if (`SELECT $CRC_ARG_type = 2`) {
|
||||
# It will be unsafe to call this procedure.
|
||||
--let $CRC_name= proc_$CRC_ARG_level
|
||||
--let $CRC_create= CREATE PROCEDURE $CRC_name() BEGIN INSERT INTO ta$CRC_ARG_level VALUES (47); $CRC_ARG_stmt_sidef; END
|
||||
--let $CRC_RET_stmt_sidef= CALL $CRC_name()
|
||||
--let $CRC_RET_value=
|
||||
--let $CRC_RET_sel_retval=
|
||||
--let $CRC_RET_sel_sidef=
|
||||
--let $CRC_RET_drop= DROP PROCEDURE $CRC_name
|
||||
--let $CRC_RET_is_toplevel= 0
|
||||
--let $CRC_RET_desc= procedure $CRC_name invoking $CRC_ARG_desc
|
||||
}
|
||||
|
||||
######## trig ########
|
||||
if (`SELECT $CRC_ARG_type = 3`) {
|
||||
# It will be unsafe to invoke this trigger.
|
||||
--let $CRC_name= trig_$CRC_ARG_level
|
||||
--let $CRC_create= CREATE TRIGGER $CRC_name BEFORE INSERT ON trigger_table_$CRC_ARG_level FOR EACH ROW BEGIN INSERT INTO ta$CRC_ARG_level VALUES (47); $CRC_ARG_stmt_sidef; END
|
||||
--let $CRC_RET_stmt_sidef= INSERT INTO trigger_table_$CRC_ARG_level VALUES (1)
|
||||
--let $CRC_RET_value=
|
||||
--let $CRC_RET_sel_retval=
|
||||
--let $CRC_RET_sel_sidef=
|
||||
--let $CRC_RET_drop= DROP TRIGGER $CRC_name
|
||||
--let $CRC_RET_is_toplevel= 0
|
||||
--let $CRC_RET_desc= trigger $CRC_name invoking $CRC_ARG_desc
|
||||
}
|
||||
|
||||
######## view_retval ########
|
||||
if (`SELECT $CRC_ARG_type = 4 AND '$CRC_ARG_sel_retval' != ''`) {
|
||||
# It will be safe to select from this view if you discard the result
|
||||
# set, but unsafe to use result set (e.g., in INSERT..SELECT).
|
||||
--let $CRC_name= view_retval_$CRC_ARG_level
|
||||
--let $CRC_create= CREATE VIEW $CRC_name AS $CRC_ARG_sel_retval
|
||||
--let $CRC_RET_stmt_sidef= INSERT INTO t$CRC_ARG_LEVEL SELECT * FROM $CRC_name
|
||||
--let $CRC_RET_value=
|
||||
--let $CRC_RET_sel_retval= SELECT * FROM $CRC_name
|
||||
--let $CRC_RET_sel_sidef=
|
||||
--let $CRC_RET_drop= DROP VIEW $CRC_name
|
||||
--let $CRC_RET_is_toplevel= 0
|
||||
--let $CRC_RET_desc= view $CRC_name returning value from $CRC_ARG_desc
|
||||
}
|
||||
|
||||
######## view_sidef ########
|
||||
if (`SELECT $CRC_ARG_type = 5 AND '$CRC_ARG_sel_sidef' != ''`) {
|
||||
# It will be unsafe to select from this view, even if you discard
|
||||
# the return value.
|
||||
--let $CRC_name= view_sidef_$CRC_ARG_level
|
||||
--let $CRC_create= CREATE VIEW $CRC_name AS $CRC_ARG_sel_sidef
|
||||
--let $CRC_RET_stmt_sidef= INSERT INTO t$CRC_ARG_level SELECT * FROM $CRC_name
|
||||
--let $CRC_RET_value=
|
||||
--let $CRC_RET_sel_retval=
|
||||
--let $CRC_RET_sel_sidef= SELECT * FROM $CRC_name
|
||||
--let $CRC_RET_drop= DROP VIEW $CRC_name
|
||||
--let $CRC_RET_is_toplevel= 0
|
||||
--let $CRC_RET_desc= view $CRC_name invoking $CRC_ARG_desc
|
||||
}
|
||||
|
||||
######## prep ########
|
||||
if (`SELECT $CRC_ARG_type = 6`) {
|
||||
# It will be unsafe to execute this prepared statement
|
||||
--let $CRC_name= prep_$CRC_ARG_level
|
||||
--let $CRC_create= PREPARE $CRC_name FROM "$CRC_ARG_stmt_sidef"
|
||||
--let $CRC_RET_stmt_sidef= EXECUTE $CRC_name
|
||||
--let $CRC_RET_value=
|
||||
--let $CRC_RET_sel_retval=
|
||||
--let $CRC_RET_sel_sidef=
|
||||
--let $CRC_RET_drop= DROP PREPARE $CRC_name
|
||||
--let $CRC_RET_is_toplevel= 1
|
||||
--let $CRC_RET_desc= prepared statement $CRC_name invoking $CRC_ARG_desc
|
||||
}
|
||||
|
||||
######## no recursive construct: just return the given statement ########
|
||||
if (`SELECT $CRC_ARG_type = 7`) {
|
||||
# CRC_ARG_type=7 is a special case. We just set $CRC_RET_x =
|
||||
# $CRC_ARG_x. This way, the $CRC_ARG_stmt gets executed directly
|
||||
# (below). In binlog_unsafe.test, it is used to invoke the unsafe
|
||||
# statement created in the outermost loop directly, without
|
||||
# enclosing it in a recursive construct.
|
||||
--let $CRC_RET_stmt_sidef= $CRC_ARG_stmt_sidef
|
||||
--let $CRC_RET_value= $CRC_ARG_value
|
||||
--let $CRC_RET_sel_retval= $CRC_ARG_sel_retval
|
||||
--let $CRC_RET_sel_sidef= $CRC_ARG_sel_sidef
|
||||
--let $CRC_RET_drop=
|
||||
--let $CRC_RET_is_toplevel= 1
|
||||
--let $CRC_RET_desc= $CRC_ARG_desc
|
||||
}
|
||||
|
||||
######## execute! ########
|
||||
if (`SELECT '$CRC_RET_stmt_sidef' != ''`) {
|
||||
--echo
|
||||
--echo Invoking $CRC_RET_desc.
|
||||
if (`SELECT '$CRC_create' != ''`) {
|
||||
--eval $CRC_create
|
||||
}
|
||||
|
||||
--echo * binlog_format = STATEMENT: expect $CRC_ARG_expected_number_of_warnings warnings.
|
||||
--eval $CRC_RET_stmt_sidef
|
||||
--let $n_warnings= `SHOW COUNT(*) WARNINGS`
|
||||
if (`SELECT '$n_warnings' != '$CRC_ARG_expected_number_of_warnings'`) {
|
||||
--echo Failure! Expected $CRC_ARG_expected_number_of_warnings warnings, got $n_warnings warnings.
|
||||
SHOW WARNINGS;
|
||||
SHOW BINLOG EVENTS;
|
||||
--exit
|
||||
}
|
||||
|
||||
# These queries are run without query log, to make result file more
|
||||
# readable. Debug info is only printed if something abnormal
|
||||
# happens.
|
||||
--disable_query_log
|
||||
|
||||
--echo * SQL_LOG_BIN = 0: expect nothing logged and no warning.
|
||||
SET SQL_LOG_BIN = 0;
|
||||
RESET MASTER;
|
||||
--eval $CRC_RET_stmt_sidef
|
||||
--let $n_warnings= `SHOW COUNT(*) WARNINGS`
|
||||
if (`SELECT '$n_warnings' != '0'`) {
|
||||
--echo Failure! Expected 0 warnings, got $n_warnings warnings.
|
||||
SHOW WARNINGS;
|
||||
SHOW BINLOG EVENTS;
|
||||
--exit
|
||||
}
|
||||
--let $binlog_event= query_get_value(SHOW BINLOG EVENTS, Event_type, 2)
|
||||
if (`SELECT '$binlog_event' != 'No such row'`) {
|
||||
--enable_query_log
|
||||
--echo Failure! Something was written to the binlog despite SQL_LOG_BIN=0:
|
||||
SHOW BINLOG EVENTS;
|
||||
--exit
|
||||
}
|
||||
SET SQL_LOG_BIN = 1;
|
||||
|
||||
--echo * binlog_format = MIXED: expect row events in binlog and no warning.
|
||||
SET binlog_format = MIXED;
|
||||
RESET MASTER;
|
||||
--eval $CRC_RET_stmt_sidef
|
||||
--let $n_warnings= `SHOW COUNT(*) WARNINGS`
|
||||
if (`SELECT '$n_warnings' != '0'`) {
|
||||
--echo Failure! Expected 0 warnings, got $n_warnings warnings.
|
||||
SHOW WARNINGS;
|
||||
SHOW BINLOG EVENTS;
|
||||
--exit
|
||||
}
|
||||
# The first event is format_description, the second is
|
||||
# Query_event('BEGIN'), and the third should be our Table_map.
|
||||
--let $event_type= query_get_value(SHOW BINLOG EVENTS, Event_type, 3)
|
||||
if (`SELECT '$event_type' != 'Table_map'`) {
|
||||
--enable_query_log
|
||||
--echo Failure! Event number 3 was a '$event_type', not a 'Table_map'.
|
||||
|
||||
# Currently, there is a bug causing some statements to be logged
|
||||
# partially in statement format. Hence, we don't fail here, we
|
||||
# just print the events (masking out nondeterministic components
|
||||
# of the output) and continue. When binloggging works perfectly,
|
||||
# we should instead execute:
|
||||
#--enable_query_log
|
||||
#SHOW BINLOG EVENTS;
|
||||
#--exit
|
||||
|
||||
# Here, we should really source
|
||||
# include/show_binlog_events.inc. But due to BUG#41913, that
|
||||
# doesn't work, and we have to inline the entire file here. Sigh
|
||||
# :-(
|
||||
--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR 106 <binlog_start>
|
||||
--replace_column 2 # 4 # 5 #
|
||||
--replace_regex /\/\* xid=.* \*\//\/* XID *\// /table_id: [0-9]+/table_id: #/ /file_id=[0-9]+/file_id=#/ /block_len=[0-9]+/block_len=#/
|
||||
--eval SHOW BINLOG EVENTS FROM 106
|
||||
--disable_query_log
|
||||
}
|
||||
SET binlog_format = STATEMENT;
|
||||
|
||||
--enable_query_log
|
||||
}
|
||||
|
||||
# Invoke created object, discarding the return value. This should not
|
||||
# give any warning.
|
||||
if (`SELECT '$CRC_RET_sel_retval' != ''`) {
|
||||
--echo * Invoke statement so that return value is dicarded: expect no warning.
|
||||
--disable_result_log
|
||||
--eval $CRC_RET_sel_retval
|
||||
--enable_result_log
|
||||
|
||||
# Currently, due to a bug, we do get warnings here, so we don't
|
||||
# fail. When the bug is fixed, we should execute the following.
|
||||
|
||||
#--let $n_warnings= `SHOW COUNT(*) WARNINGS`
|
||||
#if (`SELECT '$n_warnings' != '0'`) {
|
||||
# --enable_query_log
|
||||
# --echo Failure! Expected 0 warnings, got $n_warnings warnings.
|
||||
# SHOW WARNINGS;
|
||||
# SHOW BINLOG EVENTS;
|
||||
# --exit
|
||||
#}
|
||||
}
|
||||
|
||||
#--echo debug: <<<<EXIT create_recursive_construct
|
||||
#--echo debug: stmt_sidef=$CRC_RET_stmt_sidef
|
||||
#--echo debug: value=$CRC_RET_value
|
||||
#--echo debug: sel_retval=$CRC_RET_sel_retval
|
||||
#--echo debug: sel_sidef=$CRC_RET_sel_sidef
|
||||
#--echo debug: drop=$CRC_RET_drop
|
||||
#--echo debug: is_toplevel=$CRC_RET_is_toplevel
|
||||
#--echo debug: desc=$CRC_RET_desc
|
|
@ -47,7 +47,6 @@ insert into t1 set b=1;
|
|||
insert into t2 set a=1, b=1;
|
||||
|
||||
set foreign_key_checks=0;
|
||||
set @@session.binlog_format=row;
|
||||
delete from t1;
|
||||
|
||||
--echo must sync w/o a problem (could not with the buggy code)
|
||||
|
|
|
@ -38,14 +38,14 @@ connection master;
|
|||
truncate table t1;
|
||||
# first scenario: duplicate on first row
|
||||
insert delayed into t1 values(10, "my name");
|
||||
if ($binlog_format_statement)
|
||||
if (`SELECT @@global.binlog_format = 'STATEMENT'`)
|
||||
{
|
||||
# statement below will be converted to non-delayed INSERT and so
|
||||
# will stop at first error, guaranteeing replication.
|
||||
--error ER_DUP_ENTRY
|
||||
insert delayed into t1 values(10, "is Bond"), (20, "James Bond");
|
||||
}
|
||||
if (!$binlog_format_statement)
|
||||
if (`SELECT @@global.binlog_format != 'STATEMENT'`)
|
||||
{
|
||||
insert delayed into t1 values(10, "is Bond"), (20, "James Bond");
|
||||
}
|
||||
|
@ -59,7 +59,7 @@ select * from t1;
|
|||
# second scenario: duplicate on second row
|
||||
connection master;
|
||||
delete from t1 where id!=10;
|
||||
if ($binlog_format_statement)
|
||||
if (`SELECT @@global.binlog_format = 'STATEMENT'`)
|
||||
{
|
||||
# statement below will be converted to non-delayed INSERT and so
|
||||
# will be binlogged with its ER_DUP_ENTRY error code, guaranteeing
|
||||
|
@ -67,7 +67,7 @@ if ($binlog_format_statement)
|
|||
--error ER_DUP_ENTRY
|
||||
insert delayed into t1 values(20, "is Bond"), (10, "James Bond");
|
||||
}
|
||||
if (!$binlog_format_statement)
|
||||
if (`SELECT @@global.binlog_format != 'STATEMENT'`)
|
||||
{
|
||||
insert delayed into t1 values(20, "is Bond"), (10, "James Bond");
|
||||
}
|
||||
|
@ -108,6 +108,7 @@ if (`SELECT @@global.binlog_format != 'ROW'`)
|
|||
{
|
||||
#must show two INSERT DELAYED
|
||||
--replace_column 1 x 2 x 3 x 4 x 5 x
|
||||
--replace_regex /table_id: [0-9]+/table_id: #/
|
||||
show binlog events in 'master-bin.000002' LIMIT 2,2;
|
||||
}
|
||||
select * from t1;
|
||||
|
@ -118,6 +119,7 @@ if (`SELECT @@global.binlog_format != 'ROW'`)
|
|||
{
|
||||
#must show two INSERT DELAYED
|
||||
--replace_column 1 x 2 x 3 x 4 x 5 x
|
||||
--replace_regex /table_id: [0-9]+/table_id: #/
|
||||
show binlog events in 'slave-bin.000002' LIMIT 2,2;
|
||||
}
|
||||
select * from t1;
|
||||
|
|
|
@ -141,7 +141,9 @@ let $run= 5;
|
|||
while ($run)
|
||||
{
|
||||
START TRANSACTION;
|
||||
--disable_warnings
|
||||
--eval CALL tpcb.trans($rpl_format);
|
||||
--enable_warnings
|
||||
eval SET @my_errno= $mysql_errno;
|
||||
let $run_good= `SELECT @my_errno = 0`;
|
||||
let $run_bad= `SELECT @my_errno <> 0`;
|
||||
|
@ -190,7 +192,9 @@ let $run= 5;
|
|||
while ($run)
|
||||
{
|
||||
START TRANSACTION;
|
||||
--disable_warnings
|
||||
--eval CALL tpcb.trans($rpl_format);
|
||||
--enable_warnings
|
||||
eval SET @my_errno= $mysql_errno;
|
||||
let $run_good= `SELECT @my_errno = 0`;
|
||||
let $run_bad= `SELECT @my_errno <> 0`;
|
||||
|
@ -240,7 +244,9 @@ let $run= 5;
|
|||
while ($run)
|
||||
{
|
||||
START TRANSACTION;
|
||||
--disable_warnings
|
||||
--eval CALL tpcb.trans($rpl_format);
|
||||
--enable_warnings
|
||||
eval SET @my_errno= $mysql_errno;
|
||||
let $run_good= `SELECT @my_errno = 0`;
|
||||
let $run_bad= `SELECT @my_errno <> 0`;
|
||||
|
|
|
@ -1,16 +1,21 @@
|
|||
#
|
||||
# Check if server has support for loading udf's
|
||||
# i.e it will support dlopen
|
||||
# Check if server has support for loading plugins
|
||||
#
|
||||
--require r/have_dynamic_loading.require
|
||||
disable_query_log;
|
||||
show variables like 'have_dynamic_loading';
|
||||
enable_query_log;
|
||||
if (`SELECT @@have_dynamic_loading != 'YES'`) {
|
||||
--skip Example plugin requires dynamic loading
|
||||
}
|
||||
|
||||
#
|
||||
# Check if the variable EXAMPLE_PLUGIN is set
|
||||
#
|
||||
--require r/have_example_plugin.require
|
||||
disable_query_log;
|
||||
eval select LENGTH('$EXAMPLE_PLUGIN') > 0 as 'have_example_plugin';
|
||||
if (`SELECT LENGTH('$EXAMPLE_PLUGIN') = 0`) {
|
||||
--skip Example plugin requires the environment variable \$EXAMPLE_PLUGIN to be set (normally done by mtr)
|
||||
}
|
||||
|
||||
#
|
||||
# Check if --plugin-dir was setup for exampledb
|
||||
#
|
||||
if (`SELECT CONCAT('--plugin-dir=', @@plugin_dir) != '$EXAMPLE_PLUGIN_OPT'`) {
|
||||
--skip Example plugin requires that --plugin-dir is set to the example plugin dir (either the .opt file does not contain \$EXAMPLE_PLUGIN_OPT or another plugin is in use)
|
||||
}
|
||||
enable_query_log;
|
||||
|
|
|
@ -1,16 +1,20 @@
|
|||
#
|
||||
# Check if server has support for loading udf's
|
||||
# i.e it will support dlopen
|
||||
# Check if server has support for loading plugins
|
||||
#
|
||||
--require r/have_dynamic_loading.require
|
||||
disable_query_log;
|
||||
show variables like 'have_dynamic_loading';
|
||||
enable_query_log;
|
||||
if (`SELECT @@have_dynamic_loading != 'YES'`) {
|
||||
--skip simple parser requires dynamic loading
|
||||
}
|
||||
|
||||
#
|
||||
# Check if the variable SIMPLE_PARSER is set
|
||||
#
|
||||
--require r/have_simple_parser.require
|
||||
disable_query_log;
|
||||
eval select LENGTH('$SIMPLE_PARSER') > 0 as 'have_simple_parser';
|
||||
enable_query_log;
|
||||
if (`SELECT LENGTH('$SIMPLE_PARSER') = 0`) {
|
||||
--skip simple parser requires the environment variable \$SIMPLE_PARSER to be set (normally done by mtr)
|
||||
}
|
||||
|
||||
#
|
||||
# Check if --plugin-dir was setup for simple parser
|
||||
#
|
||||
if (`SELECT CONCAT('--plugin-dir=', @@plugin_dir) != '$SIMPLE_PARSER_OPT'`) {
|
||||
--skip simple parser requires that --plugin-dir is set to the udf plugin dir (either the .opt file does not contain \$UDF_EXAMPLE_LIB_OPT or another plugin is in use)
|
||||
}
|
||||
|
|
|
@ -1,16 +1,20 @@
|
|||
#
|
||||
# Check if server has support for loading udf's
|
||||
# i.e it will support dlopen
|
||||
# Check if server has support for loading plugins
|
||||
#
|
||||
--require r/have_dynamic_loading.require
|
||||
disable_query_log;
|
||||
show variables like 'have_dynamic_loading';
|
||||
enable_query_log;
|
||||
if (`SELECT @@have_dynamic_loading != 'YES'`) {
|
||||
--skip UDF requires dynamic loading
|
||||
}
|
||||
|
||||
#
|
||||
# Check if the variable UDF_EXAMPLE_LIB is set
|
||||
#
|
||||
--require r/have_udf_example.require
|
||||
disable_query_log;
|
||||
eval select LENGTH('$UDF_EXAMPLE_LIB') > 0 as 'have_udf_example_lib';
|
||||
enable_query_log;
|
||||
if (`SELECT LENGTH('$UDF_EXAMPLE_LIB') = 0`) {
|
||||
--skip UDF requires the environment variable \$UDF_EXAMPLE_LIB to be set (normally done by mtr)
|
||||
}
|
||||
|
||||
#
|
||||
# Check if --plugin-dir was setup for udf
|
||||
#
|
||||
if (`SELECT CONCAT('--plugin-dir=', @@plugin_dir) != '$UDF_EXAMPLE_LIB_OPT'`) {
|
||||
--skip UDF requires that --plugin-dir is set to the udf plugin dir (either the .opt file does not contain \$UDF_EXAMPLE_LIB_OPT or another plugin is in use)
|
||||
}
|
||||
|
|
|
@ -55,11 +55,13 @@ connection master;
|
|||
--echo "Running on the master"
|
||||
--enable_info
|
||||
eval CREATE TABLE t1(sum INT, price FLOAT(24)) ENGINE=$engine_type;
|
||||
--disable_warnings
|
||||
INSERT INTO t1 VALUES(myfunc_int(100), myfunc_double(50.00));
|
||||
INSERT INTO t1 VALUES(myfunc_int(10), myfunc_double(5.00));
|
||||
INSERT INTO t1 VALUES(myfunc_int(200), myfunc_double(25.00));
|
||||
INSERT INTO t1 VALUES(myfunc_int(1), myfunc_double(500.00));
|
||||
SELECT * FROM t1 ORDER BY sum;
|
||||
--enable_warnings
|
||||
--disable_info
|
||||
|
||||
sync_slave_with_master;
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
Variable_name Value
|
||||
have_dynamic_loading YES
|
|
@ -1,2 +0,0 @@
|
|||
have_example_plugin
|
||||
1
|
|
@ -1,2 +0,0 @@
|
|||
have_simple_parser
|
||||
1
|
|
@ -1,2 +0,0 @@
|
|||
have_udf_example_lib
|
||||
1
|
|
@ -42,7 +42,7 @@ id
|
|||
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
|
||||
BEGIN;
|
||||
INSERT INTO t1 VALUES(9);
|
||||
ERROR HY000: Binary logging not possible. Message: Transaction level 'READ-COMMITTED' in InnoDB is not safe for binlog mode 'STATEMENT'
|
||||
ERROR HY000: Cannot execute statement: binlogging impossible since BINLOG_FORMAT = STATEMENT and at least one table uses a storage engine limited to row-logging. InnoDB is limited to row-logging when transaction isolation level is READ COMMITTED or READ UNCOMMITTED.
|
||||
COMMIT;
|
||||
COMMIT;
|
||||
DROP TABLE t1;
|
||||
|
|
|
@ -506,6 +506,8 @@ select count(*)*255 from t3 into table_size;
|
|||
until table_size > max_table_size*2 end repeat;
|
||||
end|
|
||||
call bug14210_fill_table()|
|
||||
Warnings:
|
||||
Note 1592 Unsafe statement binlogged in statement format since BINLOG_FORMAT = STATEMENT. Reason: Statement uses a system variable whose value may differ on slave.
|
||||
drop procedure bug14210_fill_table|
|
||||
create table t4 like t3|
|
||||
create procedure bug14210()
|
||||
|
|
|
@ -14,12 +14,12 @@ SET BINLOG_FORMAT=STATEMENT;
|
|||
BEGIN;
|
||||
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
UPDATE t1 SET b = 1*a WHERE a > 1;
|
||||
ERROR HY000: Binary logging not possible. Message: Transaction level 'READ-UNCOMMITTED' in InnoDB is not safe for binlog mode 'STATEMENT'
|
||||
ERROR HY000: Cannot execute statement: binlogging impossible since BINLOG_FORMAT = STATEMENT and at least one table uses a storage engine limited to row-logging. InnoDB is limited to row-logging when transaction isolation level is READ COMMITTED or READ UNCOMMITTED.
|
||||
COMMIT;
|
||||
BEGIN;
|
||||
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
|
||||
UPDATE t1 SET b = 2*a WHERE a > 2;
|
||||
ERROR HY000: Binary logging not possible. Message: Transaction level 'READ-COMMITTED' in InnoDB is not safe for binlog mode 'STATEMENT'
|
||||
ERROR HY000: Cannot execute statement: binlogging impossible since BINLOG_FORMAT = STATEMENT and at least one table uses a storage engine limited to row-logging. InnoDB is limited to row-logging when transaction isolation level is READ COMMITTED or READ UNCOMMITTED.
|
||||
COMMIT;
|
||||
BEGIN;
|
||||
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
|
||||
|
|
|
@ -42,7 +42,7 @@ INSERT INTO t1m 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 HY000: Binary logging not possible. Message: Statement cannot be written atomically since more than one engine involved and at least one engine is self-logging
|
||||
ERROR HY000: Cannot execute statement: binlogging impossible since more than one engine is involved and at least one engine is self-logging.
|
||||
TRUNCATE t1m;
|
||||
TRUNCATE t1b;
|
||||
TRUNCATE t1n;
|
||||
|
@ -68,9 +68,9 @@ 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, t1n SET m = 2, e = 3 WHERE n = f;
|
||||
ERROR HY000: Binary logging not possible. Message: Statement cannot be written atomically since more than one engine involved and at least one engine is self-logging
|
||||
ERROR HY000: Cannot execute statement: binlogging impossible since more than one engine is involved and at least one engine is self-logging.
|
||||
UPDATE t1n, t1b SET e = 2, b = 3 WHERE f = c;
|
||||
ERROR HY000: Binary logging not possible. Message: Statement cannot be written atomically since more than one engine involved and at least one engine is self-logging
|
||||
ERROR HY000: Cannot execute statement: binlogging impossible since more than one engine is involved and at least one engine is self-logging.
|
||||
show binlog events from <binlog_start>;
|
||||
Log_name Pos Event_type Server_id End_log_pos Info
|
||||
mysqld-bin.000001 # Query # # BEGIN
|
||||
|
|
|
@ -12,7 +12,11 @@ master-bin.000001 # Query # # use `test`; insert delayed into t1 values (null)
|
|||
master-bin.000001 # Query # # use `test`; insert delayed into t1 values (300)
|
||||
master-bin.000001 # Query # # use `test`; FLUSH TABLES
|
||||
insert delayed into t1 values (null),(null),(null),(null);
|
||||
Warnings:
|
||||
Note 1592 Unsafe statement binlogged in statement format since BINLOG_FORMAT = STATEMENT. Reason: Statement uses INSERT DELAYED. This is unsafe because the time when rows are inserted cannot be predicted.
|
||||
insert delayed into t1 values (null),(null),(400),(null);
|
||||
Warnings:
|
||||
Note 1592 Unsafe statement binlogged in statement format since BINLOG_FORMAT = STATEMENT. Reason: Statement uses INSERT DELAYED. This is unsafe because the time when rows are inserted cannot be predicted.
|
||||
select * from t1;
|
||||
a
|
||||
207
|
||||
|
|
|
@ -11,7 +11,7 @@ prepare s from "insert into t1 select 100 limit ?";
|
|||
set @a=100;
|
||||
execute s using @a;
|
||||
Warnings:
|
||||
Note 1592 Statement may not be safe to log in statement format.
|
||||
Note 1592 Unsafe statement binlogged in statement format since BINLOG_FORMAT = STATEMENT. Reason: Statement uses a LIMIT clause. This is unsafe because the set of rows included cannot be predicted.
|
||||
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)
|
||||
|
|
|
@ -4,10 +4,10 @@ CREATE TABLE t1 (a int, b int, primary key (a));
|
|||
INSERT INTO t1 VALUES (1,2), (2,3);
|
||||
UPDATE t1 SET b='4' WHERE a=1 LIMIT 1;
|
||||
Warnings:
|
||||
Note 1592 Statement may not be safe to log in statement format.
|
||||
Note 1592 Unsafe statement binlogged in statement format since BINLOG_FORMAT = STATEMENT. Reason: Statement uses a LIMIT clause. This is unsafe because the set of rows included cannot be predicted.
|
||||
UPDATE t1 SET b='5' WHERE a=2 ORDER BY a LIMIT 1;
|
||||
Warnings:
|
||||
Note 1592 Statement may not be safe to log in statement format.
|
||||
Note 1592 Unsafe statement binlogged in statement format since BINLOG_FORMAT = STATEMENT. Reason: Statement uses a LIMIT clause. This is unsafe because the set of rows included cannot be predicted.
|
||||
DROP TABLE t1;
|
||||
### NOT filtered database => assertion: binlog disabled and warnings ARE NOT shown
|
||||
SET SQL_LOG_BIN= 0;
|
||||
|
@ -38,11 +38,11 @@ CREATE TABLE t1 (a VARCHAR(36), b VARCHAR(10));
|
|||
SET GLOBAL LOG_WARNINGS = 0;
|
||||
INSERT INTO t1 VALUES(UUID(), 'Bug#46265');
|
||||
Warnings:
|
||||
Note 1592 Statement may not be safe to log in statement format.
|
||||
Note 1592 Unsafe statement binlogged in statement format since BINLOG_FORMAT = STATEMENT. Reason: Statement uses a system function whose value may differ on slave.
|
||||
SET GLOBAL LOG_WARNINGS = 1;
|
||||
INSERT INTO t1 VALUES(UUID(), 'Bug#46265');
|
||||
Warnings:
|
||||
Note 1592 Statement may not be safe to log in statement format.
|
||||
Note 1592 Unsafe statement binlogged in statement format since BINLOG_FORMAT = STATEMENT. Reason: Statement uses a system function whose value may differ on slave.
|
||||
DROP TABLE t1;
|
||||
SET GLOBAL log_warnings = @old_log_warnings;
|
||||
# Count the number of times the "Unsafe" message was printed
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -27,13 +27,13 @@ SET BINLOG_FORMAT=STATEMENT;
|
|||
|
||||
BEGIN;
|
||||
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
error ER_BINLOG_LOGGING_IMPOSSIBLE;
|
||||
error ER_BINLOG_STMT_MODE_AND_ROW_ENGINE;
|
||||
UPDATE t1 SET b = 1*a WHERE a > 1;
|
||||
COMMIT;
|
||||
|
||||
BEGIN;
|
||||
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
|
||||
error ER_BINLOG_LOGGING_IMPOSSIBLE;
|
||||
error ER_BINLOG_STMT_MODE_AND_ROW_ENGINE;
|
||||
UPDATE t1 SET b = 2*a WHERE a > 2;
|
||||
COMMIT;
|
||||
|
||||
|
|
|
@ -60,7 +60,7 @@ let $wait_binlog_event= COMMIT;
|
|||
source include/wait_for_binlog_event.inc;
|
||||
|
||||
UPDATE t1m, t1b SET m = 2, b = 3 WHERE n = c;
|
||||
error ER_BINLOG_LOGGING_IMPOSSIBLE;
|
||||
error ER_BINLOG_MULTIPLE_ENGINES_AND_SELF_LOGGING_ENGINE;
|
||||
UPDATE t1m, t1n SET m = 2, e = 3 WHERE n = f;
|
||||
|
||||
# Not possible to test this since NDB writes its own binlog, which
|
||||
|
@ -84,7 +84,7 @@ 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 ER_BINLOG_LOGGING_IMPOSSIBLE;
|
||||
error ER_BINLOG_MULTIPLE_ENGINES_AND_SELF_LOGGING_ENGINE;
|
||||
UPDATE t1m, t1n SET m = 2, e = 3 WHERE n = f;
|
||||
|
||||
# Not possible to test this since NDB writes its own binlog, which
|
||||
|
@ -93,7 +93,7 @@ UPDATE t1m, t1n SET m = 2, e = 3 WHERE n = f;
|
|||
|
||||
#UPDATE t1m, t1n SET m = 2, e = 3 WHERE n = f;
|
||||
|
||||
error ER_BINLOG_LOGGING_IMPOSSIBLE;
|
||||
error ER_BINLOG_MULTIPLE_ENGINES_AND_SELF_LOGGING_ENGINE;
|
||||
UPDATE t1n, t1b SET e = 2, b = 3 WHERE f = c;
|
||||
|
||||
source include/show_binlog_events.inc;
|
||||
|
|
1
mysql-test/suite/binlog/t/binlog_unsafe-master.opt
Normal file
1
mysql-test/suite/binlog/t/binlog_unsafe-master.opt
Normal file
|
@ -0,0 +1 @@
|
|||
$UDF_EXAMPLE_LIB_OPT
|
|
@ -1,34 +1,61 @@
|
|||
# ==== Background ====
|
||||
#
|
||||
# Some statements may execute differently on master and slave when
|
||||
# logged in statement format. Such statements are called unsafe.
|
||||
# Unsafe statements include:
|
||||
#
|
||||
# - statements using @@variables (with a small number of exceptions;
|
||||
# see below);
|
||||
# - statements using certain functions, e.g., UUID();
|
||||
# - statements using LIMIT;
|
||||
# - INSERT DELAYED;
|
||||
# - insert into two autoinc columns;
|
||||
# - statements using UDF's.
|
||||
# - statements reading from log tables in the mysql database.
|
||||
#
|
||||
# Note that statements that use stored functions, stored procedures,
|
||||
# triggers, views, or prepared statements that invoke unsafe
|
||||
# statements shall also be unsafe.
|
||||
#
|
||||
# Unsafeness of a statement shall have the following consequences:
|
||||
#
|
||||
# 1. If the binlogging is on and the unsafe statement is logged:
|
||||
# - If binlog_format=STATEMENT, the statement shall give a warning.
|
||||
# - If binlog_format=MIXED or binlog_format=ROW, the statement shall
|
||||
# be logged in row format.
|
||||
#
|
||||
# 2. If binlogging is off or the statement is not logged (e.g. SELECT
|
||||
# UUID()), no warning shall be issued and the statement shall not
|
||||
# be logged.
|
||||
#
|
||||
# Moreover, when a sub-statement of a recursive construct (i.e.,
|
||||
# stored function, stored procedure, trigger, view, or prepared
|
||||
# statement) is unsafe and binlog_format=STATEMENT, then a warning
|
||||
# shall be issued for every recursive construct. In effect, this
|
||||
# creates a stack trace from the top-level statement to the unsafe
|
||||
# statement.
|
||||
#
|
||||
#
|
||||
# ==== Purpose ====
|
||||
#
|
||||
# Some statements can not be written to the binlog in a safe manner
|
||||
# with statement-based replication, either because they rely on
|
||||
# features that are local to the server they are replicated from
|
||||
# (e.g., @@variables), or because they include nondeterministic
|
||||
# queries (e.g., LIMIT), or because the time at which the query is
|
||||
# executed cannot be determined (e.g., INSERT DELAYED). Such
|
||||
# statements should be marked unsafe. All unsafe statements should
|
||||
# give a warning.
|
||||
# Yet the warning/error message isn't issued when SQL_LOG_BIN is turned off.
|
||||
# This test verifies that a warning is generated when it should,
|
||||
# according to the rules above.
|
||||
#
|
||||
# This test verifies that a warning is generated for statements that
|
||||
# should be unsafe, when they are executed under statement mode
|
||||
# logging.
|
||||
#
|
||||
# All variables should be unsafe, with some exceptions. Therefore,
|
||||
# this test also verifies that the exceptions do *not* generare a
|
||||
# All @@variables should be unsafe, with some exceptions. Therefore,
|
||||
# this test also verifies that the exceptions do *not* generate a
|
||||
# warning.
|
||||
#
|
||||
#
|
||||
# ==== Method ====
|
||||
#
|
||||
# We try an INSERT DELAYED statement and verify that a warning is
|
||||
# issued.
|
||||
# 1. Each type of statements listed above is executed.
|
||||
#
|
||||
# We try to insert unsafe variables into a table in several ways:
|
||||
# directly with an INSERT statement, from a stored procedure, from a
|
||||
# stored function, from a trigger, from a prepared statement, and from
|
||||
# a complicated nesting of triggers, functions, procedures, and
|
||||
# prepared statements. In all cases, a warning should be issued.
|
||||
# 2. Each unsafe statement is wrapped in each type of recursive
|
||||
# construct (stored function, stored procedure, trigger, view, or
|
||||
# prepared statement).
|
||||
#
|
||||
# 3. Each unsafe statement is wrapped in two levels of recursive
|
||||
# constructs (function invoking trigger invoking UUID(), etc).
|
||||
#
|
||||
# We try to insert the variables that should not be unsafe into a
|
||||
# table, and verify that *no* warning is issued.
|
||||
|
@ -38,7 +65,8 @@
|
|||
# Execute a unsafe statement calling a trigger or stored function
|
||||
# or neither when @@SQL_LOG_BIN is turned OFF,
|
||||
# no warning/error is issued
|
||||
|
||||
#
|
||||
#
|
||||
# ==== Related bugs and worklogs ====
|
||||
#
|
||||
# WL#3339: Issue warnings when statement-based replication may fail
|
||||
|
@ -47,6 +75,9 @@
|
|||
# BUG#34768: nondeterministic INSERT using LIMIT logged in stmt mode if binlog_format=mixed
|
||||
# BUG#41980, SBL, INSERT .. SELECT .. LIMIT = ERROR, even when @@SQL_LOG_BIN is 0
|
||||
# BUG#42640: mysqld crashes when unsafe statements are executed (STRICT_TRANS_TABLES mode)
|
||||
# BUG#45825: INSERT DELAYED is not unsafe: logged in statement format
|
||||
# BUG#45785: LIMIT in SP does not cause RBL if binlog_format=MIXED
|
||||
#
|
||||
#
|
||||
# ==== Related test cases ====
|
||||
#
|
||||
|
@ -57,192 +88,311 @@
|
|||
# rpl.rpl_variables_stm tests the small subset of variables that
|
||||
# actually can be replicated safely in statement mode.
|
||||
#
|
||||
#
|
||||
# ==== Todo ====
|
||||
#
|
||||
# There are several other ways to create unsafe statements: see, e.g.,
|
||||
# WL#3339, BUG#34768.
|
||||
# rpl_ndb.rpl_ndb_binlog_format_errors tests all errors and warnings
|
||||
# related to logging format (not just 'Unsafe statement binlogged in
|
||||
# statement mode since BINLOG_FORMAT = STATEMENT').
|
||||
|
||||
source include/have_log_bin.inc;
|
||||
source include/have_binlog_format_statement.inc;
|
||||
--source include/have_udf.inc
|
||||
--source include/have_log_bin.inc
|
||||
--source include/have_binlog_format_statement.inc
|
||||
|
||||
--echo ==== Setup tables ====
|
||||
--echo #### Setup tables ####
|
||||
|
||||
CREATE TABLE t1 (a INT);
|
||||
CREATE TABLE t2 (a CHAR(40));
|
||||
CREATE TABLE t3 (a INT AUTO_INCREMENT PRIMARY KEY);
|
||||
CREATE TABLE trigger_table (a CHAR(7));
|
||||
CREATE TABLE trigger_table2 (a INT);
|
||||
CREATE TABLE t0 (a CHAR(100));
|
||||
CREATE TABLE t1 (a CHAR(100));
|
||||
CREATE TABLE t2 (a CHAR(100));
|
||||
CREATE TABLE t3 (a CHAR(100));
|
||||
CREATE TABLE ta0 (a CHAR(100));
|
||||
CREATE TABLE ta1 (a CHAR(100));
|
||||
CREATE TABLE ta2 (a CHAR(100));
|
||||
CREATE TABLE ta3 (a CHAR(100));
|
||||
CREATE TABLE autoinc_table (a INT PRIMARY KEY AUTO_INCREMENT);
|
||||
CREATE TABLE data_table (a CHAR(100));
|
||||
INSERT INTO data_table VALUES ('foo');
|
||||
CREATE TABLE trigger_table_1 (a INT);
|
||||
CREATE TABLE trigger_table_2 (a INT);
|
||||
CREATE TABLE trigger_table_3 (a INT);
|
||||
CREATE TABLE double_autoinc_table (a INT PRIMARY KEY AUTO_INCREMENT);
|
||||
|
||||
|
||||
--echo ==== Non-deterministic statements ====
|
||||
|
||||
INSERT DELAYED INTO t1 VALUES (5);
|
||||
|
||||
|
||||
--echo ==== Some variables that *should* be unsafe ====
|
||||
|
||||
--echo ---- Insert directly ----
|
||||
|
||||
INSERT INTO t1 VALUES (@@global.sync_binlog);
|
||||
INSERT INTO t1 VALUES (@@session.insert_id);
|
||||
INSERT INTO t1 VALUES (@@global.auto_increment_increment);
|
||||
INSERT INTO t2 SELECT UUID();
|
||||
INSERT INTO t2 VALUES (@@session.sql_mode);
|
||||
INSERT INTO t2 VALUES (@@global.init_slave);
|
||||
INSERT INTO t2 VALUES (@@hostname);
|
||||
|
||||
--echo ---- Insert from stored procedure ----
|
||||
|
||||
DELIMITER |;
|
||||
CREATE PROCEDURE proc()
|
||||
--DELIMITER |
|
||||
CREATE TRIGGER double_autoinc_trig
|
||||
BEFORE INSERT ON double_autoinc_table FOR EACH ROW
|
||||
BEGIN
|
||||
INSERT INTO t1 VALUES (@@global.sync_binlog);
|
||||
INSERT INTO t1 VALUES (@@session.insert_id);
|
||||
INSERT INTO t1 VALUES (@@global.auto_increment_increment);
|
||||
INSERT INTO t2 SELECT UUID();
|
||||
INSERT INTO t2 VALUES (@@session.sql_mode);
|
||||
INSERT INTO t2 VALUES (@@global.init_slave);
|
||||
INSERT INTO t2 VALUES (@@hostname);
|
||||
END|
|
||||
DELIMITER ;|
|
||||
|
||||
CALL proc();
|
||||
|
||||
--echo ---- Insert from stored function ----
|
||||
|
||||
DELIMITER |;
|
||||
CREATE FUNCTION func()
|
||||
RETURNS INT
|
||||
BEGIN
|
||||
INSERT INTO t1 VALUES (@@global.sync_binlog);
|
||||
INSERT INTO t1 VALUES (@@session.insert_id);
|
||||
INSERT INTO t1 VALUES (@@global.auto_increment_increment);
|
||||
INSERT INTO t2 SELECT UUID();
|
||||
INSERT INTO t2 VALUES (@@session.sql_mode);
|
||||
INSERT INTO t2 VALUES (@@global.init_slave);
|
||||
INSERT INTO t2 VALUES (@@hostname);
|
||||
RETURN 0;
|
||||
END|
|
||||
DELIMITER ;|
|
||||
|
||||
SELECT func();
|
||||
|
||||
--echo ---- Insert from trigger ----
|
||||
|
||||
DELIMITER |;
|
||||
CREATE TRIGGER trig
|
||||
BEFORE INSERT ON trigger_table
|
||||
FOR EACH ROW
|
||||
BEGIN
|
||||
INSERT INTO t1 VALUES (@@global.sync_binlog);
|
||||
INSERT INTO t1 VALUES (@@session.insert_id);
|
||||
INSERT INTO t1 VALUES (@@global.auto_increment_increment);
|
||||
INSERT INTO t2 SELECT UUID();
|
||||
INSERT INTO t2 VALUES (@@session.sql_mode);
|
||||
INSERT INTO t2 VALUES (@@global.init_slave);
|
||||
INSERT INTO t2 VALUES (@@hostname);
|
||||
END|
|
||||
DELIMITER ;|
|
||||
|
||||
INSERT INTO trigger_table VALUES ('bye.');
|
||||
|
||||
--echo ---- Insert from prepared statement ----
|
||||
|
||||
PREPARE p1 FROM 'INSERT INTO t1 VALUES (@@global.sync_binlog)';
|
||||
PREPARE p2 FROM 'INSERT INTO t1 VALUES (@@session.insert_id)';
|
||||
PREPARE p3 FROM 'INSERT INTO t1 VALUES (@@global.auto_increment_increment)';
|
||||
PREPARE p4 FROM 'INSERT INTO t2 SELECT UUID()';
|
||||
PREPARE p5 FROM 'INSERT INTO t2 VALUES (@@session.sql_mode)';
|
||||
PREPARE p6 FROM 'INSERT INTO t2 VALUES (@@global.init_slave)';
|
||||
PREPARE p7 FROM 'INSERT INTO t2 VALUES (@@hostname)';
|
||||
|
||||
EXECUTE p1; EXECUTE p2; EXECUTE p3; EXECUTE p4; EXECUTE p5;
|
||||
EXECUTE p6; EXECUTE p7;
|
||||
|
||||
--echo ---- Insert from nested call of triggers / functions / procedures ----
|
||||
|
||||
DELIMITER |;
|
||||
|
||||
# proc1: cause trigger 'trig' above to be triggered.
|
||||
CREATE PROCEDURE proc1()
|
||||
INSERT INTO trigger_table VALUES ('ha!')|
|
||||
|
||||
# func2: call proc1 above.
|
||||
CREATE FUNCTION func2()
|
||||
RETURNS INT
|
||||
BEGIN
|
||||
CALL proc1();
|
||||
RETURN 0;
|
||||
INSERT INTO autoinc_table VALUES (NULL);
|
||||
END|
|
||||
|
||||
# trig3: call func2 above
|
||||
CREATE TRIGGER trig3
|
||||
BEFORE INSERT ON trigger_table2
|
||||
FOR EACH ROW
|
||||
CREATE FUNCTION multi_unsafe_func() RETURNS INT
|
||||
BEGIN
|
||||
DECLARE tmp INT;
|
||||
SELECT func2() INTO tmp;
|
||||
INSERT INTO t0 VALUES(CONCAT(@@hostname, @@hostname));
|
||||
INSERT INTO t0 VALUES(0);
|
||||
INSERT INTO t0 VALUES(CONCAT(UUID(), @@hostname));
|
||||
RETURN 1;
|
||||
END|
|
||||
--DELIMITER ;
|
||||
|
||||
# proc4: cause trig3 above to be triggered.
|
||||
CREATE PROCEDURE proc4()
|
||||
INSERT INTO trigger_table2 VALUES (1)|
|
||||
--replace_result $UDF_EXAMPLE_LIB UDF_EXAMPLE_LIB
|
||||
--eval CREATE FUNCTION myfunc_int RETURNS INTEGER SONAME "$UDF_EXAMPLE_LIB"
|
||||
|
||||
# func5: call proc4 above.
|
||||
CREATE FUNCTION func5()
|
||||
RETURNS INT
|
||||
BEGIN
|
||||
CALL proc4;
|
||||
RETURN 0;
|
||||
END|
|
||||
# In each iteration of this loop, we select one method to make the
|
||||
# statement unsafe.
|
||||
--let $unsafe_type= 0
|
||||
while (`SELECT $unsafe_type < 9`) {
|
||||
|
||||
# prep6: call func5() above.
|
||||
PREPARE prep6 FROM 'SELECT func5()'|
|
||||
--echo
|
||||
|
||||
DELIMITER ;|
|
||||
if (`SELECT $unsafe_type = 0`) {
|
||||
--echo ==== Testing UUID() unsafeness ====
|
||||
--let $desc_0= unsafe UUID() function
|
||||
--let $stmt_sidef_0= INSERT INTO t0 VALUES (UUID())
|
||||
--let $value_0= UUID()
|
||||
--let $sel_sidef_0=
|
||||
--let $sel_retval_0= SELECT UUID()
|
||||
--let $CRC_ARG_expected_number_of_warnings= 1
|
||||
}
|
||||
|
||||
# try a complicated call path to trigger 'trig'.
|
||||
EXECUTE prep6;
|
||||
if (`SELECT $unsafe_type = 1`) {
|
||||
--echo ==== Testing @@hostname unsafeness ====
|
||||
--let $desc_0= unsafe @@hostname variable
|
||||
--let $stmt_sidef_0= INSERT INTO t0 VALUES (@@hostname)
|
||||
--let $value_0= @@hostname
|
||||
--let $sel_sidef_0=
|
||||
# $sel_retval is going to be used in views. Views cannot execute
|
||||
# statements that refer to @@variables. Hence, we set $set_retval
|
||||
# to empty instead of SELECT @@hostname.
|
||||
--let $sel_retval_0=
|
||||
--let $CRC_ARG_expected_number_of_warnings= 1
|
||||
}
|
||||
|
||||
if (`SELECT $unsafe_type = 2`) {
|
||||
--echo ==== Testing SELECT...LIMIT unsafeness ====
|
||||
--let $desc_0= unsafe SELECT...LIMIT statement
|
||||
--let $stmt_sidef_0= INSERT INTO t0 SELECT * FROM data_table LIMIT 1
|
||||
--let $value_0=
|
||||
--let $sel_sidef_0=
|
||||
--let $sel_retval_0= SELECT * FROM data_table LIMIT 1
|
||||
--let $CRC_ARG_expected_number_of_warnings= 1
|
||||
}
|
||||
|
||||
if (`SELECT $unsafe_type = 3`) {
|
||||
--echo ==== Testing INSERT DELAYED unsafeness ====
|
||||
--let $desc_0= unsafe INSERT DELAYED statement
|
||||
--let $stmt_sidef_0= INSERT DELAYED INTO t0 VALUES (1), (2)
|
||||
--let $value_0=
|
||||
--let $sel_sidef_0=
|
||||
--let $sel_retval_0=
|
||||
--let $CRC_ARG_expected_number_of_warnings= 1
|
||||
}
|
||||
|
||||
if (`SELECT $unsafe_type = 4`) {
|
||||
--echo ==== Testing unsafeness of insert of two autoinc values ====
|
||||
--let $desc_0= unsafe update of two autoinc columns
|
||||
--let $stmt_sidef_0= INSERT INTO double_autoinc_table VALUES (NULL)
|
||||
--let $value_0=
|
||||
--let $sel_sidef_0=
|
||||
--let $sel_retval_0=
|
||||
# Note: we will expect 1 warning when BUG#45827 is fixed.
|
||||
--let $CRC_ARG_expected_number_of_warnings= 0
|
||||
}
|
||||
|
||||
if (`SELECT $unsafe_type = 5`) {
|
||||
--echo ==== Testing unsafeness of UDF's ====
|
||||
--let $desc_0= unsafe UDF
|
||||
--let $stmt_sidef_0= INSERT INTO t0 VALUES (myfunc_int(10))
|
||||
--let $value_0= myfunc_int(10)
|
||||
--let $sel_sidef_0= SELECT myfunc_int(10)
|
||||
--let $sel_retval_0=
|
||||
--let $CRC_ARG_expected_number_of_warnings= 1
|
||||
}
|
||||
|
||||
if (`SELECT $unsafe_type = 6`) {
|
||||
--echo ==== Testing unsafeness of access to mysql.general_log ====
|
||||
--let $desc_0= unsafe use of mysql.general_log
|
||||
--let $stmt_sidef_0= INSERT INTO t0 SELECT COUNT(*) FROM mysql.general_log
|
||||
--let $value_0=
|
||||
--let $sel_sidef_0=
|
||||
--let $sel_retval_0= SELECT COUNT(*) FROM mysql.general_log
|
||||
--let $CRC_ARG_expected_number_of_warnings= 1
|
||||
}
|
||||
|
||||
if (`SELECT $unsafe_type = 7`) {
|
||||
--echo ==== Testing a statement that is unsafe in many ways ====
|
||||
--let $desc_0= statement that is unsafe in many ways
|
||||
# Concatenate three unsafe values, and then concatenate NULL to
|
||||
# that so that the result is NULL and we instead use autoinc.
|
||||
--let $stmt_sidef_0= INSERT DELAYED INTO double_autoinc_table SELECT CONCAT(UUID(), @@hostname, myfunc_int(), NULL) FROM mysql.general_log LIMIT 1
|
||||
--let $value_0=
|
||||
--let $sel_sidef_0=
|
||||
--let $sel_retval_0=
|
||||
# Note: we will expect 7 warnings when BUG#45827 is fixed.
|
||||
--let $CRC_ARG_expected_number_of_warnings= 6
|
||||
}
|
||||
|
||||
if (`SELECT $unsafe_type = 8`) {
|
||||
--echo ==== Testing a statement that is unsafe several times ====
|
||||
--let $desc_0= statement that is unsafe several times
|
||||
--let $stmt_sidef_0= INSERT INTO ta0 VALUES (multi_unsafe_func())
|
||||
--let $value_0=
|
||||
--let $sel_sidef_0= SELECT multi_unsafe_func()
|
||||
--let $sel_retval_0=
|
||||
--let $CRC_ARG_expected_number_of_warnings= 2
|
||||
}
|
||||
|
||||
# In each iteration of the following loop, we select one way to
|
||||
# enclose the unsafe statement as a sub-statement of a recursive
|
||||
# construct (i.e., a function, procedure, trigger, view, or prepared
|
||||
# statement).
|
||||
#
|
||||
# In the last iteration, $call_type_1=7, we don't create a recursive
|
||||
# construct. Instead, we just invoke the unsafe statement directly.
|
||||
|
||||
--let $call_type_1= 0
|
||||
while (`SELECT $call_type_1 < 8`) {
|
||||
#--echo debug: level 1, types $call_type_1 -> $unsafe_type
|
||||
--let $CRC_ARG_level= 1
|
||||
--let $CRC_ARG_type= $call_type_1
|
||||
--let $CRC_ARG_stmt_sidef= $stmt_sidef_0
|
||||
--let $CRC_ARG_value= $value_0
|
||||
--let $CRC_ARG_sel_sidef= $sel_sidef_0
|
||||
--let $CRC_ARG_sel_retval= $sel_retval_0
|
||||
--let $CRC_ARG_desc= $desc_0
|
||||
--source extra/rpl_tests/create_recursive_construct.inc
|
||||
--let $stmt_sidef_1= $CRC_RET_stmt_sidef
|
||||
--let $value_1= $CRC_RET_value
|
||||
--let $sel_sidef_1= $CRC_RET_sel_sidef
|
||||
--let $sel_retval_1= $CRC_RET_sel_retval
|
||||
--let $is_toplevel_1= $CRC_RET_is_toplevel
|
||||
--let $drop_1= $CRC_RET_drop
|
||||
--let $desc_1= $CRC_RET_desc
|
||||
|
||||
# Some statements must be top-level statements, i.e., cannot be
|
||||
# called as a sub-statement of any recursive construct. (One
|
||||
# example is 'EXECUTE prepared_stmt'). When
|
||||
# create_recursive_construct.inc creates a top-level statement, it
|
||||
# sets $CRC_RET_is_toplevel=1.
|
||||
|
||||
if (!$is_toplevel_1) {
|
||||
|
||||
# In each iteration of this loop, we select one way to enclose
|
||||
# the previous recursive construct in another recursive
|
||||
# construct.
|
||||
|
||||
--let $call_type_2= 0
|
||||
while (`SELECT $call_type_2 < 7`) {
|
||||
#--echo debug: level 2, types $call_type_2 -> $call_type_1 -> $unsafe_type
|
||||
--let $CRC_ARG_level= 2
|
||||
--let $CRC_ARG_type= $call_type_2
|
||||
--let $CRC_ARG_stmt_sidef= $stmt_sidef_1
|
||||
--let $CRC_ARG_value= $value_1
|
||||
--let $CRC_ARG_sel_sidef= $sel_sidef_1
|
||||
--let $CRC_ARG_sel_retval= $sel_retval_1
|
||||
--let $CRC_ARG_desc= $desc_1
|
||||
--source extra/rpl_tests/create_recursive_construct.inc
|
||||
--let $stmt_sidef_2= $CRC_RET_stmt_sidef
|
||||
--let $value_2= $CRC_RET_value
|
||||
--let $sel_sidef_2= $CRC_RET_sel_sidef
|
||||
--let $sel_retval_2= $CRC_RET_sel_retval
|
||||
--let $is_toplevel_2= $CRC_RET_is_toplevel
|
||||
--let $drop_2= $CRC_RET_drop
|
||||
--let $desc_2= $CRC_RET_desc
|
||||
|
||||
if (!$is_toplevel_2) {
|
||||
|
||||
# Conditioned out since it makes result file really big.
|
||||
|
||||
if (0) {
|
||||
|
||||
# In each iteration of this loop, we select one way to enclose
|
||||
# the previous recursive construct in another recursive
|
||||
# construct.
|
||||
|
||||
--let $call_type_3= 0
|
||||
while (`SELECT $call_type_3 < 7`) {
|
||||
#--echo debug: level 3, types $call_type_2 -> $call_type_2 -> $call_type_1 -> $unsafe_type
|
||||
--let $CRC_ARG_level= 3
|
||||
--let $CRC_ARG_type= $call_type_3
|
||||
--let $CRC_ARG_stmt_sidef= $stmt_sidef_2
|
||||
--let $CRC_ARG_value= $value_2
|
||||
--let $CRC_ARG_sel_sidef= $sel_sidef_2
|
||||
--let $CRC_ARG_sel_retval= $sel_retval_2
|
||||
--let $CRC_ARG_desc= $desc_2
|
||||
--source extra/rpl_tests/create_recursive_construct.inc
|
||||
|
||||
# Drop created object.
|
||||
if (`SELECT '$drop_3' != ''`) {
|
||||
--eval $drop_3
|
||||
}
|
||||
--inc $call_type_3
|
||||
} # while (call_type_3)
|
||||
} # if (0)
|
||||
} # if (!is_toplevel_2)
|
||||
|
||||
# Drop created object.
|
||||
if (`SELECT '$drop_2' != ''`) {
|
||||
--eval $drop_2
|
||||
}
|
||||
--inc $call_type_2
|
||||
} # while (call_type_2)
|
||||
} # if (!is_toplevel_1)
|
||||
|
||||
# Drop created object.
|
||||
if (`SELECT '$drop_1' != ''`) {
|
||||
--eval $drop_1
|
||||
}
|
||||
--inc $call_type_1
|
||||
} # while (call_type_1)
|
||||
|
||||
--inc $unsafe_type
|
||||
} # while (unsafe_type)
|
||||
|
||||
DROP TRIGGER double_autoinc_trig;
|
||||
DROP TABLE t0, t1, t2, t3, ta0, ta1, ta2, ta3,
|
||||
autoinc_table, double_autoinc_table,
|
||||
data_table,
|
||||
trigger_table_1, trigger_table_2, trigger_table_3;
|
||||
DROP FUNCTION myfunc_int;
|
||||
DROP FUNCTION multi_unsafe_func;
|
||||
|
||||
|
||||
--echo ==== Variables that should *not* be unsafe ====
|
||||
--echo ==== Special system variables that should *not* be unsafe ====
|
||||
|
||||
CREATE TABLE t1 (a VARCHAR(1000));
|
||||
CREATE TABLE autoinc_table (a INT PRIMARY KEY AUTO_INCREMENT);
|
||||
|
||||
INSERT INTO t1 VALUES (@@session.pseudo_thread_id);
|
||||
INSERT INTO t1 VALUES (@@session.pseudo_thread_id);
|
||||
INSERT INTO t1 VALUES (@@session.foreign_key_checks);
|
||||
INSERT INTO t1 VALUES (@@session.sql_auto_is_null);
|
||||
INSERT INTO t1 VALUES (@@session.unique_checks);
|
||||
INSERT INTO t1 VALUES (@@session.auto_increment_increment);
|
||||
INSERT INTO t1 VALUES (@@session.auto_increment_offset);
|
||||
INSERT INTO t2 VALUES (@@session.character_set_client);
|
||||
INSERT INTO t2 VALUES (@@session.collation_connection);
|
||||
INSERT INTO t2 VALUES (@@session.collation_server);
|
||||
INSERT INTO t2 VALUES (@@session.time_zone);
|
||||
INSERT INTO t2 VALUES (@@session.lc_time_names);
|
||||
INSERT INTO t2 VALUES (@@session.collation_database);
|
||||
INSERT INTO t2 VALUES (@@session.timestamp);
|
||||
INSERT INTO t2 VALUES (@@session.last_insert_id);
|
||||
INSERT INTO t1 VALUES (@@session.character_set_client);
|
||||
INSERT INTO t1 VALUES (@@session.character_set_connection);
|
||||
INSERT INTO t1 VALUES (@@session.character_set_database);
|
||||
INSERT INTO t1 VALUES (@@session.character_set_server);
|
||||
INSERT INTO t1 VALUES (@@session.collation_connection);
|
||||
INSERT INTO t1 VALUES (@@session.collation_database);
|
||||
INSERT INTO t1 VALUES (@@session.collation_server);
|
||||
INSERT INTO t1 VALUES (@@session.foreign_key_checks);
|
||||
INSERT INTO t1 VALUES (@@session.identity);
|
||||
INSERT INTO t1 VALUES (@@session.last_insert_id);
|
||||
INSERT INTO t1 VALUES (@@session.lc_time_names);
|
||||
INSERT INTO t1 VALUES (@@session.pseudo_thread_id);
|
||||
INSERT INTO t1 VALUES (@@session.sql_auto_is_null);
|
||||
INSERT INTO t1 VALUES (@@session.timestamp);
|
||||
INSERT INTO t1 VALUES (@@session.time_zone);
|
||||
INSERT INTO t1 VALUES (@@session.unique_checks);
|
||||
|
||||
SET @my_var= 4711;
|
||||
INSERT INTO t1 VALUES (@my_var);
|
||||
|
||||
# using insert_id implicitly should be ok.
|
||||
SET insert_id=12;
|
||||
INSERT INTO t3 VALUES (NULL);
|
||||
SET insert_id= 12;
|
||||
INSERT INTO autoinc_table VALUES (NULL);
|
||||
|
||||
# See set_var.cc for explanation.
|
||||
--echo The following variables *should* give a warning, despite they are replicated.
|
||||
INSERT INTO t1 VALUES (@@session.sql_mode);
|
||||
INSERT INTO t1 VALUES (@@session.insert_id);
|
||||
|
||||
|
||||
--echo ==== Clean up ====
|
||||
DROP TABLE t1, autoinc_table;
|
||||
|
||||
|
||||
DROP PROCEDURE proc;
|
||||
DROP FUNCTION func;
|
||||
DROP TRIGGER trig;
|
||||
DROP PROCEDURE proc1;
|
||||
DROP FUNCTION func2;
|
||||
DROP TRIGGER trig3;
|
||||
DROP PROCEDURE proc4;
|
||||
DROP FUNCTION func5;
|
||||
DROP PREPARE prep6;
|
||||
DROP TABLE t1, t2, t3, trigger_table, trigger_table2;
|
||||
#
|
||||
# BUG#34768 - nondeterministic INSERT using LIMIT logged in stmt mode if
|
||||
# binlog_format=mixed
|
||||
|
@ -388,4 +538,41 @@ DELETE FROM t1 LIMIT 1;
|
|||
|
||||
DROP TABLE t1, t2;
|
||||
SET @@SESSION.SQL_MODE = @save_sql_mode;
|
||||
|
||||
#
|
||||
# BUG#45825: INSERT DELAYED is not unsafe: logged in statement format
|
||||
# BUG#45785: LIMIT in SP does not cause RBL if binlog_format=MIXED
|
||||
#
|
||||
SET @old_binlog_format = @@session.binlog_format;
|
||||
SET binlog_format = MIXED;
|
||||
|
||||
CREATE TABLE t1 (a INT);
|
||||
CREATE TABLE t2 (a INT);
|
||||
INSERT INTO t2 VALUES (1), (2);
|
||||
|
||||
--DELIMITER |
|
||||
CREATE PROCEDURE proc_insert_delayed ()
|
||||
BEGIN
|
||||
INSERT DELAYED INTO t1 VALUES (1), (2);
|
||||
END|
|
||||
|
||||
CREATE FUNCTION func_limit ()
|
||||
RETURNS INT
|
||||
BEGIN
|
||||
INSERT INTO t1 SELECT * FROM t2 LIMIT 1;
|
||||
RETURN 1;
|
||||
END|
|
||||
--DELIMITER ;
|
||||
|
||||
RESET MASTER;
|
||||
CALL proc_insert_delayed();
|
||||
SELECT func_limit();
|
||||
source include/show_binlog_events.inc;
|
||||
|
||||
SET @@session.binlog_format = @old_binlog_format;
|
||||
DROP TABLE t1, t2;
|
||||
DROP PROCEDURE proc_insert_delayed;
|
||||
DROP FUNCTION func_limit;
|
||||
|
||||
|
||||
--echo "End of tests"
|
||||
|
|
|
@ -11,6 +11,17 @@ SET SESSION binlog_format = 'ROW';
|
|||
select @@global.binlog_format, @@session.binlog_format;
|
||||
@@global.binlog_format ROW
|
||||
@@session.binlog_format ROW
|
||||
[on slave]
|
||||
set @old_global_binlog_format= @@global.binlog_format;
|
||||
set @old_session_binlog_format= @@session.binlog_format;
|
||||
SET GLOBAL binlog_format = 'ROW';
|
||||
SET SESSION binlog_format = 'ROW';
|
||||
select @@global.binlog_format, @@session.binlog_format;
|
||||
@@global.binlog_format ROW
|
||||
@@session.binlog_format ROW
|
||||
include/stop_slave.inc
|
||||
include/start_slave.inc
|
||||
[on master]
|
||||
DROP TABLE IF EXISTS t1, t2, t3;
|
||||
DROP PROCEDURE IF EXISTS p1;
|
||||
DROP PROCEDURE IF EXISTS p2;
|
||||
|
@ -189,3 +200,6 @@ DROP TABLE t1, t2, t3;
|
|||
DROP PROCEDURE IF EXISTS p1;
|
||||
DROP PROCEDURE IF EXISTS p2;
|
||||
DROP PROCEDURE IF EXISTS p3;
|
||||
[on slave]
|
||||
set @@global.binlog_format= @old_global_binlog_format;
|
||||
set @@session.binlog_format= @old_session_binlog_format;
|
||||
|
|
|
@ -11,6 +11,19 @@ set @old_session_binlog_format= @@session.binlog_format;
|
|||
SET GLOBAL binlog_format = 'ROW';
|
||||
SET SESSION binlog_format = 'ROW';
|
||||
select @@global.binlog_format, @@session.binlog_format;
|
||||
--echo [on slave]
|
||||
connection slave;
|
||||
set @old_global_binlog_format= @@global.binlog_format;
|
||||
set @old_session_binlog_format= @@session.binlog_format;
|
||||
SET GLOBAL binlog_format = 'ROW';
|
||||
SET SESSION binlog_format = 'ROW';
|
||||
select @@global.binlog_format, @@session.binlog_format;
|
||||
# restart slave so that slave sql thread's binlog format is re-read
|
||||
# from @@global.binlog_format
|
||||
--source include/stop_slave.inc
|
||||
--source include/start_slave.inc
|
||||
--echo [on master]
|
||||
connection master;
|
||||
|
||||
--disable_warnings
|
||||
DROP TABLE IF EXISTS t1, t2, t3;
|
||||
|
@ -158,8 +171,9 @@ DROP TABLE t1, t2, t3;
|
|||
DROP PROCEDURE IF EXISTS p1;
|
||||
DROP PROCEDURE IF EXISTS p2;
|
||||
DROP PROCEDURE IF EXISTS p3;
|
||||
save_master_pos;
|
||||
connection slave;
|
||||
sync_with_master;
|
||||
--echo [on slave]
|
||||
sync_slave_with_master;
|
||||
set @@global.binlog_format= @old_global_binlog_format;
|
||||
set @@session.binlog_format= @old_session_binlog_format;
|
||||
|
||||
# End of 5.1 tests
|
||||
|
|
|
@ -6,96 +6,6 @@ drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
|
|||
start slave;
|
||||
SET @old_event_scheduler = @@global.event_scheduler;
|
||||
set global event_scheduler=1;
|
||||
set binlog_format=row;
|
||||
DROP EVENT IF EXISTS test.justonce;
|
||||
drop table if exists t1,t2;
|
||||
CREATE TABLE `t1` (
|
||||
`id` INT(10) UNSIGNED NOT NULL,
|
||||
`c` VARCHAR(50) NOT NULL,
|
||||
`ts` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
|
||||
INSERT INTO t1 (id, c) VALUES (1, 'manually');
|
||||
"Creating event test.justonce on the master"
|
||||
CREATE EVENT test.justonce ON SCHEDULE EVERY 2 SECOND DO
|
||||
INSERT IGNORE INTO t1 (id, c) VALUES (2, 'from justonce');
|
||||
"Checking event is active on master"
|
||||
SELECT db, name, status, originator FROM mysql.event WHERE db = 'test' AND name = 'justonce';
|
||||
db name status originator
|
||||
test justonce ENABLED 1
|
||||
"Checking event data on the master"
|
||||
ONE
|
||||
1
|
||||
"Checking event data on the slave"
|
||||
ZERO
|
||||
0
|
||||
"Checking event is inactive on slave"
|
||||
SELECT db, name, status, originator FROM mysql.event WHERE db = 'test' AND name = 'justonce';
|
||||
db name status originator
|
||||
test justonce SLAVESIDE_DISABLED 1
|
||||
"Dropping event test.slave_once on the slave"
|
||||
DROP EVENT IF EXISTS test.slave_once;
|
||||
CREATE EVENT test.slave_once ON SCHEDULE EVERY 5 MINUTE STARTS CURRENT_TIMESTAMP + INTERVAL 1 HOUR DO
|
||||
INSERT IGNORE INTO t1(id, c) VALUES (3, 'from slave_once');
|
||||
"Checking event status on the slave for originator value = slave's server_id"
|
||||
SELECT db, name, status, originator FROM mysql.event WHERE db = 'test' AND name = 'slave_once';
|
||||
db name status originator
|
||||
test slave_once ENABLED 2
|
||||
"Dropping event test.slave_once on the slave"
|
||||
DROP EVENT IF EXISTS test.slave_once;
|
||||
"Dropping event test.justonce on the master"
|
||||
DROP EVENT IF EXISTS test.justonce;
|
||||
"Creating event test.er on the master"
|
||||
CREATE EVENT test.er ON SCHEDULE EVERY 3 SECOND STARTS CURRENT_TIMESTAMP + INTERVAL 1 HOUR DO
|
||||
INSERT IGNORE INTO t1(id, c) VALUES (4, 'from er');
|
||||
"Checking event status on the master"
|
||||
SELECT db, name, status, originator, body FROM mysql.event WHERE db = 'test' AND name = 'er';
|
||||
db name status originator body
|
||||
test er ENABLED 1 INSERT IGNORE INTO t1(id, c) VALUES (4, 'from er')
|
||||
"Checking event status on the slave"
|
||||
SELECT db, name, status, originator, body FROM mysql.event WHERE db = 'test' AND name = 'er';
|
||||
db name status originator body
|
||||
test er SLAVESIDE_DISABLED 1 INSERT IGNORE INTO t1(id, c) VALUES (4, 'from er')
|
||||
"Altering event test.er on the master"
|
||||
ALTER EVENT test.er ON SCHEDULE EVERY 5 SECOND STARTS CURRENT_TIMESTAMP + INTERVAL 1 HOUR DO
|
||||
INSERT IGNORE INTO t1(id, c) VALUES (5, 'from alter er');
|
||||
"Checking event status on the master"
|
||||
SELECT db, name, status, originator, body FROM mysql.event WHERE db = 'test' AND name = 'er';
|
||||
db name status originator body
|
||||
test er ENABLED 1 INSERT IGNORE INTO t1(id, c) VALUES (5, 'from alter er')
|
||||
"Checking event status on the slave"
|
||||
SELECT db, name, status, originator, body FROM mysql.event WHERE db = 'test' AND name = 'er';
|
||||
db name status originator body
|
||||
test er SLAVESIDE_DISABLED 1 INSERT IGNORE INTO t1(id, c) VALUES (5, 'from alter er')
|
||||
"Dropping event test.er on the master"
|
||||
DROP EVENT test.er;
|
||||
"Checking event status on the master"
|
||||
SELECT db, name, status, originator FROM mysql.event WHERE db = 'test';
|
||||
db name status originator
|
||||
"Checking event status on the slave"
|
||||
SELECT db, name, status, originator FROM mysql.event WHERE db = 'test';
|
||||
db name status originator
|
||||
"Creating event test.slave_terminate on the slave"
|
||||
CREATE EVENT test.slave_terminate ON SCHEDULE EVERY 3 SECOND STARTS CURRENT_TIMESTAMP + INTERVAL 1 HOUR DO
|
||||
INSERT IGNORE INTO t1(id, c) VALUES (6, 'from slave_terminate');
|
||||
"Checking event status on the slave"
|
||||
SELECT db, name, status, originator FROM mysql.event WHERE db = 'test' AND name = 'slave_terminate';
|
||||
db name status originator
|
||||
test slave_terminate ENABLED 2
|
||||
"Dropping event test.slave_terminate on the slave"
|
||||
DROP EVENT test.slave_terminate;
|
||||
"Creating event test.slave_terminate with DISABLE ON SLAVE on the slave"
|
||||
CREATE EVENT test.slave_terminate ON SCHEDULE EVERY 3 SECOND DISABLE ON SLAVE DO
|
||||
INSERT IGNORE INTO t1(c) VALUES (7, 'from slave_terminate');
|
||||
"Checking event status on the slave"
|
||||
SELECT db, name, status, originator FROM mysql.event WHERE db = 'test' AND name = 'slave_terminate';
|
||||
db name status originator
|
||||
test slave_terminate SLAVESIDE_DISABLED 2
|
||||
"Dropping event test.slave_terminate on the slave"
|
||||
DROP EVENT test.slave_terminate;
|
||||
"Cleanup"
|
||||
DROP TABLE t1;
|
||||
set binlog_format=statement;
|
||||
DROP EVENT IF EXISTS test.justonce;
|
||||
drop table if exists t1,t2;
|
||||
CREATE TABLE `t1` (
|
||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -46,7 +46,6 @@ engine = INNODB;
|
|||
insert into t1 set b=1;
|
||||
insert into t2 set a=1, b=1;
|
||||
set foreign_key_checks=0;
|
||||
set @@session.binlog_format=row;
|
||||
delete from t1;
|
||||
must sync w/o a problem (could not with the buggy code)
|
||||
select count(*) from t1 /* must be zero */;
|
||||
|
|
|
@ -6,11 +6,12 @@ drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
|
|||
start slave;
|
||||
call mtr.add_suppression("Slave: Can\'t find record in \'t1\' Error_code: 1032");
|
||||
call mtr.add_suppression("Slave: Cannot add or update a child row: a foreign key constraint fails .* Error_code: 1452");
|
||||
SET @old_slave_exec_mode= @@global.slave_exec_mode;
|
||||
CREATE TABLE t1 (a INT PRIMARY KEY);
|
||||
CREATE TABLE t2 (a INT);
|
||||
INSERT INTO t1 VALUES (-1),(-2),(-3);
|
||||
INSERT INTO t2 VALUES (-1),(-2),(-3);
|
||||
SET @old_slave_exec_mode= @@global.slave_exec_mode;
|
||||
SET @@global.slave_exec_mode= IDEMPOTENT;
|
||||
DELETE FROM t1 WHERE a = -2;
|
||||
DELETE FROM t2 WHERE a = -2;
|
||||
DELETE FROM t1 WHERE a = -2;
|
||||
|
@ -72,158 +73,4 @@ a
|
|||
Last_SQL_Error
|
||||
0
|
||||
DROP TABLE t1, t2;
|
||||
select @@global.slave_exec_mode /* must be IDEMPOTENT */;
|
||||
@@global.slave_exec_mode
|
||||
IDEMPOTENT
|
||||
create table ti1 (b int primary key) engine = innodb;
|
||||
create table ti2 (a int primary key, b int, foreign key (b) references ti1(b))
|
||||
engine = innodb;
|
||||
set foreign_key_checks=1 /* ensure the check */;
|
||||
insert into ti1 values (1),(2),(3);
|
||||
insert into ti2 set a=2, b=2;
|
||||
select * from ti1 order by b /* must be (1),(2),(3) */;
|
||||
b
|
||||
1
|
||||
2
|
||||
3
|
||||
insert into ti2 set a=1, b=1;
|
||||
select * from ti2 order by b /* must be (1,1) (2,2) */;
|
||||
a b
|
||||
1 1
|
||||
2 2
|
||||
set @save_binlog_format= @@session.binlog_format;
|
||||
set @@session.binlog_format= row;
|
||||
delete from ti1 where b=1;
|
||||
select * from ti1 order by b /* must be (2),(3) */;
|
||||
b
|
||||
2
|
||||
3
|
||||
select * from ti1 order by b /* must stays as were on master (1),(2),(3) */;
|
||||
b
|
||||
1
|
||||
2
|
||||
3
|
||||
delete from ti1 where b=3;
|
||||
insert into ti2 set a=3, b=3;
|
||||
select * from ti2 order by b /* must be (1,1),(2,2) - not inserted */;
|
||||
a b
|
||||
1 1
|
||||
2 2
|
||||
set global slave_exec_mode='IDEMPOTENT';
|
||||
set global slave_exec_mode='STRICT';
|
||||
set global slave_exec_mode='IDEMPOTENT,STRICT';
|
||||
ERROR HY000: Ambiguous slave modes combination.
|
||||
select @@global.slave_exec_mode /* must be STRICT */;
|
||||
@@global.slave_exec_mode
|
||||
STRICT
|
||||
*** foreign keys errors as above now forces to stop
|
||||
set foreign_key_checks=0;
|
||||
drop table ti2, ti1;
|
||||
create table ti1 (b int primary key) engine = innodb;
|
||||
create table ti2 (a int primary key, b int, foreign key (b) references ti1(b))
|
||||
engine = innodb;
|
||||
set foreign_key_checks=1 /* ensure the check */;
|
||||
insert into ti1 values (1),(2),(3);
|
||||
insert into ti2 set a=2, b=2;
|
||||
select * from ti1 order by b /* must be (1),(2),(3) */;
|
||||
b
|
||||
1
|
||||
2
|
||||
3
|
||||
*** conspire future problem
|
||||
insert into ti2 set a=1, b=1;
|
||||
select * from ti2 order by b /* must be (1,1) (2,2) */;
|
||||
a b
|
||||
1 1
|
||||
2 2
|
||||
delete from ti1 where b=1 /* offending delete event */;
|
||||
select * from ti1 order by b /* must be (2),(3) */;
|
||||
b
|
||||
2
|
||||
3
|
||||
*** slave must stop (Trying to delete a referenced foreing key)
|
||||
Last_SQL_Error
|
||||
1451
|
||||
select * from ti1 order by b /* must be (1),(2),(3) - not deleted */;
|
||||
b
|
||||
1
|
||||
2
|
||||
3
|
||||
set foreign_key_checks= 0;
|
||||
delete from ti2 where b=1;
|
||||
set foreign_key_checks= 1;
|
||||
set global slave_exec_mode='IDEMPOTENT';
|
||||
start slave sql_thread;
|
||||
set global slave_exec_mode='STRICT';
|
||||
*** conspire the following insert failure
|
||||
*** conspire future problem
|
||||
delete from ti1 where b=3;
|
||||
insert into ti2 set a=3, b=3 /* offending write event */;
|
||||
*** slave must stop (Trying to insert an invalid foreign key)
|
||||
Last_SQL_Error
|
||||
1452
|
||||
select * from ti2 order by b /* must be (2,2) */;
|
||||
a b
|
||||
2 2
|
||||
set foreign_key_checks= 0;
|
||||
insert into ti1 set b=3;
|
||||
set foreign_key_checks= 1;
|
||||
set global slave_exec_mode='IDEMPOTENT';
|
||||
start slave sql_thread;
|
||||
set global slave_exec_mode='STRICT';
|
||||
select * from ti2 order by b /* must be (2,2),(3,3) */;
|
||||
a b
|
||||
2 2
|
||||
3 3
|
||||
*** other errors
|
||||
*** conspiring query
|
||||
insert into ti1 set b=1;
|
||||
insert into ti1 set b=1 /* offending write event */;
|
||||
*** slave must stop (Trying to insert a dupliacte key)
|
||||
Last_SQL_Error
|
||||
1062
|
||||
set foreign_key_checks= 0;
|
||||
delete from ti1 where b=1;
|
||||
set foreign_key_checks= 1;
|
||||
set global slave_exec_mode='IDEMPOTENT';
|
||||
start slave sql_thread;
|
||||
set global slave_exec_mode='STRICT';
|
||||
CREATE TABLE t1 (a INT PRIMARY KEY);
|
||||
CREATE TABLE t2 (a INT);
|
||||
INSERT INTO t1 VALUES (-1),(-2),(-3);
|
||||
INSERT INTO t2 VALUES (-1),(-2),(-3);
|
||||
DELETE FROM t1 WHERE a = -2;
|
||||
DELETE FROM t2 WHERE a = -2;
|
||||
DELETE FROM t1 WHERE a = -2;
|
||||
*** slave must stop (Key was not found)
|
||||
Last_SQL_Error
|
||||
1032
|
||||
set global slave_exec_mode='IDEMPOTENT';
|
||||
start slave sql_thread;
|
||||
set global slave_exec_mode='STRICT';
|
||||
DELETE FROM t2 WHERE a = -2;
|
||||
*** slave must stop (Key was not found)
|
||||
Last_SQL_Error
|
||||
1032
|
||||
set global slave_exec_mode='IDEMPOTENT';
|
||||
start slave sql_thread;
|
||||
set global slave_exec_mode='STRICT';
|
||||
UPDATE t1 SET a = 1 WHERE a = -1;
|
||||
UPDATE t2 SET a = 1 WHERE a = -1;
|
||||
UPDATE t1 SET a = 1 WHERE a = -1;
|
||||
*** slave must stop (Key was not found)
|
||||
Last_SQL_Error
|
||||
1032
|
||||
set global slave_exec_mode='IDEMPOTENT';
|
||||
start slave sql_thread;
|
||||
set global slave_exec_mode='STRICT';
|
||||
UPDATE t2 SET a = 1 WHERE a = -1;
|
||||
*** slave must stop (Key was not found)
|
||||
Last_SQL_Error
|
||||
1032
|
||||
set global slave_exec_mode='IDEMPOTENT';
|
||||
start slave sql_thread;
|
||||
SET @@global.slave_exec_mode= @old_slave_exec_mode;
|
||||
set @@session.binlog_format= @save_binlog_format;
|
||||
drop table t1,t2,ti2,ti1;
|
||||
*** end of tests
|
||||
|
|
|
@ -4,8 +4,7 @@ reset master;
|
|||
reset slave;
|
||||
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
|
||||
start slave;
|
||||
==== 0. Setting it all up ====
|
||||
SET BINLOG_FORMAT=STATEMENT;
|
||||
==== Initialize ====
|
||||
**** On Master ****
|
||||
CREATE TABLE t1 (a INT);
|
||||
CREATE TABLE logtbl (sect INT, test INT, count INT);
|
||||
|
@ -16,106 +15,12 @@ INSERT INTO t1 SELECT 2*a+3 FROM t1;
|
|||
INSERT INTO t1 SELECT 2*a+3 FROM t1;
|
||||
INSERT INTO t1 SELECT 2*a+3 FROM t1;
|
||||
INSERT INTO t1 SELECT 2*a+3 FROM t1;
|
||||
#### 1. Using statement mode ####
|
||||
==== 1.1. Simple test ====
|
||||
SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1;
|
||||
a
|
||||
7
|
||||
SELECT FOUND_ROWS() INTO @a;
|
||||
INSERT INTO logtbl VALUES(1,1,@a);
|
||||
SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a < 5 ORDER BY a LIMIT 1;
|
||||
a
|
||||
1
|
||||
SELECT FOUND_ROWS() INTO @a;
|
||||
INSERT INTO logtbl VALUES(1,2,@a);
|
||||
SELECT * FROM logtbl WHERE sect = 1 ORDER BY sect,test;
|
||||
sect test count
|
||||
1 1 183
|
||||
1 2 3
|
||||
**** On Slave ****
|
||||
SELECT * FROM logtbl WHERE sect = 1 ORDER BY sect,test;
|
||||
sect test count
|
||||
1 1 183
|
||||
1 2 3
|
||||
==== 1.2. Stored procedure ====
|
||||
==== Checking a procedure ====
|
||||
**** On Master ****
|
||||
CREATE PROCEDURE calc_and_log(sect INT, test INT) BEGIN
|
||||
DECLARE cnt INT;
|
||||
SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a < 5 ORDER BY a LIMIT 1;
|
||||
SELECT FOUND_ROWS() INTO cnt;
|
||||
INSERT INTO logtbl VALUES(sect,test,cnt);
|
||||
SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1;
|
||||
SELECT FOUND_ROWS() INTO cnt;
|
||||
INSERT INTO logtbl VALUES(sect,test+1,cnt);
|
||||
END $$
|
||||
CALL calc_and_log(2,1);
|
||||
a
|
||||
1
|
||||
a
|
||||
7
|
||||
CREATE PROCEDURE just_log(sect INT, test INT, found_rows INT) BEGIN
|
||||
INSERT INTO logtbl VALUES (sect,test,found_rows);
|
||||
END $$
|
||||
SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1;
|
||||
a
|
||||
7
|
||||
SELECT FOUND_ROWS() INTO @found_rows;
|
||||
CALL just_log(2,3,@found_rows);
|
||||
SELECT * FROM logtbl WHERE sect = 2 ORDER BY sect,test;
|
||||
sect test count
|
||||
2 1 3
|
||||
2 2 183
|
||||
2 3 183
|
||||
**** On Slave ****
|
||||
SELECT * FROM logtbl WHERE sect = 2 ORDER BY sect,test;
|
||||
sect test count
|
||||
2 1 3
|
||||
2 2 183
|
||||
2 3 183
|
||||
==== 1.3. Stored functions ====
|
||||
**** On Master ****
|
||||
CREATE FUNCTION log_rows(sect INT, test INT, found_rows INT)
|
||||
RETURNS INT
|
||||
BEGIN
|
||||
INSERT INTO logtbl VALUES(sect,test,found_rows);
|
||||
RETURN found_rows;
|
||||
END $$
|
||||
SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1;
|
||||
a
|
||||
7
|
||||
SELECT FOUND_ROWS() INTO @found_rows;
|
||||
SELECT log_rows(3,1,@found_rows), log_rows(3,2,@found_rows);
|
||||
log_rows(3,1,@found_rows) log_rows(3,2,@found_rows)
|
||||
183 183
|
||||
SELECT * FROM logtbl WHERE sect = 3 ORDER BY sect,test;
|
||||
sect test count
|
||||
3 1 183
|
||||
3 2 183
|
||||
**** On Slave ****
|
||||
SELECT * FROM logtbl WHERE sect = 3 ORDER BY sect,test;
|
||||
sect test count
|
||||
3 1 183
|
||||
3 2 183
|
||||
==== 1.9. Cleanup ====
|
||||
**** On Master ****
|
||||
DELETE FROM logtbl;
|
||||
DROP PROCEDURE just_log;
|
||||
DROP PROCEDURE calc_and_log;
|
||||
DROP FUNCTION log_rows;
|
||||
**** Resetting master and slave ****
|
||||
include/stop_slave.inc
|
||||
RESET SLAVE;
|
||||
RESET MASTER;
|
||||
include/start_slave.inc
|
||||
#### 2. Using mixed mode ####
|
||||
==== 2.1. Checking a procedure ====
|
||||
**** On Master ****
|
||||
SET BINLOG_FORMAT=MIXED;
|
||||
CREATE PROCEDURE just_log(sect INT, test INT) BEGIN
|
||||
INSERT INTO logtbl VALUES (sect,test,FOUND_ROWS());
|
||||
END $$
|
||||
**** On Master 1 ****
|
||||
SET BINLOG_FORMAT=MIXED;
|
||||
SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1;
|
||||
a
|
||||
7
|
||||
|
@ -148,7 +53,7 @@ sect test count
|
|||
1 2 183
|
||||
1 3 3
|
||||
1 4 183
|
||||
==== 2.1. Checking a stored function ====
|
||||
==== Checking a stored function ====
|
||||
**** On Master ****
|
||||
CREATE FUNCTION log_rows(sect INT, test INT)
|
||||
RETURNS INT
|
71
mysql-test/suite/rpl/r/rpl_mix_insert_delayed.result
Normal file
71
mysql-test/suite/rpl/r/rpl_mix_insert_delayed.result
Normal file
|
@ -0,0 +1,71 @@
|
|||
stop slave;
|
||||
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
|
||||
reset master;
|
||||
reset slave;
|
||||
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
|
||||
start slave;
|
||||
CREATE SCHEMA IF NOT EXISTS mysqlslap;
|
||||
USE mysqlslap;
|
||||
select @@global.binlog_format;
|
||||
@@global.binlog_format
|
||||
MIXED
|
||||
CREATE TABLE t1 (id INT primary key auto_increment, name VARCHAR(64));
|
||||
FLUSH TABLE t1;
|
||||
SELECT COUNT(*) FROM t1;
|
||||
COUNT(*)
|
||||
5000
|
||||
use mysqlslap;
|
||||
SELECT COUNT(*) FROM t1;
|
||||
COUNT(*)
|
||||
5000
|
||||
truncate table t1;
|
||||
insert delayed into t1 values(10, "my name");
|
||||
insert delayed into t1 values(10, "is Bond"), (20, "James Bond");
|
||||
flush table t1;
|
||||
select * from t1;
|
||||
id name
|
||||
10 my name
|
||||
20 James Bond
|
||||
select * from t1;
|
||||
id name
|
||||
10 my name
|
||||
20 James Bond
|
||||
delete from t1 where id!=10;
|
||||
insert delayed into t1 values(20, "is Bond"), (10, "James Bond");
|
||||
flush table t1;
|
||||
select * from t1;
|
||||
id name
|
||||
10 my name
|
||||
20 is Bond
|
||||
select * from t1;
|
||||
id name
|
||||
10 my name
|
||||
20 is Bond
|
||||
USE test;
|
||||
DROP SCHEMA mysqlslap;
|
||||
use test;
|
||||
FLUSH LOGS;
|
||||
FLUSH LOGS;
|
||||
CREATE TABLE t1(a int, UNIQUE(a));
|
||||
INSERT DELAYED IGNORE INTO t1 VALUES(1);
|
||||
INSERT DELAYED IGNORE INTO t1 VALUES(1);
|
||||
flush table t1;
|
||||
show binlog events in 'master-bin.000002' LIMIT 2,2;
|
||||
Log_name Pos Event_type Server_id End_log_pos Info
|
||||
x x x x x BEGIN
|
||||
x x x x x table_id: # (test.t1)
|
||||
select * from t1;
|
||||
a
|
||||
1
|
||||
On slave
|
||||
show binlog events in 'slave-bin.000002' LIMIT 2,2;
|
||||
Log_name Pos Event_type Server_id End_log_pos Info
|
||||
x x x x x BEGIN
|
||||
x x x x x table_id: # (test.t1)
|
||||
select * from t1;
|
||||
a
|
||||
1
|
||||
drop table t1;
|
||||
FLUSH LOGS;
|
||||
FLUSH LOGS;
|
||||
End of 5.0 tests
|
|
@ -4,12 +4,6 @@ reset master;
|
|||
reset slave;
|
||||
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
|
||||
start slave;
|
||||
SET @old_binlog_format= @@global.binlog_format;
|
||||
SET BINLOG_FORMAT=MIXED;
|
||||
SET GLOBAL BINLOG_FORMAT=MIXED;
|
||||
SELECT @@GLOBAL.BINLOG_FORMAT, @@SESSION.BINLOG_FORMAT;
|
||||
@@GLOBAL.BINLOG_FORMAT @@SESSION.BINLOG_FORMAT
|
||||
MIXED MIXED
|
||||
**** On Master ****
|
||||
CREATE TABLE t1 (a INT, b LONG);
|
||||
INSERT INTO t1 VALUES (1,1), (2,2);
|
||||
|
@ -73,4 +67,3 @@ slave-bin.000001 # Table_map 1 # table_id: # (test.t1)
|
|||
slave-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F
|
||||
slave-bin.000001 # Query 1 # COMMIT
|
||||
DROP TABLE IF EXISTS t1;
|
||||
SET @@global.binlog_format= @old_binlog_format;
|
||||
|
|
160
mysql-test/suite/rpl/r/rpl_row_idempotency.result
Normal file
160
mysql-test/suite/rpl/r/rpl_row_idempotency.result
Normal file
|
@ -0,0 +1,160 @@
|
|||
stop slave;
|
||||
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
|
||||
reset master;
|
||||
reset slave;
|
||||
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
|
||||
start slave;
|
||||
set @old_slave_exec_mode= @@global.slave_exec_mode;
|
||||
set @@global.slave_exec_mode= IDEMPOTENT;
|
||||
create table ti1 (b int primary key) engine = innodb;
|
||||
create table ti2 (a int primary key, b int, foreign key (b) references ti1(b))
|
||||
engine = innodb;
|
||||
set foreign_key_checks=1 /* ensure the check */;
|
||||
insert into ti1 values (1),(2),(3);
|
||||
insert into ti2 set a=2, b=2;
|
||||
select * from ti1 order by b /* must be (1),(2),(3) */;
|
||||
b
|
||||
1
|
||||
2
|
||||
3
|
||||
insert into ti2 set a=1, b=1;
|
||||
select * from ti2 order by b /* must be (1,1) (2,2) */;
|
||||
a b
|
||||
1 1
|
||||
2 2
|
||||
set @save_binlog_format= @@session.binlog_format;
|
||||
set @@session.binlog_format= row;
|
||||
delete from ti1 where b=1;
|
||||
select * from ti1 order by b /* must be (2),(3) */;
|
||||
b
|
||||
2
|
||||
3
|
||||
select * from ti1 order by b /* must stays as were on master (1),(2),(3) */;
|
||||
b
|
||||
1
|
||||
2
|
||||
3
|
||||
delete from ti1 where b=3;
|
||||
insert into ti2 set a=3, b=3;
|
||||
select * from ti2 order by b /* must be (1,1),(2,2) - not inserted */;
|
||||
a b
|
||||
1 1
|
||||
2 2
|
||||
set global slave_exec_mode='IDEMPOTENT';
|
||||
set global slave_exec_mode='STRICT';
|
||||
set global slave_exec_mode='IDEMPOTENT,STRICT';
|
||||
ERROR HY000: Ambiguous slave modes combination.
|
||||
select @@global.slave_exec_mode /* must be STRICT */;
|
||||
@@global.slave_exec_mode
|
||||
STRICT
|
||||
*** foreign keys errors as above now forces to stop
|
||||
set foreign_key_checks=0;
|
||||
drop table ti2, ti1;
|
||||
create table ti1 (b int primary key) engine = innodb;
|
||||
create table ti2 (a int primary key, b int, foreign key (b) references ti1(b))
|
||||
engine = innodb;
|
||||
set foreign_key_checks=1 /* ensure the check */;
|
||||
insert into ti1 values (1),(2),(3);
|
||||
insert into ti2 set a=2, b=2;
|
||||
select * from ti1 order by b /* must be (1),(2),(3) */;
|
||||
b
|
||||
1
|
||||
2
|
||||
3
|
||||
*** conspire future problem
|
||||
insert into ti2 set a=1, b=1;
|
||||
select * from ti2 order by b /* must be (1,1) (2,2) */;
|
||||
a b
|
||||
1 1
|
||||
2 2
|
||||
delete from ti1 where b=1 /* offending delete event */;
|
||||
select * from ti1 order by b /* must be (2),(3) */;
|
||||
b
|
||||
2
|
||||
3
|
||||
*** slave must stop (Trying to delete a referenced foreing key)
|
||||
Last_SQL_Error
|
||||
1451
|
||||
select * from ti1 order by b /* must be (1),(2),(3) - not deleted */;
|
||||
b
|
||||
1
|
||||
2
|
||||
3
|
||||
set foreign_key_checks= 0;
|
||||
delete from ti2 where b=1;
|
||||
set foreign_key_checks= 1;
|
||||
set global slave_exec_mode='IDEMPOTENT';
|
||||
start slave sql_thread;
|
||||
set global slave_exec_mode='STRICT';
|
||||
*** conspire the following insert failure
|
||||
*** conspire future problem
|
||||
delete from ti1 where b=3;
|
||||
insert into ti2 set a=3, b=3 /* offending write event */;
|
||||
*** slave must stop (Trying to insert an invalid foreign key)
|
||||
Last_SQL_Error
|
||||
1452
|
||||
select * from ti2 order by b /* must be (2,2) */;
|
||||
a b
|
||||
2 2
|
||||
set foreign_key_checks= 0;
|
||||
insert into ti1 set b=3;
|
||||
set foreign_key_checks= 1;
|
||||
set global slave_exec_mode='IDEMPOTENT';
|
||||
start slave sql_thread;
|
||||
set global slave_exec_mode='STRICT';
|
||||
select * from ti2 order by b /* must be (2,2),(3,3) */;
|
||||
a b
|
||||
2 2
|
||||
3 3
|
||||
*** other errors
|
||||
*** conspiring query
|
||||
insert into ti1 set b=1;
|
||||
insert into ti1 set b=1 /* offending write event */;
|
||||
*** slave must stop (Trying to insert a dupliacte key)
|
||||
Last_SQL_Error
|
||||
1062
|
||||
set foreign_key_checks= 0;
|
||||
delete from ti1 where b=1;
|
||||
set foreign_key_checks= 1;
|
||||
set global slave_exec_mode='IDEMPOTENT';
|
||||
start slave sql_thread;
|
||||
set global slave_exec_mode='STRICT';
|
||||
CREATE TABLE t1 (a INT PRIMARY KEY);
|
||||
CREATE TABLE t2 (a INT);
|
||||
INSERT INTO t1 VALUES (-1),(-2),(-3);
|
||||
INSERT INTO t2 VALUES (-1),(-2),(-3);
|
||||
DELETE FROM t1 WHERE a = -2;
|
||||
DELETE FROM t2 WHERE a = -2;
|
||||
DELETE FROM t1 WHERE a = -2;
|
||||
*** slave must stop (Key was not found)
|
||||
Last_SQL_Error
|
||||
1032
|
||||
set global slave_exec_mode='IDEMPOTENT';
|
||||
start slave sql_thread;
|
||||
set global slave_exec_mode='STRICT';
|
||||
DELETE FROM t2 WHERE a = -2;
|
||||
*** slave must stop (Key was not found)
|
||||
Last_SQL_Error
|
||||
1032
|
||||
set global slave_exec_mode='IDEMPOTENT';
|
||||
start slave sql_thread;
|
||||
set global slave_exec_mode='STRICT';
|
||||
UPDATE t1 SET a = 1 WHERE a = -1;
|
||||
UPDATE t2 SET a = 1 WHERE a = -1;
|
||||
UPDATE t1 SET a = 1 WHERE a = -1;
|
||||
*** slave must stop (Key was not found)
|
||||
Last_SQL_Error
|
||||
1032
|
||||
set global slave_exec_mode='IDEMPOTENT';
|
||||
start slave sql_thread;
|
||||
set global slave_exec_mode='STRICT';
|
||||
UPDATE t2 SET a = 1 WHERE a = -1;
|
||||
*** slave must stop (Key was not found)
|
||||
Last_SQL_Error
|
||||
1032
|
||||
set global slave_exec_mode='IDEMPOTENT';
|
||||
start slave sql_thread;
|
||||
SET @@global.slave_exec_mode= @old_slave_exec_mode;
|
||||
drop table t1,t2,ti2,ti1;
|
||||
set @@global.slave_exec_mode= @old_slave_exec_mode;
|
||||
*** end of tests
|
|
@ -4,8 +4,6 @@ reset master;
|
|||
reset slave;
|
||||
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
|
||||
start slave;
|
||||
set @old_global_binlog_format = @@global.binlog_format;
|
||||
set @@global.binlog_format = row;
|
||||
CREATE SCHEMA IF NOT EXISTS mysqlslap;
|
||||
USE mysqlslap;
|
||||
select @@global.binlog_format;
|
||||
|
@ -59,4 +57,3 @@ a
|
|||
1
|
||||
drop table t1;
|
||||
End of 5.0 tests
|
||||
set @@global.binlog_format = @old_global_binlog_format;
|
||||
|
|
110
mysql-test/suite/rpl/r/rpl_stm_found_rows.result
Normal file
110
mysql-test/suite/rpl/r/rpl_stm_found_rows.result
Normal file
|
@ -0,0 +1,110 @@
|
|||
stop slave;
|
||||
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
|
||||
reset master;
|
||||
reset slave;
|
||||
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
|
||||
start slave;
|
||||
==== Initialize ====
|
||||
**** On Master ****
|
||||
CREATE TABLE t1 (a INT);
|
||||
CREATE TABLE logtbl (sect INT, test INT, count INT);
|
||||
INSERT INTO t1 VALUES (1),(2),(3);
|
||||
INSERT INTO t1 SELECT 2*a+3 FROM t1;
|
||||
INSERT INTO t1 SELECT 2*a+3 FROM t1;
|
||||
INSERT INTO t1 SELECT 2*a+3 FROM t1;
|
||||
INSERT INTO t1 SELECT 2*a+3 FROM t1;
|
||||
INSERT INTO t1 SELECT 2*a+3 FROM t1;
|
||||
INSERT INTO t1 SELECT 2*a+3 FROM t1;
|
||||
==== Simple test ====
|
||||
SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1;
|
||||
a
|
||||
7
|
||||
SELECT FOUND_ROWS() INTO @a;
|
||||
INSERT INTO logtbl VALUES(1,1,@a);
|
||||
SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a < 5 ORDER BY a LIMIT 1;
|
||||
a
|
||||
1
|
||||
SELECT FOUND_ROWS() INTO @a;
|
||||
INSERT INTO logtbl VALUES(1,2,@a);
|
||||
SELECT * FROM logtbl WHERE sect = 1 ORDER BY sect,test;
|
||||
sect test count
|
||||
1 1 183
|
||||
1 2 3
|
||||
**** On Slave ****
|
||||
SELECT * FROM logtbl WHERE sect = 1 ORDER BY sect,test;
|
||||
sect test count
|
||||
1 1 183
|
||||
1 2 3
|
||||
==== Stored procedure ====
|
||||
**** On Master ****
|
||||
CREATE PROCEDURE calc_and_log(sect INT, test INT) BEGIN
|
||||
DECLARE cnt INT;
|
||||
SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a < 5 ORDER BY a LIMIT 1;
|
||||
SELECT FOUND_ROWS() INTO cnt;
|
||||
INSERT INTO logtbl VALUES(sect,test,cnt);
|
||||
SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1;
|
||||
SELECT FOUND_ROWS() INTO cnt;
|
||||
INSERT INTO logtbl VALUES(sect,test+1,cnt);
|
||||
END $$
|
||||
CALL calc_and_log(2,1);
|
||||
a
|
||||
1
|
||||
a
|
||||
7
|
||||
Warnings:
|
||||
Note 1592 Unsafe statement binlogged in statement format since BINLOG_FORMAT = STATEMENT. Reason: Statement uses a LIMIT clause. This is unsafe because the set of rows included cannot be predicted.
|
||||
Note 1592 Unsafe statement binlogged in statement format since BINLOG_FORMAT = STATEMENT. Reason: Statement uses a system function whose value may differ on slave.
|
||||
CREATE PROCEDURE just_log(sect INT, test INT, found_rows INT) BEGIN
|
||||
INSERT INTO logtbl VALUES (sect,test,found_rows);
|
||||
END $$
|
||||
SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1;
|
||||
a
|
||||
7
|
||||
SELECT FOUND_ROWS() INTO @found_rows;
|
||||
CALL just_log(2,3,@found_rows);
|
||||
SELECT * FROM logtbl WHERE sect = 2 ORDER BY sect,test;
|
||||
sect test count
|
||||
2 1 3
|
||||
2 2 183
|
||||
2 3 183
|
||||
**** On Slave ****
|
||||
SELECT * FROM logtbl WHERE sect = 2 ORDER BY sect,test;
|
||||
sect test count
|
||||
2 1 3
|
||||
2 2 183
|
||||
2 3 183
|
||||
==== Stored functions ====
|
||||
**** On Master ****
|
||||
CREATE FUNCTION log_rows(sect INT, test INT, found_rows INT)
|
||||
RETURNS INT
|
||||
BEGIN
|
||||
INSERT INTO logtbl VALUES(sect,test,found_rows);
|
||||
RETURN found_rows;
|
||||
END $$
|
||||
SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1;
|
||||
a
|
||||
7
|
||||
SELECT FOUND_ROWS() INTO @found_rows;
|
||||
SELECT log_rows(3,1,@found_rows), log_rows(3,2,@found_rows);
|
||||
log_rows(3,1,@found_rows) log_rows(3,2,@found_rows)
|
||||
183 183
|
||||
SELECT * FROM logtbl WHERE sect = 3 ORDER BY sect,test;
|
||||
sect test count
|
||||
3 1 183
|
||||
3 2 183
|
||||
**** On Slave ****
|
||||
SELECT * FROM logtbl WHERE sect = 3 ORDER BY sect,test;
|
||||
sect test count
|
||||
3 1 183
|
||||
3 2 183
|
||||
==== Cleanup ====
|
||||
**** On Master ****
|
||||
DROP TABLE t1, logtbl;
|
||||
DROP PROCEDURE just_log;
|
||||
DROP PROCEDURE calc_and_log;
|
||||
DROP FUNCTION log_rows;
|
||||
**** Resetting master and slave ****
|
||||
include/stop_slave.inc
|
||||
RESET SLAVE;
|
||||
RESET MASTER;
|
||||
include/start_slave.inc
|
|
@ -4,8 +4,6 @@ reset master;
|
|||
reset slave;
|
||||
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
|
||||
start slave;
|
||||
set @old_global_binlog_format = @@global.binlog_format;
|
||||
set @@global.binlog_format = statement;
|
||||
CREATE SCHEMA IF NOT EXISTS mysqlslap;
|
||||
USE mysqlslap;
|
||||
select @@global.binlog_format;
|
||||
|
@ -71,70 +69,3 @@ drop table t1;
|
|||
FLUSH LOGS;
|
||||
FLUSH LOGS;
|
||||
End of 5.0 tests
|
||||
set @@global.binlog_format = mixed;
|
||||
CREATE SCHEMA IF NOT EXISTS mysqlslap;
|
||||
USE mysqlslap;
|
||||
select @@global.binlog_format;
|
||||
@@global.binlog_format
|
||||
MIXED
|
||||
CREATE TABLE t1 (id INT primary key auto_increment, name VARCHAR(64));
|
||||
FLUSH TABLE t1;
|
||||
SELECT COUNT(*) FROM t1;
|
||||
COUNT(*)
|
||||
5000
|
||||
use mysqlslap;
|
||||
SELECT COUNT(*) FROM t1;
|
||||
COUNT(*)
|
||||
5000
|
||||
truncate table t1;
|
||||
insert delayed into t1 values(10, "my name");
|
||||
insert delayed into t1 values(10, "is Bond"), (20, "James Bond");
|
||||
flush table t1;
|
||||
select * from t1;
|
||||
id name
|
||||
10 my name
|
||||
20 James Bond
|
||||
select * from t1;
|
||||
id name
|
||||
10 my name
|
||||
20 James Bond
|
||||
delete from t1 where id!=10;
|
||||
insert delayed into t1 values(20, "is Bond"), (10, "James Bond");
|
||||
flush table t1;
|
||||
select * from t1;
|
||||
id name
|
||||
10 my name
|
||||
20 is Bond
|
||||
select * from t1;
|
||||
id name
|
||||
10 my name
|
||||
20 is Bond
|
||||
USE test;
|
||||
DROP SCHEMA mysqlslap;
|
||||
use test;
|
||||
FLUSH LOGS;
|
||||
FLUSH LOGS;
|
||||
CREATE TABLE t1(a int, UNIQUE(a));
|
||||
INSERT DELAYED IGNORE INTO t1 VALUES(1);
|
||||
INSERT DELAYED IGNORE INTO t1 VALUES(1);
|
||||
flush table t1;
|
||||
show binlog events in 'master-bin.000002' LIMIT 2,2;
|
||||
Log_name Pos Event_type Server_id End_log_pos Info
|
||||
x x x x x use `test`; INSERT DELAYED IGNORE INTO t1 VALUES(1)
|
||||
x x x x x use `test`; INSERT DELAYED IGNORE INTO t1 VALUES(1)
|
||||
select * from t1;
|
||||
a
|
||||
1
|
||||
On slave
|
||||
show binlog events in 'slave-bin.000002' LIMIT 2,2;
|
||||
Log_name Pos Event_type Server_id End_log_pos Info
|
||||
x x x x x use `test`; INSERT DELAYED IGNORE INTO t1 VALUES(1)
|
||||
x x x x x use `test`; INSERT DELAYED IGNORE INTO t1 VALUES(1)
|
||||
select * from t1;
|
||||
a
|
||||
1
|
||||
drop table t1;
|
||||
FLUSH LOGS;
|
||||
FLUSH LOGS;
|
||||
End of 5.0 tests
|
||||
set @@global.binlog_format = @old_global_binlog_format;
|
||||
|
|
|
@ -10,7 +10,7 @@ CREATE TABLE test.t1 (a INT, blob_column LONGBLOB, PRIMARY KEY(a));
|
|||
INSERT INTO test.t1 VALUES(1,'test');
|
||||
UPDATE test.t1 SET blob_column=LOAD_FILE('../../std_data/words2.dat') WHERE a=1;
|
||||
Warnings:
|
||||
Note 1592 Statement may not be safe to log in statement format.
|
||||
Note 1592 Unsafe statement binlogged in statement format since BINLOG_FORMAT = STATEMENT. Reason: Statement uses a system function whose value may differ on slave.
|
||||
create procedure test.p1()
|
||||
begin
|
||||
INSERT INTO test.t1 VALUES(2,'test');
|
||||
|
@ -18,7 +18,7 @@ UPDATE test.t1 SET blob_column=LOAD_FILE('../../std_data/words2.dat') WHERE a=2;
|
|||
end|
|
||||
CALL test.p1();
|
||||
Warnings:
|
||||
Note 1592 Statement may not be safe to log in statement format.
|
||||
Note 1592 Unsafe statement binlogged in statement format since BINLOG_FORMAT = STATEMENT. Reason: Statement uses a system function whose value may differ on slave.
|
||||
SELECT * FROM test.t1 ORDER BY blob_column;
|
||||
a blob_column
|
||||
1 abase
|
||||
|
|
|
@ -6,7 +6,6 @@ drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
|
|||
start slave;
|
||||
call mtr.add_suppression("Deadlock found");
|
||||
**** On Master ****
|
||||
SET SESSION BINLOG_FORMAT=ROW;
|
||||
CREATE TABLE t1 (a INT PRIMARY KEY, b INT);
|
||||
INSERT INTO t1 VALUES (1,1), (2,2), (3,3), (4,4);
|
||||
**** On Slave ****
|
||||
|
|
|
@ -4,7 +4,6 @@ reset master;
|
|||
reset slave;
|
||||
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
|
||||
start slave;
|
||||
set binlog_format=row;
|
||||
drop table if exists t1;
|
||||
"*** Test 1) Test UDFs via loadable libraries ***
|
||||
"Running on the master"
|
||||
|
@ -156,163 +155,3 @@ affected rows: 0
|
|||
"Running on the master"
|
||||
DROP TABLE t1;
|
||||
affected rows: 0
|
||||
set binlog_format=statement;
|
||||
drop table if exists t1;
|
||||
"*** Test 1) Test UDFs via loadable libraries ***
|
||||
"Running on the master"
|
||||
CREATE FUNCTION myfunc_double RETURNS REAL SONAME "UDF_EXAMPLE_LIB";
|
||||
affected rows: 0
|
||||
CREATE FUNCTION myfunc_int RETURNS INTEGER SONAME "UDF_EXAMPLE_LIB";
|
||||
affected rows: 0
|
||||
CREATE FUNCTION myfunc_nonexist RETURNS INTEGER SONAME "UDF_EXAMPLE_LIB";
|
||||
ERROR HY000: Can't find symbol 'myfunc_nonexist' in library
|
||||
SELECT * FROM mysql.func ORDER BY name;
|
||||
name ret dl type
|
||||
myfunc_double 1 UDF_LIB function
|
||||
myfunc_int 2 UDF_LIB function
|
||||
affected rows: 2
|
||||
"Running on the slave"
|
||||
SELECT * FROM mysql.func ORDER BY name;
|
||||
name ret dl type
|
||||
myfunc_double 1 UDF_LIB function
|
||||
myfunc_int 2 UDF_LIB function
|
||||
affected rows: 2
|
||||
"Running on the master"
|
||||
CREATE TABLE t1(sum INT, price FLOAT(24)) ENGINE=MyISAM;
|
||||
affected rows: 0
|
||||
INSERT INTO t1 VALUES(myfunc_int(100), myfunc_double(50.00));
|
||||
Warnings:
|
||||
Note 1592 Statement may not be safe to log in statement format.
|
||||
affected rows: 1
|
||||
INSERT INTO t1 VALUES(myfunc_int(10), myfunc_double(5.00));
|
||||
Warnings:
|
||||
Note 1592 Statement may not be safe to log in statement format.
|
||||
affected rows: 1
|
||||
INSERT INTO t1 VALUES(myfunc_int(200), myfunc_double(25.00));
|
||||
Warnings:
|
||||
Note 1592 Statement may not be safe to log in statement format.
|
||||
affected rows: 1
|
||||
INSERT INTO t1 VALUES(myfunc_int(1), myfunc_double(500.00));
|
||||
Warnings:
|
||||
Note 1592 Statement may not be safe to log in statement format.
|
||||
affected rows: 1
|
||||
SELECT * FROM t1 ORDER BY sum;
|
||||
sum price
|
||||
1 48.5
|
||||
10 48.75
|
||||
100 48.6
|
||||
200 49
|
||||
affected rows: 4
|
||||
"Running on the slave"
|
||||
SELECT * FROM t1 ORDER BY sum;
|
||||
sum price
|
||||
1 48.5
|
||||
10 48.75
|
||||
100 48.6
|
||||
200 49
|
||||
affected rows: 4
|
||||
SELECT myfunc_int(25);
|
||||
myfunc_int(25)
|
||||
25
|
||||
affected rows: 1
|
||||
SELECT myfunc_double(75.00);
|
||||
myfunc_double(75.00)
|
||||
50.00
|
||||
affected rows: 1
|
||||
"Running on the master"
|
||||
DROP FUNCTION myfunc_double;
|
||||
affected rows: 0
|
||||
DROP FUNCTION myfunc_int;
|
||||
affected rows: 0
|
||||
SELECT * FROM mysql.func ORDER BY name;
|
||||
name ret dl type
|
||||
affected rows: 0
|
||||
"Running on the slave"
|
||||
SELECT * FROM mysql.func ORDER BY name;
|
||||
name ret dl type
|
||||
affected rows: 0
|
||||
"Running on the master"
|
||||
DROP TABLE t1;
|
||||
affected rows: 0
|
||||
"*** Test 2) Test UDFs with SQL body ***
|
||||
"Running on the master"
|
||||
CREATE FUNCTION myfuncsql_int(i INT) RETURNS INTEGER DETERMINISTIC RETURN i;
|
||||
affected rows: 0
|
||||
CREATE FUNCTION myfuncsql_double(d DOUBLE) RETURNS INTEGER DETERMINISTIC RETURN d * 2.00;
|
||||
affected rows: 0
|
||||
SELECT db, name, type, param_list, body, comment FROM mysql.proc WHERE db = 'test' AND name LIKE 'myfuncsql%' ORDER BY name;
|
||||
db name type param_list body comment
|
||||
test myfuncsql_double FUNCTION d DOUBLE RETURN d * 2.00
|
||||
test myfuncsql_int FUNCTION i INT RETURN i
|
||||
affected rows: 2
|
||||
"Running on the slave"
|
||||
SELECT db, name, type, param_list, body, comment FROM mysql.proc WHERE db = 'test' AND name LIKE 'myfuncsql%' ORDER BY name;
|
||||
db name type param_list body comment
|
||||
test myfuncsql_double FUNCTION d DOUBLE RETURN d * 2.00
|
||||
test myfuncsql_int FUNCTION i INT RETURN i
|
||||
affected rows: 2
|
||||
"Running on the master"
|
||||
CREATE TABLE t1(sum INT, price FLOAT(24)) ENGINE=MyISAM;
|
||||
affected rows: 0
|
||||
INSERT INTO t1 VALUES(myfuncsql_int(100), myfuncsql_double(50.00));
|
||||
affected rows: 1
|
||||
INSERT INTO t1 VALUES(myfuncsql_int(10), myfuncsql_double(5.00));
|
||||
affected rows: 1
|
||||
INSERT INTO t1 VALUES(myfuncsql_int(200), myfuncsql_double(25.00));
|
||||
affected rows: 1
|
||||
INSERT INTO t1 VALUES(myfuncsql_int(1), myfuncsql_double(500.00));
|
||||
affected rows: 1
|
||||
SELECT * FROM t1 ORDER BY sum;
|
||||
sum price
|
||||
1 1000
|
||||
10 10
|
||||
100 100
|
||||
200 50
|
||||
affected rows: 4
|
||||
"Running on the slave"
|
||||
SELECT * FROM t1 ORDER BY sum;
|
||||
sum price
|
||||
1 1000
|
||||
10 10
|
||||
100 100
|
||||
200 50
|
||||
affected rows: 4
|
||||
"Running on the master"
|
||||
ALTER FUNCTION myfuncsql_int COMMENT "This was altered.";
|
||||
affected rows: 0
|
||||
ALTER FUNCTION myfuncsql_double COMMENT "This was altered.";
|
||||
affected rows: 0
|
||||
SELECT db, name, type, param_list, body, comment FROM mysql.proc WHERE db = 'test' AND name LIKE 'myfuncsql%' ORDER BY name;
|
||||
db name type param_list body comment
|
||||
test myfuncsql_double FUNCTION d DOUBLE RETURN d * 2.00 This was altered.
|
||||
test myfuncsql_int FUNCTION i INT RETURN i This was altered.
|
||||
affected rows: 2
|
||||
"Running on the slave"
|
||||
SELECT db, name, type, param_list, body, comment FROM mysql.proc WHERE db = 'test' AND name LIKE 'myfuncsql%' ORDER BY name;
|
||||
db name type param_list body comment
|
||||
test myfuncsql_double FUNCTION d DOUBLE RETURN d * 2.00 This was altered.
|
||||
test myfuncsql_int FUNCTION i INT RETURN i This was altered.
|
||||
affected rows: 2
|
||||
SELECT myfuncsql_int(25);
|
||||
myfuncsql_int(25)
|
||||
25
|
||||
affected rows: 1
|
||||
SELECT myfuncsql_double(75.00);
|
||||
myfuncsql_double(75.00)
|
||||
150
|
||||
affected rows: 1
|
||||
"Running on the master"
|
||||
DROP FUNCTION myfuncsql_double;
|
||||
affected rows: 0
|
||||
DROP FUNCTION myfuncsql_int;
|
||||
affected rows: 0
|
||||
SELECT db, name, type, param_list, body, comment FROM mysql.proc WHERE db = 'test' AND name LIKE 'myfuncsql%' ORDER BY name;
|
||||
db name type param_list body comment
|
||||
affected rows: 0
|
||||
"Running on the slave"
|
||||
SELECT db, name, type, param_list, body, comment FROM mysql.proc WHERE db = 'test' AND name LIKE 'myfuncsql%' ORDER BY name;
|
||||
db name type param_list body comment
|
||||
affected rows: 0
|
||||
"Running on the master"
|
||||
DROP TABLE t1;
|
||||
affected rows: 0
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
source include/have_binlog_format_mixed_or_row.inc;
|
||||
source include/master-slave.inc;
|
||||
|
||||
CREATE DATABASE track;
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
##################################################################
|
||||
# Author: Giuseppe #
|
||||
# Date: 2006-12-20 #
|
||||
# Purpose: To test that event effects are replicated #
|
||||
# in both row based and statement based format #
|
||||
# Purpose: To test that event effects are replicated. #
|
||||
##################################################################
|
||||
|
||||
--source include/not_embedded.inc
|
||||
--source include/master-slave.inc
|
||||
|
||||
SET @old_event_scheduler = @@global.event_scheduler;
|
||||
|
@ -13,14 +11,6 @@ set global event_scheduler=1;
|
|||
|
||||
let $engine_type= MyISAM;
|
||||
|
||||
set binlog_format=row;
|
||||
|
||||
# Embedded server doesn't support binlogging
|
||||
--source include/rpl_events.inc
|
||||
|
||||
set binlog_format=statement;
|
||||
|
||||
# Embedded server doesn't support binlogging
|
||||
--source include/rpl_events.inc
|
||||
|
||||
#
|
||||
|
|
|
@ -1,16 +1,9 @@
|
|||
#############################################################
|
||||
# Purpose: To test having extra columns on the master WL#3915
|
||||
#############################################################
|
||||
-- source include/have_binlog_format_row.inc
|
||||
-- source include/master-slave.inc
|
||||
-- source include/have_innodb.inc
|
||||
|
||||
let $engine_type = 'InnoDB';
|
||||
|
||||
set binlog_format=row;
|
||||
-- source extra/rpl_tests/rpl_extraMaster_Col.test
|
||||
|
||||
set binlog_format=statement;
|
||||
-- source extra/rpl_tests/rpl_extraMaster_Col.test
|
||||
|
||||
set binlog_format=mixed;
|
||||
-- source extra/rpl_tests/rpl_extraMaster_Col.test
|
||||
--source extra/rpl_tests/rpl_extraMaster_Col.test
|
||||
|
|
|
@ -1,15 +1,8 @@
|
|||
#############################################################
|
||||
# Purpose: To test having extra columns on the master WL#3915
|
||||
#############################################################
|
||||
-- source include/have_binlog_format_row.inc
|
||||
-- source include/master-slave.inc
|
||||
|
||||
let $engine_type = 'MyISAM';
|
||||
|
||||
set binlog_format=row;
|
||||
-- source extra/rpl_tests/rpl_extraMaster_Col.test
|
||||
|
||||
set binlog_format=statement;
|
||||
-- source extra/rpl_tests/rpl_extraMaster_Col.test
|
||||
|
||||
set binlog_format=mixed;
|
||||
-- source extra/rpl_tests/rpl_extraMaster_Col.test
|
||||
--source extra/rpl_tests/rpl_extraMaster_Col.test
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
--slave-exec-mode=IDEMPOTENT
|
|
@ -2,17 +2,11 @@
|
|||
# work the same way under statement based as under row based.
|
||||
|
||||
source include/master-slave.inc;
|
||||
connection master;
|
||||
source include/have_innodb.inc;
|
||||
connection slave;
|
||||
source include/have_innodb.inc;
|
||||
|
||||
# Add suppression for expected warning(s) in slaves error log
|
||||
call mtr.add_suppression("Slave: Can\'t find record in \'t1\' Error_code: 1032");
|
||||
call mtr.add_suppression("Slave: Cannot add or update a child row: a foreign key constraint fails .* Error_code: 1452");
|
||||
|
||||
SET @old_slave_exec_mode= @@global.slave_exec_mode;
|
||||
|
||||
connection master;
|
||||
CREATE TABLE t1 (a INT PRIMARY KEY);
|
||||
CREATE TABLE t2 (a INT);
|
||||
|
@ -20,6 +14,9 @@ INSERT INTO t1 VALUES (-1),(-2),(-3);
|
|||
INSERT INTO t2 VALUES (-1),(-2),(-3);
|
||||
sync_slave_with_master;
|
||||
|
||||
SET @old_slave_exec_mode= @@global.slave_exec_mode;
|
||||
SET @@global.slave_exec_mode= IDEMPOTENT;
|
||||
|
||||
# A delete for a row that does not exist, the statement is
|
||||
# deliberately written to be idempotent for statement-based
|
||||
# replication as well. We test this towards both a table with a
|
||||
|
@ -57,6 +54,7 @@ disable_query_log;
|
|||
eval SELECT "$last_error" AS Last_SQL_Error;
|
||||
enable_query_log;
|
||||
|
||||
|
||||
# BUG#19958: RBR idempotency issue for UPDATE and DELETE
|
||||
|
||||
# Statement-based and row-based replication have different behaviour
|
||||
|
@ -88,316 +86,4 @@ connection master;
|
|||
DROP TABLE t1, t2;
|
||||
sync_slave_with_master;
|
||||
|
||||
# bug#31609 Not all RBR slave errors reported as errors
|
||||
# bug#31552 Replication breaks when deleting rows from out-of-sync table
|
||||
# without PK
|
||||
|
||||
#
|
||||
# Idempotent applying is not default any longer.
|
||||
# The default for slave-exec-mode option and server
|
||||
# variable slave_exec_mode is 'STRICT'.
|
||||
# When 'STRICT' mode is set, the slave SQL thread will stop whenever
|
||||
# the row to change is not found. In 'IDEMPOTENT' mode, the SQL thread
|
||||
# will continue running and apply the row - replace if it's Write_rows event -
|
||||
# or skip to the next event.
|
||||
|
||||
# the previous part of the tests was with IDEMPOTENT slave's mode.
|
||||
|
||||
|
||||
#
|
||||
# Other than above idempotent errors dealing with foreign keys constraint
|
||||
#
|
||||
|
||||
select @@global.slave_exec_mode /* must be IDEMPOTENT */;
|
||||
|
||||
connection master;
|
||||
|
||||
create table ti1 (b int primary key) engine = innodb;
|
||||
create table ti2 (a int primary key, b int, foreign key (b) references ti1(b))
|
||||
engine = innodb;
|
||||
set foreign_key_checks=1 /* ensure the check */;
|
||||
|
||||
insert into ti1 values (1),(2),(3);
|
||||
insert into ti2 set a=2, b=2;
|
||||
|
||||
sync_slave_with_master;
|
||||
|
||||
#connection slave;
|
||||
select * from ti1 order by b /* must be (1),(2),(3) */;
|
||||
insert into ti2 set a=1, b=1;
|
||||
select * from ti2 order by b /* must be (1,1) (2,2) */;
|
||||
|
||||
connection master;
|
||||
|
||||
# from now on checking rbr specific idempotent errors
|
||||
set @save_binlog_format= @@session.binlog_format;
|
||||
set @@session.binlog_format= row;
|
||||
delete from ti1 where b=1;
|
||||
|
||||
select * from ti1 order by b /* must be (2),(3) */;
|
||||
|
||||
# slave must catch up (expect some warnings in error.log)
|
||||
sync_slave_with_master;
|
||||
|
||||
#connection slave;
|
||||
select * from ti1 order by b /* must stays as were on master (1),(2),(3) */;
|
||||
|
||||
delete from ti1 where b=3;
|
||||
|
||||
connection master;
|
||||
insert into ti2 set a=3, b=3;
|
||||
|
||||
# slave must catch up (expect some warnings in error.log)
|
||||
sync_slave_with_master;
|
||||
|
||||
#connection slave;
|
||||
select * from ti2 order by b /* must be (1,1),(2,2) - not inserted */;
|
||||
|
||||
|
||||
#
|
||||
# Checking the new global sys variable
|
||||
#
|
||||
|
||||
connection slave;
|
||||
|
||||
set global slave_exec_mode='IDEMPOTENT';
|
||||
set global slave_exec_mode='STRICT';
|
||||
|
||||
# checking mutual exclusion for the options
|
||||
--error ER_SLAVE_AMBIGOUS_EXEC_MODE
|
||||
set global slave_exec_mode='IDEMPOTENT,STRICT';
|
||||
|
||||
select @@global.slave_exec_mode /* must be STRICT */;
|
||||
|
||||
#
|
||||
# Checking stops.
|
||||
# In the following sections strict slave sql thread is going to
|
||||
# stop when faces an idempotent error. In order to proceed
|
||||
# the mode is temporarily switched to indempotent.
|
||||
#
|
||||
|
||||
#
|
||||
--echo *** foreign keys errors as above now forces to stop
|
||||
#
|
||||
|
||||
connection master;
|
||||
|
||||
set foreign_key_checks=0;
|
||||
drop table ti2, ti1;
|
||||
|
||||
create table ti1 (b int primary key) engine = innodb;
|
||||
create table ti2 (a int primary key, b int, foreign key (b) references ti1(b))
|
||||
engine = innodb;
|
||||
set foreign_key_checks=1 /* ensure the check */;
|
||||
|
||||
insert into ti1 values (1),(2),(3);
|
||||
insert into ti2 set a=2, b=2;
|
||||
|
||||
sync_slave_with_master;
|
||||
|
||||
#connection slave;
|
||||
select * from ti1 order by b /* must be (1),(2),(3) */;
|
||||
--echo *** conspire future problem
|
||||
insert into ti2 set a=1, b=1;
|
||||
select * from ti2 order by b /* must be (1,1) (2,2) */;
|
||||
|
||||
connection master;
|
||||
|
||||
delete from ti1 where b=1 /* offending delete event */;
|
||||
select * from ti1 order by b /* must be (2),(3) */;
|
||||
|
||||
# foreign key: row is referenced
|
||||
|
||||
--echo *** slave must stop (Trying to delete a referenced foreing key)
|
||||
connection slave;
|
||||
source include/wait_for_slave_sql_to_stop.inc;
|
||||
|
||||
let $last_error = query_get_value("SHOW SLAVE STATUS", Last_SQL_Errno, 1);
|
||||
disable_query_log;
|
||||
eval SELECT "$last_error" AS Last_SQL_Error;
|
||||
enable_query_log;
|
||||
|
||||
select * from ti1 order by b /* must be (1),(2),(3) - not deleted */;
|
||||
set foreign_key_checks= 0;
|
||||
delete from ti2 where b=1;
|
||||
set foreign_key_checks= 1;
|
||||
set global slave_exec_mode='IDEMPOTENT';
|
||||
start slave sql_thread;
|
||||
connection master;
|
||||
sync_slave_with_master;
|
||||
#connection slave;
|
||||
set global slave_exec_mode='STRICT';
|
||||
|
||||
connection master;
|
||||
|
||||
sync_slave_with_master;
|
||||
|
||||
#connection slave;
|
||||
--echo *** conspire the following insert failure
|
||||
# foreign key: no referenced row
|
||||
|
||||
--echo *** conspire future problem
|
||||
delete from ti1 where b=3;
|
||||
|
||||
connection master;
|
||||
insert into ti2 set a=3, b=3 /* offending write event */;
|
||||
|
||||
--echo *** slave must stop (Trying to insert an invalid foreign key)
|
||||
connection slave;
|
||||
source include/wait_for_slave_sql_to_stop.inc;
|
||||
|
||||
let $last_error = query_get_value("SHOW SLAVE STATUS", Last_SQL_Errno, 1);
|
||||
disable_query_log;
|
||||
eval SELECT "$last_error" AS Last_SQL_Error;
|
||||
enable_query_log;
|
||||
|
||||
select * from ti2 order by b /* must be (2,2) */;
|
||||
set foreign_key_checks= 0;
|
||||
insert into ti1 set b=3;
|
||||
set foreign_key_checks= 1;
|
||||
set global slave_exec_mode='IDEMPOTENT';
|
||||
start slave sql_thread;
|
||||
connection master;
|
||||
sync_slave_with_master;
|
||||
#connection slave;
|
||||
set global slave_exec_mode='STRICT';
|
||||
|
||||
connection master;
|
||||
|
||||
sync_slave_with_master;
|
||||
|
||||
select * from ti2 order by b /* must be (2,2),(3,3) */;
|
||||
|
||||
#
|
||||
--echo *** other errors
|
||||
#
|
||||
|
||||
# dup key insert
|
||||
|
||||
#connection slave;
|
||||
--echo *** conspiring query
|
||||
insert into ti1 set b=1;
|
||||
|
||||
connection master;
|
||||
insert into ti1 set b=1 /* offending write event */;
|
||||
|
||||
--echo *** slave must stop (Trying to insert a dupliacte key)
|
||||
connection slave;
|
||||
source include/wait_for_slave_sql_to_stop.inc;
|
||||
|
||||
let $last_error = query_get_value("SHOW SLAVE STATUS", Last_SQL_Errno, 1);
|
||||
disable_query_log;
|
||||
eval SELECT "$last_error" AS Last_SQL_Error;
|
||||
enable_query_log;
|
||||
|
||||
set foreign_key_checks= 0;
|
||||
delete from ti1 where b=1;
|
||||
set foreign_key_checks= 1;
|
||||
set global slave_exec_mode='IDEMPOTENT';
|
||||
start slave sql_thread;
|
||||
connection master;
|
||||
sync_slave_with_master;
|
||||
#connection slave;
|
||||
set global slave_exec_mode='STRICT';
|
||||
|
||||
# key not found
|
||||
|
||||
connection master;
|
||||
|
||||
CREATE TABLE t1 (a INT PRIMARY KEY);
|
||||
CREATE TABLE t2 (a INT);
|
||||
INSERT INTO t1 VALUES (-1),(-2),(-3);
|
||||
INSERT INTO t2 VALUES (-1),(-2),(-3);
|
||||
sync_slave_with_master;
|
||||
|
||||
#connection slave;
|
||||
DELETE FROM t1 WHERE a = -2;
|
||||
DELETE FROM t2 WHERE a = -2;
|
||||
connection master;
|
||||
DELETE FROM t1 WHERE a = -2;
|
||||
|
||||
--echo *** slave must stop (Key was not found)
|
||||
connection slave;
|
||||
source include/wait_for_slave_sql_to_stop.inc;
|
||||
|
||||
let $last_error = query_get_value("SHOW SLAVE STATUS", Last_SQL_Errno, 1);
|
||||
disable_query_log;
|
||||
eval SELECT "$last_error" AS Last_SQL_Error;
|
||||
enable_query_log;
|
||||
|
||||
set global slave_exec_mode='IDEMPOTENT';
|
||||
start slave sql_thread;
|
||||
connection master;
|
||||
sync_slave_with_master;
|
||||
#connection slave;
|
||||
set global slave_exec_mode='STRICT';
|
||||
|
||||
connection master;
|
||||
DELETE FROM t2 WHERE a = -2;
|
||||
--echo *** slave must stop (Key was not found)
|
||||
connection slave;
|
||||
source include/wait_for_slave_sql_to_stop.inc;
|
||||
|
||||
let $last_error = query_get_value("SHOW SLAVE STATUS", Last_SQL_Errno, 1);
|
||||
disable_query_log;
|
||||
eval SELECT "$last_error" AS Last_SQL_Error;
|
||||
enable_query_log;
|
||||
|
||||
set global slave_exec_mode='IDEMPOTENT';
|
||||
start slave sql_thread;
|
||||
connection master;
|
||||
sync_slave_with_master;
|
||||
#connection slave;
|
||||
set global slave_exec_mode='STRICT';
|
||||
|
||||
UPDATE t1 SET a = 1 WHERE a = -1;
|
||||
UPDATE t2 SET a = 1 WHERE a = -1;
|
||||
|
||||
connection master;
|
||||
UPDATE t1 SET a = 1 WHERE a = -1;
|
||||
|
||||
--echo *** slave must stop (Key was not found)
|
||||
connection slave;
|
||||
source include/wait_for_slave_sql_to_stop.inc;
|
||||
|
||||
let $last_error = query_get_value("SHOW SLAVE STATUS", Last_SQL_Errno, 1);
|
||||
disable_query_log;
|
||||
eval SELECT "$last_error" AS Last_SQL_Error;
|
||||
enable_query_log;
|
||||
|
||||
set global slave_exec_mode='IDEMPOTENT';
|
||||
start slave sql_thread;
|
||||
connection master;
|
||||
sync_slave_with_master;
|
||||
#connection slave;
|
||||
set global slave_exec_mode='STRICT';
|
||||
|
||||
|
||||
connection master;
|
||||
UPDATE t2 SET a = 1 WHERE a = -1;
|
||||
|
||||
--echo *** slave must stop (Key was not found)
|
||||
connection slave;
|
||||
source include/wait_for_slave_sql_to_stop.inc;
|
||||
|
||||
let $last_error = query_get_value("SHOW SLAVE STATUS", Last_SQL_Errno, 1);
|
||||
disable_query_log;
|
||||
eval SELECT "$last_error" AS Last_SQL_Error;
|
||||
enable_query_log;
|
||||
|
||||
set global slave_exec_mode='IDEMPOTENT';
|
||||
start slave sql_thread;
|
||||
connection master;
|
||||
sync_slave_with_master;
|
||||
#connection slave;
|
||||
SET @@global.slave_exec_mode= @old_slave_exec_mode;
|
||||
|
||||
# cleanup for bug#31609 tests
|
||||
|
||||
connection master;
|
||||
set @@session.binlog_format= @save_binlog_format;
|
||||
drop table t1,t2,ti2,ti1;
|
||||
|
||||
--source include/master-slave-end.inc
|
||||
|
||||
--echo *** end of tests
|
||||
|
|
|
@ -1,16 +1,15 @@
|
|||
source include/master-slave.inc;
|
||||
source include/have_binlog_format_mixed.inc;
|
||||
|
||||
# It is not possible to replicate FOUND_ROWS() using statement-based
|
||||
# replication, but there is a workaround that stores the result of
|
||||
# FOUND_ROWS() into a user variable and then replicates this instead.
|
||||
#
|
||||
# The purpose of this test case is to test that the workaround works
|
||||
# properly even when inside stored programs (i.e., stored routines and
|
||||
# triggers).
|
||||
|
||||
# The purpose of this test case is to test that the workaround
|
||||
# function properly even when inside stored programs (i.e., stored
|
||||
# routines and triggers).
|
||||
|
||||
--echo ==== 0. Setting it all up ====
|
||||
|
||||
SET BINLOG_FORMAT=STATEMENT;
|
||||
--echo ==== Initialize ====
|
||||
|
||||
--echo **** On Master ****
|
||||
connection master;
|
||||
|
@ -25,106 +24,10 @@ INSERT INTO t1 SELECT 2*a+3 FROM t1;
|
|||
INSERT INTO t1 SELECT 2*a+3 FROM t1;
|
||||
INSERT INTO t1 SELECT 2*a+3 FROM t1;
|
||||
|
||||
--echo #### 1. Using statement mode ####
|
||||
|
||||
--echo ==== 1.1. Simple test ====
|
||||
|
||||
SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1;
|
||||
|
||||
# Instead of
|
||||
# INSERT INTO logtbl VALUES(1, 1, FOUND_ROWS());
|
||||
# we write
|
||||
SELECT FOUND_ROWS() INTO @a;
|
||||
INSERT INTO logtbl VALUES(1,1,@a);
|
||||
|
||||
SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a < 5 ORDER BY a LIMIT 1;
|
||||
# Instead of
|
||||
# INSERT INTO logtbl VALUES(1, 2, FOUND_ROWS());
|
||||
# we write
|
||||
SELECT FOUND_ROWS() INTO @a;
|
||||
INSERT INTO logtbl VALUES(1,2,@a);
|
||||
|
||||
SELECT * FROM logtbl WHERE sect = 1 ORDER BY sect,test;
|
||||
--echo **** On Slave ****
|
||||
sync_slave_with_master;
|
||||
SELECT * FROM logtbl WHERE sect = 1 ORDER BY sect,test;
|
||||
|
||||
--echo ==== 1.2. Stored procedure ====
|
||||
|
||||
# Here we do both the calculation and the logging. We also do it twice
|
||||
# to make sure that there are no limitations on how many times it can
|
||||
# be used.
|
||||
--echo ==== Checking a procedure ====
|
||||
|
||||
--echo **** On Master ****
|
||||
connection master;
|
||||
--delimiter $$
|
||||
CREATE PROCEDURE calc_and_log(sect INT, test INT) BEGIN
|
||||
DECLARE cnt INT;
|
||||
SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a < 5 ORDER BY a LIMIT 1;
|
||||
SELECT FOUND_ROWS() INTO cnt;
|
||||
INSERT INTO logtbl VALUES(sect,test,cnt);
|
||||
SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1;
|
||||
SELECT FOUND_ROWS() INTO cnt;
|
||||
INSERT INTO logtbl VALUES(sect,test+1,cnt);
|
||||
END $$
|
||||
--delimiter ;
|
||||
|
||||
CALL calc_and_log(2,1);
|
||||
|
||||
--delimiter $$
|
||||
CREATE PROCEDURE just_log(sect INT, test INT, found_rows INT) BEGIN
|
||||
INSERT INTO logtbl VALUES (sect,test,found_rows);
|
||||
END $$
|
||||
--delimiter ;
|
||||
|
||||
SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1;
|
||||
SELECT FOUND_ROWS() INTO @found_rows;
|
||||
CALL just_log(2,3,@found_rows);
|
||||
|
||||
SELECT * FROM logtbl WHERE sect = 2 ORDER BY sect,test;
|
||||
--echo **** On Slave ****
|
||||
sync_slave_with_master;
|
||||
SELECT * FROM logtbl WHERE sect = 2 ORDER BY sect,test;
|
||||
|
||||
--echo ==== 1.3. Stored functions ====
|
||||
--echo **** On Master ****
|
||||
connection master;
|
||||
--delimiter $$
|
||||
CREATE FUNCTION log_rows(sect INT, test INT, found_rows INT)
|
||||
RETURNS INT
|
||||
BEGIN
|
||||
INSERT INTO logtbl VALUES(sect,test,found_rows);
|
||||
RETURN found_rows;
|
||||
END $$
|
||||
--delimiter ;
|
||||
|
||||
SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1;
|
||||
SELECT FOUND_ROWS() INTO @found_rows;
|
||||
SELECT log_rows(3,1,@found_rows), log_rows(3,2,@found_rows);
|
||||
|
||||
SELECT * FROM logtbl WHERE sect = 3 ORDER BY sect,test;
|
||||
--echo **** On Slave ****
|
||||
sync_slave_with_master;
|
||||
SELECT * FROM logtbl WHERE sect = 3 ORDER BY sect,test;
|
||||
|
||||
--echo ==== 1.9. Cleanup ====
|
||||
--echo **** On Master ****
|
||||
connection master;
|
||||
DELETE FROM logtbl;
|
||||
DROP PROCEDURE just_log;
|
||||
DROP PROCEDURE calc_and_log;
|
||||
DROP FUNCTION log_rows;
|
||||
sync_slave_with_master;
|
||||
|
||||
source include/reset_master_and_slave.inc;
|
||||
|
||||
--echo #### 2. Using mixed mode ####
|
||||
|
||||
--echo ==== 2.1. Checking a procedure ====
|
||||
|
||||
--echo **** On Master ****
|
||||
connection master;
|
||||
SET BINLOG_FORMAT=MIXED;
|
||||
|
||||
# We will now check some stuff that will not work in statement-based
|
||||
# replication, but which should cause the binary log to switch to
|
||||
|
@ -139,7 +42,6 @@ sync_slave_with_master;
|
|||
|
||||
--echo **** On Master 1 ****
|
||||
connection master1;
|
||||
SET BINLOG_FORMAT=MIXED;
|
||||
SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1;
|
||||
CALL just_log(1,1);
|
||||
|
||||
|
@ -167,7 +69,7 @@ SELECT * FROM logtbl WHERE sect = 1 ORDER BY sect,test;
|
|||
sync_slave_with_master;
|
||||
SELECT * FROM logtbl WHERE sect = 1 ORDER BY sect,test;
|
||||
|
||||
--echo ==== 2.1. Checking a stored function ====
|
||||
--echo ==== Checking a stored function ====
|
||||
--echo **** On Master ****
|
||||
connection master;
|
||||
--delimiter $$
|
5
mysql-test/suite/rpl/t/rpl_mix_insert_delayed.test
Normal file
5
mysql-test/suite/rpl/t/rpl_mix_insert_delayed.test
Normal file
|
@ -0,0 +1,5 @@
|
|||
--source include/have_binlog_format_mixed.inc
|
||||
--source include/master-slave.inc
|
||||
--source include/not_embedded.inc
|
||||
--source include/not_windows.inc
|
||||
--source extra/rpl_tests/rpl_insert_delayed.test
|
|
@ -1,15 +1,9 @@
|
|||
-- source include/have_binlog_format_mixed_or_statement.inc
|
||||
-- source include/have_binlog_format_mixed.inc
|
||||
-- source include/not_ndb_default.inc
|
||||
-- source include/master-slave.inc
|
||||
|
||||
# Test that the slave temporarily switches to ROW when seeing binrow
|
||||
# events when it is in STATEMENT or MIXED mode
|
||||
|
||||
SET @old_binlog_format= @@global.binlog_format;
|
||||
|
||||
SET BINLOG_FORMAT=MIXED;
|
||||
SET GLOBAL BINLOG_FORMAT=MIXED;
|
||||
SELECT @@GLOBAL.BINLOG_FORMAT, @@SESSION.BINLOG_FORMAT;
|
||||
# Test that the slave temporarily switches to ROW when seeing row
|
||||
# events when it is in MIXED mode
|
||||
|
||||
--echo **** On Master ****
|
||||
CREATE TABLE t1 (a INT, b LONG);
|
||||
|
@ -35,7 +29,6 @@ SHOW BINLOG EVENTS;
|
|||
|
||||
connection master;
|
||||
DROP TABLE IF EXISTS t1;
|
||||
SET @@global.binlog_format= @old_binlog_format;
|
||||
|
||||
# Let's compare. Note: If they match test will pass, if they do not match
|
||||
# the test will show that the diff statement failed and not reject file
|
||||
|
|
325
mysql-test/suite/rpl/t/rpl_row_idempotency.test
Normal file
325
mysql-test/suite/rpl/t/rpl_row_idempotency.test
Normal file
|
@ -0,0 +1,325 @@
|
|||
# Testing various forms of idempotency for replication. This file is
|
||||
# for tests that should only be executed in row mode.
|
||||
|
||||
source include/have_binlog_format_row.inc;
|
||||
source include/master-slave.inc;
|
||||
connection master;
|
||||
source include/have_innodb.inc;
|
||||
connection slave;
|
||||
source include/have_innodb.inc;
|
||||
|
||||
# bug#31609 Not all RBR slave errors reported as errors
|
||||
# bug#31552 Replication breaks when deleting rows from out-of-sync table
|
||||
# without PK
|
||||
|
||||
# The default for slave-exec-mode option and server
|
||||
# variable slave_exec_mode is 'STRICT'.
|
||||
# When 'STRICT' mode is set, the slave SQL thread will stop whenever
|
||||
# the row to change is not found. In 'IDEMPOTENT' mode, the SQL thread
|
||||
# will continue running and apply the row - replace if it's Write_rows event -
|
||||
# or skip to the next event.
|
||||
|
||||
# the previous part of the tests was with IDEMPOTENT slave's mode.
|
||||
|
||||
|
||||
#
|
||||
# Other than above idempotent errors dealing with foreign keys constraint
|
||||
#
|
||||
connection slave;
|
||||
|
||||
set @old_slave_exec_mode= @@global.slave_exec_mode;
|
||||
set @@global.slave_exec_mode= IDEMPOTENT;
|
||||
|
||||
connection master;
|
||||
|
||||
create table ti1 (b int primary key) engine = innodb;
|
||||
create table ti2 (a int primary key, b int, foreign key (b) references ti1(b))
|
||||
engine = innodb;
|
||||
set foreign_key_checks=1 /* ensure the check */;
|
||||
|
||||
insert into ti1 values (1),(2),(3);
|
||||
insert into ti2 set a=2, b=2;
|
||||
|
||||
sync_slave_with_master;
|
||||
|
||||
#connection slave;
|
||||
select * from ti1 order by b /* must be (1),(2),(3) */;
|
||||
insert into ti2 set a=1, b=1;
|
||||
select * from ti2 order by b /* must be (1,1) (2,2) */;
|
||||
|
||||
connection master;
|
||||
|
||||
# from now on checking rbr specific idempotent errors
|
||||
set @save_binlog_format= @@session.binlog_format;
|
||||
set @@session.binlog_format= row;
|
||||
delete from ti1 where b=1;
|
||||
|
||||
select * from ti1 order by b /* must be (2),(3) */;
|
||||
|
||||
# slave must catch up (expect some warnings in error.log)
|
||||
sync_slave_with_master;
|
||||
|
||||
#connection slave;
|
||||
select * from ti1 order by b /* must stays as were on master (1),(2),(3) */;
|
||||
|
||||
delete from ti1 where b=3;
|
||||
|
||||
connection master;
|
||||
insert into ti2 set a=3, b=3;
|
||||
|
||||
# slave must catch up (expect some warnings in error.log)
|
||||
sync_slave_with_master;
|
||||
|
||||
#connection slave;
|
||||
select * from ti2 order by b /* must be (1,1),(2,2) - not inserted */;
|
||||
|
||||
|
||||
#
|
||||
# Checking the new global sys variable
|
||||
#
|
||||
|
||||
connection slave;
|
||||
|
||||
set global slave_exec_mode='IDEMPOTENT';
|
||||
set global slave_exec_mode='STRICT';
|
||||
|
||||
# checking mutual exclusion for the options
|
||||
--error ER_SLAVE_AMBIGOUS_EXEC_MODE
|
||||
set global slave_exec_mode='IDEMPOTENT,STRICT';
|
||||
|
||||
select @@global.slave_exec_mode /* must be STRICT */;
|
||||
|
||||
#
|
||||
# Checking stops.
|
||||
# In the following sections strict slave sql thread is going to
|
||||
# stop when faces an idempotent error. In order to proceed
|
||||
# the mode is temporarily switched to indempotent.
|
||||
#
|
||||
|
||||
#
|
||||
--echo *** foreign keys errors as above now forces to stop
|
||||
#
|
||||
|
||||
connection master;
|
||||
|
||||
set foreign_key_checks=0;
|
||||
drop table ti2, ti1;
|
||||
|
||||
create table ti1 (b int primary key) engine = innodb;
|
||||
create table ti2 (a int primary key, b int, foreign key (b) references ti1(b))
|
||||
engine = innodb;
|
||||
set foreign_key_checks=1 /* ensure the check */;
|
||||
|
||||
insert into ti1 values (1),(2),(3);
|
||||
insert into ti2 set a=2, b=2;
|
||||
|
||||
sync_slave_with_master;
|
||||
|
||||
#connection slave;
|
||||
select * from ti1 order by b /* must be (1),(2),(3) */;
|
||||
--echo *** conspire future problem
|
||||
insert into ti2 set a=1, b=1;
|
||||
select * from ti2 order by b /* must be (1,1) (2,2) */;
|
||||
|
||||
connection master;
|
||||
|
||||
delete from ti1 where b=1 /* offending delete event */;
|
||||
select * from ti1 order by b /* must be (2),(3) */;
|
||||
|
||||
# foreign key: row is referenced
|
||||
|
||||
--echo *** slave must stop (Trying to delete a referenced foreing key)
|
||||
connection slave;
|
||||
source include/wait_for_slave_sql_to_stop.inc;
|
||||
|
||||
let $last_error = query_get_value("SHOW SLAVE STATUS", Last_SQL_Errno, 1);
|
||||
disable_query_log;
|
||||
eval SELECT "$last_error" AS Last_SQL_Error;
|
||||
enable_query_log;
|
||||
|
||||
select * from ti1 order by b /* must be (1),(2),(3) - not deleted */;
|
||||
set foreign_key_checks= 0;
|
||||
delete from ti2 where b=1;
|
||||
set foreign_key_checks= 1;
|
||||
set global slave_exec_mode='IDEMPOTENT';
|
||||
start slave sql_thread;
|
||||
connection master;
|
||||
sync_slave_with_master;
|
||||
#connection slave;
|
||||
set global slave_exec_mode='STRICT';
|
||||
|
||||
connection master;
|
||||
|
||||
sync_slave_with_master;
|
||||
|
||||
#connection slave;
|
||||
--echo *** conspire the following insert failure
|
||||
# foreign key: no referenced row
|
||||
|
||||
--echo *** conspire future problem
|
||||
delete from ti1 where b=3;
|
||||
|
||||
connection master;
|
||||
insert into ti2 set a=3, b=3 /* offending write event */;
|
||||
|
||||
--echo *** slave must stop (Trying to insert an invalid foreign key)
|
||||
connection slave;
|
||||
source include/wait_for_slave_sql_to_stop.inc;
|
||||
|
||||
let $last_error = query_get_value("SHOW SLAVE STATUS", Last_SQL_Errno, 1);
|
||||
disable_query_log;
|
||||
eval SELECT "$last_error" AS Last_SQL_Error;
|
||||
enable_query_log;
|
||||
|
||||
select * from ti2 order by b /* must be (2,2) */;
|
||||
set foreign_key_checks= 0;
|
||||
insert into ti1 set b=3;
|
||||
set foreign_key_checks= 1;
|
||||
set global slave_exec_mode='IDEMPOTENT';
|
||||
start slave sql_thread;
|
||||
connection master;
|
||||
sync_slave_with_master;
|
||||
#connection slave;
|
||||
set global slave_exec_mode='STRICT';
|
||||
|
||||
connection master;
|
||||
|
||||
sync_slave_with_master;
|
||||
|
||||
select * from ti2 order by b /* must be (2,2),(3,3) */;
|
||||
|
||||
#
|
||||
--echo *** other errors
|
||||
#
|
||||
|
||||
# dup key insert
|
||||
|
||||
#connection slave;
|
||||
--echo *** conspiring query
|
||||
insert into ti1 set b=1;
|
||||
|
||||
connection master;
|
||||
insert into ti1 set b=1 /* offending write event */;
|
||||
|
||||
--echo *** slave must stop (Trying to insert a dupliacte key)
|
||||
connection slave;
|
||||
source include/wait_for_slave_sql_to_stop.inc;
|
||||
|
||||
let $last_error = query_get_value("SHOW SLAVE STATUS", Last_SQL_Errno, 1);
|
||||
disable_query_log;
|
||||
eval SELECT "$last_error" AS Last_SQL_Error;
|
||||
enable_query_log;
|
||||
|
||||
set foreign_key_checks= 0;
|
||||
delete from ti1 where b=1;
|
||||
set foreign_key_checks= 1;
|
||||
set global slave_exec_mode='IDEMPOTENT';
|
||||
start slave sql_thread;
|
||||
connection master;
|
||||
sync_slave_with_master;
|
||||
#connection slave;
|
||||
set global slave_exec_mode='STRICT';
|
||||
|
||||
# key not found
|
||||
|
||||
connection master;
|
||||
|
||||
CREATE TABLE t1 (a INT PRIMARY KEY);
|
||||
CREATE TABLE t2 (a INT);
|
||||
INSERT INTO t1 VALUES (-1),(-2),(-3);
|
||||
INSERT INTO t2 VALUES (-1),(-2),(-3);
|
||||
sync_slave_with_master;
|
||||
|
||||
#connection slave;
|
||||
DELETE FROM t1 WHERE a = -2;
|
||||
DELETE FROM t2 WHERE a = -2;
|
||||
connection master;
|
||||
DELETE FROM t1 WHERE a = -2;
|
||||
|
||||
--echo *** slave must stop (Key was not found)
|
||||
connection slave;
|
||||
source include/wait_for_slave_sql_to_stop.inc;
|
||||
|
||||
let $last_error = query_get_value("SHOW SLAVE STATUS", Last_SQL_Errno, 1);
|
||||
disable_query_log;
|
||||
eval SELECT "$last_error" AS Last_SQL_Error;
|
||||
enable_query_log;
|
||||
|
||||
set global slave_exec_mode='IDEMPOTENT';
|
||||
start slave sql_thread;
|
||||
connection master;
|
||||
sync_slave_with_master;
|
||||
#connection slave;
|
||||
set global slave_exec_mode='STRICT';
|
||||
|
||||
connection master;
|
||||
DELETE FROM t2 WHERE a = -2;
|
||||
--echo *** slave must stop (Key was not found)
|
||||
connection slave;
|
||||
source include/wait_for_slave_sql_to_stop.inc;
|
||||
|
||||
let $last_error = query_get_value("SHOW SLAVE STATUS", Last_SQL_Errno, 1);
|
||||
disable_query_log;
|
||||
eval SELECT "$last_error" AS Last_SQL_Error;
|
||||
enable_query_log;
|
||||
|
||||
set global slave_exec_mode='IDEMPOTENT';
|
||||
start slave sql_thread;
|
||||
connection master;
|
||||
sync_slave_with_master;
|
||||
#connection slave;
|
||||
set global slave_exec_mode='STRICT';
|
||||
|
||||
UPDATE t1 SET a = 1 WHERE a = -1;
|
||||
UPDATE t2 SET a = 1 WHERE a = -1;
|
||||
|
||||
connection master;
|
||||
UPDATE t1 SET a = 1 WHERE a = -1;
|
||||
|
||||
--echo *** slave must stop (Key was not found)
|
||||
connection slave;
|
||||
source include/wait_for_slave_sql_to_stop.inc;
|
||||
|
||||
let $last_error = query_get_value("SHOW SLAVE STATUS", Last_SQL_Errno, 1);
|
||||
disable_query_log;
|
||||
eval SELECT "$last_error" AS Last_SQL_Error;
|
||||
enable_query_log;
|
||||
|
||||
set global slave_exec_mode='IDEMPOTENT';
|
||||
start slave sql_thread;
|
||||
connection master;
|
||||
sync_slave_with_master;
|
||||
#connection slave;
|
||||
set global slave_exec_mode='STRICT';
|
||||
|
||||
|
||||
connection master;
|
||||
UPDATE t2 SET a = 1 WHERE a = -1;
|
||||
|
||||
--echo *** slave must stop (Key was not found)
|
||||
connection slave;
|
||||
source include/wait_for_slave_sql_to_stop.inc;
|
||||
|
||||
let $last_error = query_get_value("SHOW SLAVE STATUS", Last_SQL_Errno, 1);
|
||||
disable_query_log;
|
||||
eval SELECT "$last_error" AS Last_SQL_Error;
|
||||
enable_query_log;
|
||||
|
||||
set global slave_exec_mode='IDEMPOTENT';
|
||||
start slave sql_thread;
|
||||
connection master;
|
||||
sync_slave_with_master;
|
||||
#connection slave;
|
||||
SET @@global.slave_exec_mode= @old_slave_exec_mode;
|
||||
|
||||
# cleanup for bug#31609 tests
|
||||
|
||||
connection master;
|
||||
|
||||
drop table t1,t2,ti2,ti1;
|
||||
sync_slave_with_master;
|
||||
set @@global.slave_exec_mode= @old_slave_exec_mode;
|
||||
|
||||
--source include/master-slave-end.inc
|
||||
|
||||
--echo *** end of tests
|
|
@ -2,13 +2,4 @@
|
|||
--source include/master-slave.inc
|
||||
--source include/not_embedded.inc
|
||||
--source include/not_windows.inc
|
||||
|
||||
connection master;
|
||||
set @old_global_binlog_format = @@global.binlog_format;
|
||||
|
||||
let $binlog_format_statement=0;
|
||||
set @@global.binlog_format = row;
|
||||
--source extra/rpl_tests/rpl_insert_delayed.test
|
||||
|
||||
connection master;
|
||||
set @@global.binlog_format = @old_global_binlog_format;
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
# Every statement in this test is either executing under ROW or
|
||||
# STATEMENT format, which requires the slave thread to be able to apply
|
||||
# both statement and row events. Hence, we only need to execute this
|
||||
# test for MIXED mode.
|
||||
source include/have_binlog_format_mixed.inc;
|
||||
|
||||
source include/master-slave.inc;
|
||||
source include/have_innodb.inc;
|
||||
|
||||
|
|
121
mysql-test/suite/rpl/t/rpl_stm_found_rows.test
Normal file
121
mysql-test/suite/rpl/t/rpl_stm_found_rows.test
Normal file
|
@ -0,0 +1,121 @@
|
|||
source include/have_binlog_format_statement.inc;
|
||||
source include/master-slave.inc;
|
||||
|
||||
# It is not possible to replicate FOUND_ROWS() using statement-based
|
||||
# replication, but there is a workaround that stores the result of
|
||||
# FOUND_ROWS() into a user variable and then replicates this instead.
|
||||
#
|
||||
# The purpose of this test case is to test that the workaround works
|
||||
# properly even when inside stored programs (i.e., stored routines and
|
||||
# triggers).
|
||||
|
||||
--echo ==== Initialize ====
|
||||
|
||||
--echo **** On Master ****
|
||||
connection master;
|
||||
CREATE TABLE t1 (a INT);
|
||||
CREATE TABLE logtbl (sect INT, test INT, count INT);
|
||||
|
||||
INSERT INTO t1 VALUES (1),(2),(3);
|
||||
INSERT INTO t1 SELECT 2*a+3 FROM t1;
|
||||
INSERT INTO t1 SELECT 2*a+3 FROM t1;
|
||||
INSERT INTO t1 SELECT 2*a+3 FROM t1;
|
||||
INSERT INTO t1 SELECT 2*a+3 FROM t1;
|
||||
INSERT INTO t1 SELECT 2*a+3 FROM t1;
|
||||
INSERT INTO t1 SELECT 2*a+3 FROM t1;
|
||||
|
||||
|
||||
--echo ==== Simple test ====
|
||||
|
||||
SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1;
|
||||
|
||||
# Instead of
|
||||
# INSERT INTO logtbl VALUES(1, 1, FOUND_ROWS());
|
||||
# we write
|
||||
SELECT FOUND_ROWS() INTO @a;
|
||||
INSERT INTO logtbl VALUES(1,1,@a);
|
||||
|
||||
SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a < 5 ORDER BY a LIMIT 1;
|
||||
# Instead of
|
||||
# INSERT INTO logtbl VALUES(1, 2, FOUND_ROWS());
|
||||
# we write
|
||||
SELECT FOUND_ROWS() INTO @a;
|
||||
INSERT INTO logtbl VALUES(1,2,@a);
|
||||
|
||||
SELECT * FROM logtbl WHERE sect = 1 ORDER BY sect,test;
|
||||
--echo **** On Slave ****
|
||||
sync_slave_with_master;
|
||||
SELECT * FROM logtbl WHERE sect = 1 ORDER BY sect,test;
|
||||
|
||||
|
||||
--echo ==== Stored procedure ====
|
||||
|
||||
# Here we do both the calculation and the logging. We also do it twice
|
||||
# to make sure that there are no limitations on how many times it can
|
||||
# be used.
|
||||
|
||||
--echo **** On Master ****
|
||||
connection master;
|
||||
--delimiter $$
|
||||
CREATE PROCEDURE calc_and_log(sect INT, test INT) BEGIN
|
||||
DECLARE cnt INT;
|
||||
SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a < 5 ORDER BY a LIMIT 1;
|
||||
SELECT FOUND_ROWS() INTO cnt;
|
||||
INSERT INTO logtbl VALUES(sect,test,cnt);
|
||||
SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1;
|
||||
SELECT FOUND_ROWS() INTO cnt;
|
||||
INSERT INTO logtbl VALUES(sect,test+1,cnt);
|
||||
END $$
|
||||
--delimiter ;
|
||||
|
||||
CALL calc_and_log(2,1);
|
||||
|
||||
--delimiter $$
|
||||
CREATE PROCEDURE just_log(sect INT, test INT, found_rows INT) BEGIN
|
||||
INSERT INTO logtbl VALUES (sect,test,found_rows);
|
||||
END $$
|
||||
--delimiter ;
|
||||
|
||||
SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1;
|
||||
SELECT FOUND_ROWS() INTO @found_rows;
|
||||
CALL just_log(2,3,@found_rows);
|
||||
|
||||
SELECT * FROM logtbl WHERE sect = 2 ORDER BY sect,test;
|
||||
--echo **** On Slave ****
|
||||
sync_slave_with_master;
|
||||
SELECT * FROM logtbl WHERE sect = 2 ORDER BY sect,test;
|
||||
|
||||
|
||||
--echo ==== Stored functions ====
|
||||
--echo **** On Master ****
|
||||
connection master;
|
||||
--delimiter $$
|
||||
CREATE FUNCTION log_rows(sect INT, test INT, found_rows INT)
|
||||
RETURNS INT
|
||||
BEGIN
|
||||
INSERT INTO logtbl VALUES(sect,test,found_rows);
|
||||
RETURN found_rows;
|
||||
END $$
|
||||
--delimiter ;
|
||||
|
||||
SELECT SQL_CALC_FOUND_ROWS * FROM t1 WHERE a > 5 ORDER BY a LIMIT 1;
|
||||
SELECT FOUND_ROWS() INTO @found_rows;
|
||||
SELECT log_rows(3,1,@found_rows), log_rows(3,2,@found_rows);
|
||||
|
||||
SELECT * FROM logtbl WHERE sect = 3 ORDER BY sect,test;
|
||||
--echo **** On Slave ****
|
||||
sync_slave_with_master;
|
||||
SELECT * FROM logtbl WHERE sect = 3 ORDER BY sect,test;
|
||||
|
||||
|
||||
--echo ==== Cleanup ====
|
||||
--echo **** On Master ****
|
||||
connection master;
|
||||
DROP TABLE t1, logtbl;
|
||||
DROP PROCEDURE just_log;
|
||||
DROP PROCEDURE calc_and_log;
|
||||
DROP FUNCTION log_rows;
|
||||
sync_slave_with_master;
|
||||
|
||||
source include/reset_master_and_slave.inc;
|
||||
|
|
@ -1,20 +1,5 @@
|
|||
# we run first in statement-based then in mixed binlogging
|
||||
|
||||
--source include/have_binlog_format_mixed_or_statement.inc
|
||||
--source include/have_binlog_format_statement.inc
|
||||
--source include/master-slave.inc
|
||||
--source include/not_embedded.inc
|
||||
--source include/not_windows.inc
|
||||
|
||||
connection master;
|
||||
set @old_global_binlog_format = @@global.binlog_format;
|
||||
|
||||
let $binlog_format_statement=1;
|
||||
set @@global.binlog_format = statement;
|
||||
--source extra/rpl_tests/rpl_insert_delayed.test
|
||||
|
||||
let $binlog_format_statement=0;
|
||||
set @@global.binlog_format = mixed;
|
||||
--source extra/rpl_tests/rpl_insert_delayed.test
|
||||
|
||||
connection master;
|
||||
set @@global.binlog_format = @old_global_binlog_format;
|
||||
|
|
|
@ -1,17 +1,25 @@
|
|||
#
|
||||
# rpl_switch_stm_row_mixed tests covers
|
||||
#
|
||||
# - switching explicitly between STATEMENT, ROW, and MIXED binlog format
|
||||
# showing when it is possible and when not.
|
||||
# - switching from MIXED to RBR implicitly listing all use cases,
|
||||
# e.g a query invokes UUID(), thereafter to serve as the definition
|
||||
# of MIXED binlog format
|
||||
# - Master is switching explicitly between STATEMENT, ROW, and MIXED
|
||||
# binlog format showing when it is possible and when not.
|
||||
# - Master switching from MIXED to RBR implicitly listing all use
|
||||
# cases, e.g a query invokes UUID(), thereafter to serve as the
|
||||
# definition of MIXED binlog format
|
||||
# - correctness of execution
|
||||
|
||||
|
||||
-- source include/not_ndb_default.inc
|
||||
-- source include/master-slave.inc
|
||||
|
||||
# Since this test generates row-based events in the binary log, the
|
||||
# slave SQL thread cannot be in STATEMENT mode to execute this test,
|
||||
# so we only execute it for MIXED and ROW as default value of
|
||||
# BINLOG_FORMAT.
|
||||
|
||||
connection slave;
|
||||
-- source include/have_binlog_format_mixed_or_row.inc
|
||||
|
||||
connection master;
|
||||
--disable_warnings
|
||||
drop database if exists mysqltest1;
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
source include/have_binlog_format_row.inc;
|
||||
source include/master-slave.inc;
|
||||
|
||||
call mtr.add_suppression("Deadlock found");
|
||||
|
||||
--echo **** On Master ****
|
||||
connection master;
|
||||
SET SESSION BINLOG_FORMAT=ROW;
|
||||
CREATE TABLE t1 (a INT PRIMARY KEY, b INT);
|
||||
INSERT INTO t1 VALUES (1,1), (2,2), (3,3), (4,4);
|
||||
--echo **** On Slave ****
|
||||
|
|
|
@ -5,18 +5,7 @@
|
|||
# statement based format. This tests work completed in WL#3629. #
|
||||
###################################################################
|
||||
|
||||
--source include/not_embedded.inc
|
||||
--source include/master-slave.inc
|
||||
|
||||
let $engine_type= MyISAM;
|
||||
|
||||
set binlog_format=row;
|
||||
|
||||
# Embedded server doesn't support binlogging
|
||||
--source include/rpl_udf.inc
|
||||
|
||||
set binlog_format=statement;
|
||||
|
||||
# Embedded server doesn't support binlogging
|
||||
--source include/rpl_udf.inc
|
||||
|
||||
|
|
8
mysql-test/suite/rpl_ndb/combinations
Normal file
8
mysql-test/suite/rpl_ndb/combinations
Normal file
|
@ -0,0 +1,8 @@
|
|||
[row]
|
||||
binlog-format=row
|
||||
|
||||
[stmt]
|
||||
binlog-format=statement
|
||||
|
||||
[mix]
|
||||
binlog-format=mixed
|
130
mysql-test/suite/rpl_ndb/r/rpl_ndb_binlog_format_errors.result
Normal file
130
mysql-test/suite/rpl_ndb/r/rpl_ndb_binlog_format_errors.result
Normal file
|
@ -0,0 +1,130 @@
|
|||
stop slave;
|
||||
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
|
||||
reset master;
|
||||
reset slave;
|
||||
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
|
||||
start slave;
|
||||
==== Initialize ====
|
||||
[on slave]
|
||||
SET @old_binlog_format= @@global.binlog_format;
|
||||
INSTALL PLUGIN example SONAME 'ha_example.so';
|
||||
[on master]
|
||||
SET @old_binlog_format= @@global.binlog_format;
|
||||
INSTALL PLUGIN example SONAME 'ha_example.so';
|
||||
CREATE TABLE t (a VARCHAR(100)) ENGINE = MYISAM;
|
||||
CREATE TABLE t_self_logging (a VARCHAR(100)) ENGINE = NDB;
|
||||
CREATE TABLE t_row (a VARCHAR(100)) ENGINE = INNODB;
|
||||
CREATE TABLE t_stmt (a VARCHAR(100)) ENGINE = EXAMPLE;
|
||||
CREATE TABLE t_slave_stmt (a VARCHAR(100)) ENGINE = MYISAM;
|
||||
CREATE DATABASE other;
|
||||
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
|
||||
[on slave]
|
||||
DROP TABLE t_slave_stmt;
|
||||
CREATE TABLE t_slave_stmt (a INT) ENGINE = EXAMPLE;
|
||||
[on master]
|
||||
BINLOG '
|
||||
1gRVSg8BAAAAZgAAAGoAAAABAAQANS4xLjM2LWRlYnVnLWxvZwAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAADWBFVKEzgNAAgAEgAEBAQEEgAAUwAEGggAAAAICAgC
|
||||
';
|
||||
==== Test ====
|
||||
---- binlog_format=row ----
|
||||
* Modify tables of more than one engine, one of which is self-logging
|
||||
CREATE TRIGGER trig_1 AFTER INSERT ON t_self_logging FOR EACH ROW BEGIN INSERT INTO t VALUES (1); END;
|
||||
INSERT INTO t_self_logging VALUES (1);
|
||||
ERROR HY000: Cannot execute statement: binlogging impossible since more than one engine is involved and at least one engine is self-logging.
|
||||
DROP trigger trig_1;
|
||||
* Modify both row-only and stmt-only table
|
||||
CREATE TRIGGER trig_2 AFTER INSERT ON t_stmt FOR EACH ROW BEGIN INSERT INTO t_row VALUES(1); END;
|
||||
INSERT INTO t_stmt VALUES (1);
|
||||
ERROR HY000: Cannot execute statement: binlogging impossible since both row-incapable engines and statement-incapable engines are involved.
|
||||
DROP TRIGGER trig_2;
|
||||
* Stmt-only table and binlog_format=row
|
||||
INSERT INTO t_stmt VALUES (1);
|
||||
ERROR HY000: Cannot execute statement: binlogging impossible since BINLOG_FORMAT = ROW and at least one table uses a storage engine limited to statement-logging.
|
||||
* Row injection and stmt-only table: in slave sql thread
|
||||
INSERT INTO t_slave_stmt VALUES (1);
|
||||
[on slave]
|
||||
--source include/wait_for_slave_sql_error_and_skip.inc
|
||||
Last_SQL_Error = Error 'Cannot execute row injection: binlogging impossible since at least one table uses a storage engine limited to statement-logging.' on opening tables
|
||||
set global sql_slave_skip_counter=1;
|
||||
include/start_slave.inc
|
||||
* Row injection and stmt-only table: use BINLOG statement
|
||||
BINLOG '
|
||||
1gRVShMBAAAALwAAAEABAAAAABcAAAAAAAAABHRlc3QABnRfc3RtdAABDwJkAAE=
|
||||
1gRVShcBAAAAIAAAAGABAAAQABcAAAAAAAEAAf/+ATE=
|
||||
';
|
||||
ERROR HY000: Cannot execute row injection: binlogging impossible since at least one table uses a storage engine limited to statement-logging.
|
||||
---- binlog_format=mixed ----
|
||||
[on slave]
|
||||
include/stop_slave.inc
|
||||
SET @@global.binlog_format = MIXED;
|
||||
include/start_slave.inc
|
||||
[on master]
|
||||
SET @@global.binlog_format = MIXED;
|
||||
SET @@session.binlog_format = MIXED;
|
||||
* Unsafe statement and stmt-only engine
|
||||
INSERT INTO t_stmt VALUES (UUID());
|
||||
Warnings:
|
||||
Note 1641 Unsafe statement binlogged as statement since storage engine is limited to statement-logging. Reason: Statement uses a system function whose value may differ on slave.
|
||||
---- binlog_format=statement ----
|
||||
[on slave]
|
||||
include/stop_slave.inc
|
||||
SET @@global.binlog_format = STATEMENT;
|
||||
include/start_slave.inc
|
||||
[on master]
|
||||
SET @@global.binlog_format = STATEMENT;
|
||||
SET @@session.binlog_format = STATEMENT;
|
||||
* Row-only engine and binlog_format=statement: innodb-specific message
|
||||
INSERT INTO t_row VALUES (1);
|
||||
ERROR HY000: Cannot execute statement: binlogging impossible since BINLOG_FORMAT = STATEMENT and at least one table uses a storage engine limited to row-logging. InnoDB is limited to row-logging when transaction isolation level is READ COMMITTED or READ UNCOMMITTED.
|
||||
* Row-only engine and binlog_format=statement: generic message
|
||||
SET @@session.debug= '+d,no_innodb_binlog_errors';
|
||||
INSERT INTO t_row VALUES (1);
|
||||
ERROR HY000: Cannot execute statement: binlogging impossible since BINLOG_FORMAT = STATEMENT and at least one table uses a storage engine limited to row-logging.
|
||||
* Same statement, but db filtered out - no error
|
||||
USE other;
|
||||
INSERT INTO test.t_row VALUES (1);
|
||||
USE test;
|
||||
SET @@session.debug= '';
|
||||
* Row injection and binlog_format=statement: BINLOG statement
|
||||
BINLOG '
|
||||
cNpVShMBAAAAKgAAADYBAAAAABcAAAAAAAAABHRlc3QAAXQAAQ8CZAAB
|
||||
cNpVShcBAAAAIAAAAFYBAAAQABcAAAAAAAEAAf/+ATE=
|
||||
';
|
||||
ERROR HY000: Cannot execute row injection: binlogging impossible since BINLOG_FORMAT = STATEMENT.
|
||||
* Same statement, but db filtered out - no error
|
||||
USE other;
|
||||
BINLOG '
|
||||
cNpVShMBAAAAKgAAADYBAAAAABcAAAAAAAAABHRlc3QAAXQAAQ8CZAAB
|
||||
cNpVShcBAAAAIAAAAFYBAAAQABcAAAAAAAEAAf/+ATE=
|
||||
';
|
||||
USE test;
|
||||
* Unsafe statement and binlog_format=statement
|
||||
INSERT INTO t VALUES (UUID());
|
||||
Warnings:
|
||||
Note 1592 Unsafe statement binlogged in statement format since BINLOG_FORMAT = STATEMENT. Reason: Statement uses a system function whose value may differ on slave.
|
||||
* Same statement, but db filtered out - no message
|
||||
USE other;
|
||||
INSERT INTO test.t VALUES (UUID());
|
||||
USE test;
|
||||
---- master: binlog_format=mixed, slave: binlog_format=statement ----
|
||||
SET @@global.binlog_format = MIXED;
|
||||
SET @@session.binlog_format = MIXED;
|
||||
* Row injection and binlog_format=statement: in slave sql thread
|
||||
INSERT INTO t VALUES (UUID());
|
||||
[on slave]
|
||||
--source include/wait_for_slave_sql_error_and_skip.inc
|
||||
Last_SQL_Error = Error 'Cannot execute row injection: binlogging impossible since BINLOG_FORMAT = STATEMENT.' on opening tables
|
||||
set global sql_slave_skip_counter=1;
|
||||
include/start_slave.inc
|
||||
[on master]
|
||||
==== Clean up ====
|
||||
DROP TABLE t, t_self_logging, t_row, t_stmt, t_slave_stmt;
|
||||
DROP DATABASE other;
|
||||
SET @@global.binlog_format = @old_binlog_format;
|
||||
SET @@session.binlog_format = @old_binlog_format;
|
||||
UNINSTALL PLUGIN example;
|
||||
[on slave]
|
||||
SET @@global.binlog_format = @old_binlog_format;
|
||||
SET @@session.binlog_format = @old_binlog_format;
|
||||
UNINSTALL PLUGIN example;
|
|
@ -102,3 +102,4 @@ Last_IO_Errno #
|
|||
Last_IO_Error #
|
||||
Last_SQL_Errno 0
|
||||
Last_SQL_Error
|
||||
DROP TABLE t1;
|
||||
|
|
|
@ -8,6 +8,9 @@
|
|||
# test and to have control over the tests.
|
||||
##############################################################
|
||||
-- source include/have_ndb.inc
|
||||
# Since the master generates row-based events, the slave must be in
|
||||
# ROW or MIXED mode to accept the events.
|
||||
-- source include/have_binlog_format_mixed_or_row.inc
|
||||
-- source include/master-slave.inc
|
||||
|
||||
-- connection slave
|
||||
|
|
|
@ -8,6 +8,9 @@
|
|||
# test and to have control over the tests.
|
||||
##############################################################
|
||||
-- source include/have_ndb.inc
|
||||
# Since the master generates row-based events, the slave must be in
|
||||
# ROW or MIXED mode to accept the events.
|
||||
-- source include/have_binlog_format_mixed_or_row.inc
|
||||
-- source include/master-slave.inc
|
||||
|
||||
-- connection slave
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
--source include/have_ndb.inc
|
||||
# Since the master generates row-based events, the slave must be in
|
||||
# ROW or MIXED mode to accept the events.
|
||||
--source include/have_binlog_format_mixed_or_row.inc
|
||||
--source include/ndb_master-slave.inc
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
--innodb $EXAMPLE_PLUGIN_OPT --binlog-ignore-db=other
|
|
@ -0,0 +1 @@
|
|||
--innodb $EXAMPLE_PLUGIN_OPT
|
225
mysql-test/suite/rpl_ndb/t/rpl_ndb_binlog_format_errors.test
Normal file
225
mysql-test/suite/rpl_ndb/t/rpl_ndb_binlog_format_errors.test
Normal file
|
@ -0,0 +1,225 @@
|
|||
# ==== Purpose ====
|
||||
#
|
||||
# Verify that errors or warnings are issued for all error conditions
|
||||
# related to deciding the binlog format of a statement. The possible
|
||||
# errors are listed in a comment above decide_logging_format() in
|
||||
# sql_base.cc.
|
||||
#
|
||||
# ==== Method ====
|
||||
#
|
||||
# Each error condition is executed; we verify that there is an error.
|
||||
#
|
||||
# ==== Related bugs ====
|
||||
#
|
||||
# BUG#39934: Slave stops for engine that only support row-based logging
|
||||
# BUG#42829: binlogging enabled for all schemas regardless of binlog-db-db / binlog-ignore-db
|
||||
#
|
||||
# ==== Related test cases ====
|
||||
#
|
||||
# binlog.binlog_unsafe verifies more thoroughly that a warning is
|
||||
# given for the case when an unsafe statement is executed and
|
||||
# binlog_format = STATEMENT.
|
||||
|
||||
# Need debug so that 'SET @@session.debug' works.
|
||||
--source include/have_debug.inc
|
||||
# Need example plugin because it is the only statement-only engine.
|
||||
--source include/have_example_plugin.inc
|
||||
# The test changes binlog_format, so there is no reason to run it
|
||||
# under more than one binlog format.
|
||||
--source include/have_binlog_format_row.inc
|
||||
--source include/have_ndb.inc
|
||||
--source include/have_innodb.inc
|
||||
--source include/ndb_master-slave.inc
|
||||
|
||||
|
||||
--echo ==== Initialize ====
|
||||
|
||||
--echo [on slave]
|
||||
--connection slave
|
||||
|
||||
SET @old_binlog_format= @@global.binlog_format;
|
||||
INSTALL PLUGIN example SONAME 'ha_example.so';
|
||||
|
||||
--echo [on master]
|
||||
--connection master
|
||||
|
||||
SET @old_binlog_format= @@global.binlog_format;
|
||||
INSTALL PLUGIN example SONAME 'ha_example.so';
|
||||
|
||||
CREATE TABLE t (a VARCHAR(100)) ENGINE = MYISAM;
|
||||
CREATE TABLE t_self_logging (a VARCHAR(100)) ENGINE = NDB;
|
||||
CREATE TABLE t_row (a VARCHAR(100)) ENGINE = INNODB;
|
||||
CREATE TABLE t_stmt (a VARCHAR(100)) ENGINE = EXAMPLE;
|
||||
CREATE TABLE t_slave_stmt (a VARCHAR(100)) ENGINE = MYISAM;
|
||||
|
||||
CREATE DATABASE other;
|
||||
|
||||
# This makes the innodb table row-only
|
||||
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
|
||||
|
||||
--echo [on slave]
|
||||
--sync_slave_with_master
|
||||
|
||||
DROP TABLE t_slave_stmt;
|
||||
CREATE TABLE t_slave_stmt (a INT) ENGINE = EXAMPLE;
|
||||
|
||||
--echo [on master]
|
||||
--connection master
|
||||
|
||||
# This is a format description event. It is needed because any BINLOG
|
||||
# statement containing a row event must be preceded by a BINLOG
|
||||
# statement containing a format description event.
|
||||
BINLOG '
|
||||
1gRVSg8BAAAAZgAAAGoAAAABAAQANS4xLjM2LWRlYnVnLWxvZwAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAADWBFVKEzgNAAgAEgAEBAQEEgAAUwAEGggAAAAICAgC
|
||||
';
|
||||
|
||||
|
||||
--echo ==== Test ====
|
||||
|
||||
--echo ---- binlog_format=row ----
|
||||
|
||||
--echo * Modify tables of more than one engine, one of which is self-logging
|
||||
--eval CREATE TRIGGER trig_1 AFTER INSERT ON t_self_logging FOR EACH ROW BEGIN INSERT INTO t VALUES (1); END
|
||||
--error ER_BINLOG_MULTIPLE_ENGINES_AND_SELF_LOGGING_ENGINE
|
||||
INSERT INTO t_self_logging VALUES (1);
|
||||
DROP trigger trig_1;
|
||||
|
||||
--echo * Modify both row-only and stmt-only table
|
||||
--eval CREATE TRIGGER trig_2 AFTER INSERT ON t_stmt FOR EACH ROW BEGIN INSERT INTO t_row VALUES(1); END
|
||||
--error ER_BINLOG_ROW_ENGINE_AND_STMT_ENGINE
|
||||
INSERT INTO t_stmt VALUES (1);
|
||||
DROP TRIGGER trig_2;
|
||||
|
||||
--echo * Stmt-only table and binlog_format=row
|
||||
--error ER_BINLOG_ROW_MODE_AND_STMT_ENGINE
|
||||
INSERT INTO t_stmt VALUES (1);
|
||||
|
||||
--echo * Row injection and stmt-only table: in slave sql thread
|
||||
INSERT INTO t_slave_stmt VALUES (1);
|
||||
--echo [on slave]
|
||||
--connection slave
|
||||
# 1642 = ER_BINLOG_ROW_INJECTION_AND_STMT_ENGINE
|
||||
--let $slave_sql_errno= 1642
|
||||
--let $show_sql_error= 1
|
||||
--source include/wait_for_slave_sql_error_and_skip.inc
|
||||
|
||||
--echo * Row injection and stmt-only table: use BINLOG statement
|
||||
# This is a Table_map_event and a Write_rows_event. Together, they are
|
||||
# equivalent to 'INSERT INTO t_stmt VALUES (1)'
|
||||
--error ER_BINLOG_ROW_INJECTION_AND_STMT_ENGINE
|
||||
BINLOG '
|
||||
1gRVShMBAAAALwAAAEABAAAAABcAAAAAAAAABHRlc3QABnRfc3RtdAABDwJkAAE=
|
||||
1gRVShcBAAAAIAAAAGABAAAQABcAAAAAAAEAAf/+ATE=
|
||||
';
|
||||
|
||||
|
||||
--echo ---- binlog_format=mixed ----
|
||||
|
||||
--echo [on slave]
|
||||
--sync_slave_with_master
|
||||
--source include/stop_slave.inc
|
||||
SET @@global.binlog_format = MIXED;
|
||||
--source include/start_slave.inc
|
||||
--echo [on master]
|
||||
--connection master
|
||||
SET @@global.binlog_format = MIXED;
|
||||
SET @@session.binlog_format = MIXED;
|
||||
|
||||
--echo * Unsafe statement and stmt-only engine
|
||||
# This will give a warning.
|
||||
INSERT INTO t_stmt VALUES (UUID());
|
||||
|
||||
|
||||
--echo ---- binlog_format=statement ----
|
||||
|
||||
--echo [on slave]
|
||||
--sync_slave_with_master
|
||||
--source include/stop_slave.inc
|
||||
SET @@global.binlog_format = STATEMENT;
|
||||
--source include/start_slave.inc
|
||||
--echo [on master]
|
||||
--connection master
|
||||
SET @@global.binlog_format = STATEMENT;
|
||||
SET @@session.binlog_format = STATEMENT;
|
||||
|
||||
--echo * Row-only engine and binlog_format=statement: innodb-specific message
|
||||
--error ER_BINLOG_STMT_MODE_AND_ROW_ENGINE
|
||||
INSERT INTO t_row VALUES (1);
|
||||
|
||||
# Commented out since innodb gives an error (this is a bug)
|
||||
#--echo * Same statement, but db filtered out - no error
|
||||
#USE other;
|
||||
#INSERT INTO test.t_row VALUES (1);
|
||||
#USE test;
|
||||
|
||||
--echo * Row-only engine and binlog_format=statement: generic message
|
||||
SET @@session.debug= '+d,no_innodb_binlog_errors';
|
||||
--error ER_BINLOG_STMT_MODE_AND_ROW_ENGINE
|
||||
INSERT INTO t_row VALUES (1);
|
||||
|
||||
--echo * Same statement, but db filtered out - no error
|
||||
USE other;
|
||||
INSERT INTO test.t_row VALUES (1);
|
||||
USE test;
|
||||
SET @@session.debug= '';
|
||||
|
||||
--echo * Row injection and binlog_format=statement: BINLOG statement
|
||||
# This is a Table_map_event and a Write_rows_event. Together, they are
|
||||
# equivalent to 'INSERT INTO t VALUES (1)'.
|
||||
--error ER_BINLOG_ROW_INJECTION_AND_STMT_MODE
|
||||
BINLOG '
|
||||
cNpVShMBAAAAKgAAADYBAAAAABcAAAAAAAAABHRlc3QAAXQAAQ8CZAAB
|
||||
cNpVShcBAAAAIAAAAFYBAAAQABcAAAAAAAEAAf/+ATE=
|
||||
';
|
||||
|
||||
--echo * Same statement, but db filtered out - no error
|
||||
# This is a Table_map_event and a Write_rows_event. Together, they are
|
||||
# equivalent to 'INSERT INTO t VALUES (1)'.
|
||||
USE other;
|
||||
BINLOG '
|
||||
cNpVShMBAAAAKgAAADYBAAAAABcAAAAAAAAABHRlc3QAAXQAAQ8CZAAB
|
||||
cNpVShcBAAAAIAAAAFYBAAAQABcAAAAAAAEAAf/+ATE=
|
||||
';
|
||||
USE test;
|
||||
|
||||
--echo * Unsafe statement and binlog_format=statement
|
||||
# This will give a warning.
|
||||
INSERT INTO t VALUES (UUID());
|
||||
|
||||
--echo * Same statement, but db filtered out - no message
|
||||
USE other;
|
||||
INSERT INTO test.t VALUES (UUID());
|
||||
USE test;
|
||||
|
||||
|
||||
--echo ---- master: binlog_format=mixed, slave: binlog_format=statement ----
|
||||
|
||||
SET @@global.binlog_format = MIXED;
|
||||
SET @@session.binlog_format = MIXED;
|
||||
|
||||
--echo * Row injection and binlog_format=statement: in slave sql thread
|
||||
INSERT INTO t VALUES (UUID());
|
||||
--echo [on slave]
|
||||
--connection slave
|
||||
# 1644 = ER_BINLOG_ROW_INJECTION_AND_STMT_MODE
|
||||
--let $slave_sql_errno= 1644
|
||||
--let $show_sql_error= 1
|
||||
--source include/wait_for_slave_sql_error_and_skip.inc
|
||||
|
||||
--echo [on master]
|
||||
--connection master
|
||||
|
||||
|
||||
--echo ==== Clean up ====
|
||||
|
||||
DROP TABLE t, t_self_logging, t_row, t_stmt, t_slave_stmt;
|
||||
DROP DATABASE other;
|
||||
SET @@global.binlog_format = @old_binlog_format;
|
||||
SET @@session.binlog_format = @old_binlog_format;
|
||||
UNINSTALL PLUGIN example;
|
||||
--echo [on slave]
|
||||
--sync_slave_with_master
|
||||
SET @@global.binlog_format = @old_binlog_format;
|
||||
SET @@session.binlog_format = @old_binlog_format;
|
||||
UNINSTALL PLUGIN example;
|
|
@ -1,4 +1,7 @@
|
|||
--source include/have_ndb.inc
|
||||
# Since the master generates row-based events, the slave must be in
|
||||
# ROW or MIXED mode to accept the events.
|
||||
--source include/have_binlog_format_mixed_or_row.inc
|
||||
--source include/ndb_master-slave.inc
|
||||
|
||||
#
|
||||
|
|
|
@ -3,6 +3,11 @@
|
|||
# Using wrapper to share test #
|
||||
# code between engine tests #
|
||||
#################################
|
||||
#
|
||||
# Since the master generates row-based events, the slave may not be in
|
||||
# STATEMENT mode to accept the events.
|
||||
#
|
||||
-- source include/have_binlog_format_mixed_or_row.inc
|
||||
-- source include/have_ndb.inc
|
||||
-- source include/ndb_master-slave.inc
|
||||
let $engine_type=NDBCLUSTER;
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
--source include/have_ndb.inc
|
||||
# Since the master generates row-based events, the slave must be in
|
||||
# ROW or MIXED mode to accept the events.
|
||||
--source include/have_binlog_format_mixed_or_row.inc
|
||||
--source include/ndb_master-slave.inc
|
||||
|
||||
# set up circular replication
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
--source include/have_ndb.inc
|
||||
# Since the master generates row-based events, the slave must be in
|
||||
# ROW or MIXED mode to accept the events.
|
||||
--source include/have_binlog_format_mixed_or_row.inc
|
||||
--source include/ndb_master-slave.inc
|
||||
|
||||
connection master;
|
||||
|
@ -78,3 +81,7 @@ SELECT * FROM t1 ORDER BY a;
|
|||
--replace_result $MASTER_MYPORT MASTER_PORT
|
||||
--replace_column 1 # 7 # 8 # 9 # 22 # 23 # 33 # 35 # 36 #
|
||||
query_vertical SHOW SLAVE STATUS;
|
||||
|
||||
connection master;
|
||||
DROP TABLE t1;
|
||||
sync_slave_with_master;
|
||||
|
|
|
@ -4,6 +4,10 @@
|
|||
# Different engines #
|
||||
# By JBM 2004-02-15 #
|
||||
#####################################
|
||||
|
||||
# Since the master generates row-based events, the slave must be in
|
||||
# ROW or MIXED mode to accept the events.
|
||||
-- source include/have_binlog_format_mixed_or_row.inc
|
||||
-- source include/have_ndb.inc
|
||||
-- source include/ndb_master-slave.inc
|
||||
let $engine_type=NDB;
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
--source include/have_ucs2.inc
|
||||
--source include/have_ndb.inc
|
||||
# Since the master generates row-based events, the slave must be in
|
||||
# ROW or MIXED mode to accept the events.
|
||||
--source include/have_binlog_format_mixed_or_row.inc
|
||||
--source include/ndb_master-slave.inc
|
||||
|
||||
#
|
||||
|
|
|
@ -3,6 +3,9 @@
|
|||
# Share test code between engine tests #
|
||||
#########################################
|
||||
--source include/have_ndb.inc
|
||||
# Since the master generates row-based events, the slave must be in
|
||||
# ROW or MIXED mode to accept the events.
|
||||
--source include/have_binlog_format_mixed_or_row.inc
|
||||
-- source include/ndb_master-slave.inc
|
||||
let $engine_type=NDB;
|
||||
-- source extra/rpl_tests/rpl_delete_no_where.test
|
||||
|
|
|
@ -6,6 +6,9 @@
|
|||
##########################################################
|
||||
|
||||
--source include/have_ndb.inc
|
||||
# Since the master generates row-based events, the slave must be in
|
||||
# ROW or MIXED mode to accept the events.
|
||||
--source include/have_binlog_format_mixed_or_row.inc
|
||||
--source include/ndb_master-slave.inc
|
||||
|
||||
--disable_warnings
|
||||
|
|
|
@ -6,6 +6,9 @@
|
|||
##########################################################
|
||||
|
||||
--source include/have_ndb.inc
|
||||
# Since the master generates row-based events, the slave must be in
|
||||
# ROW or MIXED mode to accept the events.
|
||||
--source include/have_binlog_format_mixed_or_row.inc
|
||||
--source include/ndb_master-slave.inc
|
||||
|
||||
--disable_warnings
|
||||
|
|
|
@ -7,6 +7,9 @@
|
|||
# reduce test case code #
|
||||
###################################
|
||||
-- source include/have_ndb.inc
|
||||
# Since the master generates row-based events, the slave must be in
|
||||
# ROW or MIXED mode to accept the events.
|
||||
-- source include/have_binlog_format_mixed_or_row.inc
|
||||
-- source include/ndb_master-slave.inc
|
||||
let $engine_type=NDB;
|
||||
-- source extra/rpl_tests/rpl_row_func003.test
|
||||
|
|
|
@ -2,6 +2,9 @@
|
|||
|
||||
-- source include/have_ndb.inc
|
||||
-- source include/have_innodb.inc
|
||||
# Since the master generates row-based events, the slave must be in
|
||||
# ROW or MIXED mode to accept the events.
|
||||
-- source include/have_binlog_format_mixed_or_row.inc
|
||||
-- source include/ndb_master-slave.inc
|
||||
|
||||
create table t1 (a int, unique(a)) engine=ndbcluster;
|
||||
|
|
|
@ -2,6 +2,9 @@
|
|||
# Wrapper for rpl_insert_ignore.test#
|
||||
#####################################
|
||||
-- source include/have_ndb.inc
|
||||
# Since the master generates row-based events, the slave must be in
|
||||
# ROW or MIXED mode to accept the events.
|
||||
-- source include/have_binlog_format_mixed_or_row.inc
|
||||
-- source include/ndb_master-slave.inc
|
||||
let $engine_type=NDB;
|
||||
let $engine_type2=myisam;
|
||||
|
|
|
@ -23,6 +23,9 @@
|
|||
|
||||
|
||||
source include/have_ndb.inc;
|
||||
# Since the master generates row-based events, the slave must be in
|
||||
# ROW or MIXED mode to accept the events.
|
||||
source include/have_binlog_format_mixed_or_row.inc;
|
||||
source include/ndb_master-slave.inc;
|
||||
source include/have_innodb.inc;
|
||||
|
||||
|
|
|
@ -3,6 +3,9 @@
|
|||
# to reuse test code between engine runs #
|
||||
############################################################
|
||||
-- source include/have_ndb.inc
|
||||
# Since the master generates row-based events, the slave must be in
|
||||
# ROW or MIXED mode to accept the events.
|
||||
-- source include/have_binlog_format_mixed_or_row.inc
|
||||
-- source include/ndb_master-slave.inc
|
||||
let $engine_type=NDB;
|
||||
-- source extra/rpl_tests/rpl_multi_update3.test
|
||||
|
|
|
@ -7,6 +7,9 @@
|
|||
##########################################################
|
||||
|
||||
--source include/have_ndb.inc
|
||||
# Since the master generates row-based events, the slave must be in
|
||||
# ROW or MIXED mode to accept the events.
|
||||
--source include/have_binlog_format_mixed_or_row.inc
|
||||
--source include/ndb_master-slave.inc
|
||||
|
||||
--disable_warnings
|
||||
|
|
|
@ -2,6 +2,9 @@
|
|||
# By JBM 2005-02-15 Wrapped to allow reuse of test code#
|
||||
########################################################
|
||||
--source include/have_ndb.inc
|
||||
# Since the master generates row-based events, the slave must be in
|
||||
# ROW or MIXED mode to accept the events.
|
||||
--source include/have_binlog_format_mixed_or_row.inc
|
||||
-- source include/ndb_master-slave.inc
|
||||
let $engine_type=NDB;
|
||||
-- source extra/rpl_tests/rpl_row_001.test
|
||||
|
|
|
@ -5,6 +5,9 @@
|
|||
# For different engines #
|
||||
#################################
|
||||
-- source include/have_ndb.inc
|
||||
# Since the master generates row-based events, the slave must be in
|
||||
# ROW or MIXED mode to accept the events.
|
||||
-- source include/have_binlog_format_mixed_or_row.inc
|
||||
-- source include/ndb_master-slave.inc
|
||||
let $engine_type=NDBCLUSTER;
|
||||
-- source extra/rpl_tests/rpl_row_sp003.test
|
||||
|
|
|
@ -5,6 +5,9 @@
|
|||
# For different engines #
|
||||
#################################
|
||||
-- source include/have_ndb.inc
|
||||
# Since the master generates row-based events, the slave must be in
|
||||
# ROW or MIXED mode to accept the events.
|
||||
-- source include/have_binlog_format_mixed_or_row.inc
|
||||
-- source include/ndb_master-slave.inc
|
||||
let $engine_type=NDBCLUSTER;
|
||||
-- source extra/rpl_tests/rpl_row_sp006.test
|
||||
|
|
|
@ -8,6 +8,9 @@
|
|||
|
||||
# Includes
|
||||
-- source include/have_ndb.inc
|
||||
# Since the master generates row-based events, the slave must be in
|
||||
# ROW or MIXED mode to accept the events.
|
||||
-- source include/have_binlog_format_mixed_or_row.inc
|
||||
-- source include/ndb_master-slave.inc
|
||||
let $engine_type=NDB;
|
||||
-- source extra/rpl_tests/rpl_trig004.test
|
||||
|
|
|
@ -875,8 +875,13 @@ select * from t1;
|
|||
create view v1 as
|
||||
select * from v3 where b in (1, 2, 3, 4, 5, 6, 7);
|
||||
|
||||
# Disable warnings since LIMIT warning for unsafe statement if
|
||||
# binlog_format = STATEMENT. Note: after BUG#45832, the warning should
|
||||
# not be issued.
|
||||
--disable_warnings
|
||||
create view v2 as
|
||||
select v3.a from v3, v1 where v1.a=v3.a and v3.b=3 limit 1;
|
||||
--enable_warnings
|
||||
|
||||
--exec $MYSQL_DUMP --skip-comments test
|
||||
|
||||
|
|
|
@ -50,7 +50,7 @@ connection con1;
|
|||
--echo # connection con1
|
||||
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
|
||||
BEGIN;
|
||||
--error ER_BINLOG_LOGGING_IMPOSSIBLE
|
||||
--error ER_BINLOG_STMT_MODE_AND_ROW_ENGINE
|
||||
INSERT INTO t1 VALUES(9);
|
||||
COMMIT;
|
||||
|
||||
|
|
|
@ -1034,8 +1034,8 @@ update_timing_fields_for_event(THD *thd,
|
|||
Turn off row binlogging of event timing updates. These are not used
|
||||
for RBR of events replicated to the slave.
|
||||
*/
|
||||
if (thd->current_stmt_binlog_row_based)
|
||||
thd->clear_current_stmt_binlog_row_based();
|
||||
if (thd->is_current_stmt_binlog_format_row())
|
||||
thd->clear_current_stmt_binlog_format_row();
|
||||
|
||||
DBUG_ASSERT(thd->security_ctx->master_access & SUPER_ACL);
|
||||
|
||||
|
|
|
@ -430,8 +430,8 @@ Events::create_event(THD *thd, Event_parse_data *parse_data,
|
|||
Turn off row binlogging of this statement and use statement-based
|
||||
so that all supporting tables are updated for CREATE EVENT command.
|
||||
*/
|
||||
if (thd->current_stmt_binlog_row_based)
|
||||
thd->clear_current_stmt_binlog_row_based();
|
||||
if (thd->is_current_stmt_binlog_format_row())
|
||||
thd->clear_current_stmt_binlog_format_row();
|
||||
|
||||
pthread_mutex_lock(&LOCK_event_metadata);
|
||||
|
||||
|
@ -563,8 +563,8 @@ Events::update_event(THD *thd, Event_parse_data *parse_data,
|
|||
Turn off row binlogging of this statement and use statement-based
|
||||
so that all supporting tables are updated for UPDATE EVENT command.
|
||||
*/
|
||||
if (thd->current_stmt_binlog_row_based)
|
||||
thd->clear_current_stmt_binlog_row_based();
|
||||
if (thd->is_current_stmt_binlog_format_row())
|
||||
thd->clear_current_stmt_binlog_format_row();
|
||||
|
||||
pthread_mutex_lock(&LOCK_event_metadata);
|
||||
|
||||
|
@ -660,8 +660,8 @@ Events::drop_event(THD *thd, LEX_STRING dbname, LEX_STRING name, bool if_exists)
|
|||
Turn off row binlogging of this statement and use statement-based so
|
||||
that all supporting tables are updated for DROP EVENT command.
|
||||
*/
|
||||
if (thd->current_stmt_binlog_row_based)
|
||||
thd->clear_current_stmt_binlog_row_based();
|
||||
if (thd->is_current_stmt_binlog_format_row())
|
||||
thd->clear_current_stmt_binlog_format_row();
|
||||
|
||||
pthread_mutex_lock(&LOCK_event_metadata);
|
||||
/* On error conditions my_error() is called so no need to handle here */
|
||||
|
|
|
@ -302,6 +302,7 @@ static void run_query(THD *thd, char *buf, char *end,
|
|||
thd->transaction.all= save_thd_transaction_all;
|
||||
thd->transaction.stmt= save_thd_transaction_stmt;
|
||||
thd->net= save_thd_net;
|
||||
thd->set_current_stmt_binlog_format_row();
|
||||
|
||||
if (thd == injector_thd)
|
||||
{
|
||||
|
@ -3647,6 +3648,7 @@ pthread_handler_t ndb_binlog_thread_func(void *arg)
|
|||
|
||||
thd= new THD; /* note that contructor of THD uses DBUG_ */
|
||||
THD_CHECK_SENTRY(thd);
|
||||
thd->set_current_stmt_binlog_format_row();
|
||||
|
||||
/* We need to set thd->thread_id before thd->store_globals, or it will
|
||||
set an invalid value for thd->variables.pseudo_thread_id.
|
||||
|
|
|
@ -6195,7 +6195,7 @@ void ha_partition::get_auto_increment(ulonglong offset, ulonglong increment,
|
|||
if (!auto_increment_safe_stmt_log_lock &&
|
||||
thd->lex->sql_command != SQLCOM_INSERT &&
|
||||
mysql_bin_log.is_open() &&
|
||||
!thd->current_stmt_binlog_row_based &&
|
||||
!thd->is_current_stmt_binlog_format_row() &&
|
||||
(thd->options & OPTION_BIN_LOG))
|
||||
{
|
||||
DBUG_PRINT("info", ("locking auto_increment_safe_stmt_log_lock"));
|
||||
|
|
|
@ -2416,7 +2416,7 @@ int handler::update_auto_increment()
|
|||
variables->auto_increment_increment);
|
||||
auto_inc_intervals_count++;
|
||||
/* Row-based replication does not need to store intervals in binlog */
|
||||
if (mysql_bin_log.is_open() && !thd->current_stmt_binlog_row_based)
|
||||
if (mysql_bin_log.is_open() && !thd->is_current_stmt_binlog_format_row())
|
||||
thd->auto_inc_intervals_in_cur_stmt_for_binlog.append(auto_inc_interval_for_cur_row.minimum(),
|
||||
auto_inc_interval_for_cur_row.values(),
|
||||
variables->auto_increment_increment);
|
||||
|
@ -4447,7 +4447,7 @@ static bool check_table_binlog_row_based(THD *thd, TABLE *table)
|
|||
DBUG_ASSERT(table->s->cached_row_logging_check == 0 ||
|
||||
table->s->cached_row_logging_check == 1);
|
||||
|
||||
return (thd->current_stmt_binlog_row_based &&
|
||||
return (thd->is_current_stmt_binlog_format_row() &&
|
||||
table->s->cached_row_logging_check &&
|
||||
(thd->options & OPTION_BIN_LOG) &&
|
||||
mysql_bin_log.is_open());
|
||||
|
|
|
@ -2375,10 +2375,11 @@ Create_udf_func::create(THD *thd, udf_func *udf, List<Item> *item_list)
|
|||
Item *func= NULL;
|
||||
int arg_count= 0;
|
||||
|
||||
DBUG_ENTER("Create_udf_func::create");
|
||||
if (item_list != NULL)
|
||||
arg_count= item_list->elements;
|
||||
|
||||
thd->lex->set_stmt_unsafe();
|
||||
thd->lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_UDF);
|
||||
|
||||
DBUG_ASSERT( (udf->type == UDFTYPE_FUNCTION)
|
||||
|| (udf->type == UDFTYPE_AGGREGATE));
|
||||
|
@ -2462,7 +2463,7 @@ Create_udf_func::create(THD *thd, udf_func *udf, List<Item> *item_list)
|
|||
}
|
||||
}
|
||||
thd->lex->safe_to_cache_query= 0;
|
||||
return func;
|
||||
DBUG_RETURN(func);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -3363,9 +3364,10 @@ Create_func_found_rows Create_func_found_rows::s_singleton;
|
|||
Item*
|
||||
Create_func_found_rows::create(THD *thd)
|
||||
{
|
||||
thd->lex->set_stmt_unsafe();
|
||||
DBUG_ENTER("Create_func_found_rows::create");
|
||||
thd->lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_SYSTEM_FUNCTION);
|
||||
thd->lex->safe_to_cache_query= 0;
|
||||
return new (thd->mem_root) Item_func_found_rows();
|
||||
DBUG_RETURN(new (thd->mem_root) Item_func_found_rows());
|
||||
}
|
||||
|
||||
|
||||
|
@ -3791,9 +3793,10 @@ Create_func_load_file Create_func_load_file::s_singleton;
|
|||
Item*
|
||||
Create_func_load_file::create(THD *thd, Item *arg1)
|
||||
{
|
||||
thd->lex->set_stmt_unsafe();
|
||||
DBUG_ENTER("Create_func_load_file::create");
|
||||
thd->lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_SYSTEM_FUNCTION);
|
||||
thd->lex->uncacheable(UNCACHEABLE_SIDEEFFECT);
|
||||
return new (thd->mem_root) Item_load_file(arg1);
|
||||
DBUG_RETURN(new (thd->mem_root) Item_load_file(arg1));
|
||||
}
|
||||
|
||||
|
||||
|
@ -4260,9 +4263,10 @@ Create_func_row_count Create_func_row_count::s_singleton;
|
|||
Item*
|
||||
Create_func_row_count::create(THD *thd)
|
||||
{
|
||||
thd->lex->set_stmt_unsafe();
|
||||
DBUG_ENTER("Create_func_row_count::create");
|
||||
thd->lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_SYSTEM_FUNCTION);
|
||||
thd->lex->safe_to_cache_query= 0;
|
||||
return new (thd->mem_root) Item_func_row_count();
|
||||
DBUG_RETURN(new (thd->mem_root) Item_func_row_count());
|
||||
}
|
||||
|
||||
|
||||
|
@ -4569,9 +4573,10 @@ Create_func_uuid Create_func_uuid::s_singleton;
|
|||
Item*
|
||||
Create_func_uuid::create(THD *thd)
|
||||
{
|
||||
thd->lex->set_stmt_unsafe();
|
||||
DBUG_ENTER("Create_func_uuid::create");
|
||||
thd->lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_SYSTEM_FUNCTION);
|
||||
thd->lex->safe_to_cache_query= 0;
|
||||
return new (thd->mem_root) Item_func_uuid();
|
||||
DBUG_RETURN(new (thd->mem_root) Item_func_uuid());
|
||||
}
|
||||
|
||||
|
||||
|
@ -4580,9 +4585,10 @@ Create_func_uuid_short Create_func_uuid_short::s_singleton;
|
|||
Item*
|
||||
Create_func_uuid_short::create(THD *thd)
|
||||
{
|
||||
thd->lex->set_stmt_unsafe();
|
||||
DBUG_ENTER("Create_func_uuid_short::create");
|
||||
thd->lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_SYSTEM_FUNCTION);
|
||||
thd->lex->safe_to_cache_query= 0;
|
||||
return new (thd->mem_root) Item_func_uuid_short();
|
||||
DBUG_RETURN(new (thd->mem_root) Item_func_uuid_short());
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -3837,7 +3837,7 @@ int THD::binlog_write_table_map(TABLE *table, bool is_trans)
|
|||
table->s->table_map_id));
|
||||
|
||||
/* Pre-conditions */
|
||||
DBUG_ASSERT(current_stmt_binlog_row_based && mysql_bin_log.is_open());
|
||||
DBUG_ASSERT(is_current_stmt_binlog_format_row() && mysql_bin_log.is_open());
|
||||
DBUG_ASSERT(table->s->table_map_id != ULONG_MAX);
|
||||
|
||||
Table_map_log_event::flag_set const
|
||||
|
@ -4114,7 +4114,7 @@ bool MYSQL_BIN_LOG::write(Log_event *event_info)
|
|||
*/
|
||||
if (thd)
|
||||
{
|
||||
if (!thd->current_stmt_binlog_row_based)
|
||||
if (!thd->is_current_stmt_binlog_format_row())
|
||||
{
|
||||
if (thd->stmt_depends_on_first_successful_insert_id_in_prev_stmt)
|
||||
{
|
||||
|
|
|
@ -7223,7 +7223,7 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli)
|
|||
|
||||
We also call the mysql_reset_thd_for_next_command(), since this
|
||||
is the logical start of the next "statement". Note that this
|
||||
call might reset the value of current_stmt_binlog_row_based, so
|
||||
call might reset the value of current_stmt_binlog_format, so
|
||||
we need to do any changes to that value after this function.
|
||||
*/
|
||||
lex_start(thd);
|
||||
|
@ -7235,16 +7235,12 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli)
|
|||
*/
|
||||
thd->transaction.stmt.modified_non_trans_table= FALSE;
|
||||
/*
|
||||
Check if the slave is set to use SBR. If so, it should switch
|
||||
to using RBR until the end of the "statement", i.e., next
|
||||
STMT_END_F or next error.
|
||||
This is a row injection, so we flag the "statement" as
|
||||
such. Note that this code is called both when the slave does row
|
||||
injections and when the BINLOG statement is used to do row
|
||||
injections.
|
||||
*/
|
||||
if (!thd->current_stmt_binlog_row_based &&
|
||||
mysql_bin_log.is_open() && (thd->options & OPTION_BIN_LOG))
|
||||
{
|
||||
thd->set_current_stmt_binlog_row_based();
|
||||
}
|
||||
|
||||
thd->lex->set_stmt_row_injection();
|
||||
|
||||
/*
|
||||
There are a few flags that are replicated with each row event.
|
||||
|
@ -7492,7 +7488,14 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli)
|
|||
slave_rows_error_report(ERROR_LEVEL, error, rli, thd, table,
|
||||
get_type_str(),
|
||||
RPL_LOG_NAME, (ulong) log_pos);
|
||||
thd->reset_current_stmt_binlog_row_based();
|
||||
/*
|
||||
@todo We should probably not call
|
||||
reset_current_stmt_binlog_format_row() from here.
|
||||
|
||||
Note: this applies to log_event_old.cc too.
|
||||
/Sven
|
||||
*/
|
||||
thd->reset_current_stmt_binlog_format_row();
|
||||
const_cast<Relay_log_info*>(rli)->cleanup_context(thd, error);
|
||||
thd->is_slave_error= 1;
|
||||
}
|
||||
|
@ -7593,7 +7596,17 @@ static int rows_event_stmt_cleanup(Relay_log_info const *rli, THD * thd)
|
|||
event flushed.
|
||||
*/
|
||||
|
||||
thd->reset_current_stmt_binlog_row_based();
|
||||
/*
|
||||
@todo We should probably not call
|
||||
reset_current_stmt_binlog_format_row() from here.
|
||||
|
||||
Note: this applies to log_event_old.cc too
|
||||
|
||||
Btw, the previous comment about transactional engines does not
|
||||
seem related to anything that happens here.
|
||||
/Sven
|
||||
*/
|
||||
thd->reset_current_stmt_binlog_format_row();
|
||||
|
||||
const_cast<Relay_log_info*>(rli)->cleanup_context(thd, 0);
|
||||
}
|
||||
|
|
|
@ -59,22 +59,19 @@ Old_rows_log_event::do_apply_event(Old_rows_log_event *ev, const Relay_log_info
|
|||
|
||||
We also call the mysql_reset_thd_for_next_command(), since this
|
||||
is the logical start of the next "statement". Note that this
|
||||
call might reset the value of current_stmt_binlog_row_based, so
|
||||
call might reset the value of current_stmt_binlog_format, so
|
||||
we need to do any changes to that value after this function.
|
||||
*/
|
||||
lex_start(thd);
|
||||
mysql_reset_thd_for_next_command(thd);
|
||||
|
||||
/*
|
||||
Check if the slave is set to use SBR. If so, it should switch
|
||||
to using RBR until the end of the "statement", i.e., next
|
||||
STMT_END_F or next error.
|
||||
This is a row injection, so we flag the "statement" as
|
||||
such. Note that this code is called both when the slave does row
|
||||
injections and when the BINLOG statement is used to do row
|
||||
injections.
|
||||
*/
|
||||
if (!thd->current_stmt_binlog_row_based &&
|
||||
mysql_bin_log.is_open() && (thd->options & OPTION_BIN_LOG))
|
||||
{
|
||||
thd->set_current_stmt_binlog_row_based();
|
||||
}
|
||||
thd->lex->set_stmt_row_injection();
|
||||
|
||||
if (simple_open_n_lock_tables(thd, rli->tables_to_lock))
|
||||
{
|
||||
|
@ -263,7 +260,7 @@ Old_rows_log_event::do_apply_event(Old_rows_log_event *ev, const Relay_log_info
|
|||
thread is certainly going to stop.
|
||||
rollback at the caller along with sbr.
|
||||
*/
|
||||
thd->reset_current_stmt_binlog_row_based();
|
||||
thd->reset_current_stmt_binlog_format_row();
|
||||
const_cast<Relay_log_info*>(rli)->cleanup_context(thd, error);
|
||||
thd->is_slave_error= 1;
|
||||
DBUG_RETURN(error);
|
||||
|
@ -1781,7 +1778,7 @@ int Old_rows_log_event::do_apply_event(Relay_log_info const *rli)
|
|||
thread is certainly going to stop.
|
||||
rollback at the caller along with sbr.
|
||||
*/
|
||||
thd->reset_current_stmt_binlog_row_based();
|
||||
thd->reset_current_stmt_binlog_format_row();
|
||||
const_cast<Relay_log_info*>(rli)->cleanup_context(thd, error);
|
||||
thd->is_slave_error= 1;
|
||||
DBUG_RETURN(error);
|
||||
|
@ -1881,7 +1878,7 @@ Old_rows_log_event::do_update_pos(Relay_log_info *rli)
|
|||
event flushed.
|
||||
*/
|
||||
|
||||
thd->reset_current_stmt_binlog_row_based();
|
||||
thd->reset_current_stmt_binlog_format_row();
|
||||
rli->cleanup_context(thd, 0);
|
||||
if (error == 0)
|
||||
{
|
||||
|
|
|
@ -1566,7 +1566,6 @@ TABLE *open_n_lock_single_table(THD *thd, TABLE_LIST *table_l,
|
|||
thr_lock_type lock_type);
|
||||
bool open_normal_and_derived_tables(THD *thd, TABLE_LIST *tables, uint flags);
|
||||
int lock_tables(THD *thd, TABLE_LIST *tables, uint counter, bool *need_reopen);
|
||||
int decide_logging_format(THD *thd, TABLE_LIST *tables);
|
||||
TABLE *open_temporary_table(THD *thd, const char *path, const char *db,
|
||||
const char *table_name, bool link_in_list);
|
||||
bool rm_temporary_table(handlerton *base, char *path);
|
||||
|
|
|
@ -36,8 +36,6 @@ injector::transaction::transaction(MYSQL_BIN_LOG *log, THD *thd)
|
|||
m_start_pos.m_file_pos= log_info.pos;
|
||||
|
||||
begin_trans(m_thd);
|
||||
|
||||
thd->set_current_stmt_binlog_row_based();
|
||||
}
|
||||
|
||||
injector::transaction::~transaction()
|
||||
|
|
|
@ -1292,7 +1292,12 @@ bool sys_var_thd_binlog_format::is_readonly() const
|
|||
|
||||
void fix_binlog_format_after_update(THD *thd, enum_var_type type)
|
||||
{
|
||||
thd->reset_current_stmt_binlog_row_based();
|
||||
/*
|
||||
@todo This function should be eliminated. We should not set the
|
||||
current binlog format anywhere else than in decide_logging_format.
|
||||
/Sven
|
||||
*/
|
||||
thd->reset_current_stmt_binlog_format_row();
|
||||
}
|
||||
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue