diff --git a/mysql-test/r/create.result b/mysql-test/r/create.result index 6f0d5d376a1..4cb14aabb2c 100644 --- a/mysql-test/r/create.result +++ b/mysql-test/r/create.result @@ -2411,11 +2411,14 @@ insert into t1 values (1,1); lock tables t1 read; set @@lock_wait_timeout=5; create table if not exists t1 (a int, b int); -ERROR 42S01: Table 't1' already exists +Warnings: +Note 1050 Table 't1' already exists create table if not exists t1 (a int, b int) select 2,2; -ERROR 42S01: Table 't1' already exists +Warnings: +Note 1050 Table 't1' already exists create table if not exists t1 like t2; -ERROR 42S01: Table 't1' already exists +Warnings: +Note 1050 Table 't1' already exists create table t1 (a int, b int); ERROR 42S01: Table 't1' already exists create table t1 (a int, b int) select 2,2; diff --git a/mysql-test/t/create.test b/mysql-test/t/create.test index 4c9592e9dab..1fabb49138c 100644 --- a/mysql-test/t/create.test +++ b/mysql-test/t/create.test @@ -2007,11 +2007,8 @@ insert into t1 values (1,1); lock tables t1 read; connect (user1,localhost,root,,test); set @@lock_wait_timeout=5; ---error ER_TABLE_EXISTS_ERROR create table if not exists t1 (a int, b int); ---error ER_TABLE_EXISTS_ERROR create table if not exists t1 (a int, b int) select 2,2; ---error ER_TABLE_EXISTS_ERROR create table if not exists t1 like t2; --error ER_TABLE_EXISTS_ERROR create table t1 (a int, b int); diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 75b69eebfa9..c7f93c955f3 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -4681,13 +4681,18 @@ extern "C" uchar *schema_set_get_key(const uchar *record, size_t *length, open, see open_table() description for details. @retval FALSE Success. - @retval TRUE Failure (e.g. connection was killed) + @retval TRUE Failure (e.g. connection was killed) or table existed + for a CREATE TABLE. @notes - In case of CREATE TABLE IF NOT EXISTS we avoid a wait for tables that - are in use by first trying to do a meta data lock with timeout= 0. - If we get a timeout we will check if table exists (it should) and - retry with normal timeout if it didn't exists. + In case of CREATE TABLE we avoid a wait for tables that are in use + by first trying to do a meta data lock with timeout == 0. If we get a + timeout we will check if table exists (it should) and retry with + normal timeout if it didn't exists. + Note that for CREATE TABLE IF EXISTS we only generate a warning + but still return TRUE (to abort the calling open_table() function). + On must check THD->is_error() if one wants to distinguish between warning + and error. */ bool @@ -4701,7 +4706,8 @@ lock_table_names(THD *thd, Hash_set schema_set; ulong org_lock_wait_timeout= lock_wait_timeout; /* Check if we are using CREATE TABLE ... IF NOT EXISTS */ - bool create_if_not_exists; + bool create_table; + Dummy_error_handler error_handler; DBUG_ENTER("lock_table_names"); DBUG_ASSERT(!thd->locked_tables_mode); @@ -4727,8 +4733,8 @@ lock_table_names(THD *thd, DBUG_RETURN(FALSE); /* Check if CREATE TABLE IF NOT EXISTS was used */ - create_if_not_exists= (tables_start && tables_start->open_strategy == - TABLE_LIST::OPEN_IF_EXISTS); + create_table= (tables_start && tables_start->open_strategy == + TABLE_LIST::OPEN_IF_EXISTS); if (!(flags & MYSQL_OPEN_SKIP_SCOPED_MDL_LOCK)) { @@ -4759,17 +4765,24 @@ lock_table_names(THD *thd, MDL_STATEMENT); mdl_requests.push_front(&global_request); - if (create_if_not_exists) + if (create_table) lock_wait_timeout= 0; // Don't wait for timeout } for (;;) { bool exists= TRUE; - if (!thd->mdl_context.acquire_locks(&mdl_requests, lock_wait_timeout)) + bool res; + + if (create_table) + thd->push_internal_handler(&error_handler); // Avoid warnings & errors + res= thd->mdl_context.acquire_locks(&mdl_requests, lock_wait_timeout); + if (create_table) + thd->pop_internal_handler(); + if (!res) DBUG_RETURN(FALSE); // Got locks - if (!create_if_not_exists) + if (!create_table) DBUG_RETURN(TRUE); // Return original error /* @@ -4779,11 +4792,16 @@ lock_table_names(THD *thd, */ if (check_if_table_exists(thd, tables_start, 1, &exists)) DBUG_RETURN(TRUE); // Should never happen - thd->warning_info->clear_warning_info(thd->query_id); - thd->clear_error(); // Forget timeout error if (exists) { - my_error(ER_TABLE_EXISTS_ERROR, MYF(0), tables_start->table_name); + if (thd->lex->create_info.options & HA_LEX_CREATE_IF_NOT_EXISTS) + { + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, + ER_TABLE_EXISTS_ERROR, ER(ER_TABLE_EXISTS_ERROR), + tables_start->table_name); + } + else + my_error(ER_TABLE_EXISTS_ERROR, MYF(0), tables_start->table_name); DBUG_RETURN(TRUE); } /* purecov: begin inspected */ @@ -4792,9 +4810,9 @@ lock_table_names(THD *thd, In theory this should never happen, except maybe in CREATE or DROP DATABASE scenario. We play safe and restart the original acquire_locks with the - orginal timeout + original timeout */ - create_if_not_exists= 0; + create_table= 0; lock_wait_timeout= org_lock_wait_timeout; /* purecov: end */ } diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 5dac052b749..de35d2f3d27 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2512,7 +2512,14 @@ case SQLCOM_PREPARE: goto end_with_restore_list; } - if (!(res= open_and_lock_tables(thd, lex->query_tables, TRUE, 0))) + res= open_and_lock_tables(thd, lex->query_tables, TRUE, 0); + if (res) + { + /* Got error or warning. Set res to 1 if error */ + if (!(res= thd->is_error())) + my_ok(thd); // CREATE ... IF NOT EXISTS + } + else { /* The table already exists */ if (create_table->table) diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 5ab00f34c97..330c28ebbd8 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -4552,7 +4552,8 @@ bool mysql_create_table(THD *thd, TABLE_LIST *create_table, */ if (open_and_lock_tables(thd, thd->lex->query_tables, FALSE, 0)) { - result= TRUE; + /* is_error() may be 0 if table existed and we generated a warning */ + result= thd->is_error(); goto end; } @@ -4747,7 +4748,10 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, TABLE_LIST* src_table, properly isolated from all concurrent operations which matter. */ if (open_tables(thd, &thd->lex->query_tables, ¬_used, 0)) + { + res= thd->is_error(); goto err; + } src_table->table->use_all_columns(); DEBUG_SYNC(thd, "create_table_like_after_open");