diff options
author | Alexander Barkov <bar@mariadb.org> | 2014-12-10 08:13:08 +0400 |
---|---|---|
committer | Alexander Barkov <bar@mariadb.org> | 2014-12-10 08:13:08 +0400 |
commit | dd270e43bf84e7dbf2a9ee7c6c3a6de372128e83 (patch) | |
tree | ca8985f1c09a483871af76066068269c55c23647 | |
parent | c6d3f8058db30a6621e36b05564a1b2ae68bec7f (diff) | |
download | mariadb-git-dd270e43bf84e7dbf2a9ee7c6c3a6de372128e83.tar.gz |
MDEV-7280 DATABASE: CREATE OR REPLACE
-rw-r--r-- | mysql-test/r/create_drop_binlog.result | 29 | ||||
-rw-r--r-- | mysql-test/r/create_drop_db.result | 40 | ||||
-rw-r--r-- | mysql-test/suite/rpl/r/rpl_create_drop_db.result | 43 | ||||
-rw-r--r-- | mysql-test/suite/rpl/t/rpl_create_drop_db.test | 33 | ||||
-rw-r--r-- | mysql-test/t/create_drop_binlog.test | 20 | ||||
-rw-r--r-- | mysql-test/t/create_drop_db.test | 32 | ||||
-rw-r--r-- | sql/sql_db.cc | 123 | ||||
-rw-r--r-- | sql/sql_db.h | 6 | ||||
-rw-r--r-- | sql/sql_parse.cc | 4 | ||||
-rw-r--r-- | sql/sql_yacc.yy | 5 |
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 |