From 14d00cd7f6291cb9b28e9f3ee273143da4aa4744 Mon Sep 17 00:00:00 2001 From: Michael Widenius Date: Wed, 30 Jul 2014 22:01:10 +0300 Subject: [PATCH] Fixed MDEV-6451: "Error 'Table 't1' already exists' on query" with slave_ddl_exec_mode=IDEMPOTENT There was a race condition in lock_table_names() which didn't properly test for CREATE OR REPLACE for slaves. sql/sql_parse.cc: Copy create_info flags to thd for lock_table_names() sql/sql_table.cc: Copy create_info flags to thd for lock_table_names() --- sql/sql_parse.cc | 4 ++++ sql/sql_table.cc | 21 ++++++++++++++++++--- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index d7fdb4d0473..da313be2d71 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2945,7 +2945,11 @@ case SQLCOM_PREPARE: goto end_with_restore_list; } + /* Copy temporarily the statement flags to thd for lock_table_names() */ + uint save_thd_create_info_options= thd->lex->create_info.options; + thd->lex->create_info.options|= create_info.options; res= open_and_lock_tables(thd, lex->query_tables, TRUE, 0); + thd->lex->create_info.options= save_thd_create_info_options; if (res) { /* Got error or warning. Set res to 1 if error */ diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 3fcb54cee00..3a44303e3ba 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -4971,7 +4971,7 @@ bool mysql_create_table(THD *thd, TABLE_LIST *create_table, const char *db= create_table->db; const char *table_name= create_table->table_name; bool is_trans= FALSE; - bool result= 0; + bool result; int create_table_mode; TABLE_LIST *pos_in_locked_tables= 0; MDL_ticket *mdl_ticket= 0; @@ -4979,8 +4979,16 @@ bool mysql_create_table(THD *thd, TABLE_LIST *create_table, DBUG_ASSERT(create_table == thd->lex->query_tables); + /* Copy temporarily the statement flags to thd for lock_table_names() */ + uint save_thd_create_info_options= thd->lex->create_info.options; + thd->lex->create_info.options|= create_info->options; + /* Open or obtain an exclusive metadata lock on table being created */ - if (open_and_lock_tables(thd, create_table, FALSE, 0)) + result= open_and_lock_tables(thd, create_table, FALSE, 0); + + thd->lex->create_info.options= save_thd_create_info_options; + + if (result) { /* is_error() may be 0 if table existed and we generated a warning */ DBUG_RETURN(thd->is_error()); @@ -5275,7 +5283,14 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, Thus by holding both these locks we ensure that our statement is properly isolated from all concurrent operations which matter. */ - if (open_tables(thd, &thd->lex->query_tables, ¬_used, 0)) + + /* Copy temporarily the statement flags to thd for lock_table_names() */ + uint save_thd_create_info_options= thd->lex->create_info.options; + thd->lex->create_info.options|= create_info->options; + res= open_tables(thd, &thd->lex->query_tables, ¬_used, 0); + thd->lex->create_info.options= save_thd_create_info_options; + + if (res) { res= thd->is_error(); goto err;