Commit 61eb9e40 authored by unknown's avatar unknown

Last part of WL#1062: better replication of timezones: no more use

of SET ONE_SHOT; storing tz info directly in event (if this info is needed),
it's now allowed to have different global tz on master and slave.


client/mysqlbinlog.cc:
  we need MAX_TIME_ZONE_NAME_LENGTH when processing log_event.h, and it's declared in mysql_priv.h
mysql-test/r/rpl_timezone.result:
  result update
mysql-test/t/rpl_timezone-slave.opt:
  Now that we can have different global value of timezone on master and slave, let's test it.
mysql-test/t/rpl_timezone.test:
  Tests of the new replication of timezones: checking the output of mysqlbinlog,
  replication of CONVERT_TZ().
sql/ha_innodb.cc:
  No very fast shutdown on Netware (anyway it's disabled on all platforms,
  but this is so that we don't forget to keep it disabled on Netware in the future).
sql/log.cc:
  No more need to write SET ONE_SHOT to binlog for character set and timezone
  (as we store this info  directly nin the Query_log_event now).
sql/log_event.cc:
  Exclude ::write() methods if MYSQL_CLIENT.
  Storing timezone info in the Query_log_event in master. Re-reading it in slave.
  Small code cleanups. I plan to not store the end 0 of catalog in binlog
  events soon.
sql/log_event.h:
  replication of time zones: a place for tz info in Query_log_event,
  in LAST_EVENT_INFO. Plus if we are compiling a client, we don't need
  the ::write() methods, so keeping them out (of mysqlbinlog.cc;
  keeping them in, resulted in problem that mysqlbinlog does not know Timezone
  structure).
sql/mysql_priv.h:
  moving this define from tztime.h (tztime.h has things which are
  too much for a client like mysqlbinlog).
sql/set_var.cc:
  It's now allowed to change global value of charset or timezone even if using binlogging
  or if being a slave.
  Making CONVERT_TZ(,,@@session.time_zone) replicate.
sql/set_var.h:
  these ::check()s are not needed anymore (changing global charset
  or timezone is now allowed even if binlogging or slave)
sql/slave.cc:
  No more need to check for same global timezone if master is 5.x
  (ok, strictly speaking if it is > 5.0.3 but this is alpha).
sql/slave.h:
  a function to wrap settings of charset to default.
sql/tztime.cc:
  Adaptation of my_tz_find() to the case where it's not called from inside
  a query (i.e. cannot join its tz tables to the query's ones): this variant
  opens the tz tables itself, reads from them, and closes them. This is presently
  only used by the slave SQL thread (when it sets the tz before executing a query).
sql/tztime.h:
  declaration of new function, plus moving symbol to mysql_priv.h
  for easier usage in mysqlbinlog (Dmitri, pardon me).
BitKeeper/etc/logging_ok:
  Logging to logging@openlogging.org accepted
parent a3b092e5
...@@ -48,6 +48,7 @@ dlenev@build.mysql.com ...@@ -48,6 +48,7 @@ dlenev@build.mysql.com
dlenev@jabberwock.localdomain dlenev@jabberwock.localdomain
dlenev@mysql.com dlenev@mysql.com
ejonore@mc03.ndb.mysql.com ejonore@mc03.ndb.mysql.com
gbichot@production.mysql.com
gbichot@quadita2.mysql.com gbichot@quadita2.mysql.com
georg@beethoven.local georg@beethoven.local
georg@beethoven.site georg@beethoven.site
......
...@@ -33,9 +33,9 @@ ...@@ -33,9 +33,9 @@
#undef MYSQL_SERVER #undef MYSQL_SERVER
#include "client_priv.h" #include "client_priv.h"
#include <my_time.h> #include <my_time.h>
#include "log_event.h"
/* That one is necessary for defines of OPTION_NO_FOREIGN_KEY_CHECKS etc */ /* That one is necessary for defines of OPTION_NO_FOREIGN_KEY_CHECKS etc */
#include "mysql_priv.h" #include "mysql_priv.h"
#include "log_event.h"
#define BIN_LOG_HEADER_SIZE 4 #define BIN_LOG_HEADER_SIZE 4
#define PROBE_HEADER_LEN (EVENT_LEN_OFFSET+4) #define PROBE_HEADER_LEN (EVENT_LEN_OFFSET+4)
......
...@@ -4,21 +4,31 @@ reset master; ...@@ -4,21 +4,31 @@ reset master;
reset slave; reset slave;
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
start slave; start slave;
set timestamp=100000000;
create table t1 (t timestamp); create table t1 (t timestamp);
create table t2 (t char(32)); create table t2 (t char(32));
select @@time_zone; select @@time_zone;
@@time_zone @@time_zone
Japan
select @@time_zone;
@@time_zone
Europe/Moscow Europe/Moscow
insert into t1 values ('20050101000000'), ('20050611093902');
set time_zone='UTC'; set time_zone='UTC';
insert into t1 values ('20040101000000'), ('20040611093902'); insert into t1 values ('20040101000000'), ('20040611093902');
select * from t1; select * from t1;
t t
2004-12-31 21:00:00
2005-06-11 05:39:02
2004-01-01 00:00:00 2004-01-01 00:00:00
2004-06-11 09:39:02 2004-06-11 09:39:02
set time_zone='UTC';
select * from t1; select * from t1;
t t
2004-01-01 03:00:00 2004-12-31 21:00:00
2004-06-11 13:39:02 2005-06-11 05:39:02
2004-01-01 00:00:00
2004-06-11 09:39:02
delete from t1; delete from t1;
set time_zone='Europe/Moscow'; set time_zone='Europe/Moscow';
insert into t1 values ('20040101000000'), ('20040611093902'); insert into t1 values ('20040101000000'), ('20040611093902');
...@@ -26,19 +36,35 @@ select * from t1; ...@@ -26,19 +36,35 @@ select * from t1;
t t
2004-01-01 00:00:00 2004-01-01 00:00:00
2004-06-11 09:39:02 2004-06-11 09:39:02
set time_zone='Europe/Moscow';
select * from t1; select * from t1;
t t
2004-01-01 00:00:00 2004-01-01 00:00:00
2004-06-11 09:39:02 2004-06-11 09:39:02
show binlog events; /*!40019 SET @@session.max_insert_delayed_threads=0*/;
Log_name Pos Event_type Server_id End_log_pos Info /*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
master-bin.000001 # Format_desc 1 # Server ver: VERSION, Binlog ver: 4 ROLLBACK;
master-bin.000001 # Query 1 # use `test`; create table t1 (t timestamp) use test;
master-bin.000001 # Query 1 # use `test`; create table t2 (t char(32)) SET TIMESTAMP=100000000;
master-bin.000001 # Query 1 # use `test`; SET ONE_SHOT TIME_ZONE='UTC' SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1;
master-bin.000001 # Query 1 # use `test`; insert into t1 values ('20040101000000'), ('20040611093902') SET @@session.sql_mode=0;
master-bin.000001 # Query 1 # use `test`; delete from t1 SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8;
master-bin.000001 # Query 1 # use `test`; insert into t1 values ('20040101000000'), ('20040611093902') create table t1 (t timestamp);
SET TIMESTAMP=100000000;
create table t2 (t char(32));
SET TIMESTAMP=100000000;
SET @@session.time_zone='Europe/Moscow';
insert into t1 values ('20050101000000'), ('20050611093902');
SET TIMESTAMP=100000000;
SET @@session.time_zone='UTC';
insert into t1 values ('20040101000000'), ('20040611093902');
SET TIMESTAMP=100000000;
delete from t1;
SET TIMESTAMP=100000000;
SET @@session.time_zone='Europe/Moscow';
insert into t1 values ('20040101000000'), ('20040611093902');
ROLLBACK;
/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
set time_zone='MET'; set time_zone='MET';
insert into t2 (select t from t1); insert into t2 (select t from t1);
select * from t1; select * from t1;
...@@ -52,10 +78,6 @@ t ...@@ -52,10 +78,6 @@ t
delete from t2; delete from t2;
set timestamp=1000072000; set timestamp=1000072000;
insert into t2 values (current_timestamp), (current_date), (current_time); insert into t2 values (current_timestamp), (current_date), (current_time);
set timestamp=1000072000;
select current_timestamp, current_date, current_time;
current_timestamp current_date current_time
2001-09-10 01:46:40 2001-09-10 01:46:40
select * from t2; select * from t2;
t t
2001-09-09 23:46:40 2001-09-09 23:46:40
...@@ -73,5 +95,16 @@ t ...@@ -73,5 +95,16 @@ t
2001-09-09 03:46:40 2001-09-09 03:46:40
1000000000 1000000000
set global time_zone='MET'; set global time_zone='MET';
ERROR HY000: Binary logging and replication forbid changing the global server time zone delete from t2;
set time_zone='UTC';
insert into t2 values(convert_tz('2004-01-01 00:00:00','MET',@@time_zone));
insert into t2 values(convert_tz('2005-01-01 00:00:00','MET','Japan'));
select * from t2;
t
2003-12-31 23:00:00
2005-01-01 08:00:00
select * from t2;
t
2003-12-31 23:00:00
2005-01-01 08:00:00
drop table t1, t2; drop table t1, t2;
--default-time-zone=Europe/Moscow --default-time-zone=Japan
...@@ -3,21 +3,25 @@ source include/master-slave.inc; ...@@ -3,21 +3,25 @@ source include/master-slave.inc;
# Some preparations # Some preparations
let $VERSION=`select version()`; let $VERSION=`select version()`;
set timestamp=100000000; # for fixed output of mysqlbinlog
create table t1 (t timestamp); create table t1 (t timestamp);
create table t2 (t char(32)); create table t2 (t char(32));
connection slave;
select @@time_zone;
# #
# Let us check how well replication works when we are saving datetime # Let us check how well replication works when we are saving datetime
# value in TIMESTAMP field. # value in TIMESTAMP field.
# #
connection master; connection master;
select @@time_zone; select @@time_zone;
insert into t1 values ('20050101000000'), ('20050611093902');
set time_zone='UTC'; set time_zone='UTC';
insert into t1 values ('20040101000000'), ('20040611093902'); insert into t1 values ('20040101000000'), ('20040611093902');
select * from t1; select * from t1;
# On slave we still in 'Europe/Moscow' so we should see equivalent but
# textually different values.
sync_slave_with_master; sync_slave_with_master;
set time_zone='UTC';
select * from t1; select * from t1;
# Let us check also that setting of time_zone back to default also works # Let us check also that setting of time_zone back to default also works
...@@ -28,12 +32,11 @@ set time_zone='Europe/Moscow'; ...@@ -28,12 +32,11 @@ set time_zone='Europe/Moscow';
insert into t1 values ('20040101000000'), ('20040611093902'); insert into t1 values ('20040101000000'), ('20040611093902');
select * from t1; select * from t1;
sync_slave_with_master; sync_slave_with_master;
set time_zone='Europe/Moscow';
select * from t1; select * from t1;
connection master; connection master;
# We should not see SET ONE_SHOT time_zone before second insert --replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR
--replace_result $VERSION VERSION --exec $MYSQL_BINLOG --short-form $MYSQL_TEST_DIR/var/log/master-bin.000001
--replace_column 2 # 5 #
show binlog events;
# #
# Now let us check how well we replicate statments reading TIMESTAMP fields # Now let us check how well we replicate statments reading TIMESTAMP fields
...@@ -54,10 +57,6 @@ delete from t2; ...@@ -54,10 +57,6 @@ delete from t2;
set timestamp=1000072000; set timestamp=1000072000;
insert into t2 values (current_timestamp), (current_date), (current_time); insert into t2 values (current_timestamp), (current_date), (current_time);
sync_slave_with_master; sync_slave_with_master;
# Values in ouput of these to queries should differ because we are in
# in 'MET' on master and in 'Europe/Moscow on slave...
set timestamp=1000072000;
select current_timestamp, current_date, current_time;
select * from t2; select * from t2;
# #
...@@ -73,13 +72,24 @@ sync_slave_with_master; ...@@ -73,13 +72,24 @@ sync_slave_with_master;
select * from t2; select * from t2;
# #
# Let us check that we are not allowing to set global time_zone with # Let us check that we are allowing to set global time_zone with
# replication # replication
# #
connection master; connection master;
--error 1387
set global time_zone='MET'; set global time_zone='MET';
#
# Let us see if CONVERT_TZ(@@time_zone) replicates
#
delete from t2;
set time_zone='UTC';
insert into t2 values(convert_tz('2004-01-01 00:00:00','MET',@@time_zone));
insert into t2 values(convert_tz('2005-01-01 00:00:00','MET','Japan'));
select * from t2;
sync_slave_with_master;
select * from t2;
# Clean up # Clean up
connection master;
drop table t1, t2; drop table t1, t2;
sync_slave_with_master; sync_slave_with_master;
...@@ -1307,6 +1307,9 @@ innobase_end(void) ...@@ -1307,6 +1307,9 @@ innobase_end(void)
} }
#endif #endif
if (innodb_inited) { if (innodb_inited) {
#ifndef __NETWARE__ /* NetWare can't close unclosed files, kill remaining
threads, etc, so we disable the very fast shutdown */
if (innobase_very_fast_shutdown) { if (innobase_very_fast_shutdown) {
srv_very_fast_shutdown = TRUE; srv_very_fast_shutdown = TRUE;
fprintf(stderr, fprintf(stderr,
...@@ -1314,6 +1317,7 @@ innobase_end(void) ...@@ -1314,6 +1317,7 @@ innobase_end(void)
"InnoDB: the InnoDB buffer pool to data files. At the next mysqld startup\n" "InnoDB: the InnoDB buffer pool to data files. At the next mysqld startup\n"
"InnoDB: InnoDB will do a crash recovery!\n"); "InnoDB: InnoDB will do a crash recovery!\n");
} }
#endif
innodb_inited = 0; innodb_inited = 0;
if (innobase_shutdown_for_mysql() != DB_SUCCESS) { if (innobase_shutdown_for_mysql() != DB_SUCCESS) {
......
...@@ -1638,57 +1638,6 @@ bool MYSQL_LOG::write(Log_event *event_info) ...@@ -1638,57 +1638,6 @@ bool MYSQL_LOG::write(Log_event *event_info)
if (thd) if (thd)
{ {
#if MYSQL_VERSION_ID < 50003
/*
To make replication of charsets working in 4.1 we are writing values
of charset related variables before every statement in the binlog,
if values of those variables differ from global server-wide defaults.
We are using SET ONE_SHOT command so that the charset vars get reset
to default after the first non-SET statement.
In the next 5.0 this won't be needed as we will use the new binlog
format to store charset info.
*/
if ((thd->variables.character_set_client->number !=
global_system_variables.collation_server->number) ||
(thd->variables.character_set_client->number !=
thd->variables.collation_connection->number) ||
(thd->variables.collation_server->number !=
thd->variables.collation_connection->number))
{
char buf[200];
int written= my_snprintf(buf, sizeof(buf)-1,
"SET ONE_SHOT CHARACTER_SET_CLIENT=%u,\
COLLATION_CONNECTION=%u,COLLATION_DATABASE=%u,COLLATION_SERVER=%u",
(uint) thd->variables.character_set_client->number,
(uint) thd->variables.collation_connection->number,
(uint) thd->variables.collation_database->number,
(uint) thd->variables.collation_server->number);
Query_log_event e(thd, buf, written, 0, FALSE);
if (e.write(file))
goto err;
}
#endif
/*
We use the same ONE_SHOT trick for making replication of time zones
working in 4.1. Again in 5.0 we have better means for doing this.
TODO: we should do like we now do with charsets (no more ONE_SHOT;
logging in each event in a compact format). Dmitri says we can do:
if (time_zone_used) write the timezone to binlog (in a format to be
defined).
*/
if (thd->time_zone_used &&
thd->variables.time_zone != global_system_variables.time_zone)
{
char buf[MAX_TIME_ZONE_NAME_LENGTH + 26];
char *buf_end= strxmov(buf, "SET ONE_SHOT TIME_ZONE='",
thd->variables.time_zone->get_name()->ptr(),
"'", NullS);
Query_log_event e(thd, buf, buf_end - buf, 0, FALSE);
if (e.write(file))
goto err;
}
if (thd->last_insert_id_used) if (thd->last_insert_id_used)
{ {
Intvar_log_event e(thd,(uchar) LAST_INSERT_ID_EVENT, Intvar_log_event e(thd,(uchar) LAST_INSERT_ID_EVENT,
......
This diff is collapsed.
...@@ -237,6 +237,7 @@ struct sql_ex_info ...@@ -237,6 +237,7 @@ struct sql_ex_info
#define Q_CATALOG_CODE 2 #define Q_CATALOG_CODE 2
#define Q_AUTO_INCREMENT 3 #define Q_AUTO_INCREMENT 3
#define Q_CHARSET_CODE 4 #define Q_CHARSET_CODE 4
#define Q_TIME_ZONE_CODE 5
/* Intvar event post-header */ /* Intvar event post-header */
...@@ -448,6 +449,7 @@ typedef struct st_last_event_info ...@@ -448,6 +449,7 @@ typedef struct st_last_event_info
ulong auto_increment_increment, auto_increment_offset; ulong auto_increment_increment, auto_increment_offset;
bool charset_inited; bool charset_inited;
char charset[6]; // 3 variables, each of them storable in 2 bytes char charset[6]; // 3 variables, each of them storable in 2 bytes
char time_zone_str[MAX_TIME_ZONE_NAME_LENGTH];
st_last_event_info() st_last_event_info()
:flags2_inited(0), sql_mode_inited(0), :flags2_inited(0), sql_mode_inited(0),
auto_increment_increment(1),auto_increment_offset(1), charset_inited(0) auto_increment_increment(1),auto_increment_offset(1), charset_inited(0)
...@@ -459,6 +461,7 @@ typedef struct st_last_event_info ...@@ -459,6 +461,7 @@ typedef struct st_last_event_info
*/ */
bzero(db, sizeof(db)); bzero(db, sizeof(db));
bzero(charset, sizeof(charset)); bzero(charset, sizeof(charset));
bzero(time_zone_str, sizeof(time_zone_str));
} }
} LAST_EVENT_INFO; } LAST_EVENT_INFO;
#endif #endif
...@@ -583,6 +586,7 @@ class Log_event ...@@ -583,6 +586,7 @@ class Log_event
my_free((gptr) ptr, MYF(MY_WME|MY_ALLOW_ZERO_PTR)); my_free((gptr) ptr, MYF(MY_WME|MY_ALLOW_ZERO_PTR));
} }
#ifndef MYSQL_CLIENT
bool write_header(IO_CACHE* file, ulong data_length); bool write_header(IO_CACHE* file, ulong data_length);
virtual bool write(IO_CACHE* file) virtual bool write(IO_CACHE* file)
{ {
...@@ -590,13 +594,14 @@ class Log_event ...@@ -590,13 +594,14 @@ class Log_event
write_data_header(file) || write_data_header(file) ||
write_data_body(file)); write_data_body(file));
} }
virtual bool is_artificial_event() { return 0; }
virtual bool write_data_header(IO_CACHE* file) virtual bool write_data_header(IO_CACHE* file)
{ return 0; } { return 0; }
virtual bool write_data_body(IO_CACHE* file __attribute__((unused))) virtual bool write_data_body(IO_CACHE* file __attribute__((unused)))
{ return 0; } { return 0; }
#endif
virtual Log_event_type get_type_code() = 0; virtual Log_event_type get_type_code() = 0;
virtual bool is_valid() const = 0; virtual bool is_valid() const = 0;
virtual bool is_artificial_event() { return 0; }
inline bool get_cache_stmt() { return cache_stmt; } inline bool get_cache_stmt() { return cache_stmt; }
Log_event(const char* buf, const Format_description_log_event* description_event); Log_event(const char* buf, const Format_description_log_event* description_event);
virtual ~Log_event() { free_temp_buf();} virtual ~Log_event() { free_temp_buf();}
...@@ -672,7 +677,7 @@ class Query_log_event: public Log_event ...@@ -672,7 +677,7 @@ class Query_log_event: public Log_event
concerned) from here. concerned) from here.
*/ */
int catalog_len; // <= 255 char; -1 means uninited uint catalog_len; // <= 255 char; 0 means uninited
/* /*
We want to be able to store a variable number of N-bit status vars: We want to be able to store a variable number of N-bit status vars:
...@@ -714,6 +719,8 @@ class Query_log_event: public Log_event ...@@ -714,6 +719,8 @@ class Query_log_event: public Log_event
ulong sql_mode; ulong sql_mode;
ulong auto_increment_increment, auto_increment_offset; ulong auto_increment_increment, auto_increment_offset;
char charset[6]; char charset[6];
uint time_zone_len; /* 0 means uninited */
const char *time_zone_str;
#ifndef MYSQL_CLIENT #ifndef MYSQL_CLIENT
...@@ -737,12 +744,13 @@ class Query_log_event: public Log_event ...@@ -737,12 +744,13 @@ class Query_log_event: public Log_event
~Query_log_event() ~Query_log_event()
{ {
if (data_buf) if (data_buf)
{
my_free((gptr) data_buf, MYF(0)); my_free((gptr) data_buf, MYF(0));
}
} }
Log_event_type get_type_code() { return QUERY_EVENT; } Log_event_type get_type_code() { return QUERY_EVENT; }
#ifndef MYSQL_CLIENT
bool write(IO_CACHE* file); bool write(IO_CACHE* file);
virtual bool write_post_header_for_derived(IO_CACHE* file) { return FALSE; }
#endif
bool is_valid() const { return query != 0; } bool is_valid() const { return query != 0; }
/* /*
...@@ -751,7 +759,6 @@ class Query_log_event: public Log_event ...@@ -751,7 +759,6 @@ class Query_log_event: public Log_event
*/ */
virtual ulong get_post_header_size_for_derived() { return 0; } virtual ulong get_post_header_size_for_derived() { return 0; }
/* Writes derived event-specific part of post header. */ /* Writes derived event-specific part of post header. */
virtual bool write_post_header_for_derived(IO_CACHE* file) { return FALSE; }
}; };
#ifdef HAVE_REPLICATION #ifdef HAVE_REPLICATION
...@@ -790,7 +797,9 @@ class Slave_log_event: public Log_event ...@@ -790,7 +797,9 @@ class Slave_log_event: public Log_event
int get_data_size(); int get_data_size();
bool is_valid() const { return master_host != 0; } bool is_valid() const { return master_host != 0; }
Log_event_type get_type_code() { return SLAVE_EVENT; } Log_event_type get_type_code() { return SLAVE_EVENT; }
#ifndef MYSQL_CLIENT
bool write(IO_CACHE* file); bool write(IO_CACHE* file);
#endif
}; };
#endif /* HAVE_REPLICATION */ #endif /* HAVE_REPLICATION */
...@@ -885,8 +894,10 @@ class Load_log_event: public Log_event ...@@ -885,8 +894,10 @@ class Load_log_event: public Log_event
{ {
return sql_ex.new_format() ? NEW_LOAD_EVENT: LOAD_EVENT; return sql_ex.new_format() ? NEW_LOAD_EVENT: LOAD_EVENT;
} }
#ifndef MYSQL_CLIENT
bool write_data_header(IO_CACHE* file); bool write_data_header(IO_CACHE* file);
bool write_data_body(IO_CACHE* file); bool write_data_body(IO_CACHE* file);
#endif
bool is_valid() const { return table_name != 0; } bool is_valid() const { return table_name != 0; }
int get_data_size() int get_data_size()
{ {
...@@ -962,7 +973,9 @@ class Start_log_event_v3: public Log_event ...@@ -962,7 +973,9 @@ class Start_log_event_v3: public Log_event
const Format_description_log_event* description_event); const Format_description_log_event* description_event);
~Start_log_event_v3() {} ~Start_log_event_v3() {}
Log_event_type get_type_code() { return START_EVENT_V3;} Log_event_type get_type_code() { return START_EVENT_V3;}
#ifndef MYSQL_CLIENT
bool write(IO_CACHE* file); bool write(IO_CACHE* file);
#endif
bool is_valid() const { return 1; } bool is_valid() const { return 1; }
int get_data_size() int get_data_size()
{ {
...@@ -1004,7 +1017,9 @@ class Format_description_log_event: public Start_log_event_v3 ...@@ -1004,7 +1017,9 @@ class Format_description_log_event: public Start_log_event_v3
const Format_description_log_event* description_event); const Format_description_log_event* description_event);
~Format_description_log_event() { my_free((gptr)post_header_len, MYF(0)); } ~Format_description_log_event() { my_free((gptr)post_header_len, MYF(0)); }
Log_event_type get_type_code() { return FORMAT_DESCRIPTION_EVENT;} Log_event_type get_type_code() { return FORMAT_DESCRIPTION_EVENT;}
#ifndef MYSQL_CLIENT
bool write(IO_CACHE* file); bool write(IO_CACHE* file);
#endif
bool is_valid() const bool is_valid() const
{ {
return ((common_header_len >= ((binlog_version==1) ? OLD_HEADER_LEN : return ((common_header_len >= ((binlog_version==1) ? OLD_HEADER_LEN :
...@@ -1054,7 +1069,9 @@ class Intvar_log_event: public Log_event ...@@ -1054,7 +1069,9 @@ class Intvar_log_event: public Log_event
Log_event_type get_type_code() { return INTVAR_EVENT;} Log_event_type get_type_code() { return INTVAR_EVENT;}
const char* get_var_type_name(); const char* get_var_type_name();
int get_data_size() { return 9; /* sizeof(type) + sizeof(val) */;} int get_data_size() { return 9; /* sizeof(type) + sizeof(val) */;}
#ifndef MYSQL_CLIENT
bool write(IO_CACHE* file); bool write(IO_CACHE* file);
#endif
bool is_valid() const { return 1; } bool is_valid() const { return 1; }
}; };
...@@ -1092,7 +1109,9 @@ class Rand_log_event: public Log_event ...@@ -1092,7 +1109,9 @@ class Rand_log_event: public Log_event
~Rand_log_event() {} ~Rand_log_event() {}
Log_event_type get_type_code() { return RAND_EVENT;} Log_event_type get_type_code() { return RAND_EVENT;}
int get_data_size() { return 16; /* sizeof(ulonglong) * 2*/ } int get_data_size() { return 16; /* sizeof(ulonglong) * 2*/ }
#ifndef MYSQL_CLIENT
bool write(IO_CACHE* file); bool write(IO_CACHE* file);
#endif
bool is_valid() const { return 1; } bool is_valid() const { return 1; }
}; };
...@@ -1127,7 +1146,9 @@ class Xid_log_event: public Log_event ...@@ -1127,7 +1146,9 @@ class Xid_log_event: public Log_event
~Xid_log_event() {} ~Xid_log_event() {}
Log_event_type get_type_code() { return XID_EVENT;} Log_event_type get_type_code() { return XID_EVENT;}
int get_data_size() { return sizeof(xid); } int get_data_size() { return sizeof(xid); }
#ifndef MYSQL_CLIENT
bool write(IO_CACHE* file); bool write(IO_CACHE* file);
#endif
bool is_valid() const { return 1; } bool is_valid() const { return 1; }
}; };
...@@ -1169,7 +1190,9 @@ class User_var_log_event: public Log_event ...@@ -1169,7 +1190,9 @@ class User_var_log_event: public Log_event
User_var_log_event(const char* buf, const Format_description_log_event* description_event); User_var_log_event(const char* buf, const Format_description_log_event* description_event);
~User_var_log_event() {} ~User_var_log_event() {}
Log_event_type get_type_code() { return USER_VAR_EVENT;} Log_event_type get_type_code() { return USER_VAR_EVENT;}
#ifndef MYSQL_CLIENT
bool write(IO_CACHE* file); bool write(IO_CACHE* file);
#endif
bool is_valid() const { return 1; } bool is_valid() const { return 1; }
}; };
...@@ -1239,7 +1262,9 @@ class Rotate_log_event: public Log_event ...@@ -1239,7 +1262,9 @@ class Rotate_log_event: public Log_event
Log_event_type get_type_code() { return ROTATE_EVENT;} Log_event_type get_type_code() { return ROTATE_EVENT;}
int get_data_size() { return ident_len + ROTATE_HEADER_LEN;} int get_data_size() { return ident_len + ROTATE_HEADER_LEN;}
bool is_valid() const { return new_log_ident != 0; } bool is_valid() const { return new_log_ident != 0; }
#ifndef MYSQL_CLIENT
bool write(IO_CACHE* file); bool write(IO_CACHE* file);
#endif
}; };
...@@ -1299,6 +1324,7 @@ class Create_file_log_event: public Load_log_event ...@@ -1299,6 +1324,7 @@ class Create_file_log_event: public Load_log_event
4 + 1 + block_len); 4 + 1 + block_len);
} }
bool is_valid() const { return inited_from_old || block != 0; } bool is_valid() const { return inited_from_old || block != 0; }
#ifndef MYSQL_CLIENT
bool write_data_header(IO_CACHE* file); bool write_data_header(IO_CACHE* file);
bool write_data_body(IO_CACHE* file); bool write_data_body(IO_CACHE* file);
/* /*
...@@ -1306,6 +1332,7 @@ class Create_file_log_event: public Load_log_event ...@@ -1306,6 +1332,7 @@ class Create_file_log_event: public Load_log_event
write it as Load event - used on the slave write it as Load event - used on the slave
*/ */
bool write_base(IO_CACHE* file); bool write_base(IO_CACHE* file);
#endif
}; };
...@@ -1352,7 +1379,9 @@ class Append_block_log_event: public Log_event ...@@ -1352,7 +1379,9 @@ class Append_block_log_event: public Log_event
Log_event_type get_type_code() { return APPEND_BLOCK_EVENT;} Log_event_type get_type_code() { return APPEND_BLOCK_EVENT;}
int get_data_size() { return block_len + APPEND_BLOCK_HEADER_LEN ;} int get_data_size() { return block_len + APPEND_BLOCK_HEADER_LEN ;}
bool is_valid() const { return block != 0; } bool is_valid() const { return block != 0; }
#ifndef MYSQL_CLIENT
bool write(IO_CACHE* file); bool write(IO_CACHE* file);
#endif
const char* get_db() { return db; } const char* get_db() { return db; }
}; };
...@@ -1386,7 +1415,9 @@ class Delete_file_log_event: public Log_event ...@@ -1386,7 +1415,9 @@ class Delete_file_log_event: public Log_event
Log_event_type get_type_code() { return DELETE_FILE_EVENT;} Log_event_type get_type_code() { return DELETE_FILE_EVENT;}
int get_data_size() { return DELETE_FILE_HEADER_LEN ;} int get_data_size() { return DELETE_FILE_HEADER_LEN ;}
bool is_valid() const { return file_id != 0; } bool is_valid() const { return file_id != 0; }
#ifndef MYSQL_CLIENT
bool write(IO_CACHE* file); bool write(IO_CACHE* file);
#endif
const char* get_db() { return db; } const char* get_db() { return db; }
}; };
...@@ -1419,7 +1450,9 @@ class Execute_load_log_event: public Log_event ...@@ -1419,7 +1450,9 @@ class Execute_load_log_event: public Log_event
Log_event_type get_type_code() { return EXEC_LOAD_EVENT;} Log_event_type get_type_code() { return EXEC_LOAD_EVENT;}
int get_data_size() { return EXEC_LOAD_HEADER_LEN ;} int get_data_size() { return EXEC_LOAD_HEADER_LEN ;}
bool is_valid() const { return file_id != 0; } bool is_valid() const { return file_id != 0; }
#ifndef MYSQL_CLIENT
bool write(IO_CACHE* file); bool write(IO_CACHE* file);
#endif
const char* get_db() { return db; } const char* get_db() { return db; }
}; };
...@@ -1507,7 +1540,9 @@ class Execute_load_query_log_event: public Query_log_event ...@@ -1507,7 +1540,9 @@ class Execute_load_query_log_event: public Query_log_event
bool is_valid() const { return Query_log_event::is_valid() && file_id != 0; } bool is_valid() const { return Query_log_event::is_valid() && file_id != 0; }
ulong get_post_header_size_for_derived(); ulong get_post_header_size_for_derived();
#ifndef MYSQL_CLIENT
bool write_post_header_for_derived(IO_CACHE* file); bool write_post_header_for_derived(IO_CACHE* file);
#endif
}; };
......
...@@ -257,6 +257,12 @@ extern CHARSET_INFO *national_charset_info, *table_alias_charset; ...@@ -257,6 +257,12 @@ extern CHARSET_INFO *national_charset_info, *table_alias_charset;
/* Flag set if setup_tables already done */ /* Flag set if setup_tables already done */
#define OPTION_SETUP_TABLES_DONE (1L << 30) #define OPTION_SETUP_TABLES_DONE (1L << 30)
/*
Maximum length of time zone name that we support
(Time zone name is char(64) in db). mysqlbinlog needs it.
*/
#define MAX_TIME_ZONE_NAME_LENGTH 72
/* The rest of the file is included in the server only */ /* The rest of the file is included in the server only */
#ifndef MYSQL_CLIENT #ifndef MYSQL_CLIENT
......
...@@ -2095,27 +2095,6 @@ void sys_var_character_set_server::set_default(THD *thd, enum_var_type type) ...@@ -2095,27 +2095,6 @@ void sys_var_character_set_server::set_default(THD *thd, enum_var_type type)
} }
} }
#if defined(HAVE_REPLICATION) && (MYSQL_VERSION_ID < 50003)
bool sys_var_character_set_server::check(THD *thd, set_var *var)
{
/*
To be perfect we should fail even if we are a 5.0.3 slave, a 4.1 master,
and user wants to change our global character set variables. Because
replicating a 4.1 assumes those are not changed. But that's not easy to
do.
*/
if ((var->type == OPT_GLOBAL) &&
(mysql_bin_log.is_open() ||
active_mi->slave_running || active_mi->rli.slave_running))
{
my_error(ER_LOGGING_PROHIBIT_CHANGING_OF, MYF(0),
"character set, collation");
return 1;
}
return sys_var_character_set::check(thd,var);
}
#endif
CHARSET_INFO ** sys_var_character_set_database::ci_ptr(THD *thd, CHARSET_INFO ** sys_var_character_set_database::ci_ptr(THD *thd,
enum_var_type type) enum_var_type type)
{ {
...@@ -2208,20 +2187,6 @@ void sys_var_collation_database::set_default(THD *thd, enum_var_type type) ...@@ -2208,20 +2187,6 @@ void sys_var_collation_database::set_default(THD *thd, enum_var_type type)
} }
} }
#if defined(HAVE_REPLICATION) && (MYSQL_VERSION_ID < 50003)
bool sys_var_collation_server::check(THD *thd, set_var *var)
{
if ((var->type == OPT_GLOBAL) &&
(mysql_bin_log.is_open() ||
active_mi->slave_running || active_mi->rli.slave_running))
{
my_error(ER_LOGGING_PROHIBIT_CHANGING_OF, MYF(0),
"character set, collation");
return 1;
}
return sys_var_collation::check(thd,var);
}
#endif
bool sys_var_collation_server::update(THD *thd, set_var *var) bool sys_var_collation_server::update(THD *thd, set_var *var)
{ {
...@@ -2560,16 +2525,6 @@ bool sys_var_thd_time_zone::check(THD *thd, set_var *var) ...@@ -2560,16 +2525,6 @@ bool sys_var_thd_time_zone::check(THD *thd, set_var *var)
String str(buff, sizeof(buff), &my_charset_latin1); String str(buff, sizeof(buff), &my_charset_latin1);
String *res= var->value->val_str(&str); String *res= var->value->val_str(&str);
#if defined(HAVE_REPLICATION)
if ((var->type == OPT_GLOBAL) &&
(mysql_bin_log.is_open() ||
active_mi->slave_running || active_mi->rli.slave_running))
{
my_error(ER_LOGGING_PROHIBIT_CHANGING_OF, MYF(0), "time zone");
return 1;
}
#endif
if (!(var->save_result.time_zone= if (!(var->save_result.time_zone=
my_tz_find(res, thd->lex->time_zone_tables_used))) my_tz_find(res, thd->lex->time_zone_tables_used)))
{ {
...@@ -2605,7 +2560,18 @@ byte *sys_var_thd_time_zone::value_ptr(THD *thd, enum_var_type type, ...@@ -2605,7 +2560,18 @@ byte *sys_var_thd_time_zone::value_ptr(THD *thd, enum_var_type type,
if (type == OPT_GLOBAL) if (type == OPT_GLOBAL)
return (byte *)(global_system_variables.time_zone->get_name()->ptr()); return (byte *)(global_system_variables.time_zone->get_name()->ptr());
else else
{
/*
This is an ugly fix for replication: we don't replicate properly queries
invoking system variables' values to update tables; but
CONVERT_TZ(,,@@session.time_zone) is so popular that we make it
replicable (i.e. we tell the binlog code to store the session
timezone). If it's the global value which was used we can't replicate
(binlog code stores session value only).
*/
thd->time_zone_used= 1;
return (byte *)(thd->variables.time_zone->get_name()->ptr()); return (byte *)(thd->variables.time_zone->get_name()->ptr());
}
} }
......
...@@ -565,9 +565,6 @@ class sys_var_character_set_server :public sys_var_character_set ...@@ -565,9 +565,6 @@ class sys_var_character_set_server :public sys_var_character_set
public: public:
sys_var_character_set_server(const char *name_arg) : sys_var_character_set_server(const char *name_arg) :
sys_var_character_set(name_arg) {} sys_var_character_set(name_arg) {}
#if defined(HAVE_REPLICATION) && (MYSQL_VERSION_ID < 50003)
bool check(THD *thd, set_var *var);
#endif
void set_default(THD *thd, enum_var_type type); void set_default(THD *thd, enum_var_type type);
CHARSET_INFO **ci_ptr(THD *thd, enum_var_type type); CHARSET_INFO **ci_ptr(THD *thd, enum_var_type type);
}; };
...@@ -603,9 +600,6 @@ class sys_var_collation_server :public sys_var_collation ...@@ -603,9 +600,6 @@ class sys_var_collation_server :public sys_var_collation
{ {
public: public:
sys_var_collation_server(const char *name_arg) :sys_var_collation(name_arg) {} sys_var_collation_server(const char *name_arg) :sys_var_collation(name_arg) {}
#if defined(HAVE_REPLICATION) && (MYSQL_VERSION_ID < 50003)
bool check(THD *thd, set_var *var);
#endif
bool update(THD *thd, set_var *var); bool update(THD *thd, set_var *var);
void set_default(THD *thd, enum_var_type type); void set_default(THD *thd, enum_var_type type);
byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base); byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
......
...@@ -1421,7 +1421,7 @@ not always make sense; please check the manual before using it)."; ...@@ -1421,7 +1421,7 @@ not always make sense; please check the manual before using it).";
We don't test equality of global collation_database either as it's is We don't test equality of global collation_database either as it's is
going to be deprecated (made read-only) in 4.1 very soon. going to be deprecated (made read-only) in 4.1 very soon.
The test is only relevant if master < 5.0.3 (we'll test only if it's older The test is only relevant if master < 5.0.3 (we'll test only if it's older
than the 5 branch; < 5.0.3 was alpha...), as >= 5.0.3 master stores than the 5 branch; < 5.0.4 were alpha...), as >= 5.0.4 master stores
charset info in each binlog event. charset info in each binlog event.
We don't do it for 3.23 because masters <3.23.50 hang on We don't do it for 3.23 because masters <3.23.50 hang on
SELECT @@unknown_var (BUG#7965 - see changelog of 3.23.50). So finally we SELECT @@unknown_var (BUG#7965 - see changelog of 3.23.50). So finally we
...@@ -1456,11 +1456,10 @@ be equal for replication to work"; ...@@ -1456,11 +1456,10 @@ be equal for replication to work";
such check will broke everything for them. (And now everything will such check will broke everything for them. (And now everything will
work for them because by default both their master and slave will have work for them because by default both their master and slave will have
'SYSTEM' time zone). 'SYSTEM' time zone).
This check is only necessary for 4.x masters (and < 5.0.4 masters but
TODO: when the new replication of timezones is sorted out with Dmitri, those were alpha).
change >= '4' to == '4'.
*/ */
if ((*mysql->server_version >= '4') && if ((*mysql->server_version == '4') &&
!mysql_real_query(mysql, "SELECT @@GLOBAL.TIME_ZONE", 25) && !mysql_real_query(mysql, "SELECT @@GLOBAL.TIME_ZONE", 25) &&
(master_res= mysql_store_result(mysql))) (master_res= mysql_store_result(mysql)))
{ {
...@@ -2770,6 +2769,18 @@ void set_slave_thread_options(THD* thd) ...@@ -2770,6 +2769,18 @@ void set_slave_thread_options(THD* thd)
thd->variables.completion_type= 0; thd->variables.completion_type= 0;
} }
void set_slave_thread_default_charset(THD* thd, RELAY_LOG_INFO *rli)
{
thd->variables.character_set_client=
global_system_variables.character_set_client;
thd->variables.collation_connection=
global_system_variables.collation_connection;
thd->variables.collation_server=
global_system_variables.collation_server;
thd->update_charset();
rli->cached_charset_invalidate();
}
/* /*
init_slave_thread() init_slave_thread()
*/ */
......
...@@ -562,6 +562,7 @@ int init_relay_log_pos(RELAY_LOG_INFO* rli,const char* log,ulonglong pos, ...@@ -562,6 +562,7 @@ int init_relay_log_pos(RELAY_LOG_INFO* rli,const char* log,ulonglong pos,
int purge_relay_logs(RELAY_LOG_INFO* rli, THD *thd, bool just_reset, int purge_relay_logs(RELAY_LOG_INFO* rli, THD *thd, bool just_reset,
const char** errmsg); const char** errmsg);
void set_slave_thread_options(THD* thd); void set_slave_thread_options(THD* thd);
void set_slave_thread_default_charset(THD* thd, RELAY_LOG_INFO *rli);
void rotate_relay_log(MASTER_INFO* mi); void rotate_relay_log(MASTER_INFO* mi);
extern "C" pthread_handler_decl(handle_slave_io,arg); extern "C" pthread_handler_decl(handle_slave_io,arg);
......
...@@ -2178,7 +2178,7 @@ my_tz_find(const String * name, TABLE_LIST *tz_tables) ...@@ -2178,7 +2178,7 @@ my_tz_find(const String * name, TABLE_LIST *tz_tables)
DBUG_PRINT("enter", ("time zone name='%s'", DBUG_PRINT("enter", ("time zone name='%s'",
name ? ((String *)name)->c_ptr() : "NULL")); name ? ((String *)name)->c_ptr() : "NULL"));
DBUG_ASSERT(!time_zone_tables_exist || tz_tables); DBUG_ASSERT(!time_zone_tables_exist || tz_tables || current_thd->slave_thread);
if (!name) if (!name)
DBUG_RETURN(0); DBUG_RETURN(0);
...@@ -2210,7 +2210,7 @@ my_tz_find(const String * name, TABLE_LIST *tz_tables) ...@@ -2210,7 +2210,7 @@ my_tz_find(const String * name, TABLE_LIST *tz_tables)
(const byte *)name->ptr(), (const byte *)name->ptr(),
name->length()))) name->length())))
result_tz= tmp_tzname->tz; result_tz= tmp_tzname->tz;
else if (time_zone_tables_exist) else if (time_zone_tables_exist && tz_tables)
result_tz= tz_load_from_open_tables(name, tz_tables); result_tz= tz_load_from_open_tables(name, tz_tables);
} }
...@@ -2219,6 +2219,58 @@ my_tz_find(const String * name, TABLE_LIST *tz_tables) ...@@ -2219,6 +2219,58 @@ my_tz_find(const String * name, TABLE_LIST *tz_tables)
DBUG_RETURN(result_tz); DBUG_RETURN(result_tz);
} }
/*
A more standalone version of my_tz_find(): will open tz tables if needed.
This is so far only used by replication, where time zone setting does not
happen in the usual query context.
SYNOPSIS
my_tz_find_with_opening_tz_tables()
thd - pointer to thread's THD structure
name - time zone specification
DESCRIPTION
This function tries to find a time zone which matches the named passed in
argument. If it fails, it will open time zone tables and re-try the
search.
This function is needed for the slave SQL thread, which does not do the
addition of time zone tables which is usually done during query parsing
(as time zone setting by slave does not happen in mysql_parse() but
before). So it needs to open tz tables by itself if needed.
See notes of my_tz_find() as they also apply here.
RETURN VALUE
Pointer to corresponding Time_zone object. 0 - in case of bad time zone
specification or other error.
*/
Time_zone *my_tz_find_with_opening_tz_tables(THD *thd, const String *name)
{
Time_zone *tz;
DBUG_ENTER("my_tz_find_with_opening_tables");
DBUG_ASSERT(thd);
DBUG_ASSERT(thd->slave_thread); // intended for use with slave thread only
if (!(tz= my_tz_find(name, 0)) && time_zone_tables_exist)
{
/*
Probably we have not loaded this time zone yet so let us look it up in
our time zone tables. Note that if we don't have tz tables on this
slave, we don't even try.
*/
TABLE_LIST tables[4];
TABLE_LIST *dummy;
TABLE_LIST **dummyp= &dummy;
tz_init_table_list(tables, &dummyp);
if (simple_open_n_lock_tables(thd, tables))
DBUG_RETURN(0);
tz= my_tz_find(name, tables);
/* We need to close tables _now_ to not pollute coming query */
close_thread_tables(thd);
}
DBUG_RETURN(tz);
}
#endif /* !defined(TESTTIME) && !defined(TZINFO2SQL) */ #endif /* !defined(TESTTIME) && !defined(TZINFO2SQL) */
......
...@@ -61,6 +61,7 @@ extern Time_zone * my_tz_UTC; ...@@ -61,6 +61,7 @@ extern Time_zone * my_tz_UTC;
extern Time_zone * my_tz_SYSTEM; extern Time_zone * my_tz_SYSTEM;
extern TABLE_LIST * my_tz_get_table_list(THD *thd, TABLE_LIST ***global_next_ptr); extern TABLE_LIST * my_tz_get_table_list(THD *thd, TABLE_LIST ***global_next_ptr);
extern Time_zone * my_tz_find(const String *name, TABLE_LIST *tz_tables); extern Time_zone * my_tz_find(const String *name, TABLE_LIST *tz_tables);
extern Time_zone * my_tz_find_with_opening_tz_tables(THD *thd, const String *name);
extern my_bool my_tz_init(THD *org_thd, const char *default_tzname, my_bool bootstrap); extern my_bool my_tz_init(THD *org_thd, const char *default_tzname, my_bool bootstrap);
extern void my_tz_free(); extern void my_tz_free();
...@@ -96,10 +97,4 @@ inline bool my_tz_check_n_skip_implicit_tables(TABLE_LIST **table, ...@@ -96,10 +97,4 @@ inline bool my_tz_check_n_skip_implicit_tables(TABLE_LIST **table,
return FALSE; return FALSE;
} }
/*
Maximum length of time zone name that we support
(Time zone name is char(64) in db)
*/
#define MAX_TIME_ZONE_NAME_LENGTH 72
#endif /* !defined(TESTTIME) && !defined(TZINFO2SQL) */ #endif /* !defined(TESTTIME) && !defined(TZINFO2SQL) */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment