BUG#34768 - nondeterministic INSERT using LIMIT logged in stmt mode if
binlog_format=mixed Statement-based replication of DELETE ... LIMIT, UPDATE ... LIMIT, INSERT ... SELECT ... LIMIT is not safe as order of rows is not defined. With this fix, we issue a warning that this statement is not safe to replicate in statement mode, or go to row-based mode in mixed mode. Note that we may consider a statement as safe if ORDER BY primary_key is present. However it may confuse users to see very similiar statements replicated differently. Note 2: regular UPDATE statement (w/o LIMIT) is unsafe as well, but this patch doesn't address this issue. See comment from Kristian posted 18 Mar 10:55.
This commit is contained in:
parent
bdc74bbda7
commit
6dfb184f09
@ -16,5 +16,6 @@ master-bin.000001 # Query # # use `test`; create table t1 (a int)
|
|||||||
master-bin.000001 # User var # # @`a`=98
|
master-bin.000001 # User var # # @`a`=98
|
||||||
master-bin.000001 # Query # # use `test`; insert into t1 values (@a),(98)
|
master-bin.000001 # Query # # use `test`; insert into t1 values (@a),(98)
|
||||||
master-bin.000001 # Query # # use `test`; insert into t1 values (99)
|
master-bin.000001 # Query # # use `test`; insert into t1 values (99)
|
||||||
master-bin.000001 # Query # # use `test`; insert into t1 select 100 limit 100
|
master-bin.000001 # Table_map # # table_id: # (test.t1)
|
||||||
|
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
|
||||||
drop table t1;
|
drop table t1;
|
||||||
|
@ -11,3 +11,31 @@ Level Warning
|
|||||||
Code 1592
|
Code 1592
|
||||||
Message Statement is not safe to log in statement format.
|
Message Statement is not safe to log in statement format.
|
||||||
DROP TABLE t1,t2,t3;
|
DROP TABLE t1,t2,t3;
|
||||||
|
CREATE TABLE t1(a INT, b INT, KEY(a), PRIMARY KEY(b));
|
||||||
|
INSERT INTO t1 SELECT * FROM t1 LIMIT 1;
|
||||||
|
Warnings:
|
||||||
|
Warning 1592 Statement is not safe to log in statement format.
|
||||||
|
REPLACE INTO t1 SELECT * FROM t1 LIMIT 1;
|
||||||
|
Warnings:
|
||||||
|
Warning 1592 Statement is not safe to log in statement format.
|
||||||
|
UPDATE t1 SET a=1 LIMIT 1;
|
||||||
|
Warnings:
|
||||||
|
Warning 1592 Statement is not safe to log in statement format.
|
||||||
|
DELETE FROM t1 LIMIT 1;
|
||||||
|
Warnings:
|
||||||
|
Warning 1592 Statement is not safe to log in statement format.
|
||||||
|
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|
|
||||||
|
CALL p1();
|
||||||
|
Warnings:
|
||||||
|
Warning 1592 Statement is not safe to log in statement format.
|
||||||
|
Warning 1592 Statement is not safe to log in statement format.
|
||||||
|
Warning 1592 Statement is not safe to log in statement format.
|
||||||
|
Warning 1592 Statement is not safe to log in statement format.
|
||||||
|
DROP PROCEDURE p1;
|
||||||
|
DROP TABLE t1;
|
||||||
|
@ -15,4 +15,24 @@ query_vertical SHOW WARNINGS;
|
|||||||
|
|
||||||
DROP TABLE t1,t2,t3;
|
DROP TABLE t1,t2,t3;
|
||||||
|
|
||||||
|
#
|
||||||
|
# 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;
|
||||||
|
@ -418,6 +418,19 @@ bool mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds)
|
|||||||
DBUG_ENTER("mysql_prepare_delete");
|
DBUG_ENTER("mysql_prepare_delete");
|
||||||
List<Item> all_fields;
|
List<Item> all_fields;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Statement-based replication of DELETE ... LIMIT is not safe as order of
|
||||||
|
rows is not defined, so in mixed mode we go to row-based.
|
||||||
|
|
||||||
|
Note that we may consider a statement as safe if ORDER BY primary_key
|
||||||
|
is present. However it may confuse users to see very similiar statements
|
||||||
|
replicated differently.
|
||||||
|
*/
|
||||||
|
if (thd->lex->current_select->select_limit)
|
||||||
|
{
|
||||||
|
thd->lex->set_stmt_unsafe();
|
||||||
|
thd->set_current_stmt_binlog_row_based_if_mixed();
|
||||||
|
}
|
||||||
thd->lex->allow_sum_func= 0;
|
thd->lex->allow_sum_func= 0;
|
||||||
if (setup_tables_and_check_access(thd, &thd->lex->select_lex.context,
|
if (setup_tables_and_check_access(thd, &thd->lex->select_lex.context,
|
||||||
&thd->lex->select_lex.top_join_list,
|
&thd->lex->select_lex.top_join_list,
|
||||||
|
@ -2763,6 +2763,19 @@ bool mysql_insert_select_prepare(THD *thd)
|
|||||||
TABLE_LIST *first_select_leaf_table;
|
TABLE_LIST *first_select_leaf_table;
|
||||||
DBUG_ENTER("mysql_insert_select_prepare");
|
DBUG_ENTER("mysql_insert_select_prepare");
|
||||||
|
|
||||||
|
/*
|
||||||
|
Statement-based replication of INSERT ... SELECT ... LIMIT is not safe
|
||||||
|
as order of rows is not defined, so in mixed mode we go to row-based.
|
||||||
|
|
||||||
|
Note that we may consider a statement as safe if ORDER BY primary_key
|
||||||
|
is present or we SELECT a constant. However it may confuse users to
|
||||||
|
see very similiar statements replicated differently.
|
||||||
|
*/
|
||||||
|
if (lex->current_select->select_limit)
|
||||||
|
{
|
||||||
|
lex->set_stmt_unsafe();
|
||||||
|
thd->set_current_stmt_binlog_row_based_if_mixed();
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
SELECT_LEX do not belong to INSERT statement, so we can't add WHERE
|
SELECT_LEX do not belong to INSERT statement, so we can't add WHERE
|
||||||
clause if table is VIEW
|
clause if table is VIEW
|
||||||
|
@ -859,6 +859,19 @@ bool mysql_prepare_update(THD *thd, TABLE_LIST *table_list,
|
|||||||
SELECT_LEX *select_lex= &thd->lex->select_lex;
|
SELECT_LEX *select_lex= &thd->lex->select_lex;
|
||||||
DBUG_ENTER("mysql_prepare_update");
|
DBUG_ENTER("mysql_prepare_update");
|
||||||
|
|
||||||
|
/*
|
||||||
|
Statement-based replication of UPDATE ... LIMIT is not safe as order of
|
||||||
|
rows is not defined, so in mixed mode we go to row-based.
|
||||||
|
|
||||||
|
Note that we may consider a statement as safe if ORDER BY primary_key
|
||||||
|
is present. However it may confuse users to see very similiar statements
|
||||||
|
replicated differently.
|
||||||
|
*/
|
||||||
|
if (thd->lex->current_select->select_limit)
|
||||||
|
{
|
||||||
|
thd->lex->set_stmt_unsafe();
|
||||||
|
thd->set_current_stmt_binlog_row_based_if_mixed();
|
||||||
|
}
|
||||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||||
table_list->grant.want_privilege= table->grant.want_privilege=
|
table_list->grant.want_privilege= table->grant.want_privilege=
|
||||||
(SELECT_ACL & ~table->grant.privilege);
|
(SELECT_ACL & ~table->grant.privilege);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user