summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Barkov <bar@mariadb.org>2014-12-10 08:13:08 +0400
committerAlexander Barkov <bar@mariadb.org>2014-12-10 08:13:08 +0400
commitdd270e43bf84e7dbf2a9ee7c6c3a6de372128e83 (patch)
treeca8985f1c09a483871af76066068269c55c23647
parentc6d3f8058db30a6621e36b05564a1b2ae68bec7f (diff)
downloadmariadb-git-dd270e43bf84e7dbf2a9ee7c6c3a6de372128e83.tar.gz
MDEV-7280 DATABASE: CREATE OR REPLACE
-rw-r--r--mysql-test/r/create_drop_binlog.result29
-rw-r--r--mysql-test/r/create_drop_db.result40
-rw-r--r--mysql-test/suite/rpl/r/rpl_create_drop_db.result43
-rw-r--r--mysql-test/suite/rpl/t/rpl_create_drop_db.test33
-rw-r--r--mysql-test/t/create_drop_binlog.test20
-rw-r--r--mysql-test/t/create_drop_db.test32
-rw-r--r--sql/sql_db.cc123
-rw-r--r--sql/sql_db.h6
-rw-r--r--sql/sql_parse.cc4
-rw-r--r--sql/sql_yacc.yy5
10 files changed, 287 insertions, 48 deletions
diff --git a/mysql-test/r/create_drop_binlog.result b/mysql-test/r/create_drop_binlog.result
new file mode 100644
index 00000000000..54dbfd5c75a
--- /dev/null
+++ b/mysql-test/r/create_drop_binlog.result
@@ -0,0 +1,29 @@
+CREATE OR REPLACE DATABASE d1;
+CREATE OR REPLACE DATABASE d1;
+DROP DATABASE d1;
+CREATE DATABASE IF NOT EXISTS d1;
+CREATE DATABASE IF NOT EXISTS d1;
+Warnings:
+Note 1007 Can't create database 'd1'; database exists
+DROP DATABASE IF EXISTS d1;
+DROP DATABASE IF EXISTS d1;
+Warnings:
+Note 1008 Can't drop database 'd1'; database doesn't exist
+"Runnig SHOW BINLOG EVENTS"
+Log_name Pos Event_type Server_id End_log_pos Info
+# # Gtid 1 # GTID #-#-#
+# # Query 1 # CREATE OR REPLACE DATABASE d1
+# # Gtid 1 # GTID #-#-#
+# # Query 1 # CREATE OR REPLACE DATABASE d1
+# # Gtid 1 # GTID #-#-#
+# # Query 1 # DROP DATABASE d1
+# # Gtid 1 # GTID #-#-#
+# # Query 1 # CREATE DATABASE IF NOT EXISTS d1
+# # Gtid 1 # GTID #-#-#
+# # Query 1 # CREATE DATABASE IF NOT EXISTS d1
+# # Gtid 1 # GTID #-#-#
+# # Query 1 # DROP DATABASE IF EXISTS d1
+# # Gtid 1 # GTID #-#-#
+# # Query 1 # DROP DATABASE IF EXISTS d1
+RESET MASTER;
+USE test;
diff --git a/mysql-test/r/create_drop_db.result b/mysql-test/r/create_drop_db.result
new file mode 100644
index 00000000000..aee88703c9b
--- /dev/null
+++ b/mysql-test/r/create_drop_db.result
@@ -0,0 +1,40 @@
+CREATE DATABASE IF NOT EXISTS db1;
+affected rows: 1
+CREATE DATABASE IF NOT EXISTS db1;
+affected rows: 0
+Warnings:
+Note 1007 Can't create database 'db1'; database exists
+CREATE TABLE db1.t1 (a INT);
+affected rows: 0
+SHOW TABLES IN db1;
+Tables_in_db1
+t1
+affected rows: 1
+CREATE OR REPLACE DATABASE db1;
+affected rows: 2
+SHOW TABLES IN db1;
+Tables_in_db1
+affected rows: 0
+CREATE OR REPLACE DATABASE IF NOT EXISTS db2;
+ERROR HY000: Incorrect usage of OR REPLACE and IF NOT EXISTS
+DROP DATABASE db1;
+affected rows: 0
+DROP DATABASE IF EXISTS db1;
+affected rows: 0
+Warnings:
+Note 1008 Can't drop database 'db1'; database doesn't exist
+DROP DATABASE db1;
+ERROR HY000: Can't drop database 'db1'; database doesn't exist
+CREATE OR REPLACE DATABASE db1;
+affected rows: 1
+SHOW TABLES IN db1;
+Tables_in_db1
+affected rows: 0
+CREATE DATABASE db1;
+ERROR HY000: Can't create database 'db1'; database exists
+DROP DATABASE IF EXISTS db1;
+affected rows: 0
+DROP DATABASE IF EXISTS db1;
+affected rows: 0
+Warnings:
+Note 1008 Can't drop database 'db1'; database doesn't exist
diff --git a/mysql-test/suite/rpl/r/rpl_create_drop_db.result b/mysql-test/suite/rpl/r/rpl_create_drop_db.result
new file mode 100644
index 00000000000..e550f5f574b
--- /dev/null
+++ b/mysql-test/suite/rpl/r/rpl_create_drop_db.result
@@ -0,0 +1,43 @@
+include/master-slave.inc
+[connection master]
+CREATE DATABASE db1;
+CREATE DATABASE IF NOT EXISTS db1;
+Warnings:
+Note 1007 Can't create database 'db1'; database exists
+CREATE OR REPLACE DATABASE db2;
+CREATE OR REPLACE DATABASE db1;
+SHOW DATABASES;
+Database
+db1
+db2
+information_schema
+mtr
+mysql
+performance_schema
+test
+CREATE DATABASE db1;
+ERROR HY000: Can't create database 'db1'; database exists
+DROP DATABASE db3;
+ERROR HY000: Can't drop database 'db3'; database doesn't exist
+CREATE DATABASE IF NOT EXISTS db3;
+SHOW DATABASES;
+Database
+db1
+db2
+db3
+information_schema
+mtr
+mysql
+performance_schema
+test
+DROP DATABASE db1;
+DROP DATABASE db2;
+DROP DATABASE IF EXISTS db3;
+SHOW DATABASES;
+Database
+information_schema
+mtr
+mysql
+performance_schema
+test
+include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/t/rpl_create_drop_db.test b/mysql-test/suite/rpl/t/rpl_create_drop_db.test
new file mode 100644
index 00000000000..23ea61f557a
--- /dev/null
+++ b/mysql-test/suite/rpl/t/rpl_create_drop_db.test
@@ -0,0 +1,33 @@
+--source include/master-slave.inc
+
+connection master;
+
+CREATE DATABASE db1;
+CREATE DATABASE IF NOT EXISTS db1;
+CREATE OR REPLACE DATABASE db2;
+CREATE OR REPLACE DATABASE db1;
+sync_slave_with_master;
+
+SHOW DATABASES;
+
+connection master;
+--error ER_DB_CREATE_EXISTS
+CREATE DATABASE db1;
+
+--error ER_DB_DROP_EXISTS
+DROP DATABASE db3;
+
+CREATE DATABASE IF NOT EXISTS db3;
+sync_slave_with_master;
+
+SHOW DATABASES;
+
+connection master;
+DROP DATABASE db1;
+DROP DATABASE db2;
+DROP DATABASE IF EXISTS db3;
+sync_slave_with_master;
+
+SHOW DATABASES;
+
+--source include/rpl_end.inc
diff --git a/mysql-test/t/create_drop_binlog.test b/mysql-test/t/create_drop_binlog.test
new file mode 100644
index 00000000000..27d409b8fc3
--- /dev/null
+++ b/mysql-test/t/create_drop_binlog.test
@@ -0,0 +1,20 @@
+--source include/have_log_bin.inc
+
+--let $binlog_file=query_get_value(SHOW MASTER STATUS, File, 1)
+--let $binlog_start=query_get_value(SHOW MASTER STATUS, Position, 1)
+
+CREATE OR REPLACE DATABASE d1;
+CREATE OR REPLACE DATABASE d1;
+DROP DATABASE d1;
+CREATE DATABASE IF NOT EXISTS d1;
+CREATE DATABASE IF NOT EXISTS d1;
+DROP DATABASE IF EXISTS d1;
+DROP DATABASE IF EXISTS d1;
+--echo "Runnig SHOW BINLOG EVENTS"
+--replace_column 1 # 2 # 5 #
+--replace_regex /xid=[0-9]+/xid=XX/ /GTID [0-9]+-[0-9]+-[0-9]+/GTID #-#-#/ /Server.ver.*/VERSIONS/
+--disable_query_log
+--eval SHOW BINLOG EVENTS FROM $binlog_start;
+--enable_query_log
+RESET MASTER;
+USE test;
diff --git a/mysql-test/t/create_drop_db.test b/mysql-test/t/create_drop_db.test
new file mode 100644
index 00000000000..13391c35a4d
--- /dev/null
+++ b/mysql-test/t/create_drop_db.test
@@ -0,0 +1,32 @@
+# Enable diisplaying rows affected
+--enable_info
+
+CREATE DATABASE IF NOT EXISTS db1;
+
+CREATE DATABASE IF NOT EXISTS db1;
+CREATE TABLE db1.t1 (a INT);
+SHOW TABLES IN db1;
+
+CREATE OR REPLACE DATABASE db1;
+SHOW TABLES IN db1;
+
+--error ER_WRONG_USAGE
+CREATE OR REPLACE DATABASE IF NOT EXISTS db2;
+
+DROP DATABASE db1;
+
+DROP DATABASE IF EXISTS db1;
+
+--error ER_DB_DROP_EXISTS
+DROP DATABASE db1;
+
+CREATE OR REPLACE DATABASE db1;
+SHOW TABLES IN db1;
+
+--error ER_DB_CREATE_EXISTS
+CREATE DATABASE db1;
+
+DROP DATABASE IF EXISTS db1;
+DROP DATABASE IF EXISTS db1;
+
+--disable_info
diff --git a/sql/sql_db.cc b/sql/sql_db.cc
index a2f4322d071..24814497600 100644
--- a/sql/sql_db.cc
+++ b/sql/sql_db.cc
@@ -62,6 +62,8 @@ static void mysql_change_db_impl(THD *thd,
LEX_STRING *new_db_name,
ulong new_db_access,
CHARSET_INFO *new_db_charset);
+static bool mysql_rm_db_internal(THD *thd, char *db,
+ bool if_exists, bool silent);
/* Database options hash */
@@ -542,7 +544,7 @@ CHARSET_INFO *get_default_db_collation(THD *thd, const char *db_name)
Create a database
SYNOPSIS
- mysql_create_db()
+ mysql_create_db_iternal()
thd Thread handler
db Name of database to create
Function assumes that this is already validated.
@@ -563,14 +565,13 @@ CHARSET_INFO *get_default_db_collation(THD *thd, const char *db_name)
*/
-int mysql_create_db(THD *thd, char *db,
- const DDL_options_st &options,
- Schema_specification_st *create_info,
- bool silent)
+static int
+mysql_create_db_internal(THD *thd, char *db,
+ const DDL_options_st &options,
+ Schema_specification_st *create_info,
+ bool silent)
{
char path[FN_REFLEN+16];
- long result= 1;
- int error= 0;
MY_STAT stat_info;
uint path_len;
DBUG_ENTER("mysql_create_db");
@@ -599,32 +600,45 @@ int mysql_create_db(THD *thd, char *db,
path_len= build_table_filename(path, sizeof(path) - 1, db, "", "", 0);
path[path_len-1]= 0; // Remove last '/' from path
- if (mysql_file_stat(key_file_misc, path, &stat_info, MYF(0)))
+ long affected_rows= 1;
+ if (!mysql_file_stat(key_file_misc, path, &stat_info, MYF(0)))
{
- if (!options.if_not_exists())
+ // The database directory does not exist, or my_file_stat() failed
+ if (my_errno != ENOENT)
{
- my_error(ER_DB_CREATE_EXISTS, MYF(0), db);
- error= -1;
- goto exit;
+ my_error(EE_STAT, MYF(0), path, my_errno);
+ DBUG_RETURN(1);
}
+ }
+ else if (options.or_replace())
+ {
+ if (mysql_rm_db_internal(thd, db, 0, true)) // Removing the old database
+ DBUG_RETURN(1);
+ /*
+ Reset the diagnostics m_status.
+ It might be set ot DA_OK in mysql_rm_db.
+ */
+ thd->get_stmt_da()->reset_diagnostics_area();
+ affected_rows= 2;
+ }
+ else if (options.if_not_exists())
+ {
push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
- ER_DB_CREATE_EXISTS, ER(ER_DB_CREATE_EXISTS), db);
- error= 0;
+ ER_DB_CREATE_EXISTS, ER(ER_DB_CREATE_EXISTS), db);
+ affected_rows= 0;
goto not_silent;
}
else
{
- if (my_errno != ENOENT)
- {
- my_error(EE_STAT, MYF(0), path, my_errno);
- goto exit;
- }
- if (my_mkdir(path,0777,MYF(0)) < 0)
- {
- my_error(ER_CANT_CREATE_DB, MYF(0), db, my_errno);
- error= -1;
- goto exit;
- }
+ my_error(ER_DB_CREATE_EXISTS, MYF(0), db);
+ DBUG_RETURN(-1);
+ }
+
+
+ if (my_mkdir(path, 0777, MYF(0)) < 0)
+ {
+ my_error(ER_CANT_CREATE_DB, MYF(0), db, my_errno);
+ DBUG_RETURN(-1);
}
path[path_len-1]= FN_LIBCHAR;
@@ -637,10 +651,7 @@ int mysql_create_db(THD *thd, char *db,
*/
path[path_len]= 0;
if (rmdir(path) >= 0)
- {
- error= -1;
- goto exit;
- }
+ DBUG_RETURN(-1);
/*
We come here when we managed to create the database, but not the option
file. In this case it's best to just continue as if nothing has
@@ -690,23 +701,20 @@ not_silent:
metadata lock on the schema
*/
if (mysql_bin_log.write(&qinfo))
- {
- error= -1;
- goto exit;
- }
+ DBUG_RETURN(-1);
}
- my_ok(thd, result);
+ my_ok(thd, affected_rows);
}
-exit:
- DBUG_RETURN(error);
+ DBUG_RETURN(0);
}
/* db-name is already validated when we come here */
-bool mysql_alter_db(THD *thd, const char *db,
- Schema_specification_st *create_info)
+static bool
+mysql_alter_db_internal(THD *thd, const char *db,
+ Schema_specification_st *create_info)
{
char path[FN_REFLEN+16];
long result=1;
@@ -762,6 +770,31 @@ exit:
}
+int mysql_create_db(THD *thd, char *db,
+ const DDL_options_st &options,
+ const Schema_specification_st *create_info)
+{
+ /*
+ As mysql_create_db_internal() may modify Db_create_info structure passed
+ to it, we need to use a copy to make execution prepared statement- safe.
+ */
+ Schema_specification_st tmp(*create_info);
+ return mysql_create_db_internal(thd, db, options, &tmp, false);
+}
+
+
+bool mysql_alter_db(THD *thd, const char *db,
+ const Schema_specification_st *create_info)
+{
+ /*
+ As mysql_alter_db_internal() may modify Db_create_info structure passed
+ to it, we need to use a copy to make execution prepared statement- safe.
+ */
+ Schema_specification_st tmp(*create_info);
+ return mysql_alter_db_internal(thd, db, &tmp);
+}
+
+
/**
Drop all tables, routines and events in a database and the database itself.
@@ -777,7 +810,8 @@ exit:
@retval true Error
*/
-bool mysql_rm_db(THD *thd,char *db, bool if_exists, bool silent)
+static bool
+mysql_rm_db_internal(THD *thd,char *db, bool if_exists, bool silent)
{
ulong deleted_tables= 0;
bool error= true;
@@ -1004,6 +1038,12 @@ exit:
}
+bool mysql_rm_db(THD *thd,char *db, bool if_exists)
+{
+ return mysql_rm_db_internal(thd, db, if_exists, false);
+}
+
+
static bool find_db_tables_and_rm_known_files(THD *thd, MY_DIR *dirp,
char *dbname,
const char *path,
@@ -1654,7 +1694,8 @@ bool mysql_upgrade_db(THD *thd, LEX_STRING *old_db)
}
/* Step1: Create the new database */
- if ((error= mysql_create_db(thd, new_db.str, DDL_options(), &create_info, 1)))
+ if ((error= mysql_create_db_internal(thd, new_db.str,
+ DDL_options(), &create_info, 1)))
goto exit;
/* Step2: Move tables to the new database */
@@ -1778,7 +1819,7 @@ bool mysql_upgrade_db(THD *thd, LEX_STRING *old_db)
to execute them again.
mysql_rm_db() also "unuses" if we drop the current database.
*/
- error= mysql_rm_db(thd, old_db->str, 0, 1);
+ error= mysql_rm_db_internal(thd, old_db->str, 0, true);
/* Step8: logging */
if (mysql_bin_log.is_open())
diff --git a/sql/sql_db.h b/sql/sql_db.h
index bdd525779f0..b0d99cc1ba4 100644
--- a/sql/sql_db.h
+++ b/sql/sql_db.h
@@ -22,10 +22,10 @@ class THD;
int mysql_create_db(THD *thd, char *db,
const DDL_options_st &options,
- Schema_specification_st *create, bool silent);
+ const Schema_specification_st *create);
bool mysql_alter_db(THD *thd, const char *db,
- Schema_specification_st *create);
-bool mysql_rm_db(THD *thd, char *db, bool if_exists, bool silent);
+ const Schema_specification_st *create);
+bool mysql_rm_db(THD *thd, char *db, bool if_exists);
bool mysql_upgrade_db(THD *thd, LEX_STRING *old_db);
bool mysql_change_db(THD *thd, const LEX_STRING *new_db_name,
bool force_switch);
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 60d721d710e..ae8ab32a7ec 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -4301,7 +4301,7 @@ end_with_restore_list:
if (check_access(thd, CREATE_ACL, lex->name.str, NULL, NULL, 1, 0))
break;
WSREP_TO_ISOLATION_BEGIN(lex->name.str, NULL, NULL)
- res= mysql_create_db(thd, lex->name.str, lex->create_info, &create_info, 0);
+ res= mysql_create_db(thd, lex->name.str, lex->create_info, &create_info);
break;
}
case SQLCOM_DROP_DB:
@@ -4333,7 +4333,7 @@ end_with_restore_list:
if (check_access(thd, DROP_ACL, lex->name.str, NULL, NULL, 1, 0))
break;
WSREP_TO_ISOLATION_BEGIN(lex->name.str, NULL, NULL)
- res= mysql_rm_db(thd, lex->name.str, lex->if_exists(), 0);
+ res= mysql_rm_db(thd, lex->name.str, lex->if_exists());
break;
}
case SQLCOM_ALTER_DB_UPGRADE:
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 879697e1507..f9e6c9653f5 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -2538,7 +2538,7 @@ create:
MYSQL_YYABORT;
}
opt_index_lock_algorithm { }
- | CREATE DATABASE opt_if_not_exists ident
+ | create_or_replace DATABASE opt_if_not_exists ident
{
Lex->create_info.default_table_charset= NULL;
Lex->create_info.used_fields= 0;
@@ -2546,7 +2546,8 @@ create:
opt_create_database_options
{
LEX *lex=Lex;
- lex->set_command(SQLCOM_CREATE_DB, $3);
+ if (lex->set_command_with_check(SQLCOM_CREATE_DB, 0, $1 | $3))
+ MYSQL_YYABORT;
lex->name= $4;
}
| create_or_replace