summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
Diffstat (limited to 'sql')
-rw-r--r--sql/log.cc8
-rw-r--r--sql/log_event.cc161
-rw-r--r--sql/log_event.h19
-rw-r--r--sql/mysql_priv.h6
-rw-r--r--sql/set_var.cc10
-rw-r--r--sql/set_var.h4
-rw-r--r--sql/slave.cc50
-rw-r--r--sql/slave.h10
-rw-r--r--sql/sql_yacc.yy20
9 files changed, 221 insertions, 67 deletions
diff --git a/sql/log.cc b/sql/log.cc
index 6c97581d144..7d6854b6fb4 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -1346,7 +1346,7 @@ bool MYSQL_LOG::write(Log_event* event_info)
if (thd)
{
- /* NOTE: CHARSET AND TZ REPL WILL BE REWRITTEN SHORTLY */
+#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,
@@ -1375,9 +1375,15 @@ COLLATION_CONNECTION=%u,COLLATION_DATABASE=%u,COLLATION_SERVER=%u",
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)
diff --git a/sql/log_event.cc b/sql/log_event.cc
index 5ee034d785e..d09b2b3dc03 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -953,7 +953,13 @@ void Query_log_event::pack_info(Protocol *protocol)
bool Query_log_event::write(IO_CACHE* file)
{
- uchar buf[QUERY_HEADER_LEN+1+4+1+8+1+1+FN_REFLEN+5], *start, *start_of_status;
+ uchar buf[QUERY_HEADER_LEN+
+ 1+4+ // code of flags2 and flags2
+ 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
+ ], *start, *start_of_status;
ulong event_length;
if (!query)
@@ -1048,9 +1054,15 @@ bool Query_log_event::write(IO_CACHE* file)
int2store(start+2, auto_increment_offset);
start+= 4;
}
+ if (charset_inited)
+ {
+ *(start++)= Q_CHARSET_CODE;
+ memcpy(start, charset, 6);
+ start+= 6;
+ }
/*
Here there could be code like
- if (command-line-option-which-says-"log_this_variable")
+ if (command-line-option-which-says-"log_this_variable" && inited)
{
*(start++)= Q_THIS_VARIABLE_CODE;
int4store(start, this_variable);
@@ -1095,7 +1107,7 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg,
thread_id(thd_arg->thread_id),
/* save the original thread id; we already know the server id */
slave_proxy_id(thd_arg->variables.pseudo_thread_id),
- flags2_inited(1), sql_mode_inited(1), flags2(0),
+ flags2_inited(1), sql_mode_inited(1), charset_inited(1),
sql_mode(thd_arg->variables.sql_mode),
auto_increment_increment(thd_arg->variables.auto_increment_increment),
auto_increment_offset(thd_arg->variables.auto_increment_offset)
@@ -1104,7 +1116,7 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg,
time(&end_time);
exec_time = (ulong) (end_time - thd->start_time);
catalog_len = (catalog) ? (uint32) strlen(catalog) : 0;
- status_vars_len= 1+4+1+8+1+1+catalog_len+1;
+ /* status_vars_len is set just before writing the event */
db_len = (db) ? (uint32) strlen(db) : 0;
/*
If we don't use flags2 for anything else than options contained in
@@ -1114,7 +1126,12 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg,
we will probably want to reclaim the 29 bits. So we need the &.
*/
flags2= thd_arg->options & OPTIONS_WRITTEN_TO_BIN_LOG;
-
+ DBUG_ASSERT(thd->variables.character_set_client->number < 256*256);
+ DBUG_ASSERT(thd->variables.collation_connection->number < 256*256);
+ DBUG_ASSERT(thd->variables.collation_server->number < 256*256);
+ 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);
DBUG_PRINT("info",("Query_log_event has flags2=%lu sql_mode=%lu",flags2,sql_mode));
}
#endif /* MYSQL_CLIENT */
@@ -1129,7 +1146,8 @@ Query_log_event::Query_log_event(const char* buf, uint event_len,
const Format_description_log_event *description_event)
:Log_event(buf, description_event), data_buf(0), query(NullS), catalog(NullS),
db(NullS), catalog_len(0), status_vars_len(0),
- flags2_inited(0), sql_mode_inited(0)
+ flags2_inited(0), sql_mode_inited(0), charset_inited(0),
+ auto_increment_increment(1), auto_increment_offset(1)
{
ulong data_len;
uint32 tmp;
@@ -1156,8 +1174,6 @@ Query_log_event::Query_log_event(const char* buf, uint event_len,
exec_time = uint4korr(buf + Q_EXEC_TIME_OFFSET);
db_len = (uint)buf[Q_DB_LEN_OFFSET];
error_code = uint2korr(buf + Q_ERR_CODE_OFFSET);
- /* If auto_increment is not set by query_event, they should not be used */
- auto_increment_increment= auto_increment_offset= 1;
/*
5.0 format starts here.
@@ -1216,6 +1232,13 @@ Query_log_event::Query_log_event(const char* buf, uint event_len,
auto_increment_offset= uint2korr(pos+2);
pos+= 4;
break;
+ case Q_CHARSET_CODE:
+ {
+ charset_inited= 1;
+ memcpy(charset, pos, 6);
+ pos+= 6;
+ 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\
@@ -1348,6 +1371,27 @@ void Query_log_event::print(FILE* file, bool short_form,
last_event_info->auto_increment_offset= auto_increment_offset;
}
+ if (likely(charset_inited))
+ {
+ if (unlikely(!last_event_info->charset_inited)) /* first Query event */
+ {
+ last_event_info->charset_inited= 1;
+ last_event_info->charset[0]= ~charset[0]; // force a difference to force write
+ }
+ if (unlikely(bcmp(last_event_info->charset, charset, 6)))
+ {
+ fprintf(file,"SET "
+ "@@session.character_set_client=%d,"
+ "@@session.collation_connection=%d,"
+ "@@session.collation_server=%d"
+ ";\n",
+ uint2korr(charset),
+ uint2korr(charset+2),
+ uint2korr(charset+4));
+ memcpy(last_event_info->charset, charset, 6);
+ }
+ }
+
my_fwrite(file, (byte*) query, q_len, MYF(MY_NABP | MY_WME));
fputs(";\n", file);
}
@@ -1400,34 +1444,64 @@ int Query_log_event::exec_event(struct st_relay_log_info* rli)
thd->variables.pseudo_thread_id= thread_id; // for temp tables
mysql_log.write(thd,COM_QUERY,"%s",thd->query);
DBUG_PRINT("query",("%s",thd->query));
-
- if (flags2_inited)
- /*
- all bits of thd->options which are 1 in OPTIONS_WRITTEN_TO_BIN_LOG must
- take their value from flags2.
- */
- thd->options= flags2|(thd->options & ~(ulong)OPTIONS_WRITTEN_TO_BIN_LOG);
- /*
- else, we are in a 3.23/4.0 binlog; we previously received a
- Rotate_log_event which reset thd->options and sql_mode, so nothing to do.
- */
-
- /*
- We do not replicate IGNORE_DIR_IN_CREATE. That is, if the master is a
- slave which runs with SQL_MODE=IGNORE_DIR_IN_CREATE, this should not
- force us to ignore the dir too. Imagine you are a ring of machines, and
- one has a disk problem so that you temporarily need IGNORE_DIR_IN_CREATE
- on this machine; you don't want it to propagate elsewhere (you don't want
- all slaves to start ignoring the dirs).
- */
- if (sql_mode_inited)
- thd->variables.sql_mode=
- (ulong) ((thd->variables.sql_mode & MODE_NO_DIR_IN_CREATE) |
- (sql_mode & ~(ulong) MODE_NO_DIR_IN_CREATE));
if (ignored_error_code((expected_error= error_code)) ||
!check_expected_error(thd,rli,expected_error))
+ {
+ if (flags2_inited)
+ /*
+ all bits of thd->options which are 1 in OPTIONS_WRITTEN_TO_BIN_LOG must
+ take their value from flags2.
+ */
+ thd->options= flags2|(thd->options & ~(ulong)OPTIONS_WRITTEN_TO_BIN_LOG);
+ /*
+ else, we are in a 3.23/4.0 binlog; we previously received a
+ Rotate_log_event which reset thd->options and sql_mode etc, so nothing to do.
+ */
+ /*
+ We do not replicate IGNORE_DIR_IN_CREATE. That is, if the master is a
+ slave which runs with SQL_MODE=IGNORE_DIR_IN_CREATE, this should not
+ force us to ignore the dir too. Imagine you are a ring of machines, and
+ one has a disk problem so that you temporarily need IGNORE_DIR_IN_CREATE
+ on this machine; you don't want it to propagate elsewhere (you don't want
+ all slaves to start ignoring the dirs).
+ */
+ if (sql_mode_inited)
+ thd->variables.sql_mode=
+ (ulong) ((thd->variables.sql_mode & MODE_NO_DIR_IN_CREATE) |
+ (sql_mode & ~(ulong) MODE_NO_DIR_IN_CREATE));
+ if (charset_inited)
+ {
+ if (rli->cached_charset_compare(charset))
+ {
+ /* Verify that we support the charsets found in the event. */
+ if (!(thd->variables.character_set_client=
+ get_charset(uint2korr(charset), MYF(MY_WME))) ||
+ !(thd->variables.collation_connection=
+ get_charset(uint2korr(charset+2), MYF(MY_WME))) ||
+ !(thd->variables.collation_server=
+ 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).
+ */
+ rli->cached_charset_invalidate();
+ goto compare_errors;
+ }
+ thd->update_charset(); // for the charset change to take effect
+ }
+ }
+
+ /* Execute the query (note that we bypass dispatch_command()) */
mysql_parse(thd, thd->query, q_len);
+
+ }
else
{
/*
@@ -1452,6 +1526,8 @@ START SLAVE; . Query: '%s'", expected_error, thd->query);
}
goto end;
}
+
+compare_errors:
/*
If we expected a non-zero error code, and we don't get the same error
@@ -1666,12 +1742,7 @@ bool Start_log_event_v3::write(IO_CACHE* file)
int Start_log_event_v3::exec_event(struct st_relay_log_info* rli)
{
DBUG_ENTER("Start_log_event_v3::exec_event");
- /*
- If the I/O thread has not started, mi->old_format is BINLOG_FORMAT_CURRENT
- (that's what the MASTER_INFO constructor does), so the test below is not
- perfect at all.
- */
- switch (rli->relay_log.description_event_for_exec->binlog_version)
+ switch (binlog_version)
{
case 3:
case 4:
@@ -2789,14 +2860,24 @@ int Rotate_log_event::exec_event(struct st_relay_log_info* rli)
rli->group_master_log_name,
(ulong) rli->group_master_log_pos));
/*
- Reset thd->options and sql_mode, because this could be the signal of a
- master's downgrade from 5.0 to 4.0.
+ Reset thd->options and sql_mode etc, because this could be the signal of
+ a master's downgrade from 5.0 to 4.0.
However, no need to reset description_event_for_exec: indeed, if the next
master is 5.0 (even 5.0.1) we will soon get a Format_desc; if the next
master is 4.0 then the events are in the slave's format (conversion).
*/
set_slave_thread_options(thd);
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);
diff --git a/sql/log_event.h b/sql/log_event.h
index 64bb9d502e9..7f04582a32d 100644
--- a/sql/log_event.h
+++ b/sql/log_event.h
@@ -232,6 +232,7 @@ struct sql_ex_info
#define Q_SQL_MODE_CODE 1
#define Q_CATALOG_CODE 2
#define Q_AUTO_INCREMENT 3
+#define Q_CHARSET_CODE 4
/* Intvar event post-header */
@@ -401,11 +402,19 @@ typedef struct st_last_event_info
bool sql_mode_inited;
ulong sql_mode; /* must be same as THD.variables.sql_mode */
ulong auto_increment_increment, auto_increment_offset;
+ bool charset_inited;
+ char charset[6]; // 3 variables, each of them storable in 2 bytes
st_last_event_info()
- :flags2_inited(0), flags2(0), sql_mode_inited(0), sql_mode(0),
- auto_increment_increment(1),auto_increment_offset(1)
+ :flags2_inited(0), sql_mode_inited(0),
+ auto_increment_increment(1),auto_increment_offset(1), charset_inited(0)
{
- db[0]= 0; /* initially, the db is unknown */
+ /*
+ Currently we only use static LAST_EVENT_INFO objects, so zeroed at
+ program's startup, but these explicit bzero() is for the day someone
+ creates dynamic instances.
+ */
+ bzero(db, sizeof(db));
+ bzero(charset, sizeof(charset));
}
} LAST_EVENT_INFO;
#endif
@@ -634,7 +643,7 @@ public:
status_vars on disk is a sequence of pairs (code, value) where 'code' means
'sql_mode', 'affected' etc. Sometimes 'value' must be a short string, so
its first byte is its length. For now the order of status vars is:
- flags2 - sql_mode - catalog.
+ flags2 - sql_mode - catalog - autoinc - charset
We should add the same thing to Load_log_event, but in fact
LOAD DATA INFILE is going to be logged with a new type of event (logging of
the plain text query), so Load_log_event would be frozen, so no need. The
@@ -655,11 +664,13 @@ public:
*/
bool flags2_inited;
bool sql_mode_inited;
+ bool charset_inited;
uint32 flags2;
/* In connections sql_mode is 32 bits now but will be 64 bits soon */
ulong sql_mode;
ulong auto_increment_increment, auto_increment_offset;
+ char charset[6];
#ifndef MYSQL_CLIENT
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index bf84e0a394e..6311b2d5f52 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -285,6 +285,12 @@ extern CHARSET_INFO *national_charset_info, *table_alias_charset;
#define MODE_TRADITIONAL (MODE_ERROR_FOR_DIVISION_BY_ZERO*2)
#define MODE_NO_AUTO_CREATE_USER (MODE_TRADITIONAL*2)
#define MODE_HIGH_NOT_PRECEDENCE (MODE_NO_AUTO_CREATE_USER*2)
+/*
+ Replication uses 8 bytes to store SQL_MODE in the binary log. The day you
+ use strictly more than 64 bits by adding one more define above, you should
+ contact the replication team because the replication code should then be
+ updated (to store more bytes on disk).
+*/
#define RAID_BLOCK_SIZE 1024
diff --git a/sql/set_var.cc b/sql/set_var.cc
index f4d07360282..142ef64a41f 100644
--- a/sql/set_var.cc
+++ b/sql/set_var.cc
@@ -2061,9 +2061,15 @@ void sys_var_character_set_server::set_default(THD *thd, enum_var_type type)
}
}
-#if defined(HAVE_REPLICATION)
+#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))
@@ -2168,7 +2174,7 @@ void sys_var_collation_database::set_default(THD *thd, enum_var_type type)
}
}
-#if defined(HAVE_REPLICATION)
+#if defined(HAVE_REPLICATION) && (MYSQL_VERSION_ID < 50003)
bool sys_var_collation_server::check(THD *thd, set_var *var)
{
if ((var->type == OPT_GLOBAL) &&
diff --git a/sql/set_var.h b/sql/set_var.h
index 8514b518660..3104fd38976 100644
--- a/sql/set_var.h
+++ b/sql/set_var.h
@@ -564,7 +564,7 @@ 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)
+#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);
@@ -602,7 +602,7 @@ 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)
+#if defined(HAVE_REPLICATION) && (MYSQL_VERSION_ID < 50003)
bool check(THD *thd, set_var *var);
#endif
bool update(THD *thd, set_var *var);
diff --git a/sql/slave.cc b/sql/slave.cc
index 0c5ebe0744a..380aba6f3b6 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -660,13 +660,14 @@ int terminate_slave_thread(THD* thd, pthread_mutex_t* term_lock,
pthread_cond_t* term_cond,
volatile uint *slave_running)
{
+ DBUG_ENTER("terminate_slave_thread");
if (term_lock)
{
pthread_mutex_lock(term_lock);
if (!*slave_running)
{
pthread_mutex_unlock(term_lock);
- return ER_SLAVE_NOT_RUNNING;
+ DBUG_RETURN(ER_SLAVE_NOT_RUNNING);
}
}
DBUG_ASSERT(thd != 0);
@@ -678,6 +679,7 @@ int terminate_slave_thread(THD* thd, pthread_mutex_t* term_lock,
while (*slave_running) // Should always be true
{
+ DBUG_PRINT("loop", ("killing slave thread"));
KICK_SLAVE(thd);
/*
There is a small chance that slave thread might miss the first
@@ -689,7 +691,7 @@ int terminate_slave_thread(THD* thd, pthread_mutex_t* term_lock,
}
if (term_lock)
pthread_mutex_unlock(term_lock);
- return 0;
+ DBUG_RETURN(0);
}
@@ -1418,13 +1420,20 @@ not always make sense; please check the manual before using it).";
values of these 2 are never used (new connections don't use them).
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.
- We don't do it for <3.23.57 because masters <3.23.50 hang on
- SELECT @@unknown_var (BUG#7965 - see changelog of 3.23.50).
+ 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
+ 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
+ test only if master is 4.x.
*/
- if (strncmp(mi->rli.relay_log.description_event_for_queue->server_version,
- "3.23.57",7) < 0)
+
+ /* redundant with rest of code but safer against later additions */
+ if (*mysql->server_version == '3')
goto err;
- if (!mysql_real_query(mysql, "SELECT @@GLOBAL.COLLATION_SERVER", 32) &&
+
+ if ((*mysql->server_version == '4') &&
+ !mysql_real_query(mysql, "SELECT @@GLOBAL.COLLATION_SERVER", 32) &&
(master_res= mysql_store_result(mysql)))
{
if ((master_row= mysql_fetch_row(master_res)) &&
@@ -1447,8 +1456,12 @@ 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'.
*/
- if (!mysql_real_query(mysql, "SELECT @@GLOBAL.TIME_ZONE", 25) &&
+ if ((*mysql->server_version >= '4') &&
+ !mysql_real_query(mysql, "SELECT @@GLOBAL.TIME_ZONE", 25) &&
(master_res= mysql_store_result(mysql)))
{
if ((master_row= mysql_fetch_row(master_res)) &&
@@ -2527,6 +2540,7 @@ st_relay_log_info::st_relay_log_info()
bzero((char*) &info_file, sizeof(info_file));
bzero((char*) &cache_buf, sizeof(cache_buf));
+ cached_charset_invalidate();
pthread_mutex_init(&run_lock, MY_MUTEX_INIT_FAST);
pthread_mutex_init(&data_lock, MY_MUTEX_INIT_FAST);
pthread_mutex_init(&log_space_lock, MY_MUTEX_INIT_FAST);
@@ -3078,6 +3092,24 @@ bool st_relay_log_info::is_until_satisfied()
}
+void st_relay_log_info::cached_charset_invalidate()
+{
+ /* Full of zeroes means uninitialized. */
+ bzero(cached_charset, sizeof(cached_charset));
+}
+
+
+bool st_relay_log_info::cached_charset_compare(char *charset)
+{
+ if (bcmp(cached_charset, charset, sizeof(cached_charset)))
+ {
+ memcpy(cached_charset, charset, sizeof(cached_charset));
+ return 1;
+ }
+ return 0;
+}
+
+
static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli)
{
/*
@@ -3722,6 +3754,8 @@ the slave SQL thread with \"SLAVE START\". We stopped at log \
DBUG_PRINT("info",("Signaling possibly waiting master_pos_wait() functions"));
pthread_cond_broadcast(&rli->data_cond);
rli->ignore_log_space_limit= 0; /* don't need any lock */
+ /* we die so won't remember charset - re-update them on next thread start */
+ rli->cached_charset_invalidate();
rli->save_temporary_tables = thd->temporary_tables;
/*
diff --git a/sql/slave.h b/sql/slave.h
index e0816fd45a7..598ff0a7845 100644
--- a/sql/slave.h
+++ b/sql/slave.h
@@ -291,6 +291,8 @@ typedef struct st_relay_log_info
UNTIL_LOG_NAMES_CMP_UNKNOWN= -2, UNTIL_LOG_NAMES_CMP_LESS= -1,
UNTIL_LOG_NAMES_CMP_EQUAL= 0, UNTIL_LOG_NAMES_CMP_GREATER= 1
} until_log_names_cmp_result;
+
+ char cached_charset[6];
st_relay_log_info();
~st_relay_log_info();
@@ -334,6 +336,14 @@ typedef struct st_relay_log_info
return ((until_condition == UNTIL_MASTER_POS) ? group_master_log_pos :
group_relay_log_pos);
}
+ /*
+ Last charset (6 bytes) seen by slave SQL thread is cached here; it helps
+ the thread save 3 get_charset() per Query_log_event if the charset is not
+ changing from event to event (common situation).
+ When the 6 bytes are equal to 0 is used to mean "cache is invalidated".
+ */
+ void cached_charset_invalidate();
+ bool cached_charset_compare(char *charset);
} RELAY_LOG_INFO;
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index ec2abfdbf76..a94fb31580c 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -4032,14 +4032,15 @@ bool_test:
bool_pri:
bool_pri IS NULL_SYM { $$= new Item_func_isnull($1); }
| bool_pri IS not NULL_SYM { $$= new Item_func_isnotnull($1); }
- | predicate BETWEEN_SYM bit_expr AND_SYM bool_pri
- { $$= new Item_func_between($1,$3,$5); }
- | predicate not BETWEEN_SYM bit_expr AND_SYM bool_pri
- { $$= negate_expression(YYTHD, new Item_func_between($1,$4,$6)); }
+ | bool_pri EQUAL_SYM predicate { $$= new Item_func_equal($1,$3); }
+ | bool_pri comp_op predicate %prec EQ
+ { $$= (*$2)(0)->create($1,$3); }
+ | bool_pri comp_op all_or_any in_subselect %prec EQ
+ { $$= all_any_subquery_creator($1, $2, $3, $4); }
| predicate ;
predicate:
- bit_expr IN_SYM '(' expr_list ')'
+ bit_expr IN_SYM '(' expr_list ')'
{ $4->push_front($1); $$= new Item_func_in(*$4); }
| bit_expr not IN_SYM '(' expr_list ')'
{ $5->push_front($1); $$= negate_expression(YYTHD, new Item_func_in(*$5)); }
@@ -4047,6 +4048,10 @@ predicate:
{ $$= new Item_in_subselect($1, $3); }
| bit_expr not IN_SYM in_subselect
{ $$= negate_expression(YYTHD, new Item_in_subselect($1, $4)); }
+ | bit_expr BETWEEN_SYM bit_expr AND_SYM predicate
+ { $$= new Item_func_between($1,$3,$5); }
+ | bit_expr not BETWEEN_SYM bit_expr AND_SYM predicate
+ { $$= negate_expression(YYTHD, new Item_func_between($1,$4,$6)); }
| bit_expr SOUNDS_SYM LIKE bit_expr
{ $$= new Item_func_eq(new Item_func_soundex($1),
new Item_func_soundex($4)); }
@@ -4057,11 +4062,6 @@ predicate:
| bit_expr REGEXP bit_expr { $$= new Item_func_regex($1,$3); }
| bit_expr not REGEXP bit_expr
{ $$= negate_expression(YYTHD, new Item_func_regex($1,$4)); }
- | bit_expr EQUAL_SYM bit_expr { $$= new Item_func_equal($1,$3); }
- | bit_expr comp_op bit_expr %prec EQ
- { $$= (*$2)(0)->create($1,$3); }
- | bit_expr comp_op all_or_any in_subselect %prec EQ
- { $$= all_any_subquery_creator($1, $2, $3, $4); }
| bit_expr ;
bit_expr: