1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-29 05:21:33 +03:00

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)
This commit is contained in:
Michael Widenius
2012-12-17 22:34:56 +02:00
parent d7a0148758
commit 2dbce3d089
5 changed files with 53 additions and 24 deletions

View File

@ -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;

View File

@ -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);

View File

@ -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,
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,8 +4733,8 @@ 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,
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,11 +4792,16 @@ 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)
{ {
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); DBUG_RETURN(TRUE);
} }
/* purecov: begin inspected */ /* purecov: begin inspected */
@ -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 */
} }

View File

@ -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)

View File

@ -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,
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");