summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorRohit Kalhans <rohit.kalhans@oracle.com>2012-02-08 00:33:08 +0530
committerRohit Kalhans <rohit.kalhans@oracle.com>2012-02-08 00:33:08 +0530
commitde85a60049af7af2cfdaa6f642e4ea7b7189afbe (patch)
treead0d8d355079009a9bed9b3d9a84fc0c55cdcb24 /sql
parent56e3f68c72d28a02833813f4e8591f917bbc1046 (diff)
downloadmariadb-git-de85a60049af7af2cfdaa6f642e4ea7b7189afbe.tar.gz
BUG#11758263 50440: MARK UNORDERED UPDATE WITH AUTOINC UNSAFE
Problem: Statements that write to tables with auto_increment columns based on the selection from another table, may lead to master and slave going out of sync, as the order in which the rows are retrived from the table may differ on master and slave. Solution: We mark writing to a table with auto_increment table as unsafe. This will cause the execution of such statements to throw a warning and forces the statement to be logged in ROW if the logging format is mixed. Changes: 1. All the statements that writes to a table with auto_increment column(s) based on the rows fetched from another table, will now be unsafe. 2. CREATE TABLE with SELECT will now be unsafe. sql/share/errmsg-utf8.txt: Added new Warning messages sql/sql_base.cc: created a new function that checks for select + write on a autoinc table made all such statements to be unsafe. sql/sql_parse.cc: made create autoincremnet tabble + select unsafe
Diffstat (limited to 'sql')
-rw-r--r--sql/share/errmsg-utf8.txt8
-rw-r--r--sql/sql_base.cc41
-rw-r--r--sql/sql_lex.cc2
-rw-r--r--sql/sql_lex.h15
-rw-r--r--sql/sql_parse.cc12
5 files changed, 74 insertions, 4 deletions
diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt
index f5c96761da1..d164f75d7d8 100644
--- a/sql/share/errmsg-utf8.txt
+++ b/sql/share/errmsg-utf8.txt
@@ -6486,3 +6486,11 @@ ER_PLUGIN_NO_UNINSTALL
ER_PLUGIN_NO_INSTALL
eng "Plugin '%s' is marked as not dynamically installable. You have to stop the server to install it."
+
+
+ER_BINLOG_UNSAFE_WRITE_AUTOINC_SELECT
+ eng "Statements writing to a table with an auto-increment column after selecting from another table are unsafe because the order in which rows are retrieved determines what (if any) rows will be written. This order cannot be predicted and may differ on master and the slave."
+
+ER_BINLOG_UNSAFE_CREATE_SELECT_AUTOINC
+ eng "CREATE TABLE... SELECT... on a table with an auto-increment column is unsafe because the order in which rows are retrieved by the SELECT determines which (if any) rows are inserted. This order cannot be predicted and may differ on master and the slave."
+
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index e0472e2c9b5..fda0ba61e63 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -214,7 +214,8 @@ static bool auto_repair_table(THD *thd, TABLE_LIST *table_list);
static void free_cache_entry(TABLE *entry);
static bool
has_write_table_with_auto_increment(TABLE_LIST *tables);
-
+static bool
+has_write_table_with_auto_increment_and_select(TABLE_LIST *tables);
uint cached_open_tables(void)
{
@@ -5683,6 +5684,11 @@ bool lock_tables(THD *thd, TABLE_LIST *tables, uint count,
/* We have to emulate LOCK TABLES if we are statement needs prelocking. */
if (thd->lex->requires_prelocking())
{
+
+ if (thd->variables.binlog_format != BINLOG_FORMAT_ROW && tables &&
+ has_write_table_with_auto_increment_and_select(tables))
+ thd->lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_WRITE_AUTOINC_SELECT);
+
/*
A query that modifies autoinc column in sub-statement can make the
master and slave inconsistent.
@@ -9080,6 +9086,39 @@ has_write_table_with_auto_increment(TABLE_LIST *tables)
return 0;
}
+/*
+ checks if the tables 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);
+}
+
+
/*
Open and lock system tables for read.
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index 0cabab9fae7..7598ddd3cdd 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -61,9 +61,11 @@ Query_tables_list::binlog_stmt_unsafe_errcode[BINLOG_STMT_UNSAFE_COUNT] =
ER_BINLOG_UNSAFE_MIXED_STATEMENT,
ER_BINLOG_UNSAFE_INSERT_IGNORE_SELECT,
ER_BINLOG_UNSAFE_INSERT_SELECT_UPDATE,
+ ER_BINLOG_UNSAFE_WRITE_AUTOINC_SELECT,
ER_BINLOG_UNSAFE_REPLACE_SELECT,
ER_BINLOG_UNSAFE_CREATE_IGNORE_SELECT,
ER_BINLOG_UNSAFE_CREATE_REPLACE_SELECT,
+ ER_BINLOG_UNSAFE_CREATE_SELECT_AUTOINC,
ER_BINLOG_UNSAFE_UPDATE_IGNORE
};
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 8aaead811a0..1de92057b1f 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -1269,6 +1269,13 @@ public:
BINLOG_STMT_UNSAFE_INSERT_SELECT_UPDATE,
/**
+ Query that writes to a table with auto_inc column after selecting from
+ other tables are unsafe as the order in which the rows are retrieved by
+ select may differ on master and slave.
+ */
+ BINLOG_STMT_UNSAFE_WRITE_AUTOINC_SELECT,
+
+ /**
INSERT...REPLACE SELECT is unsafe because which rows are replaced depends
on the order that rows are retrieved by SELECT. This order cannot be
predicted and may differ on master and the slave.
@@ -1290,6 +1297,14 @@ public:
BINLOG_STMT_UNSAFE_CREATE_REPLACE_SELECT,
/**
+ CREATE TABLE...SELECT on a table with auto-increment column is unsafe
+ because which rows are replaced depends on the order that rows are
+ retrieved from SELECT. This order cannot be predicted and may differ on
+ master and the slave
+ */
+ BINLOG_STMT_UNSAFE_CREATE_SELECT_AUTOINC,
+
+ /**
UPDATE...IGNORE is unsafe because which rows are ignored depends on the
order that rows are updated. This order cannot be predicted and may differ
on master and the slave.
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index a5d23858a8d..f26deb9a01a 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -2414,9 +2414,12 @@ case SQLCOM_PREPARE:
select_result *result;
/*
- CREATE TABLE...IGNORE/REPLACE SELECT... can be unsafe, unless
- ORDER BY PRIMARY KEY clause is used in SELECT statement. We therefore
- use row based logging if mixed or row based logging is available.
+ - CREATE TABLE...IGNORE
+ - REPLACE SELECT...
+ - CREATE TABLE [with auto inc. column]...SELECT
+ can be unsafe, unless ORDER BY PRIMARY KEY clause is used in SELECT
+ statement. We therefore use row based logging if mixed or row based
+ logging is available.
TODO: Check if the order of the output of the select statement is
deterministic. Waiting for BUG#42415
*/
@@ -2426,6 +2429,9 @@ case SQLCOM_PREPARE:
if(lex->duplicates == DUP_REPLACE)
lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_CREATE_REPLACE_SELECT);
+ if (lex->type & AUTO_INCREMENT_FLAG)
+ lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_CREATE_SELECT_AUTOINC);
+
/*
If:
a) we inside an SP and there was NAME_CONST substitution,