#At file:///home/lsoares/Workspace/mysql-server/bugfix/25705/5.1-bt/ based on revid:patrick.crews@stripped
2768 Luis Soares 2009-02-09
BUG#25705: Federated: CREATE SERVER logging
BUG#13684: SP: DROP PROCEDURE|FUNCTION IF EXISTS not binlogged if routine
does not exist
From BUG#25705, one finds that the drop/create server is not binlogged
in mixed or statement mode replication. Instead it gets logged only in row
based replication as rows inserted/deleted into/from mysql.servers. From
BUG#13684, one finds that the drop server if exists is not being binlogged
also.
This patch addresses these issues by binlogging CREATE/DROP server even if
the "IF EXISTS" clause is present. Furthermore, it will always log create/drop
server as statements as these are referred in the manual to be "DDL":
* http://dev.mysql.com/doc/refman/5.1/en/drop-server.html
* http://dev.mysql.com/doc/refman/5.1/en/create-server.html
added:
mysql-test/suite/binlog/r/binlog_create_server.result
mysql-test/suite/binlog/t/binlog_create_server.test
modified:
sql/sql_parse.cc
sql/sql_servers.cc
per-file messages:
sql/sql_parse.cc
Handle extra case when you get an error from writing into the binlog.
sql/sql_servers.cc
Binlog hooks calls to log create/drop server.
=== added file 'mysql-test/suite/binlog/r/binlog_create_server.result'
--- a/mysql-test/suite/binlog/r/binlog_create_server.result 1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/binlog/r/binlog_create_server.result 2009-02-09 15:53:51 +0000
@@ -0,0 +1,19 @@
+DROP SERVER IF EXISTS s1;
+CREATE SERVER s1 FOREIGN DATA WRAPPER mysql OPTIONS (user 'Remote', Host '10.10.10.10', database 'test');
+DROP SERVER IF EXISTS s1;
+CREATE SERVER s1 FOREIGN DATA WRAPPER mysql OPTIONS (user 'Remote', Host '10.10.10.10', database 'test');
+DROP SERVER s1;
+DROP SERVER s1;
+ERROR HY000: The foreign server name you are trying to reference does not exist. Data source error: s1
+CREATE SERVER s1 FOREIGN DATA WRAPPER mysql OPTIONS (user 'Remote', Host '10.10.10.10', database 'test');
+CREATE SERVER s1 FOREIGN DATA WRAPPER mysql OPTIONS (user 'Remote', Host '10.10.10.10', database 'test');
+ERROR HY000: The foreign server, s1, you are trying to create already exists.
+show binlog events from <binlog_start>;
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 # Query # # use `test`; DROP SERVER IF EXISTS s1
+master-bin.000001 # Query # # use `test`; CREATE SERVER s1 FOREIGN DATA WRAPPER mysql OPTIONS (user 'Remote', Host '10.10.10.10', database 'test')
+master-bin.000001 # Query # # use `test`; DROP SERVER IF EXISTS s1
+master-bin.000001 # Query # # use `test`; CREATE SERVER s1 FOREIGN DATA WRAPPER mysql OPTIONS (user 'Remote', Host '10.10.10.10', database 'test')
+master-bin.000001 # Query # # use `test`; DROP SERVER s1
+master-bin.000001 # Query # # use `test`; CREATE SERVER s1 FOREIGN DATA WRAPPER mysql OPTIONS (user 'Remote', Host '10.10.10.10', database 'test')
+DROP SERVER s1;
=== added file 'mysql-test/suite/binlog/t/binlog_create_server.test'
--- a/mysql-test/suite/binlog/t/binlog_create_server.test 1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/binlog/t/binlog_create_server.test 2009-02-09 15:53:51 +0000
@@ -0,0 +1,48 @@
+#
+# BUG#25705: Federated: CREATE SERVER logging
+#
+# The CREATE SERVER statement should appear in binlog
+# if I start the remote server with --log-bin.
+#
+# The CREATE SERVER and DROP SERVER [IF EXISTS] dont get binlogged.
+#
+# This test aims at testing the fix for the given bug. It is implemented
+# as follows:
+#
+# i) drop a server if exists when server does not exist
+# ii) drop a server if exists when server exists
+# iii) drop a server that exists
+# iv) drop a server that does not exist
+# v) create the same server twice and check that it does not get binlogged
+# twice
+# vi) show binlog events and:
+# - check that all 3 first drops are there and that the last one isnt.
+# - check that there are only 3 CREATE servers
+#
+
+--source include/have_log_bin.inc
+
+# i) check if drop if exists is logged without having a server object
+DROP SERVER IF EXISTS s1;
+
+# ii) check if drop server if exists is logged when server exists
+CREATE SERVER s1 FOREIGN DATA WRAPPER mysql OPTIONS (user 'Remote', Host '10.10.10.10', database 'test');
+DROP SERVER IF EXISTS s1;
+
+# iii) check if drop server is logged as it should
+CREATE SERVER s1 FOREIGN DATA WRAPPER mysql OPTIONS (user 'Remote', Host '10.10.10.10', database 'test');
+DROP SERVER s1;
+
+# iv) check that drop server is not logged when server does not exist
+--error 1477
+DROP SERVER s1;
+
+# v) duplicate server does not get binlogged
+CREATE SERVER s1 FOREIGN DATA WRAPPER mysql OPTIONS (user 'Remote', Host '10.10.10.10', database 'test');
+--error 1476
+CREATE SERVER s1 FOREIGN DATA WRAPPER mysql OPTIONS (user 'Remote', Host '10.10.10.10', database 'test');
+
+--source include/show_binlog_events.inc
+
+# CLEAN UP
+DROP SERVER s1;
=== modified file 'sql/sql_parse.cc'
--- a/sql/sql_parse.cc 2009-01-30 13:44:49 +0000
+++ b/sql/sql_parse.cc 2009-02-09 15:53:51 +0000
@@ -4802,6 +4802,11 @@ create_sp_error:
lex->server_options.server_name));
my_error(err_code, MYF(0), lex->server_options.server_name);
}
+ else if (err_code != ER_FOREIGN_SERVER_DOESNT_EXIST)
+ {
+ res= err_code;
+ break;
+ }
else
{
my_ok(thd, 0);
=== modified file 'sql/sql_servers.cc'
--- a/sql/sql_servers.cc 2008-07-15 17:46:02 +0000
+++ b/sql/sql_servers.cc 2009-02-09 15:53:51 +0000
@@ -373,14 +373,33 @@ insert_server(THD *thd, FOREIGN_SERVER *
if (! (table= open_ltable(thd, &tables, TL_WRITE, 0)))
goto end;
- /* insert the server into the table */
- if ((error= insert_server_record(table, server)))
+ /*
+ insert the server into the table. Disabling binlog as this should be
+ binlogged as statment always.
+ */
+ tmp_disable_binlog(thd);
+ error= insert_server_record(table, server);
+ reenable_binlog(thd);
+
+ if (error)
goto end;
/* insert the server into the cache */
if ((error= insert_server_record_into_cache(server)))
goto end;
+ /*
+ Time to log the insertion into the binlog. CREATE/DROP SERVER should be always
+ logged as statement.
+ */
+ if (mysql_bin_log.is_open())
+ {
+ error= thd->binlog_query(THD::STMT_QUERY_TYPE,
+ thd->query, thd->query_length,
+ FALSE /* statement non-transactional on purpose: "DDL" */,
+ FALSE /* suppress_use */,
+ thd->killed /* killed */);
+ }
end:
DBUG_RETURN(error);
}
@@ -599,7 +618,9 @@ int drop_server(THD *thd, LEX_SERVER_OPT
goto end;
}
+ tmp_disable_binlog(thd);
error= delete_server_record(table, name.str, name.length);
+ reenable_binlog(thd);
/* close the servers table before we call closed_cached_connection_tables */
close_thread_tables(thd);
@@ -611,6 +632,21 @@ int drop_server(THD *thd, LEX_SERVER_OPT
}
end:
+ /*
+ Time to log the insertion into the binlog if all went well:
+ i) no error
+ ii) drop if exists and server did not exist
+ Otherwise dont log it.
+ */
+ if (mysql_bin_log.is_open() && (!error ||
+ (thd->lex->drop_if_exists && error == ER_FOREIGN_SERVER_DOESNT_EXIST)))
+ {
+ error= thd->binlog_query(THD::STMT_QUERY_TYPE,
+ thd->query, thd->query_length,
+ FALSE /* statement non-transactional on purpose: "DDL" */,
+ FALSE /* suppress_use */,
+ thd->killed /* killed */);
+ }
rw_unlock(&THR_LOCK_servers);
DBUG_RETURN(error);
}