Commit 2dbce3d0 authored by Michael Widenius's avatar Michael Widenius

Fixed the CREATE TABLE IF EXIST generates warnings instead of errors

mysql-test/r/create.result:
  Updated test results
mysql-test/t/create.test:
  Updated test
sql/sql_base.cc:
  Use push_internal_handler/pop_internal_handler to avoid errors & warnings instead of clear_error
  Give a warnings instead of an error for CREATE TABLE IF EXISTS
sql/sql_parse.cc:
  Check if we failed because of table exists (can only happen from create)
sql/sql_table.cc:
  Check if we failed because of table exists (can only happen from create)
parent d7a01487
...@@ -2411,11 +2411,14 @@ insert into t1 values (1,1); ...@@ -2411,11 +2411,14 @@ insert into t1 values (1,1);
lock tables t1 read; lock tables t1 read;
set @@lock_wait_timeout=5; set @@lock_wait_timeout=5;
create table if not exists t1 (a int, b int); 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; 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; 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); create table t1 (a int, b int);
ERROR 42S01: Table 't1' already exists ERROR 42S01: Table 't1' already exists
create table t1 (a int, b int) select 2,2; create table t1 (a int, b int) select 2,2;
......
...@@ -2007,11 +2007,8 @@ insert into t1 values (1,1); ...@@ -2007,11 +2007,8 @@ insert into t1 values (1,1);
lock tables t1 read; lock tables t1 read;
connect (user1,localhost,root,,test); connect (user1,localhost,root,,test);
set @@lock_wait_timeout=5; set @@lock_wait_timeout=5;
--error ER_TABLE_EXISTS_ERROR
create table if not exists t1 (a int, b int); 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; 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; create table if not exists t1 like t2;
--error ER_TABLE_EXISTS_ERROR --error ER_TABLE_EXISTS_ERROR
create table t1 (a int, b int); create table t1 (a int, b int);
......
...@@ -4681,13 +4681,18 @@ extern "C" uchar *schema_set_get_key(const uchar *record, size_t *length, ...@@ -4681,13 +4681,18 @@ extern "C" uchar *schema_set_get_key(const uchar *record, size_t *length,
open, see open_table() description for details. open, see open_table() description for details.
@retval FALSE Success. @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 @notes
In case of CREATE TABLE IF NOT EXISTS we avoid a wait for tables that In case of CREATE TABLE we avoid a wait for tables that are in use
are in use by first trying to do a meta data lock with timeout= 0. by first trying to do a meta data lock with timeout == 0. If we get a
If we get a timeout we will check if table exists (it should) and timeout we will check if table exists (it should) and retry with
retry with normal timeout if it didn't exists. 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 bool
...@@ -4701,7 +4706,8 @@ lock_table_names(THD *thd, ...@@ -4701,7 +4706,8 @@ lock_table_names(THD *thd,
Hash_set<TABLE_LIST, schema_set_get_key> schema_set; Hash_set<TABLE_LIST, schema_set_get_key> schema_set;
ulong org_lock_wait_timeout= lock_wait_timeout; ulong org_lock_wait_timeout= lock_wait_timeout;
/* Check if we are using CREATE TABLE ... IF NOT EXISTS */ /* 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_ENTER("lock_table_names");
DBUG_ASSERT(!thd->locked_tables_mode); DBUG_ASSERT(!thd->locked_tables_mode);
...@@ -4727,7 +4733,7 @@ lock_table_names(THD *thd, ...@@ -4727,7 +4733,7 @@ lock_table_names(THD *thd,
DBUG_RETURN(FALSE); DBUG_RETURN(FALSE);
/* Check if CREATE TABLE IF NOT EXISTS was used */ /* Check if CREATE TABLE IF NOT EXISTS was used */
create_if_not_exists= (tables_start && tables_start->open_strategy == create_table= (tables_start && tables_start->open_strategy ==
TABLE_LIST::OPEN_IF_EXISTS); TABLE_LIST::OPEN_IF_EXISTS);
if (!(flags & MYSQL_OPEN_SKIP_SCOPED_MDL_LOCK)) if (!(flags & MYSQL_OPEN_SKIP_SCOPED_MDL_LOCK))
...@@ -4759,17 +4765,24 @@ lock_table_names(THD *thd, ...@@ -4759,17 +4765,24 @@ lock_table_names(THD *thd,
MDL_STATEMENT); MDL_STATEMENT);
mdl_requests.push_front(&global_request); mdl_requests.push_front(&global_request);
if (create_if_not_exists) if (create_table)
lock_wait_timeout= 0; // Don't wait for timeout lock_wait_timeout= 0; // Don't wait for timeout
} }
for (;;) for (;;)
{ {
bool exists= TRUE; 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 DBUG_RETURN(FALSE); // Got locks
if (!create_if_not_exists) if (!create_table)
DBUG_RETURN(TRUE); // Return original error DBUG_RETURN(TRUE); // Return original error
/* /*
...@@ -4779,10 +4792,15 @@ lock_table_names(THD *thd, ...@@ -4779,10 +4792,15 @@ lock_table_names(THD *thd,
*/ */
if (check_if_table_exists(thd, tables_start, 1, &exists)) if (check_if_table_exists(thd, tables_start, 1, &exists))
DBUG_RETURN(TRUE); // Should never happen DBUG_RETURN(TRUE); // Should never happen
thd->warning_info->clear_warning_info(thd->query_id);
thd->clear_error(); // Forget timeout error
if (exists) if (exists)
{ {
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); my_error(ER_TABLE_EXISTS_ERROR, MYF(0), tables_start->table_name);
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
} }
...@@ -4792,9 +4810,9 @@ lock_table_names(THD *thd, ...@@ -4792,9 +4810,9 @@ lock_table_names(THD *thd,
In theory this should never happen, except maybe in In theory this should never happen, except maybe in
CREATE or DROP DATABASE scenario. CREATE or DROP DATABASE scenario.
We play safe and restart the original acquire_locks with the 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; lock_wait_timeout= org_lock_wait_timeout;
/* purecov: end */ /* purecov: end */
} }
......
...@@ -2512,7 +2512,14 @@ case SQLCOM_PREPARE: ...@@ -2512,7 +2512,14 @@ case SQLCOM_PREPARE:
goto end_with_restore_list; 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 */ /* The table already exists */
if (create_table->table) if (create_table->table)
......
...@@ -4552,7 +4552,8 @@ bool mysql_create_table(THD *thd, TABLE_LIST *create_table, ...@@ -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)) 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; goto end;
} }
...@@ -4747,7 +4748,10 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, TABLE_LIST* src_table, ...@@ -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. properly isolated from all concurrent operations which matter.
*/ */
if (open_tables(thd, &thd->lex->query_tables, &not_used, 0)) if (open_tables(thd, &thd->lex->query_tables, &not_used, 0))
{
res= thd->is_error();
goto err; goto err;
}
src_table->table->use_all_columns(); src_table->table->use_all_columns();
DEBUG_SYNC(thd, "create_table_like_after_open"); DEBUG_SYNC(thd, "create_table_like_after_open");
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment