mirror of
https://github.com/MariaDB/server.git
synced 2025-01-18 04:53:01 +01:00
702 lines
23 KiB
Text
702 lines
23 KiB
Text
# ==== 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 ====
|
|
#
|
|
# This test verifies that a warning is generated when it should,
|
|
# according to the rules above.
|
|
#
|
|
# All @@variables should be unsafe, with some exceptions. Therefore,
|
|
# this test also verifies that the exceptions do *not* generate a
|
|
# warning.
|
|
#
|
|
#
|
|
# ==== Method ====
|
|
#
|
|
# 1. Each type of statements listed above is executed.
|
|
#
|
|
# 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.
|
|
#
|
|
# Execute a unsafe statement calling a trigger or stored function
|
|
# or neither when SQL_LOG_BIN is turned ON, a warning/error should be issued
|
|
# 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
|
|
# BUG#31168: @@hostname does not replicate
|
|
# BUG#34732: mysqlbinlog does not print default values for auto_increment variables
|
|
# 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
|
|
# BUG#47995: Mark user functions as unsafe
|
|
# BUG#49222: Mark RAND() unsafe
|
|
#
|
|
# ==== Related test cases ====
|
|
#
|
|
# rpl.rpl_variables verifies that variables which cannot be replicated
|
|
# safely in statement mode are replicated correctly in mixed or row
|
|
# mode.
|
|
#
|
|
# rpl.rpl_variables_stm tests the small subset of variables that
|
|
# actually can be replicated safely in statement mode.
|
|
#
|
|
# rpl_ndb.rpl_ndb_binlog_format_errors tests all errors and warnings
|
|
# related to logging format (not just 'Unsafe statement written to the
|
|
# binary log using statement format since BINLOG_FORMAT = STATEMENT').
|
|
|
|
--source include/have_udf.inc
|
|
--source include/have_log_bin.inc
|
|
--source include/have_binlog_format_statement.inc
|
|
|
|
--disable_query_log
|
|
call mtr.add_suppression("Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT");
|
|
--enable_query_log
|
|
|
|
--echo #### Setup tables ####
|
|
|
|
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);
|
|
|
|
--DELIMITER |
|
|
CREATE TRIGGER double_autoinc_trig
|
|
BEFORE INSERT ON double_autoinc_table FOR EACH ROW
|
|
BEGIN
|
|
INSERT INTO autoinc_table VALUES (NULL);
|
|
END|
|
|
|
|
CREATE FUNCTION multi_unsafe_func() RETURNS INT
|
|
BEGIN
|
|
INSERT INTO t0 VALUES(CONCAT(@@hostname, @@hostname));
|
|
INSERT INTO t0 VALUES(0);
|
|
INSERT INTO t0 VALUES(CONCAT(UUID(), @@hostname));
|
|
RETURN 1;
|
|
END|
|
|
--DELIMITER ;
|
|
|
|
--replace_result $UDF_EXAMPLE_LIB UDF_EXAMPLE_LIB
|
|
--eval CREATE FUNCTION myfunc_int RETURNS INTEGER SONAME "$UDF_EXAMPLE_LIB"
|
|
|
|
# In each iteration of this loop, we select one method to make the
|
|
# statement unsafe.
|
|
--let $unsafe_type= 0
|
|
while (`SELECT $unsafe_type < 9`) {
|
|
|
|
--echo
|
|
|
|
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
|
|
}
|
|
|
|
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=
|
|
--let $CRC_ARG_expected_number_of_warnings= 1
|
|
}
|
|
|
|
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=
|
|
--let $CRC_ARG_expected_number_of_warnings= 7
|
|
}
|
|
|
|
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 ==== 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.auto_increment_increment);
|
|
INSERT INTO t1 VALUES (@@session.auto_increment_offset);
|
|
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 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);
|
|
|
|
|
|
DROP TABLE t1, autoinc_table;
|
|
|
|
|
|
#
|
|
# BUG#34768 - nondeterministic INSERT using LIMIT logged in stmt mode if
|
|
# binlog_format=mixed
|
|
#
|
|
CREATE TABLE t1(a INT, b INT, KEY(a), PRIMARY KEY(b));
|
|
INSERT INTO t1 SELECT * FROM t1 LIMIT 1;
|
|
REPLACE INTO t1 SELECT * FROM t1 LIMIT 1;
|
|
UPDATE t1 SET a=1 LIMIT 1;
|
|
DELETE FROM t1 LIMIT 1;
|
|
delimiter |;
|
|
CREATE PROCEDURE p1()
|
|
BEGIN
|
|
INSERT INTO t1 SELECT * FROM t1 LIMIT 1;
|
|
REPLACE INTO t1 SELECT * FROM t1 LIMIT 1;
|
|
UPDATE t1 SET a=1 LIMIT 1;
|
|
DELETE FROM t1 LIMIT 1;
|
|
END|
|
|
delimiter ;|
|
|
CALL p1();
|
|
DROP PROCEDURE p1;
|
|
DROP TABLE t1;
|
|
|
|
#
|
|
# Bug#42634: % character in query can cause mysqld signal 11 segfault
|
|
#
|
|
|
|
--disable_warnings
|
|
DROP TABLE IF EXISTS t1;
|
|
--enable_warnings
|
|
|
|
CREATE TABLE t1 (a VARCHAR(100), b VARCHAR(100));
|
|
INSERT INTO t1 VALUES ('a','b');
|
|
UPDATE t1 SET b = '%s%s%s%s%s%s%s%s%s%s%s%s%s%s' WHERE a = 'a' LIMIT 1;
|
|
DROP TABLE t1;
|
|
|
|
#
|
|
#For bug#41980, SBL, INSERT .. SELECT .. LIMIT = ERROR, even when @@SQL_LOG_BIN is 0
|
|
#
|
|
|
|
--disable_warnings
|
|
DROP TABLE IF EXISTS t1, t2;
|
|
--enable_warnings
|
|
CREATE TABLE t1(i INT PRIMARY KEY);
|
|
CREATE TABLE t2(i INT PRIMARY KEY);
|
|
CREATE TABLE t3(i INT, ch CHAR(50));
|
|
|
|
--echo "Should issue message Statement may not be safe to log in statement format."
|
|
INSERT INTO t1 SELECT * FROM t2 LIMIT 1;
|
|
|
|
DELIMITER |;
|
|
CREATE FUNCTION func6()
|
|
RETURNS INT
|
|
BEGIN
|
|
INSERT INTO t1 VALUES (10);
|
|
INSERT INTO t1 VALUES (11);
|
|
INSERT INTO t1 VALUES (12);
|
|
RETURN 0;
|
|
END|
|
|
DELIMITER ;|
|
|
--echo "Should issue message Statement may not be safe to log in statement format only once"
|
|
INSERT INTO t3 VALUES(func6(), UUID());
|
|
|
|
--echo "Check whether SET @@SQL_LOG_BIN = 0/1 doesn't work in substatements"
|
|
DELIMITER |;
|
|
CREATE FUNCTION fun_check_log_bin() RETURNS INT
|
|
BEGIN
|
|
SET @@SQL_LOG_BIN = 0;
|
|
INSERT INTO t1 VALUES(@@global.sync_binlog);
|
|
RETURN 100;
|
|
END|
|
|
DELIMITER ;|
|
|
--echo "One unsafe warning should be issued in the following statement"
|
|
SELECT fun_check_log_bin();
|
|
--echo "SQL_LOG_BIN should be ON still"
|
|
SHOW VARIABLES LIKE "SQL_LOG_BIN";
|
|
|
|
set @save_log_bin = @@SESSION.SQL_LOG_BIN;
|
|
set @@SESSION.SQL_LOG_BIN = 0;
|
|
--echo "Should NOT have any warning message issued in the following statements"
|
|
INSERT INTO t1 SELECT * FROM t2 LIMIT 1;
|
|
DROP TABLE t1,t2;
|
|
|
|
--echo "Should NOT have any warning message issued in the following func7() and trig"
|
|
CREATE TABLE t1 (a INT);
|
|
CREATE TABLE t2 (a CHAR(40));
|
|
CREATE TABLE trigger_table (a CHAR(7));
|
|
DELIMITER |;
|
|
CREATE FUNCTION func7()
|
|
RETURNS INT
|
|
BEGIN
|
|
INSERT INTO t1 VALUES (@@global.sync_binlog);
|
|
INSERT INTO t1 VALUES (@@session.insert_id);
|
|
INSERT INTO t2 SELECT UUID();
|
|
INSERT INTO t2 VALUES (@@session.sql_mode);
|
|
INSERT INTO t2 VALUES (@@global.init_slave);
|
|
RETURN 0;
|
|
END|
|
|
DELIMITER ;|
|
|
SHOW VARIABLES LIKE "SQL_LOG_BIN";
|
|
SELECT func7();
|
|
|
|
--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.');
|
|
|
|
#clean up
|
|
DROP FUNCTION fun_check_log_bin;
|
|
DROP FUNCTION func6;
|
|
DROP FUNCTION func7;
|
|
DROP TRIGGER trig;
|
|
DROP TABLE t1, t2, t3, trigger_table;
|
|
set @@SESSION.SQL_LOG_BIN = @save_log_bin;
|
|
|
|
#
|
|
# For BUG#42640: mysqld crashes when unsafe statements are executed (STRICT_TRANS_TABLES mode)
|
|
#
|
|
SET @save_sql_mode = @@SESSION.SQL_MODE;
|
|
SET @@SESSION.SQL_MODE = STRICT_ALL_TABLES;
|
|
|
|
CREATE TABLE t1(i INT PRIMARY KEY);
|
|
CREATE TABLE t2(i INT PRIMARY KEY);
|
|
|
|
INSERT INTO t1 SELECT * FROM t2 LIMIT 1;
|
|
INSERT INTO t1 VALUES(@@global.sync_binlog);
|
|
|
|
UPDATE t1 SET i = 999 LIMIT 1;
|
|
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;
|
|
|
|
#
|
|
# BUG#45827
|
|
# The test verifies if stmt that have more than one
|
|
# different tables to update with autoinc columns
|
|
# will produce unsafe warning
|
|
#
|
|
|
|
# Test case1: stmt that have more than one different tables
|
|
# to update with autoinc columns should produce
|
|
# unsafe warning when calling a function
|
|
CREATE TABLE t1 (a INT, b INT PRIMARY KEY AUTO_INCREMENT);
|
|
CREATE TABLE t2 (a INT, b INT PRIMARY KEY AUTO_INCREMENT);
|
|
|
|
# The purpose of this function is to insert into t1 so that the second
|
|
# column is auto_increment'ed.
|
|
DELIMITER |;
|
|
CREATE FUNCTION func_modify_t1 ()
|
|
RETURNS INT
|
|
BEGIN
|
|
INSERT INTO t1 SET a = 1;
|
|
RETURN 0;
|
|
END|
|
|
DELIMITER ;|
|
|
--echo # The following statement causes auto-incrementation
|
|
--echo # of both t1 and t2. It is logged in statement format,
|
|
--echo # so it should produce unsafe warning.
|
|
INSERT INTO t2 SET a = func_modify_t1();
|
|
|
|
SET SESSION binlog_format = MIXED;
|
|
--echo # Check if the statement is logged in row format.
|
|
let $binlog_start= query_get_value(SHOW MASTER STATUS, Position, 1);
|
|
INSERT INTO t2 SET a = func_modify_t1();
|
|
--source include/show_binlog_events.inc
|
|
|
|
# clean up
|
|
DROP TABLE t1,t2;
|
|
DROP FUNCTION func_modify_t1;
|
|
#
|
|
# Test case2: stmt that have more than one different tables
|
|
# to update with autoinc columns should produce
|
|
# unsafe warning when invoking a trigger
|
|
SET SESSION binlog_format = STATEMENT;
|
|
CREATE TABLE t1 (a INT);
|
|
CREATE TABLE t2 (a INT, b INT PRIMARY KEY AUTO_INCREMENT);
|
|
CREATE TABLE t3 (a INT, b INT PRIMARY KEY AUTO_INCREMENT);
|
|
|
|
# The purpose of this function is to insert into t1 so that the second
|
|
# column is auto_increment'ed.
|
|
delimiter |;
|
|
create trigger tri_modify_two_tables before insert on t1 for each row begin
|
|
insert into t2(a) values(new.a);
|
|
insert into t3(a) values(new.a);
|
|
end |
|
|
delimiter ;|
|
|
--echo # The following statement causes auto-incrementation
|
|
--echo # of both t2 and t3. It is logged in statement format,
|
|
--echo # so it should produce unsafe warning
|
|
INSERT INTO t1 SET a = 1;
|
|
|
|
SET SESSION binlog_format = MIXED;
|
|
--echo # Check if the statement is logged in row format.
|
|
let $binlog_start= query_get_value(SHOW MASTER STATUS, Position, 1);
|
|
INSERT INTO t1 SET a = 2;
|
|
--source include/show_binlog_events.inc
|
|
|
|
# clean up
|
|
DROP TABLE t1,t2,t3;
|
|
|
|
#
|
|
# BUG#47995: Mark user functions as unsafe
|
|
# BUG#49222: Mare RAND() unsafe
|
|
#
|
|
# Test that the system functions that are supposed to be marked unsafe
|
|
# generate a warning. Each INSERT statement below should generate a
|
|
# warning.
|
|
#
|
|
SET SESSION binlog_format = STATEMENT;
|
|
|
|
CREATE TABLE t1 (a VARCHAR(1000));
|
|
INSERT INTO t1 VALUES (CURRENT_USER()); #marked unsafe before BUG#47995
|
|
INSERT INTO t1 VALUES (FOUND_ROWS()); #marked unsafe before BUG#47995
|
|
INSERT INTO t1 VALUES (GET_LOCK('tmp', 1)); #marked unsafe in BUG#47995
|
|
INSERT INTO t1 VALUES (IS_FREE_LOCK('tmp')); #marked unsafe in BUG#47995
|
|
INSERT INTO t1 VALUES (IS_USED_LOCK('tmp')); #marked unsafe in BUG#47995
|
|
INSERT INTO t1 VALUES (LOAD_FILE('../../std_data/words2.dat')); #marked unsafe in BUG#39701
|
|
INSERT INTO t1 VALUES (MASTER_POS_WAIT('dummy arg', 4711, 1));
|
|
INSERT INTO t1 VALUES (RELEASE_LOCK('tmp')); #marked unsafe in BUG#47995
|
|
INSERT INTO t1 VALUES (ROW_COUNT()); #marked unsafe before BUG#47995
|
|
INSERT INTO t1 VALUES (SESSION_USER()); #marked unsafe before BUG#47995
|
|
INSERT INTO t1 VALUES (SLEEP(1)); #marked unsafe in BUG#47995
|
|
INSERT INTO t1 VALUES (SYSDATE()); #marked unsafe in BUG#47995
|
|
INSERT INTO t1 VALUES (SYSTEM_USER()); #marked unsafe before BUG#47995
|
|
INSERT INTO t1 VALUES (USER()); #marked unsafe before BUG#47995
|
|
INSERT INTO t1 VALUES (UUID()); #marked unsafe before BUG#47995
|
|
INSERT INTO t1 VALUES (UUID_SHORT()); #marked unsafe before BUG#47995
|
|
INSERT INTO t1 VALUES (VERSION()); #marked unsafe in BUG#47995
|
|
INSERT INTO t1 VALUES (RAND()); #marked unsafe in BUG#49222
|
|
DELETE FROM t1;
|
|
|
|
# Since we replicate the TIMESTAMP variable, functions affected by the
|
|
# TIMESTAMP variable are safe to replicate. So we check that the
|
|
# following following functions that depend on the TIMESTAMP variable
|
|
# are not unsafe and don't generate a warning.
|
|
|
|
SET TIMESTAMP=1000000;
|
|
INSERT INTO t1 VALUES
|
|
(CURDATE()),
|
|
(CURRENT_DATE()),
|
|
(CURRENT_TIME()),
|
|
(CURRENT_TIMESTAMP()),
|
|
(CURTIME()),
|
|
(LOCALTIME()),
|
|
(LOCALTIMESTAMP()),
|
|
(NOW()),
|
|
(UNIX_TIMESTAMP()),
|
|
(UTC_DATE()),
|
|
(UTC_TIME()),
|
|
(UTC_TIMESTAMP());
|
|
SELECT * FROM t1;
|
|
|
|
DROP TABLE t1;
|
|
|
|
--echo "End of tests"
|