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);
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;
......
......@@ -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);
......
......@@ -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<TABLE_LIST, schema_set_get_key> 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 */
}
......
......@@ -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)
......
......@@ -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, &not_used, 0))
{
res= thd->is_error();
goto err;
}
src_table->table->use_all_columns();
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