mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +03:00
BUG#28722 (Multi-engine statements on has_own_binlogging engine):
WL#3931 (Multi-table statement involving self-logging engines): Adding logic to generate error if more than one engine is involved in the statement and at least one engine is self-logging (i.e., has the HA_HAS_OWN_BINLOGGING table flags set).
This commit is contained in:
@ -10,7 +10,7 @@ UPDATE t1m, t1b SET m = 2, b = 3 WHERE n = c;
|
|||||||
UPDATE t1m, t1n SET m = 2, e = 3 WHERE n = f;
|
UPDATE t1m, t1n SET m = 2, e = 3 WHERE n = f;
|
||||||
ERROR HY000: Binary logging not possible. Message: Statement-based format required for this statement, but not allowed by this combination of engines
|
ERROR HY000: Binary logging not possible. Message: Statement-based format required for this statement, but not allowed by this combination of engines
|
||||||
UPDATE t1n, t1b SET e = 2, b = 3 WHERE f = c;
|
UPDATE t1n, t1b SET e = 2, b = 3 WHERE f = c;
|
||||||
ERROR HY000: Binary logging not possible. Message: Statement cannot be logged to the binary log in row-based nor statement-based format
|
ERROR HY000: Binary logging not possible. Message: Statement-based format required for this statement, but not allowed by this combination of engines
|
||||||
TRUNCATE t1m;
|
TRUNCATE t1m;
|
||||||
TRUNCATE t1b;
|
TRUNCATE t1b;
|
||||||
TRUNCATE t1n;
|
TRUNCATE t1n;
|
||||||
@ -20,8 +20,9 @@ INSERT INTO t1b VALUES (1,1), (1,2), (2,1), (2,2);
|
|||||||
INSERT INTO t1n 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, t1b SET m = 2, b = 3 WHERE n = c;
|
||||||
UPDATE t1m, t1n SET m = 2, e = 3 WHERE n = f;
|
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
|
||||||
UPDATE t1n, t1b SET e = 2, b = 3 WHERE f = c;
|
UPDATE t1n, t1b SET e = 2, b = 3 WHERE f = c;
|
||||||
ERROR HY000: Binary logging not possible. Message: Statement cannot be logged to the binary log in row-based nor statement-based format
|
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
|
||||||
TRUNCATE t1m;
|
TRUNCATE t1m;
|
||||||
TRUNCATE t1b;
|
TRUNCATE t1b;
|
||||||
TRUNCATE t1n;
|
TRUNCATE t1n;
|
||||||
@ -33,8 +34,9 @@ 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, t1b SET m = 2, b = 3 WHERE n = c;
|
||||||
ERROR HY000: Binary logging not possible. Message: Row-based format required for this statement, but not allowed by this combination of engines
|
ERROR HY000: Binary logging not possible. Message: Row-based format required for this statement, but not allowed by this combination of engines
|
||||||
UPDATE t1m, t1n SET m = 2, e = 3 WHERE n = f;
|
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
|
||||||
UPDATE t1n, t1b SET e = 2, b = 3 WHERE f = c;
|
UPDATE t1n, t1b SET e = 2, b = 3 WHERE f = c;
|
||||||
ERROR HY000: Binary logging not possible. Message: Statement cannot be logged to the binary log in row-based nor statement-based format
|
ERROR HY000: Binary logging not possible. Message: Row-based format required for this statement, but not allowed by this combination of engines
|
||||||
DROP TABLE t1m, t1b, t1n;
|
DROP TABLE t1m, t1b, t1n;
|
||||||
show binlog events from <binlog_start>;
|
show binlog events from <binlog_start>;
|
||||||
Log_name Pos Event_type Server_id End_log_pos Info
|
Log_name Pos Event_type Server_id End_log_pos Info
|
||||||
@ -50,9 +52,6 @@ master-bin.000001 # Query # # use `test`; TRUNCATE t1n
|
|||||||
master-bin.000001 # Query # # use `test`; INSERT INTO t1m VALUES (1,1), (1,2), (2,1), (2,2)
|
master-bin.000001 # Query # # use `test`; INSERT INTO t1m VALUES (1,1), (1,2), (2,1), (2,2)
|
||||||
master-bin.000001 # Query # # use `test`; INSERT INTO t1b VALUES (1,1), (1,2), (2,1), (2,2)
|
master-bin.000001 # Query # # use `test`; INSERT INTO t1b VALUES (1,1), (1,2), (2,1), (2,2)
|
||||||
master-bin.000001 # Query # # use `test`; UPDATE t1m, t1b SET m = 2, b = 3 WHERE n = c
|
master-bin.000001 # Query # # use `test`; UPDATE t1m, t1b SET m = 2, b = 3 WHERE n = c
|
||||||
master-bin.000001 # Table_map # # table_id: # (test.t1m)
|
|
||||||
master-bin.000001 # Table_map # # table_id: # (test.t1n)
|
|
||||||
master-bin.000001 # Update_rows # # table_id: # flags: STMT_END_F
|
|
||||||
master-bin.000001 # Query # # use `test`; TRUNCATE t1m
|
master-bin.000001 # Query # # use `test`; TRUNCATE t1m
|
||||||
master-bin.000001 # Query # # use `test`; TRUNCATE t1b
|
master-bin.000001 # Query # # use `test`; TRUNCATE t1b
|
||||||
master-bin.000001 # Query # # BEGIN
|
master-bin.000001 # Query # # BEGIN
|
||||||
@ -60,23 +59,16 @@ master-bin.000001 # Table_map # # table_id: # (test.t1n)
|
|||||||
master-bin.000001 # Table_map # # table_id: # (mysql.ndb_apply_status)
|
master-bin.000001 # Table_map # # table_id: # (mysql.ndb_apply_status)
|
||||||
master-bin.000001 # Write_rows # # table_id: #
|
master-bin.000001 # Write_rows # # table_id: #
|
||||||
master-bin.000001 # Write_rows # # table_id: #
|
master-bin.000001 # Write_rows # # table_id: #
|
||||||
master-bin.000001 # Write_rows # # table_id: #
|
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
|
||||||
master-bin.000001 # Update_rows # # table_id: #
|
|
||||||
master-bin.000001 # Update_rows # # table_id: # flags: STMT_END_F
|
|
||||||
master-bin.000001 # Query # # COMMIT
|
master-bin.000001 # Query # # COMMIT
|
||||||
master-bin.000001 # Query # # use `test`; TRUNCATE t1n
|
master-bin.000001 # Query # # use `test`; TRUNCATE t1n
|
||||||
master-bin.000001 # Table_map # # table_id: # (test.t1m)
|
master-bin.000001 # Table_map # # table_id: # (test.t1m)
|
||||||
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
|
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
|
||||||
master-bin.000001 # Table_map # # table_id: # (test.t1m)
|
|
||||||
master-bin.000001 # Table_map # # table_id: # (test.t1n)
|
|
||||||
master-bin.000001 # Update_rows # # table_id: # flags: STMT_END_F
|
|
||||||
master-bin.000001 # Query # # BEGIN
|
master-bin.000001 # Query # # BEGIN
|
||||||
master-bin.000001 # Table_map # # table_id: # (test.t1n)
|
master-bin.000001 # Table_map # # table_id: # (test.t1n)
|
||||||
master-bin.000001 # Table_map # # table_id: # (mysql.ndb_apply_status)
|
master-bin.000001 # Table_map # # table_id: # (mysql.ndb_apply_status)
|
||||||
master-bin.000001 # Write_rows # # table_id: #
|
master-bin.000001 # Write_rows # # table_id: #
|
||||||
master-bin.000001 # Write_rows # # table_id: #
|
master-bin.000001 # Write_rows # # table_id: #
|
||||||
master-bin.000001 # Write_rows # # table_id: #
|
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
|
||||||
master-bin.000001 # Update_rows # # table_id: #
|
|
||||||
master-bin.000001 # Update_rows # # table_id: # flags: STMT_END_F
|
|
||||||
master-bin.000001 # Query # # COMMIT
|
master-bin.000001 # Query # # COMMIT
|
||||||
master-bin.000001 # Query # # use `test`; DROP TABLE t1m, t1b, t1n
|
master-bin.000001 # Query # # use `test`; DROP TABLE t1m, t1b, t1n
|
||||||
|
@ -1,3 +1,8 @@
|
|||||||
|
# Test to test how logging is done depending on the capabilities of
|
||||||
|
# the engines. Unfortunately, we don't have a good row-only logging
|
||||||
|
# engine, and NDB does not really cut is since it is also
|
||||||
|
# self-logging. I'm using it nevertheless.
|
||||||
|
|
||||||
source include/have_blackhole.inc;
|
source include/have_blackhole.inc;
|
||||||
source include/have_ndb.inc;
|
source include/have_ndb.inc;
|
||||||
source include/have_binlog_format_mixed_or_row.inc;
|
source include/have_binlog_format_mixed_or_row.inc;
|
||||||
@ -30,6 +35,7 @@ INSERT INTO t1b VALUES (1,1), (1,2), (2,1), (2,2);
|
|||||||
INSERT INTO t1n 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, t1b SET m = 2, b = 3 WHERE n = c;
|
||||||
|
error ER_BINLOG_LOGGING_IMPOSSIBLE;
|
||||||
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_LOGGING_IMPOSSIBLE;
|
||||||
UPDATE t1n, t1b SET e = 2, b = 3 WHERE f = c;
|
UPDATE t1n, t1b SET e = 2, b = 3 WHERE f = c;
|
||||||
@ -47,6 +53,7 @@ INSERT INTO t1n VALUES (1,1), (1,2), (2,1), (2,2);
|
|||||||
|
|
||||||
error ER_BINLOG_LOGGING_IMPOSSIBLE;
|
error ER_BINLOG_LOGGING_IMPOSSIBLE;
|
||||||
UPDATE t1m, t1b SET m = 2, b = 3 WHERE n = c;
|
UPDATE t1m, t1b SET m = 2, b = 3 WHERE n = c;
|
||||||
|
error ER_BINLOG_LOGGING_IMPOSSIBLE;
|
||||||
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_LOGGING_IMPOSSIBLE;
|
||||||
UPDATE t1n, t1b SET e = 2, b = 3 WHERE f = c;
|
UPDATE t1n, t1b SET e = 2, b = 3 WHERE f = c;
|
||||||
|
@ -28,6 +28,8 @@
|
|||||||
#include <io.h>
|
#include <io.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define FLAGSTR(S,F) ((S) & (F) ? #F " " : "")
|
||||||
|
|
||||||
/**
|
/**
|
||||||
This internal handler is used to trap internally
|
This internal handler is used to trap internally
|
||||||
errors that can occur when executing open table
|
errors that can occur when executing open table
|
||||||
@ -3996,36 +3998,47 @@ int decide_logging_format(THD *thd, TABLE_LIST *tables)
|
|||||||
{
|
{
|
||||||
if (mysql_bin_log.is_open() && (thd->options & OPTION_BIN_LOG))
|
if (mysql_bin_log.is_open() && (thd->options & OPTION_BIN_LOG))
|
||||||
{
|
{
|
||||||
handler::Table_flags binlog_flags= ~handler::Table_flags();
|
handler::Table_flags flags_some_set= handler::Table_flags();
|
||||||
|
handler::Table_flags flags_all_set= ~handler::Table_flags();
|
||||||
|
my_bool multi_engine= FALSE;
|
||||||
|
void* prev_ht= NULL;
|
||||||
for (TABLE_LIST *table= tables; table; table= table->next_global)
|
for (TABLE_LIST *table= tables; table; table= table->next_global)
|
||||||
|
{
|
||||||
if (!table->placeholder() && table->lock_type >= TL_WRITE_ALLOW_WRITE)
|
if (!table->placeholder() && table->lock_type >= TL_WRITE_ALLOW_WRITE)
|
||||||
{
|
{
|
||||||
#define FLAGSTR(S,F) ((S) & (F) ? #F " " : "")
|
ulonglong const flags= table->table->file->ha_table_flags();
|
||||||
#ifndef DBUG_OFF
|
|
||||||
ulonglong flags= table->table->file->ha_table_flags();
|
|
||||||
DBUG_PRINT("info", ("table: %s; ha_table_flags: %s%s",
|
DBUG_PRINT("info", ("table: %s; ha_table_flags: %s%s",
|
||||||
table->table_name,
|
table->table_name,
|
||||||
FLAGSTR(flags, HA_BINLOG_STMT_CAPABLE),
|
FLAGSTR(flags, HA_BINLOG_STMT_CAPABLE),
|
||||||
FLAGSTR(flags, HA_BINLOG_ROW_CAPABLE)));
|
FLAGSTR(flags, HA_BINLOG_ROW_CAPABLE)));
|
||||||
#endif
|
if (prev_ht && prev_ht != table->table->file->ht)
|
||||||
binlog_flags &= table->table->file->ha_table_flags();
|
multi_engine= TRUE;
|
||||||
|
prev_ht= table->table->file->ht;
|
||||||
|
flags_all_set &= flags;
|
||||||
|
flags_some_set |= flags;
|
||||||
}
|
}
|
||||||
binlog_flags&= HA_BINLOG_FLAGS;
|
}
|
||||||
DBUG_PRINT("info", ("binlog_flags: %s%s",
|
|
||||||
FLAGSTR(binlog_flags, HA_BINLOG_STMT_CAPABLE),
|
DBUG_PRINT("info", ("flags_all_set: %s%s",
|
||||||
FLAGSTR(binlog_flags, HA_BINLOG_ROW_CAPABLE)));
|
FLAGSTR(flags_all_set, HA_BINLOG_STMT_CAPABLE),
|
||||||
|
FLAGSTR(flags_all_set, HA_BINLOG_ROW_CAPABLE)));
|
||||||
|
DBUG_PRINT("info", ("flags_some_set: %s%s",
|
||||||
|
FLAGSTR(flags_some_set, HA_BINLOG_STMT_CAPABLE),
|
||||||
|
FLAGSTR(flags_some_set, HA_BINLOG_ROW_CAPABLE)));
|
||||||
DBUG_PRINT("info", ("thd->variables.binlog_format: %ld",
|
DBUG_PRINT("info", ("thd->variables.binlog_format: %ld",
|
||||||
thd->variables.binlog_format));
|
thd->variables.binlog_format));
|
||||||
|
DBUG_PRINT("info", ("multi_engine: %s",
|
||||||
|
multi_engine ? "TRUE" : "FALSE"));
|
||||||
|
|
||||||
int error= 0;
|
int error= 0;
|
||||||
if (binlog_flags == 0)
|
if (flags_all_set == 0)
|
||||||
{
|
{
|
||||||
my_error((error= ER_BINLOG_LOGGING_IMPOSSIBLE), MYF(0),
|
my_error((error= ER_BINLOG_LOGGING_IMPOSSIBLE), MYF(0),
|
||||||
"Statement cannot be logged to the binary log in"
|
"Statement cannot be logged to the binary log in"
|
||||||
" row-based nor statement-based format");
|
" row-based nor statement-based format");
|
||||||
}
|
}
|
||||||
else if (thd->variables.binlog_format == BINLOG_FORMAT_STMT &&
|
else if (thd->variables.binlog_format == BINLOG_FORMAT_STMT &&
|
||||||
(binlog_flags & HA_BINLOG_STMT_CAPABLE) == 0)
|
(flags_all_set & HA_BINLOG_STMT_CAPABLE) == 0)
|
||||||
{
|
{
|
||||||
my_error((error= ER_BINLOG_LOGGING_IMPOSSIBLE), MYF(0),
|
my_error((error= ER_BINLOG_LOGGING_IMPOSSIBLE), MYF(0),
|
||||||
"Statement-based format required for this statement,"
|
"Statement-based format required for this statement,"
|
||||||
@ -4033,13 +4046,29 @@ int decide_logging_format(THD *thd, TABLE_LIST *tables)
|
|||||||
}
|
}
|
||||||
else if ((thd->variables.binlog_format == BINLOG_FORMAT_ROW ||
|
else if ((thd->variables.binlog_format == BINLOG_FORMAT_ROW ||
|
||||||
thd->lex->is_stmt_unsafe()) &&
|
thd->lex->is_stmt_unsafe()) &&
|
||||||
(binlog_flags & HA_BINLOG_ROW_CAPABLE) == 0)
|
(flags_all_set & HA_BINLOG_ROW_CAPABLE) == 0)
|
||||||
{
|
{
|
||||||
my_error((error= ER_BINLOG_LOGGING_IMPOSSIBLE), MYF(0),
|
my_error((error= ER_BINLOG_LOGGING_IMPOSSIBLE), MYF(0),
|
||||||
"Row-based format required for this statement,"
|
"Row-based format required for this statement,"
|
||||||
" but not allowed by this combination of engines");
|
" but not allowed by this combination of engines");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
If more than one engine is involved in the statement and at
|
||||||
|
least one is doing it's own logging (is *self-logging*), the
|
||||||
|
statement cannot be logged atomically, so we generate an error
|
||||||
|
rather than allowing the binlog to become corrupt.
|
||||||
|
*/
|
||||||
|
if (multi_engine &&
|
||||||
|
(flags_some_set & HA_HAS_OWN_BINLOGGING))
|
||||||
|
{
|
||||||
|
error= ER_BINLOG_LOGGING_IMPOSSIBLE;
|
||||||
|
my_error(error, MYF(0),
|
||||||
|
"Statement cannot be written atomically since more"
|
||||||
|
" than one engine involved and at least one engine"
|
||||||
|
" is self-logging");
|
||||||
|
}
|
||||||
|
|
||||||
DBUG_PRINT("info", ("error: %d", error));
|
DBUG_PRINT("info", ("error: %d", error));
|
||||||
|
|
||||||
if (error)
|
if (error)
|
||||||
@ -4061,7 +4090,7 @@ int decide_logging_format(THD *thd, TABLE_LIST *tables)
|
|||||||
here.
|
here.
|
||||||
*/
|
*/
|
||||||
if (thd->lex->is_stmt_unsafe() ||
|
if (thd->lex->is_stmt_unsafe() ||
|
||||||
(binlog_flags & HA_BINLOG_STMT_CAPABLE) == 0)
|
(flags_all_set & HA_BINLOG_STMT_CAPABLE) == 0)
|
||||||
{
|
{
|
||||||
thd->set_current_stmt_binlog_row_based_if_mixed();
|
thd->set_current_stmt_binlog_row_based_if_mixed();
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user