Simplify THD::decide_logging_format()

Fixed some test for future when DELETE will not trigger row based replication
This commit is contained in:
Monty 2016-05-28 01:15:39 +03:00 committed by Sergei Golubchik
parent 6c173324ff
commit 60916a8b9e
3 changed files with 58 additions and 118 deletions

View File

@ -31,7 +31,8 @@ CREATE TABLE t3 ( i1 INT NOT NULL AUTO_INCREMENT, PRIMARY KEY (i1) );
CREATE TRIGGER tr1 AFTER DELETE ON t2 FOR EACH ROW INSERT INTO t3 () VALUES (); CREATE TRIGGER tr1 AFTER DELETE ON t2 FOR EACH ROW INSERT INTO t3 () VALUES ();
CREATE TEMPORARY TABLE t1_tmp (i1 int); CREATE TEMPORARY TABLE t1_tmp (i1 int);
ALTER TABLE t1_tmp ADD COLUMN b INT; ALTER TABLE t1_tmp ADD COLUMN b INT;
DELETE FROM t2; INSERT INTO t1 values(1);
INSERT INTO t2 (i1) select * from t1;
CREATE TEMPORARY TABLE t2_tmp (a int); CREATE TEMPORARY TABLE t2_tmp (a int);
ALTER TABLE t1_tmp ADD COLUMN c INT; ALTER TABLE t1_tmp ADD COLUMN c INT;
### assertion: assert that there is one open temp table on slave ### assertion: assert that there is one open temp table on slave
@ -66,6 +67,13 @@ slave-bin.000001 # Gtid # # GTID #-#-#
slave-bin.000001 # Query # # use `test`; CREATE TEMPORARY TABLE t1_tmp (i1 int) slave-bin.000001 # Query # # use `test`; CREATE TEMPORARY TABLE t1_tmp (i1 int)
slave-bin.000001 # Gtid # # GTID #-#-# slave-bin.000001 # Gtid # # GTID #-#-#
slave-bin.000001 # Query # # use `test`; ALTER TABLE t1_tmp ADD COLUMN b INT slave-bin.000001 # Query # # use `test`; ALTER TABLE t1_tmp ADD COLUMN b INT
slave-bin.000001 # Gtid # # BEGIN GTID #-#-#
slave-bin.000001 # Query # # use `test`; INSERT INTO t1 values(1)
slave-bin.000001 # Xid # # COMMIT /* XID */
slave-bin.000001 # Gtid # # BEGIN GTID #-#-#
slave-bin.000001 # Table_map # # table_id: # (test.t2)
slave-bin.000001 # Write_rows_v1 # # table_id: # flags: STMT_END_F
slave-bin.000001 # Query # # COMMIT
slave-bin.000001 # Gtid # # GTID #-#-# slave-bin.000001 # Gtid # # GTID #-#-#
slave-bin.000001 # Query # # DROP TEMPORARY TABLE IF EXISTS `test`.`t1_tmp` /* generated by server */ slave-bin.000001 # Query # # DROP TEMPORARY TABLE IF EXISTS `test`.`t1_tmp` /* generated by server */
slave-bin.000001 # Gtid # # GTID #-#-# slave-bin.000001 # Gtid # # GTID #-#-#

View File

@ -102,7 +102,8 @@ CREATE TEMPORARY TABLE t1_tmp (i1 int);
ALTER TABLE t1_tmp ADD COLUMN b INT; ALTER TABLE t1_tmp ADD COLUMN b INT;
# action: force switch to RBR # action: force switch to RBR
DELETE FROM t2; INSERT INTO t1 values(1);
INSERT INTO t2 (i1) select * from t1;
# assertion: assert that t2_tmp will not make into the binlog (RBR logging atm) # assertion: assert that t2_tmp will not make into the binlog (RBR logging atm)
CREATE TEMPORARY TABLE t2_tmp (a int); CREATE TEMPORARY TABLE t2_tmp (a int);

View File

@ -5528,94 +5528,6 @@ int xid_cache_iterate(THD *thd, my_hash_walk_action action, void *arg)
&argument); &argument);
} }
/*
Tells if two (or more) tables have auto_increment columns and we want to
lock those tables with a write lock.
SYNOPSIS
has_two_write_locked_tables_with_auto_increment
tables Table list
NOTES:
Call this function only when you have established the list of all tables
which you'll want to update (including stored functions, triggers, views
inside your statement).
*/
static bool
has_write_table_with_auto_increment(TABLE_LIST *tables)
{
for (TABLE_LIST *table= tables; table; table= table->next_global)
{
/* we must do preliminary checks as table->table may be NULL */
if (!table->placeholder() &&
table->table->found_next_number_field &&
(table->lock_type >= TL_WRITE_ALLOW_WRITE))
return 1;
}
return 0;
}
/*
checks if we have select tables in the table list and write tables
with auto-increment column.
SYNOPSIS
has_two_write_locked_tables_with_auto_increment_and_select
tables Table list
RETURN VALUES
-true if the table list has atleast one table with auto-increment column
and atleast one table to select from.
-false otherwise
*/
static bool
has_write_table_with_auto_increment_and_select(TABLE_LIST *tables)
{
bool has_select= false;
bool has_auto_increment_tables = has_write_table_with_auto_increment(tables);
for(TABLE_LIST *table= tables; table; table= table->next_global)
{
if (!table->placeholder() &&
(table->lock_type <= TL_READ_NO_INSERT))
{
has_select= true;
break;
}
}
return(has_select && has_auto_increment_tables);
}
/*
Tells if there is a table whose auto_increment column is a part
of a compound primary key while is not the first column in
the table definition.
@param tables Table list
@return true if the table exists, fais if does not.
*/
static bool
has_write_table_auto_increment_not_first_in_pk(TABLE_LIST *tables)
{
for (TABLE_LIST *table= tables; table; table= table->next_global)
{
/* we must do preliminary checks as table->table may be NULL */
if (!table->placeholder() &&
table->table->found_next_number_field &&
(table->lock_type >= TL_WRITE_ALLOW_WRITE)
&& table->table->s->next_number_keypart != 0)
return 1;
}
return 0;
}
/** /**
Decide on logging format to use for the statement and issue errors Decide on logging format to use for the statement and issue errors
@ -5746,17 +5658,24 @@ int THD::decide_logging_format(TABLE_LIST *tables)
If different types of engines are about to be updated. If different types of engines are about to be updated.
For example: Innodb and Falcon; Innodb and MyIsam. For example: Innodb and Falcon; Innodb and MyIsam.
*/ */
my_bool multi_write_engine= FALSE; bool multi_write_engine= FALSE;
/* /*
If different types of engines are about to be accessed If different types of engines are about to be accessed
and any of them is about to be updated. For example: and any of them is about to be updated. For example:
Innodb and Falcon; Innodb and MyIsam. Innodb and Falcon; Innodb and MyIsam.
*/ */
my_bool multi_access_engine= FALSE; bool multi_access_engine= FALSE;
/* /*
Identifies if a table is changed. Identifies if a table is changed.
*/ */
my_bool is_write= FALSE; bool is_write= FALSE; // If any write tables
bool has_read_tables= FALSE; // If any read only tables
bool has_auto_increment_write_tables= FALSE; // Write with auto-increment
/* If a write table that doesn't have auto increment part first */
bool has_write_table_auto_increment_not_first_in_pk= FALSE;
bool has_auto_increment_write_tables_not_first= FALSE;
bool found_first_not_own_table= FALSE;
/* /*
A pointer to a previous table that was changed. A pointer to a previous table that was changed.
*/ */
@ -5800,31 +5719,6 @@ int THD::decide_logging_format(TABLE_LIST *tables)
} }
#endif #endif
if (wsrep_binlog_format() != BINLOG_FORMAT_ROW && tables)
{
/*
DML statements that modify a table with an auto_increment column based on
rows selected from a table are unsafe as the order in which the rows are
fetched fron the select tables cannot be determined and may differ on
master and slave.
*/
if (has_write_table_with_auto_increment_and_select(tables))
lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_WRITE_AUTOINC_SELECT);
if (has_write_table_auto_increment_not_first_in_pk(tables))
lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_AUTOINC_NOT_FIRST);
/*
A query that modifies autoinc column in sub-statement can make the
master and slave inconsistent.
We can solve these problems in mixed mode by switching to binlogging
if at least one updated table is used by sub-statement
*/
if (lex->requires_prelocking() &&
has_write_table_with_auto_increment(lex->first_not_own_table()))
lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_AUTOINC_COLUMNS);
}
/* /*
Get the capabilities vector for all involved storage engines and Get the capabilities vector for all involved storage engines and
mask out the flags for the binary log. mask out the flags for the binary log.
@ -5863,9 +5757,22 @@ int THD::decide_logging_format(TABLE_LIST *tables)
continue; continue;
} }
} }
if (table == lex->first_not_own_table())
found_first_not_own_table= true;
replicated_tables_count++; replicated_tables_count++;
if (table->lock_type <= TL_READ_NO_INSERT)
has_read_tables= true;
else if (table->table->found_next_number_field &&
(table->lock_type >= TL_WRITE_ALLOW_WRITE))
{
has_auto_increment_write_tables= true;
has_auto_increment_write_tables_not_first= found_first_not_own_table;
if (table->table->s->next_number_keypart != 0)
has_write_table_auto_increment_not_first_in_pk= true;
}
if (table->lock_type >= TL_WRITE_ALLOW_WRITE) if (table->lock_type >= TL_WRITE_ALLOW_WRITE)
{ {
if (prev_write_table && prev_write_table->file->ht != if (prev_write_table && prev_write_table->file->ht !=
@ -5910,6 +5817,30 @@ int THD::decide_logging_format(TABLE_LIST *tables)
prev_access_table= table->table; prev_access_table= table->table;
} }
if (wsrep_binlog_format() != BINLOG_FORMAT_ROW)
{
/*
DML statements that modify a table with an auto_increment
column based on rows selected from a table are unsafe as the
order in which the rows are fetched fron the select tables
cannot be determined and may differ on master and slave.
*/
if (has_auto_increment_write_tables && has_read_tables)
lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_WRITE_AUTOINC_SELECT);
if (has_write_table_auto_increment_not_first_in_pk)
lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_AUTOINC_NOT_FIRST);
/*
A query that modifies autoinc column in sub-statement can make the
master and slave inconsistent.
We can solve these problems in mixed mode by switching to binlogging
if at least one updated table is used by sub-statement
*/
if (lex->requires_prelocking() &&
has_auto_increment_write_tables_not_first)
lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_AUTOINC_COLUMNS);
}
DBUG_PRINT("info", ("flags_write_all_set: 0x%llx", flags_write_all_set)); DBUG_PRINT("info", ("flags_write_all_set: 0x%llx", flags_write_all_set));
DBUG_PRINT("info", ("flags_write_some_set: 0x%llx", flags_write_some_set)); DBUG_PRINT("info", ("flags_write_some_set: 0x%llx", flags_write_some_set));
DBUG_PRINT("info", ("flags_access_some_set: 0x%llx", flags_access_some_set)); DBUG_PRINT("info", ("flags_access_some_set: 0x%llx", flags_access_some_set));