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:
@ -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, ¬_used, 0))
|
||||
{
|
||||
res= thd->is_error();
|
||||
goto err;
|
||||
}
|
||||
src_table->table->use_all_columns();
|
||||
|
||||
DEBUG_SYNC(thd, "create_table_like_after_open");
|
||||
|
Reference in New Issue
Block a user