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()
This commit is contained in:
Michael Widenius 2014-07-30 22:01:10 +03:00
parent 7019d450fd
commit 14d00cd7f6
2 changed files with 22 additions and 3 deletions

View File

@ -2945,7 +2945,11 @@ case SQLCOM_PREPARE:
goto end_with_restore_list; 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); res= open_and_lock_tables(thd, lex->query_tables, TRUE, 0);
thd->lex->create_info.options= save_thd_create_info_options;
if (res) if (res)
{ {
/* Got error or warning. Set res to 1 if error */ /* Got error or warning. Set res to 1 if error */

View File

@ -4971,7 +4971,7 @@ bool mysql_create_table(THD *thd, TABLE_LIST *create_table,
const char *db= create_table->db; const char *db= create_table->db;
const char *table_name= create_table->table_name; const char *table_name= create_table->table_name;
bool is_trans= FALSE; bool is_trans= FALSE;
bool result= 0; bool result;
int create_table_mode; int create_table_mode;
TABLE_LIST *pos_in_locked_tables= 0; TABLE_LIST *pos_in_locked_tables= 0;
MDL_ticket *mdl_ticket= 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); 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 */ /* 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 */ /* is_error() may be 0 if table existed and we generated a warning */
DBUG_RETURN(thd->is_error()); 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 Thus by holding both these locks we ensure that our statement is
properly isolated from all concurrent operations which matter. properly isolated from all concurrent operations which matter.
*/ */
if (open_tables(thd, &thd->lex->query_tables, &not_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, &not_used, 0);
thd->lex->create_info.options= save_thd_create_info_options;
if (res)
{ {
res= thd->is_error(); res= thd->is_error();
goto err; goto err;