diff options
author | unknown <gbichot@production.mysql.com> | 2005-03-22 00:26:12 +0100 |
---|---|---|
committer | unknown <gbichot@production.mysql.com> | 2005-03-22 00:26:12 +0100 |
commit | ac46bf77aecd84eae40400afd5ffb79e93ab4b24 (patch) | |
tree | a68553da2993095e4192c9deed704a0dc63b5e8b | |
parent | 6fc7c0742e99d45a1cedf9363ef705e85f8a563d (diff) | |
download | mariadb-git-ac46bf77aecd84eae40400afd5ffb79e93ab4b24.tar.gz |
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
-rw-r--r-- | BitKeeper/etc/logging_ok | 1 | ||||
-rw-r--r-- | client/mysqlbinlog.cc | 2 | ||||
-rw-r--r-- | mysql-test/r/rpl_timezone.result | 65 | ||||
-rw-r--r-- | mysql-test/t/rpl_timezone-slave.opt | 2 | ||||
-rw-r--r-- | mysql-test/t/rpl_timezone.test | 34 | ||||
-rw-r--r-- | sql/ha_innodb.cc | 4 | ||||
-rw-r--r-- | sql/log.cc | 51 | ||||
-rw-r--r-- | sql/log_event.cc | 165 | ||||
-rw-r--r-- | sql/log_event.h | 45 | ||||
-rw-r--r-- | sql/mysql_priv.h | 6 | ||||
-rw-r--r-- | sql/set_var.cc | 56 | ||||
-rw-r--r-- | sql/set_var.h | 6 | ||||
-rw-r--r-- | sql/slave.cc | 21 | ||||
-rw-r--r-- | sql/slave.h | 1 | ||||
-rw-r--r-- | sql/tztime.cc | 56 | ||||
-rw-r--r-- | sql/tztime.h | 7 |
16 files changed, 322 insertions, 200 deletions
diff --git a/BitKeeper/etc/logging_ok b/BitKeeper/etc/logging_ok index eff53f4a789..46814ec8517 100644 --- a/BitKeeper/etc/logging_ok +++ b/BitKeeper/etc/logging_ok @@ -48,6 +48,7 @@ dlenev@build.mysql.com dlenev@jabberwock.localdomain dlenev@mysql.com ejonore@mc03.ndb.mysql.com +gbichot@production.mysql.com gbichot@quadita2.mysql.com georg@beethoven.local georg@beethoven.site diff --git a/client/mysqlbinlog.cc b/client/mysqlbinlog.cc index c296447def9..59c90f59e8e 100644 --- a/client/mysqlbinlog.cc +++ b/client/mysqlbinlog.cc @@ -33,9 +33,9 @@ #undef MYSQL_SERVER #include "client_priv.h" #include <my_time.h> -#include "log_event.h" /* That one is necessary for defines of OPTION_NO_FOREIGN_KEY_CHECKS etc */ #include "mysql_priv.h" +#include "log_event.h" #define BIN_LOG_HEADER_SIZE 4 #define PROBE_HEADER_LEN (EVENT_LEN_OFFSET+4) diff --git a/mysql-test/r/rpl_timezone.result b/mysql-test/r/rpl_timezone.result index cd2c4d099be..8975333d1db 100644 --- a/mysql-test/r/rpl_timezone.result +++ b/mysql-test/r/rpl_timezone.result @@ -4,21 +4,31 @@ reset master; reset slave; drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; start slave; +set timestamp=100000000; create table t1 (t timestamp); create table t2 (t char(32)); select @@time_zone; @@time_zone +Japan +select @@time_zone; +@@time_zone Europe/Moscow +insert into t1 values ('20050101000000'), ('20050611093902'); set time_zone='UTC'; insert into t1 values ('20040101000000'), ('20040611093902'); select * from t1; t +2004-12-31 21:00:00 +2005-06-11 05:39:02 2004-01-01 00:00:00 2004-06-11 09:39:02 +set time_zone='UTC'; select * from t1; t -2004-01-01 03:00:00 -2004-06-11 13:39:02 +2004-12-31 21:00:00 +2005-06-11 05:39:02 +2004-01-01 00:00:00 +2004-06-11 09:39:02 delete from t1; set time_zone='Europe/Moscow'; insert into t1 values ('20040101000000'), ('20040611093902'); @@ -26,19 +36,35 @@ select * from t1; t 2004-01-01 00:00:00 2004-06-11 09:39:02 +set time_zone='Europe/Moscow'; select * from t1; t 2004-01-01 00:00:00 2004-06-11 09:39:02 -show binlog events; -Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 # Format_desc 1 # Server ver: VERSION, Binlog ver: 4 -master-bin.000001 # Query 1 # use `test`; create table t1 (t timestamp) -master-bin.000001 # Query 1 # use `test`; create table t2 (t char(32)) -master-bin.000001 # Query 1 # use `test`; SET ONE_SHOT TIME_ZONE='UTC' -master-bin.000001 # Query 1 # use `test`; insert into t1 values ('20040101000000'), ('20040611093902') -master-bin.000001 # Query 1 # use `test`; delete from t1 -master-bin.000001 # Query 1 # use `test`; insert into t1 values ('20040101000000'), ('20040611093902') +/*!40019 SET @@session.max_insert_delayed_threads=0*/; +/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/; +ROLLBACK; +use test; +SET TIMESTAMP=100000000; +SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1; +SET @@session.sql_mode=0; +SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8; +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'; insert into t2 (select t from t1); select * from t1; @@ -52,10 +78,6 @@ t delete from t2; set timestamp=1000072000; 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; t 2001-09-09 23:46:40 @@ -73,5 +95,16 @@ t 2001-09-09 03:46:40 1000000000 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; diff --git a/mysql-test/t/rpl_timezone-slave.opt b/mysql-test/t/rpl_timezone-slave.opt index 8e43bfbbb7e..191182c329c 100644 --- a/mysql-test/t/rpl_timezone-slave.opt +++ b/mysql-test/t/rpl_timezone-slave.opt @@ -1 +1 @@ ---default-time-zone=Europe/Moscow +--default-time-zone=Japan diff --git a/mysql-test/t/rpl_timezone.test b/mysql-test/t/rpl_timezone.test index 3c180ca8849..a49cdd0acd2 100644 --- a/mysql-test/t/rpl_timezone.test +++ b/mysql-test/t/rpl_timezone.test @@ -3,21 +3,25 @@ source include/master-slave.inc; # Some preparations let $VERSION=`select version()`; +set timestamp=100000000; # for fixed output of mysqlbinlog create table t1 (t timestamp); create table t2 (t char(32)); +connection slave; +select @@time_zone; + # # Let us check how well replication works when we are saving datetime # value in TIMESTAMP field. # connection master; select @@time_zone; +insert into t1 values ('20050101000000'), ('20050611093902'); set time_zone='UTC'; insert into t1 values ('20040101000000'), ('20040611093902'); select * from t1; -# On slave we still in 'Europe/Moscow' so we should see equivalent but -# textually different values. sync_slave_with_master; +set time_zone='UTC'; select * from t1; # Let us check also that setting of time_zone back to default also works @@ -28,12 +32,11 @@ set time_zone='Europe/Moscow'; insert into t1 values ('20040101000000'), ('20040611093902'); select * from t1; sync_slave_with_master; +set time_zone='Europe/Moscow'; select * from t1; connection master; -# We should not see SET ONE_SHOT time_zone before second insert ---replace_result $VERSION VERSION ---replace_column 2 # 5 # -show binlog events; +--replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR +--exec $MYSQL_BINLOG --short-form $MYSQL_TEST_DIR/var/log/master-bin.000001 # # Now let us check how well we replicate statments reading TIMESTAMP fields @@ -54,10 +57,6 @@ delete from t2; set timestamp=1000072000; insert into t2 values (current_timestamp), (current_date), (current_time); 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; # @@ -73,13 +72,24 @@ sync_slave_with_master; 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 # connection master; ---error 1387 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 +connection master; drop table t1, t2; sync_slave_with_master; diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index 870ad1af52b..24f1579544b 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -1307,6 +1307,9 @@ innobase_end(void) } #endif 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) { srv_very_fast_shutdown = TRUE; fprintf(stderr, @@ -1314,6 +1317,7 @@ innobase_end(void) "InnoDB: the InnoDB buffer pool to data files. At the next mysqld startup\n" "InnoDB: InnoDB will do a crash recovery!\n"); } +#endif innodb_inited = 0; if (innobase_shutdown_for_mysql() != DB_SUCCESS) { diff --git a/sql/log.cc b/sql/log.cc index 43786990797..0c1d6836cce 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -1638,57 +1638,6 @@ bool MYSQL_LOG::write(Log_event *event_info) 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) { Intvar_log_event e(thd,(uchar) LAST_INSERT_ID_EVENT, diff --git a/sql/log_event.cc b/sql/log_event.cc index ba018e859c1..666c2427ac5 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -506,8 +506,6 @@ void Log_event::init_show_field_list(List<Item>* field_list) field_list->push_back(new Item_empty_string("Info", 20)); } -#endif /* !MYSQL_CLIENT */ - /* Log_event::write() @@ -592,7 +590,6 @@ bool Log_event::write_header(IO_CACHE* file, ulong event_data_length) */ -#ifndef MYSQL_CLIENT int Log_event::read_log_event(IO_CACHE* file, String* packet, pthread_mutex_t* log_lock) { @@ -956,6 +953,7 @@ void Query_log_event::pack_info(Protocol *protocol) } #endif +#ifndef MYSQL_CLIENT /* Query_log_event::write() @@ -973,7 +971,8 @@ bool Query_log_event::write(IO_CACHE* file) 1+8+ // code of sql_mode and sql_mode 1+1+FN_REFLEN+ // code of catalog and catalog length and catalog 1+4+ // code of autoinc and the 2 autoinc variables - 1+6 // code of charset and charset + 1+6+ // code of charset and charset + 1+1+MAX_TIME_ZONE_NAME_LENGTH // code of tz and tz length and tz name ], *start, *start_of_status; ulong event_length; @@ -1030,20 +1029,20 @@ bool Query_log_event::write(IO_CACHE* file) start_of_status= start= buf+QUERY_HEADER_LEN; if (flags2_inited) { - *(start++)= Q_FLAGS2_CODE; + *start++= Q_FLAGS2_CODE; int4store(start, flags2); start+= 4; } if (sql_mode_inited) { - *(start++)= Q_SQL_MODE_CODE; + *start++= Q_SQL_MODE_CODE; int8store(start, (ulonglong)sql_mode); start+= 8; } - if (catalog_len >= 0) // i.e. "catalog inited" (false for 4.0 events) + if (catalog_len) // i.e. "catalog inited" (false for 4.0 events) { - *(start++)= Q_CATALOG_CODE; - *(start++)= (uchar) catalog_len; + *start++= Q_CATALOG_CODE; + *start++= (uchar) catalog_len; bmove(start, catalog, catalog_len); start+= catalog_len; /* @@ -1071,15 +1070,24 @@ bool Query_log_event::write(IO_CACHE* file) } if (charset_inited) { - *(start++)= Q_CHARSET_CODE; + *start++= Q_CHARSET_CODE; memcpy(start, charset, 6); start+= 6; } + if (time_zone_len) + { + /* In the TZ sys table, column Name is of length 64 so this should be ok */ + DBUG_ASSERT(time_zone_len <= MAX_TIME_ZONE_NAME_LENGTH); + *start++= Q_TIME_ZONE_CODE; + *start++= time_zone_len; + memcpy(start, time_zone_str, time_zone_len); + start+= time_zone_len; + } /* Here there could be code like if (command-line-option-which-says-"log_this_variable" && inited) { - *(start++)= Q_THIS_VARIABLE_CODE; + *start++= Q_THIS_VARIABLE_CODE; int4store(start, this_variable); start+= 4; } @@ -1108,8 +1116,6 @@ bool Query_log_event::write(IO_CACHE* file) /* Query_log_event::Query_log_event() */ - -#ifndef MYSQL_CLIENT Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg, ulong query_length, bool using_trans, bool suppress_use) @@ -1150,6 +1156,18 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg, int2store(charset, thd_arg->variables.character_set_client->number); int2store(charset+2, thd_arg->variables.collation_connection->number); int2store(charset+4, thd_arg->variables.collation_server->number); + if (thd_arg->time_zone_used) + { + /* + Note that our event becomes dependent on the Time_zone object + representing the time zone. Fortunately such objects are never deleted + or changed during mysqld's lifetime. + */ + time_zone_len= thd_arg->variables.time_zone->get_name()->length(); + time_zone_str= thd_arg->variables.time_zone->get_name()->ptr(); + } + else + time_zone_len= 0; DBUG_PRINT("info",("Query_log_event has flags2=%lu sql_mode=%lu",flags2,sql_mode)); } #endif /* MYSQL_CLIENT */ @@ -1163,15 +1181,17 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg, Query_log_event::Query_log_event(const char* buf, uint event_len, const Format_description_log_event *description_event, Log_event_type event_type) - :Log_event(buf, description_event), data_buf(0), query(NullS), catalog(NullS), + :Log_event(buf, description_event), data_buf(0), query(NullS), db(NullS), catalog_len(0), status_vars_len(0), flags2_inited(0), sql_mode_inited(0), charset_inited(0), - auto_increment_increment(1), auto_increment_offset(1) + auto_increment_increment(1), auto_increment_offset(1), + time_zone_len(0) { ulong data_len; uint32 tmp; uint8 common_header_len, post_header_len; - const char *start, *end; + char *start; + const char *end; DBUG_ENTER("Query_log_event::Query_log_event(char*,...)"); common_header_len= description_event->common_header_len; @@ -1191,7 +1211,7 @@ Query_log_event::Query_log_event(const char* buf, uint event_len, slave_proxy_id= thread_id = uint4korr(buf + Q_THREAD_ID_OFFSET); exec_time = uint4korr(buf + Q_EXEC_TIME_OFFSET); - db_len = (uint)buf[Q_DB_LEN_OFFSET]; + db_len = (uint)buf[Q_DB_LEN_OFFSET]; // TODO: add a check of all *_len vars error_code = uint2korr(buf + Q_ERR_CODE_OFFSET); /* @@ -1217,7 +1237,7 @@ Query_log_event::Query_log_event(const char* buf, uint event_len, /* variable-part: the status vars; only in MySQL 5.0 */ start= (char*) (buf+post_header_len); - end= (char*) (start+status_vars_len); + end= (const char*) (start+status_vars_len); for (const uchar* pos= (const uchar*) start; pos < (const uchar*) end;) { switch (*pos++) { @@ -1240,8 +1260,7 @@ Query_log_event::Query_log_event(const char* buf, uint event_len, break; } case Q_CATALOG_CODE: - catalog_len= *pos; - if (catalog_len) + if ((catalog_len= *pos)) catalog= (char*) pos+1; // Will be copied later pos+= catalog_len+2; break; @@ -1257,6 +1276,13 @@ Query_log_event::Query_log_event(const char* buf, uint event_len, pos+= 6; break; } + case Q_TIME_ZONE_CODE: + { + if ((time_zone_len= *pos)) + time_zone_str= (char *)(pos+1); + pos+= time_zone_len+1; + break; + } default: /* That's why you must write status vars in growing order of code */ DBUG_PRINT("info",("Query_log_event has unknown status vars (first has\ @@ -1265,24 +1291,29 @@ Query_log_event::Query_log_event(const char* buf, uint event_len, } } - /* A 2nd variable part; this is common to all versions */ - - if (!(start= data_buf = (char*) my_malloc(catalog_len + data_len +2, MYF(MY_WME)))) + if (!(start= data_buf = (char*) my_malloc(catalog_len + 1 + + time_zone_len + 1 + + data_len + 1, MYF(MY_WME)))) DBUG_VOID_RETURN; - if (catalog) // If catalog is given + if (catalog_len) // If catalog is given { - memcpy((char*) start, catalog, catalog_len+1); // Copy name and end \0 + memcpy(start, catalog, catalog_len+1); // Copy name and end \0 catalog= start; start+= catalog_len+1; } + if (time_zone_len) + { + memcpy(start, time_zone_str, time_zone_len); + time_zone_str= start; + start+= time_zone_len; + *start++= 0; + } + /* A 2nd variable part; this is common to all versions */ memcpy((char*) start, end, data_len); // Copy db and query - ((char*) start)[data_len]= '\0'; // End query with \0 (For safetly) + start[data_len]= '\0'; // End query with \0 (For safetly) db= start; query= start + db_len + 1; q_len= data_len - db_len -1; - /* This is used to detect wrong parsing. Could be removed in the future. */ - DBUG_PRINT("info", ("catalog: '%s' len: %u db: '%s' len: %u q_len: %lu", - catalog, (uint) catalog_len, db, (uint) db_len,q_len)); DBUG_VOID_RETURN; } @@ -1390,6 +1421,8 @@ void Query_log_event::print_query_header(FILE* file, bool short_form, last_event_info->auto_increment_offset= auto_increment_offset; } + /* TODO: print the catalog when we feature SET CATALOG */ + if (likely(charset_inited)) { if (unlikely(!last_event_info->charset_inited)) /* first Query event */ @@ -1410,6 +1443,14 @@ void Query_log_event::print_query_header(FILE* file, bool short_form, memcpy(last_event_info->charset, charset, 6); } } + if (time_zone_len) + { + if (bcmp(last_event_info->time_zone_str, time_zone_str, time_zone_len+1)) + { + fprintf(file,"SET @@session.time_zone='%s';\n", time_zone_str); + memcpy(last_event_info->time_zone_str, time_zone_str, time_zone_len+1); + } + } } @@ -1443,7 +1484,7 @@ int Query_log_event::exec_event(struct st_relay_log_info* rli, const char *query alloced block (see Query_log_event::exec_event()). Same for thd->db. Thank you. */ - thd->catalog= (char*) catalog; + thd->catalog= catalog_len ? (char *) catalog : (char *)""; thd->db_length= db_len; thd->db= (char*) rewrite_db(db, &thd->db_length); thd->variables.auto_increment_increment= auto_increment_increment; @@ -1513,20 +1554,28 @@ int Query_log_event::exec_event(struct st_relay_log_info* rli, const char *query get_charset(uint2korr(charset+4), MYF(MY_WME)))) { /* - We updated the thd->variables with nonsensical values (0), and the - thread is not guaranteed to terminate now (as it may be configured - to ignore EE_UNKNOWN_CHARSET);if we're going to execute a next - statement we'll have a new charset info with it, so no problem to - have stored 0 in thd->variables. But we invalidate cached - charset to force a check next time (otherwise if next time - charset is unknown again we won't detect it). + We updated the thd->variables with nonsensical values (0). Let's + set them to something safe (i.e. which avoids crash), and we'll + stop with EE_UNKNOWN_CHARSET in compare_errors (unless set to + ignore this error). */ - rli->cached_charset_invalidate(); + set_slave_thread_default_charset(thd, rli); goto compare_errors; } thd->update_charset(); // for the charset change to take effect } } + if (time_zone_len) + { + String tmp(time_zone_str, time_zone_len, &my_charset_bin); + if (!(thd->variables.time_zone= + my_tz_find_with_opening_tz_tables(thd, &tmp))) + { + my_error(ER_UNKNOWN_TIME_ZONE, MYF(0), tmp.c_ptr()); + thd->variables.time_zone= global_system_variables.time_zone; + goto compare_errors; + } + } /* Execute the query (note that we bypass dispatch_command()) */ mysql_parse(thd, thd->query, thd->query_length); @@ -1751,6 +1800,7 @@ Start_log_event_v3::Start_log_event_v3(const char* buf, Start_log_event_v3::write() */ +#ifndef MYSQL_CLIENT bool Start_log_event_v3::write(IO_CACHE* file) { char buff[START_V3_HEADER_LEN]; @@ -1760,6 +1810,7 @@ bool Start_log_event_v3::write(IO_CACHE* file) return (write_header(file, sizeof(buff)) || my_b_safe_write(file, (byte*) buff, sizeof(buff))); } +#endif /* @@ -1975,7 +2026,7 @@ Format_description_log_event(const char* buf, DBUG_VOID_RETURN; } - +#ifndef MYSQL_CLIENT bool Format_description_log_event::write(IO_CACHE* file) { /* @@ -1992,6 +2043,7 @@ bool Format_description_log_event::write(IO_CACHE* file) return (write_header(file, sizeof(buff)) || my_b_safe_write(file, buff, sizeof(buff))); } +#endif /* SYNOPSIS @@ -2208,6 +2260,8 @@ void Load_log_event::pack_info(Protocol *protocol) #endif /* defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) */ +#ifndef MYSQL_CLIENT + /* Load_log_event::write_data_header() */ @@ -2249,7 +2303,6 @@ bool Load_log_event::write_data_body(IO_CACHE* file) Load_log_event::Load_log_event() */ -#ifndef MYSQL_CLIENT Load_log_event::Load_log_event(THD *thd_arg, sql_exchange *ex, const char *db_arg, const char *table_name_arg, List<Item> &fields_arg, @@ -2863,6 +2916,7 @@ Rotate_log_event::Rotate_log_event(const char* buf, uint event_len, Rotate_log_event::write() */ +#ifndef MYSQL_CLIENT bool Rotate_log_event::write(IO_CACHE* file) { char buf[ROTATE_HEADER_LEN]; @@ -2871,7 +2925,7 @@ bool Rotate_log_event::write(IO_CACHE* file) my_b_safe_write(file, (byte*)buf, ROTATE_HEADER_LEN) || my_b_safe_write(file, (byte*)new_log_ident, (uint) ident_len)); } - +#endif /* Rotate_log_event::exec_event() @@ -2929,17 +2983,10 @@ int Rotate_log_event::exec_event(struct st_relay_log_info* rli) master is 4.0 then the events are in the slave's format (conversion). */ set_slave_thread_options(thd); + set_slave_thread_default_charset(thd, rli); thd->variables.sql_mode= global_system_variables.sql_mode; thd->variables.auto_increment_increment= thd->variables.auto_increment_offset= 1; - 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(); } pthread_mutex_unlock(&rli->data_lock); pthread_cond_broadcast(&rli->data_cond); @@ -3001,6 +3048,7 @@ const char* Intvar_log_event::get_var_type_name() Intvar_log_event::write() */ +#ifndef MYSQL_CLIENT bool Intvar_log_event::write(IO_CACHE* file) { byte buf[9]; @@ -3009,6 +3057,7 @@ bool Intvar_log_event::write(IO_CACHE* file) return (write_header(file, sizeof(buf)) || my_b_safe_write(file, buf, sizeof(buf))); } +#endif /* @@ -3093,6 +3142,7 @@ Rand_log_event::Rand_log_event(const char* buf, } +#ifndef MYSQL_CLIENT bool Rand_log_event::write(IO_CACHE* file) { byte buf[16]; @@ -3101,6 +3151,7 @@ bool Rand_log_event::write(IO_CACHE* file) return (write_header(file, sizeof(buf)) || my_b_safe_write(file, buf, sizeof(buf))); } +#endif #ifdef MYSQL_CLIENT @@ -3164,11 +3215,13 @@ Xid_log_event(const char* buf, } +#ifndef MYSQL_CLIENT bool Xid_log_event::write(IO_CACHE* file) { return write_header(file, sizeof(xid)) || my_b_safe_write(file, (byte*) &xid, sizeof(xid)); } +#endif #ifdef MYSQL_CLIENT @@ -3302,6 +3355,7 @@ User_var_log_event(const char* buf, } +#ifndef MYSQL_CLIENT bool User_var_log_event::write(IO_CACHE* file) { char buf[UV_NAME_LEN_SIZE]; @@ -3361,6 +3415,7 @@ bool User_var_log_event::write(IO_CACHE* file) my_b_safe_write(file, (byte*) buf1, buf1_length) || my_b_safe_write(file, (byte*) pos, val_len)); } +#endif /* @@ -3634,6 +3689,7 @@ int Slave_log_event::get_data_size() } +#ifndef MYSQL_CLIENT bool Slave_log_event::write(IO_CACHE* file) { ulong event_length= get_data_size(); @@ -3644,6 +3700,7 @@ bool Slave_log_event::write(IO_CACHE* file) return (write_header(file, event_length) || my_b_safe_write(file, (byte*) mem_pool, event_length)); } +#endif void Slave_log_event::init_from_mem_pool(int data_size) @@ -3770,7 +3827,6 @@ Create_file_log_event(THD* thd_arg, sql_exchange* ex, sql_ex.force_new_format(); DBUG_VOID_RETURN; } -#endif /* !MYSQL_CLIENT */ /* @@ -3815,6 +3871,7 @@ bool Create_file_log_event::write_base(IO_CACHE* file) return res; } +#endif /* !MYSQL_CLIENT */ /* Create_file_log_event ctor @@ -4042,6 +4099,7 @@ Append_block_log_event::Append_block_log_event(const char* buf, uint len, Append_block_log_event::write() */ +#ifndef MYSQL_CLIENT bool Append_block_log_event::write(IO_CACHE* file) { byte buf[APPEND_BLOCK_HEADER_LEN]; @@ -4050,6 +4108,7 @@ bool Append_block_log_event::write(IO_CACHE* file) my_b_safe_write(file, buf, APPEND_BLOCK_HEADER_LEN) || my_b_safe_write(file, (byte*) block, block_len)); } +#endif /* @@ -4171,6 +4230,7 @@ Delete_file_log_event::Delete_file_log_event(const char* buf, uint len, Delete_file_log_event::write() */ +#ifndef MYSQL_CLIENT bool Delete_file_log_event::write(IO_CACHE* file) { byte buf[DELETE_FILE_HEADER_LEN]; @@ -4178,6 +4238,7 @@ bool Delete_file_log_event::write(IO_CACHE* file) return (write_header(file, sizeof(buf)) || my_b_safe_write(file, buf, sizeof(buf))); } +#endif /* @@ -4265,6 +4326,7 @@ Execute_load_log_event::Execute_load_log_event(const char* buf, uint len, Execute_load_log_event::write() */ +#ifndef MYSQL_CLIENT bool Execute_load_log_event::write(IO_CACHE* file) { byte buf[EXEC_LOAD_HEADER_LEN]; @@ -4272,6 +4334,7 @@ bool Execute_load_log_event::write(IO_CACHE* file) return (write_header(file, sizeof(buf)) || my_b_safe_write(file, buf, sizeof(buf))); } +#endif /* @@ -4475,6 +4538,7 @@ ulong Execute_load_query_log_event::get_post_header_size_for_derived() } +#ifndef MYSQL_CLIENT bool Execute_load_query_log_event::write_post_header_for_derived(IO_CACHE* file) { @@ -4485,6 +4549,7 @@ Execute_load_query_log_event::write_post_header_for_derived(IO_CACHE* file) *(buf + 4 + 4 + 4)= (char)dup_handling; return my_b_safe_write(file, (byte*) buf, EXECUTE_LOAD_QUERY_EXTRA_HEADER_LEN); } +#endif #ifdef MYSQL_CLIENT diff --git a/sql/log_event.h b/sql/log_event.h index 43a801da851..72142db0aa7 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -237,6 +237,7 @@ struct sql_ex_info #define Q_CATALOG_CODE 2 #define Q_AUTO_INCREMENT 3 #define Q_CHARSET_CODE 4 +#define Q_TIME_ZONE_CODE 5 /* Intvar event post-header */ @@ -448,6 +449,7 @@ typedef struct st_last_event_info ulong auto_increment_increment, auto_increment_offset; bool charset_inited; 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() :flags2_inited(0), sql_mode_inited(0), auto_increment_increment(1),auto_increment_offset(1), charset_inited(0) @@ -459,6 +461,7 @@ typedef struct st_last_event_info */ bzero(db, sizeof(db)); bzero(charset, sizeof(charset)); + bzero(time_zone_str, sizeof(time_zone_str)); } } LAST_EVENT_INFO; #endif @@ -583,6 +586,7 @@ public: my_free((gptr) ptr, MYF(MY_WME|MY_ALLOW_ZERO_PTR)); } +#ifndef MYSQL_CLIENT bool write_header(IO_CACHE* file, ulong data_length); virtual bool write(IO_CACHE* file) { @@ -590,13 +594,14 @@ public: write_data_header(file) || write_data_body(file)); } - virtual bool is_artificial_event() { return 0; } virtual bool write_data_header(IO_CACHE* file) { return 0; } virtual bool write_data_body(IO_CACHE* file __attribute__((unused))) { return 0; } +#endif virtual Log_event_type get_type_code() = 0; virtual bool is_valid() const = 0; + virtual bool is_artificial_event() { return 0; } inline bool get_cache_stmt() { return cache_stmt; } Log_event(const char* buf, const Format_description_log_event* description_event); virtual ~Log_event() { free_temp_buf();} @@ -672,7 +677,7 @@ public: 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: @@ -714,6 +719,8 @@ public: ulong sql_mode; ulong auto_increment_increment, auto_increment_offset; char charset[6]; + uint time_zone_len; /* 0 means uninited */ + const char *time_zone_str; #ifndef MYSQL_CLIENT @@ -737,12 +744,13 @@ public: ~Query_log_event() { if (data_buf) - { my_free((gptr) data_buf, MYF(0)); - } } Log_event_type get_type_code() { return QUERY_EVENT; } +#ifndef MYSQL_CLIENT 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; } /* @@ -751,7 +759,6 @@ public: */ virtual ulong get_post_header_size_for_derived() { return 0; } /* Writes derived event-specific part of post header. */ - virtual bool write_post_header_for_derived(IO_CACHE* file) { return FALSE; } }; #ifdef HAVE_REPLICATION @@ -790,7 +797,9 @@ public: int get_data_size(); bool is_valid() const { return master_host != 0; } Log_event_type get_type_code() { return SLAVE_EVENT; } +#ifndef MYSQL_CLIENT bool write(IO_CACHE* file); +#endif }; #endif /* HAVE_REPLICATION */ @@ -885,8 +894,10 @@ public: { return sql_ex.new_format() ? NEW_LOAD_EVENT: LOAD_EVENT; } +#ifndef MYSQL_CLIENT bool write_data_header(IO_CACHE* file); bool write_data_body(IO_CACHE* file); +#endif bool is_valid() const { return table_name != 0; } int get_data_size() { @@ -962,7 +973,9 @@ public: const Format_description_log_event* description_event); ~Start_log_event_v3() {} Log_event_type get_type_code() { return START_EVENT_V3;} +#ifndef MYSQL_CLIENT bool write(IO_CACHE* file); +#endif bool is_valid() const { return 1; } int get_data_size() { @@ -1004,7 +1017,9 @@ public: const Format_description_log_event* description_event); ~Format_description_log_event() { my_free((gptr)post_header_len, MYF(0)); } Log_event_type get_type_code() { return FORMAT_DESCRIPTION_EVENT;} +#ifndef MYSQL_CLIENT bool write(IO_CACHE* file); +#endif bool is_valid() const { return ((common_header_len >= ((binlog_version==1) ? OLD_HEADER_LEN : @@ -1054,7 +1069,9 @@ public: Log_event_type get_type_code() { return INTVAR_EVENT;} const char* get_var_type_name(); int get_data_size() { return 9; /* sizeof(type) + sizeof(val) */;} +#ifndef MYSQL_CLIENT bool write(IO_CACHE* file); +#endif bool is_valid() const { return 1; } }; @@ -1092,7 +1109,9 @@ class Rand_log_event: public Log_event ~Rand_log_event() {} Log_event_type get_type_code() { return RAND_EVENT;} int get_data_size() { return 16; /* sizeof(ulonglong) * 2*/ } +#ifndef MYSQL_CLIENT bool write(IO_CACHE* file); +#endif bool is_valid() const { return 1; } }; @@ -1127,7 +1146,9 @@ class Xid_log_event: public Log_event ~Xid_log_event() {} Log_event_type get_type_code() { return XID_EVENT;} int get_data_size() { return sizeof(xid); } +#ifndef MYSQL_CLIENT bool write(IO_CACHE* file); +#endif bool is_valid() const { return 1; } }; @@ -1169,7 +1190,9 @@ public: User_var_log_event(const char* buf, const Format_description_log_event* description_event); ~User_var_log_event() {} Log_event_type get_type_code() { return USER_VAR_EVENT;} +#ifndef MYSQL_CLIENT bool write(IO_CACHE* file); +#endif bool is_valid() const { return 1; } }; @@ -1239,7 +1262,9 @@ public: Log_event_type get_type_code() { return ROTATE_EVENT;} int get_data_size() { return ident_len + ROTATE_HEADER_LEN;} bool is_valid() const { return new_log_ident != 0; } +#ifndef MYSQL_CLIENT bool write(IO_CACHE* file); +#endif }; @@ -1299,6 +1324,7 @@ public: 4 + 1 + block_len); } bool is_valid() const { return inited_from_old || block != 0; } +#ifndef MYSQL_CLIENT bool write_data_header(IO_CACHE* file); bool write_data_body(IO_CACHE* file); /* @@ -1306,6 +1332,7 @@ public: write it as Load event - used on the slave */ bool write_base(IO_CACHE* file); +#endif }; @@ -1352,7 +1379,9 @@ public: Log_event_type get_type_code() { return APPEND_BLOCK_EVENT;} int get_data_size() { return block_len + APPEND_BLOCK_HEADER_LEN ;} bool is_valid() const { return block != 0; } +#ifndef MYSQL_CLIENT bool write(IO_CACHE* file); +#endif const char* get_db() { return db; } }; @@ -1386,7 +1415,9 @@ public: Log_event_type get_type_code() { return DELETE_FILE_EVENT;} int get_data_size() { return DELETE_FILE_HEADER_LEN ;} bool is_valid() const { return file_id != 0; } +#ifndef MYSQL_CLIENT bool write(IO_CACHE* file); +#endif const char* get_db() { return db; } }; @@ -1419,7 +1450,9 @@ public: Log_event_type get_type_code() { return EXEC_LOAD_EVENT;} int get_data_size() { return EXEC_LOAD_HEADER_LEN ;} bool is_valid() const { return file_id != 0; } +#ifndef MYSQL_CLIENT bool write(IO_CACHE* file); +#endif const char* get_db() { return db; } }; @@ -1507,7 +1540,9 @@ public: bool is_valid() const { return Query_log_event::is_valid() && file_id != 0; } ulong get_post_header_size_for_derived(); +#ifndef MYSQL_CLIENT bool write_post_header_for_derived(IO_CACHE* file); +#endif }; diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index ba9f382fc33..64e7b2cdccf 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -257,6 +257,12 @@ extern CHARSET_INFO *national_charset_info, *table_alias_charset; /* Flag set if setup_tables already done */ #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 */ #ifndef MYSQL_CLIENT diff --git a/sql/set_var.cc b/sql/set_var.cc index 23dbb22399b..9e74c9452da 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -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, 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) { @@ -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 *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= 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, if (type == OPT_GLOBAL) return (byte *)(global_system_variables.time_zone->get_name()->ptr()); 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()); + } } diff --git a/sql/set_var.h b/sql/set_var.h index d78c228c142..585f6df3547 100644 --- a/sql/set_var.h +++ b/sql/set_var.h @@ -565,9 +565,6 @@ class sys_var_character_set_server :public sys_var_character_set public: sys_var_character_set_server(const char *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); CHARSET_INFO **ci_ptr(THD *thd, enum_var_type type); }; @@ -603,9 +600,6 @@ class sys_var_collation_server :public sys_var_collation { public: 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); void set_default(THD *thd, enum_var_type type); byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base); diff --git a/sql/slave.cc b/sql/slave.cc index 73dd0fd13c3..9e42206d4a3 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -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 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 - 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. 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 @@ -1456,11 +1456,10 @@ be equal for replication to work"; such check will broke everything for them. (And now everything will work for them because by default both their master and slave will have 'SYSTEM' time zone). - - TODO: when the new replication of timezones is sorted out with Dmitri, - change >= '4' to == '4'. + This check is only necessary for 4.x masters (and < 5.0.4 masters but + those were alpha). */ - if ((*mysql->server_version >= '4') && + if ((*mysql->server_version == '4') && !mysql_real_query(mysql, "SELECT @@GLOBAL.TIME_ZONE", 25) && (master_res= mysql_store_result(mysql))) { @@ -2770,6 +2769,18 @@ void set_slave_thread_options(THD* thd) 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() */ diff --git a/sql/slave.h b/sql/slave.h index ee5541ffe08..bc41cd4deca 100644 --- a/sql/slave.h +++ b/sql/slave.h @@ -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, const char** errmsg); 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); extern "C" pthread_handler_decl(handle_slave_io,arg); diff --git a/sql/tztime.cc b/sql/tztime.cc index bd9d49f0ab0..983c630071e 100644 --- a/sql/tztime.cc +++ b/sql/tztime.cc @@ -2178,7 +2178,7 @@ my_tz_find(const String * name, TABLE_LIST *tz_tables) DBUG_PRINT("enter", ("time zone name='%s'", 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) DBUG_RETURN(0); @@ -2210,7 +2210,7 @@ my_tz_find(const String * name, TABLE_LIST *tz_tables) (const byte *)name->ptr(), name->length()))) 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); } @@ -2219,6 +2219,58 @@ my_tz_find(const String * name, TABLE_LIST *tz_tables) 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) */ diff --git a/sql/tztime.h b/sql/tztime.h index caf663fc8cb..777e521d761 100644 --- a/sql/tztime.h +++ b/sql/tztime.h @@ -61,6 +61,7 @@ extern Time_zone * my_tz_UTC; extern Time_zone * my_tz_SYSTEM; 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_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 void my_tz_free(); @@ -96,10 +97,4 @@ inline bool my_tz_check_n_skip_implicit_tables(TABLE_LIST **table, 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) */ |