diff --git a/mysql-test/r/create_drop_binlog.result b/mysql-test/r/create_drop_binlog.result index 6d679eef157..6aa20a8d4e1 100644 --- a/mysql-test/r/create_drop_binlog.result +++ b/mysql-test/r/create_drop_binlog.result @@ -27,6 +27,24 @@ Log_name Pos Event_type Server_id End_log_pos Info # # Query 1 # DROP DATABASE IF EXISTS d1 RESET MASTER; USE test; +# +# CREATE SERVER is not logged +# +CREATE OR REPLACE SERVER s1 FOREIGN DATA WRAPPER mysql OPTIONS (USER 'root', HOST 'localhost', DATABASE 'test'); +CREATE OR REPLACE SERVER s1 FOREIGN DATA WRAPPER mysql OPTIONS (USER 'root', HOST 'localhost', DATABASE 'test'); +DROP SERVER s1; +CREATE SERVER IF NOT EXISTS s1 FOREIGN DATA WRAPPER mysql OPTIONS (USER 'root', HOST 'localhost', DATABASE 'test'); +CREATE SERVER IF NOT EXISTS s1 FOREIGN DATA WRAPPER mysql OPTIONS (USER 'root', HOST 'localhost', DATABASE 'test'); +Warnings: +Note 1476 The foreign server, s1, you are trying to create already exists. +DROP SERVER IF EXISTS s1; +DROP SERVER IF EXISTS s1; +SHOW BINLOG EVENTS; +Log_name Pos Event_type Server_id End_log_pos Info +# # Format_desc 1 # VER +# # Gtid_list 1 # [] +# # Binlog_checkpoint 1 # master-bin.000001 +RESET MASTER; CREATE OR REPLACE VIEW v1 AS SELECT 1; CREATE OR REPLACE VIEW v1 AS SELECT 1; DROP VIEW v1; diff --git a/mysql-test/r/create_drop_server.result b/mysql-test/r/create_drop_server.result new file mode 100644 index 00000000000..5c3c15ff477 --- /dev/null +++ b/mysql-test/r/create_drop_server.result @@ -0,0 +1,37 @@ +# +# MDEV-7285 SERVER: CREATE OR REPLACE and CREATE IF NOT EXISTS +# +CREATE SERVER IF NOT EXISTS server1 FOREIGN DATA WRAPPER mysql OPTIONS (USER 'user1', HOST 'localhost', DATABASE 'test0'); +SELECT server_name, username, db FROM mysql.servers; +server_name username db +server1 user1 test0 +CREATE SERVER IF NOT EXISTS server1 FOREIGN DATA WRAPPER mysql OPTIONS (USER 'user2', HOST 'localhost', DATABASE 'test1'); +Warnings: +Note 1476 The foreign server, server1, you are trying to create already exists. +SELECT server_name, username, db FROM mysql.servers; +server_name username db +server1 user1 test0 +CREATE OR REPLACE SERVER server1 FOREIGN DATA WRAPPER mysql OPTIONS (USER 'user3', HOST 'localhost', DATABASE 'test2'); +SELECT server_name, username, db FROM mysql.servers; +server_name username db +server1 user3 test2 +DROP SERVER IF EXISTS server1; +SELECT server_name, username, db FROM mysql.servers; +server_name username db +DROP SERVER IF EXISTS server1; +CREATE SERVER server_1 FOREIGN DATA WRAPPER mysql OPTIONS (USER 'mysqltest_1', HOST 'localhost', DATABASE 'test0'); +CREATE SERVER server_1 FOREIGN DATA WRAPPER mysql OPTIONS (USER 'mysqltest_1', HOST 'localhost', DATABASE 'test1'); +ERROR HY000: The foreign server, server_1, you are trying to create already exists. +CREATE SERVER IF NOT EXISTS server_1 FOREIGN DATA WRAPPER mysql OPTIONS (USER 'mysqltest_1', HOST 'localhost', DATABASE 'test2'); +Warnings: +Note 1476 The foreign server, server_1, you are trying to create already exists. +SELECT server_name, username, db FROM mysql.servers; +server_name username db +server_1 mysqltest_1 test0 +CREATE OR REPLACE SERVER IF NOT EXISTS server_1 FOREIGN DATA WRAPPER mysql OPTIONS (USER 'mysqltest_1', HOST 'localhost', DATABASE 'test3'); +ERROR HY000: Incorrect usage of OR REPLACE and IF NOT EXISTS +CREATE OR REPLACE SERVER server_1 FOREIGN DATA WRAPPER mysql OPTIONS (USER 'mysqltest_1', HOST 'localhost', DATABASE 'test4'); +SELECT server_name, username, db FROM mysql.servers; +server_name username db +server_1 mysqltest_1 test4 +DROP SERVER server_1; diff --git a/mysql-test/t/create_drop_binlog.test b/mysql-test/t/create_drop_binlog.test index 105222f7e05..de8bc7a4933 100644 --- a/mysql-test/t/create_drop_binlog.test +++ b/mysql-test/t/create_drop_binlog.test @@ -19,6 +19,22 @@ DROP DATABASE IF EXISTS d1; RESET MASTER; USE test; +--echo # +--echo # CREATE SERVER is not logged +--echo # +CREATE OR REPLACE SERVER s1 FOREIGN DATA WRAPPER mysql OPTIONS (USER 'root', HOST 'localhost', DATABASE 'test'); +CREATE OR REPLACE SERVER s1 FOREIGN DATA WRAPPER mysql OPTIONS (USER 'root', HOST 'localhost', DATABASE 'test'); +DROP SERVER s1; +CREATE SERVER IF NOT EXISTS s1 FOREIGN DATA WRAPPER mysql OPTIONS (USER 'root', HOST 'localhost', DATABASE 'test'); +CREATE SERVER IF NOT EXISTS s1 FOREIGN DATA WRAPPER mysql OPTIONS (USER 'root', HOST 'localhost', DATABASE 'test'); +DROP SERVER IF EXISTS s1; +DROP SERVER IF EXISTS s1; +--replace_column 1 # 2 # 5 # +--replace_regex /xid=[0-9]+/xid=XX/ /GTID [0-9]+-[0-9]+-[0-9]+/GTID #-#-#/ /Server.ver.*/VER/ +SHOW BINLOG EVENTS; +RESET MASTER; + + CREATE OR REPLACE VIEW v1 AS SELECT 1; CREATE OR REPLACE VIEW v1 AS SELECT 1; diff --git a/mysql-test/t/create_drop_server.test b/mysql-test/t/create_drop_server.test new file mode 100644 index 00000000000..d634cc1ccf1 --- /dev/null +++ b/mysql-test/t/create_drop_server.test @@ -0,0 +1,25 @@ +--echo # +--echo # MDEV-7285 SERVER: CREATE OR REPLACE and CREATE IF NOT EXISTS +--echo # + +CREATE SERVER IF NOT EXISTS server1 FOREIGN DATA WRAPPER mysql OPTIONS (USER 'user1', HOST 'localhost', DATABASE 'test0'); +SELECT server_name, username, db FROM mysql.servers; +CREATE SERVER IF NOT EXISTS server1 FOREIGN DATA WRAPPER mysql OPTIONS (USER 'user2', HOST 'localhost', DATABASE 'test1'); +SELECT server_name, username, db FROM mysql.servers; +CREATE OR REPLACE SERVER server1 FOREIGN DATA WRAPPER mysql OPTIONS (USER 'user3', HOST 'localhost', DATABASE 'test2'); +SELECT server_name, username, db FROM mysql.servers; +DROP SERVER IF EXISTS server1; +SELECT server_name, username, db FROM mysql.servers; +DROP SERVER IF EXISTS server1; + + +CREATE SERVER server_1 FOREIGN DATA WRAPPER mysql OPTIONS (USER 'mysqltest_1', HOST 'localhost', DATABASE 'test0'); +--error ER_FOREIGN_SERVER_EXISTS +CREATE SERVER server_1 FOREIGN DATA WRAPPER mysql OPTIONS (USER 'mysqltest_1', HOST 'localhost', DATABASE 'test1'); +CREATE SERVER IF NOT EXISTS server_1 FOREIGN DATA WRAPPER mysql OPTIONS (USER 'mysqltest_1', HOST 'localhost', DATABASE 'test2'); +SELECT server_name, username, db FROM mysql.servers; +--error ER_WRONG_USAGE +CREATE OR REPLACE SERVER IF NOT EXISTS server_1 FOREIGN DATA WRAPPER mysql OPTIONS (USER 'mysqltest_1', HOST 'localhost', DATABASE 'test3'); +CREATE OR REPLACE SERVER server_1 FOREIGN DATA WRAPPER mysql OPTIONS (USER 'mysqltest_1', HOST 'localhost', DATABASE 'test4'); +SELECT server_name, username, db FROM mysql.servers; +DROP SERVER server_1; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 5f16f153c8a..0bbc1a2dac7 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -5446,21 +5446,13 @@ create_sp_error: } case SQLCOM_CREATE_SERVER: { - int error; LEX *lex= thd->lex; DBUG_PRINT("info", ("case SQLCOM_CREATE_SERVER")); if (check_global_access(thd, SUPER_ACL)) break; - if ((error= create_server(thd, &lex->server_options))) - { - DBUG_PRINT("info", ("problem creating server <%s>", - lex->server_options.server_name.str)); - my_error(error, MYF(0), lex->server_options.server_name.str); - break; - } - my_ok(thd, 1); + res= create_server(thd, &lex->server_options); break; } case SQLCOM_ALTER_SERVER: diff --git a/sql/sql_servers.cc b/sql/sql_servers.cc index 1fd46027725..7f4d70a6b43 100644 --- a/sql/sql_servers.cc +++ b/sql/sql_servers.cc @@ -582,8 +582,8 @@ int insert_server_record(TABLE *table, FOREIGN_SERVER *server) This function takes as its arguments a THD object pointer and a pointer to a LEX_SERVER_OPTIONS struct from the parser. The member 'server_name' of this LEX_SERVER_OPTIONS struct contains the value of the server to be - deleted. The mysql.servers table is opened via open_ltable, a table object - returned, the servers cache mutex locked, then delete_server_record is + deleted. The mysql.servers table is opened via open_ltable, + a table object returned, then delete_server_record is called with this table object and LEX_SERVER_OPTIONS server_name and server_name_length passed, containing the name of the server to be dropped/deleted, then delete_server_record_in_cache is called to delete @@ -594,20 +594,18 @@ int insert_server_record(TABLE *table, FOREIGN_SERVER *server) > 0 - error code */ -int drop_server(THD *thd, LEX_SERVER_OPTIONS *server_options) +static int drop_server_internal(THD *thd, LEX_SERVER_OPTIONS *server_options) { int error; TABLE_LIST tables; TABLE *table; - DBUG_ENTER("drop_server"); + DBUG_ENTER("drop_server_internal"); DBUG_PRINT("info", ("server name server->server_name %s", server_options->server_name.str)); tables.init_one_table("mysql", 5, "servers", 7, "servers", TL_WRITE); - mysql_rwlock_wrlock(&THR_LOCK_servers); - /* hit the memory hit first */ if ((error= delete_server_record_in_cache(server_options))) goto end; @@ -630,11 +628,22 @@ int drop_server(THD *thd, LEX_SERVER_OPTIONS *server_options) } end: - mysql_rwlock_unlock(&THR_LOCK_servers); DBUG_RETURN(error); } +/** + Drop a server with servers cache mutex lock. +*/ +int drop_server(THD *thd, LEX_SERVER_OPTIONS *server_options) +{ + mysql_rwlock_wrlock(&THR_LOCK_servers); + int rc= drop_server_internal(thd, server_options); + mysql_rwlock_unlock(&THR_LOCK_servers); + return rc; +} + + /* SYNOPSIS @@ -989,8 +998,24 @@ int create_server(THD *thd, LEX_SERVER_OPTIONS *server_options) /* hit the memory first */ if (my_hash_search(&servers_cache, (uchar*) server_options->server_name.str, server_options->server_name.length)) - goto end; - + { + if (thd->lex->create_info.or_replace()) + { + if ((error= drop_server_internal(thd, server_options))) + goto end; + } + else if (thd->lex->create_info.if_not_exists()) + { + push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE, + ER_FOREIGN_SERVER_EXISTS, + ER(ER_FOREIGN_SERVER_EXISTS), + server_options->server_name.str); + error= 0; + goto end; + } + else + goto end; + } if (!(server= prepare_server_struct_for_insert(server_options))) { @@ -1006,6 +1031,16 @@ int create_server(THD *thd, LEX_SERVER_OPTIONS *server_options) end: mysql_rwlock_unlock(&THR_LOCK_servers); + + if (error) + { + DBUG_PRINT("info", ("problem creating server <%s>", + server_options->server_name.str)); + my_error(error, MYF(0), server_options->server_name.str); + } + else + my_ok(thd); + DBUG_RETURN(error); } diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 53cfc3baadc..927de37f2f1 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -2584,18 +2584,21 @@ create: { Lex->alter_tablespace_info->ts_cmd_type= CREATE_TABLESPACE; } - | CREATE server_def - { - Lex->sql_command= SQLCOM_CREATE_SERVER; - } + | create_or_replace { Lex->set_command(SQLCOM_CREATE_SERVER, $1); } + server_def + { } ; server_def: - SERVER_SYM ident_or_text - { Lex->server_options.reset($2); } + SERVER_SYM opt_if_not_exists ident_or_text + { + if (Lex->add_create_options_with_check($2)) + MYSQL_YYABORT; + Lex->server_options.reset($3); + } FOREIGN DATA_SYM WRAPPER_SYM ident_or_text OPTIONS_SYM '(' server_options_list ')' - { Lex->server_options.scheme= $7; } + { Lex->server_options.scheme= $8; } ; server_options_list: