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;
|
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);
|
|||||||
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,
|
|||||||
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 */
|
||||||
}
|
}
|
||||||
|
@ -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,
|
|||||||
*/
|
*/
|
||||||
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, ¬_used, 0))
|
if (open_tables(thd, &thd->lex->query_tables, ¬_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");
|
||||||
|
Reference in New Issue
Block a user