summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergei Golubchik <sergii@pisem.net>2013-04-11 19:30:59 +0200
committerSergei Golubchik <sergii@pisem.net>2013-04-11 19:30:59 +0200
commit61ed0ebe7388d8302f2de7144de41da32bf085ba (patch)
tree8b47861aeeef1db8fcbf8d0a558043aab93187a8
parent48be80cd95c9121d2730ebcd1df2a1a37fe73f3d (diff)
parent7b55b59b5792d87dedd946487769bc2b1dc36833 (diff)
downloadmariadb-git-61ed0ebe7388d8302f2de7144de41da32bf085ba.tar.gz
5.1 merge
-rw-r--r--client/mysqlbinlog.cc153
-rw-r--r--include/my_global.h3
-rw-r--r--include/mysql_com.h25
-rw-r--r--sql-common/client.c6
-rw-r--r--sql/opt_range.cc7
-rw-r--r--sql/slave.cc19
-rw-r--r--strings/ctype-utf8.c8
-rw-r--r--tests/mysql_client_test.c9
8 files changed, 149 insertions, 81 deletions
diff --git a/client/mysqlbinlog.cc b/client/mysqlbinlog.cc
index 67fcbab4314..fdf38ca4219 100644
--- a/client/mysqlbinlog.cc
+++ b/client/mysqlbinlog.cc
@@ -713,6 +713,81 @@ write_event_header_and_base64(Log_event *ev, FILE *result_file,
}
+static bool print_base64(PRINT_EVENT_INFO *print_event_info, Log_event *ev)
+{
+ /*
+ These events must be printed in base64 format, if printed.
+ base64 format requires a FD event to be safe, so if no FD
+ event has been printed, we give an error. Except if user
+ passed --short-form, because --short-form disables printing
+ row events.
+ */
+ if (!print_event_info->printed_fd_event && !short_form &&
+ opt_base64_output_mode != BASE64_OUTPUT_DECODE_ROWS)
+ {
+ const char* type_str= ev->get_type_str();
+ if (opt_base64_output_mode == BASE64_OUTPUT_NEVER)
+ error("--base64-output=never specified, but binlog contains a "
+ "%s event which must be printed in base64.",
+ type_str);
+ else
+ error("malformed binlog: it does not contain any "
+ "Format_description_log_event. I now found a %s event, which "
+ "is not safe to process without a "
+ "Format_description_log_event.",
+ type_str);
+ return 1;
+ }
+ ev->print(result_file, print_event_info);
+ return print_event_info->head_cache.error == -1;
+}
+
+
+static bool print_row_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev,
+ ulong table_id, bool is_stmt_end)
+{
+ Table_map_log_event *ignored_map=
+ print_event_info->m_table_map_ignored.get_table(table_id);
+ bool skip_event= (ignored_map != NULL);
+
+ /*
+ end of statement check:
+ i) destroy/free ignored maps
+ ii) if skip event, flush cache now
+ */
+ if (is_stmt_end)
+ {
+ /*
+ Now is safe to clear ignored map (clear_tables will also
+ delete original table map events stored in the map).
+ */
+ if (print_event_info->m_table_map_ignored.count() > 0)
+ print_event_info->m_table_map_ignored.clear_tables();
+
+ /*
+ One needs to take into account an event that gets
+ filtered but was last event in the statement. If this is
+ the case, previous rows events that were written into
+ IO_CACHEs still need to be copied from cache to
+ result_file (as it would happen in ev->print(...) if
+ event was not skipped).
+ */
+ if (skip_event)
+ {
+ if ((copy_event_cache_to_file_and_reinit(&print_event_info->head_cache, result_file) ||
+ copy_event_cache_to_file_and_reinit(&print_event_info->body_cache, result_file)))
+ return 1;
+ }
+ }
+
+ /* skip the event check */
+ if (skip_event)
+ return 0;
+
+ return print_base64(print_event_info, ev);
+}
+
+
/**
Print the given event, and either delete it or delegate the deletion
to someone else.
@@ -983,79 +1058,29 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev,
error("Could not rewrite database name");
goto err;
}
+ if (print_base64(print_event_info, ev))
+ goto err;
+ break;
}
case WRITE_ROWS_EVENT:
case DELETE_ROWS_EVENT:
case UPDATE_ROWS_EVENT:
+ {
+ Rows_log_event *e= (Rows_log_event*) ev;
+ if (print_row_event(print_event_info, ev, e->get_table_id(),
+ e->get_flags(Rows_log_event::STMT_END_F)))
+ goto err;
+ break;
+ }
case PRE_GA_WRITE_ROWS_EVENT:
case PRE_GA_DELETE_ROWS_EVENT:
case PRE_GA_UPDATE_ROWS_EVENT:
{
- if (ev_type != TABLE_MAP_EVENT)
- {
- Rows_log_event *e= (Rows_log_event*) ev;
- Table_map_log_event *ignored_map=
- print_event_info->m_table_map_ignored.get_table(e->get_table_id());
- bool skip_event= (ignored_map != NULL);
-
- /*
- end of statement check:
- i) destroy/free ignored maps
- ii) if skip event, flush cache now
- */
- if (e->get_flags(Rows_log_event::STMT_END_F))
- {
- /*
- Now is safe to clear ignored map (clear_tables will also
- delete original table map events stored in the map).
- */
- if (print_event_info->m_table_map_ignored.count() > 0)
- print_event_info->m_table_map_ignored.clear_tables();
-
- /*
- One needs to take into account an event that gets
- filtered but was last event in the statement. If this is
- the case, previous rows events that were written into
- IO_CACHEs still need to be copied from cache to
- result_file (as it would happen in ev->print(...) if
- event was not skipped).
- */
- if (skip_event)
- {
- if ((copy_event_cache_to_file_and_reinit(&print_event_info->head_cache, result_file) ||
- copy_event_cache_to_file_and_reinit(&print_event_info->body_cache, result_file)))
- goto err;
- }
- }
-
- /* skip the event check */
- if (skip_event)
- goto end;
- }
- /*
- These events must be printed in base64 format, if printed.
- base64 format requires a FD event to be safe, so if no FD
- event has been printed, we give an error. Except if user
- passed --short-form, because --short-form disables printing
- row events.
- */
- if (!print_event_info->printed_fd_event && !short_form &&
- opt_base64_output_mode != BASE64_OUTPUT_DECODE_ROWS)
- {
- const char* type_str= ev->get_type_str();
- if (opt_base64_output_mode == BASE64_OUTPUT_NEVER)
- error("--base64-output=never specified, but binlog contains a "
- "%s event which must be printed in base64.",
- type_str);
- else
- error("malformed binlog: it does not contain any "
- "Format_description_log_event. I now found a %s event, which "
- "is not safe to process without a "
- "Format_description_log_event.",
- type_str);
+ Old_rows_log_event *e= (Old_rows_log_event*) ev;
+ if (print_row_event(print_event_info, ev, e->get_table_id(),
+ e->get_flags(Old_rows_log_event::STMT_END_F)))
goto err;
- }
- /* FALL THROUGH */
+ break;
}
default:
ev->print(result_file, print_event_info);
diff --git a/include/my_global.h b/include/my_global.h
index 105a346a69f..9d982373545 100644
--- a/include/my_global.h
+++ b/include/my_global.h
@@ -496,7 +496,8 @@ C_MODE_END
#define compile_time_assert(X) \
do \
{ \
- typedef char compile_time_assert[(X) ? 1 : -1]; \
+ typedef char compile_time_assert[(X) ? 1 : -1] \
+ __attribute__((unused)); \
} while(0)
#endif
diff --git a/include/mysql_com.h b/include/mysql_com.h
index d7441036a98..ec38d516172 100644
--- a/include/mysql_com.h
+++ b/include/mysql_com.h
@@ -31,6 +31,31 @@
#define MYSQL50_TABLE_NAME_PREFIX_LENGTH (sizeof(MYSQL50_TABLE_NAME_PREFIX)-1)
#define SAFE_NAME_LEN (NAME_LEN + MYSQL50_TABLE_NAME_PREFIX_LENGTH)
+/*
+ MDEV-4088
+
+ MySQL (and MariaDB 5.x before the fix) was using the first character of the
+ server version string (as sent in the first handshake protocol packet) to
+ decide on the replication event formats. And for 10.x the first character
+ is "1", which the slave thought comes from some ancient 1.x version
+ (ignoring the fact that the first ever MySQL version was 3.x).
+
+ To support replication to these old clients, we fake the version in the
+ first handshake protocol packet to start from "5.5.5-" (for example,
+ it might be "5.5.5-10.0.1-MariaDB-debug-log".
+
+ On the client side we remove this fake version prefix to restore the
+ correct server version. The version "5.5.5" did not support
+ pluggable authentication, so any version starting from "5.5.5-" and
+ claiming to support pluggable auth, must be using this fake prefix.
+*/
+#ifdef EMBEDDED_LIBRARY
+#define RPL_VERSION_HACK ""
+#else
+/* this version must be the one that *does not* support pluggable auth */
+#define RPL_VERSION_HACK "5.5.5-"
+#endif
+
#define SERVER_VERSION_LENGTH 60
#define SQLSTATE_LENGTH 5
#define LIST_PROCESS_HOST_LEN 64
diff --git a/sql-common/client.c b/sql-common/client.c
index d9444a7d976..ce88dbbbf52 100644
--- a/sql-common/client.c
+++ b/sql-common/client.c
@@ -2945,6 +2945,12 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user,
strmov(mysql->server_version,(char*) net->read_pos+1);
mysql->port=port;
+ /* remove the rpl hack from the version string, see RPL_VERSION_HACK comment */
+ if (mysql->server_capabilities & CLIENT_PLUGIN_AUTH &&
+ strncmp(mysql->server_version, RPL_VERSION_HACK,
+ sizeof(RPL_VERSION_HACK) - 1) == 0)
+ mysql->server_version+= sizeof(RPL_VERSION_HACK) - 1;
+
if (pkt_end >= end + SCRAMBLE_LENGTH - SCRAMBLE_LENGTH_323 + 1)
{
/*
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index 100b900e50d..ef6192509fd 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -83,7 +83,12 @@
static int sel_cmp(Field *f,uchar *a,uchar *b,uint8 a_flag,uint8 b_flag);
-static uchar is_null_string[2]= {1,0};
+/*
+ this should be long enough so that any memcmp with a string that
+ starts from '\0' won't cross is_null_string boundaries, even
+ if the memcmp is optimized to compare 4- 8- or 16- bytes at once
+*/
+static uchar is_null_string[20]= {1,0};
class RANGE_OPT_PARAM;
/*
diff --git a/sql/slave.cc b/sql/slave.cc
index 5abb09b797c..3c7cf166b20 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -873,6 +873,7 @@ static int get_master_version_and_clock(MYSQL* mysql, Master_info* mi)
int err_code= 0;
MYSQL_RES *master_res= 0;
MYSQL_ROW master_row;
+ uint version= mysql_get_server_version(mysql) / 10000;
DBUG_ENTER("get_master_version_and_clock");
/*
@@ -893,20 +894,20 @@ static int get_master_version_and_clock(MYSQL* mysql, Master_info* mi)
/*
Note the following switch will bug when we have MySQL branch 30 ;)
*/
- switch (*mysql->server_version)
+ switch (version)
{
- case '0':
- case '1':
- case '2':
+ case 0:
+ case 1:
+ case 2:
errmsg = "Master reported unrecognized MySQL version";
err_code= ER_SLAVE_FATAL_ERROR;
sprintf(err_buff, ER(err_code), errmsg);
break;
- case '3':
+ case 3:
mi->rli.relay_log.description_event_for_queue= new
Format_description_log_event(1, mysql->server_version);
break;
- case '4':
+ case 4:
mi->rli.relay_log.description_event_for_queue= new
Format_description_log_event(3, mysql->server_version);
break;
@@ -1070,10 +1071,10 @@ maybe it is a *VERY OLD MASTER*.");
*/
/* redundant with rest of code but safer against later additions */
- if (*mysql->server_version == '3')
+ if (version == 3)
goto err;
- if (*mysql->server_version == '4')
+ if (version == 4)
{
master_res= NULL;
if (!mysql_real_query(mysql,
@@ -1134,7 +1135,7 @@ inconsistency if replicated data deals with collation.");
This check is only necessary for 4.x masters (and < 5.0.4 masters but
those were alpha).
*/
- if (*mysql->server_version == '4')
+ if (version == 4)
{
master_res= NULL;
if (!mysql_real_query(mysql, STRING_WITH_LEN("SELECT @@GLOBAL.TIME_ZONE")) &&
diff --git a/strings/ctype-utf8.c b/strings/ctype-utf8.c
index c30498d7778..648783e73b8 100644
--- a/strings/ctype-utf8.c
+++ b/strings/ctype-utf8.c
@@ -4259,6 +4259,10 @@ static const char filename_safe_char[128]=
#define MY_FILENAME_ESCAPE '@'
+/*
+ note, that we cannot trust 'e' here, it's may be fake,
+ see strconvert()
+*/
static int
my_mb_wc_filename(CHARSET_INFO *cs __attribute__((unused)),
my_wc_t *pwc, const uchar *s, const uchar *e)
@@ -4280,7 +4284,7 @@ my_mb_wc_filename(CHARSET_INFO *cs __attribute__((unused)),
return MY_CS_TOOSMALL3;
byte1= s[1];
- byte2= s[2];
+ byte2= byte1 ? s[2] : 0;
if (byte1 >= 0x30 && byte1 <= 0x7F &&
byte2 >= 0x30 && byte2 <= 0x7F)
@@ -4305,7 +4309,7 @@ my_mb_wc_filename(CHARSET_INFO *cs __attribute__((unused)),
(byte2= hexlo(byte2)) >= 0)
{
int byte3= hexlo(s[3]);
- int byte4= hexlo(s[4]);
+ int byte4= hexlo(s[3] ? s[4] : 0);
if (byte3 >=0 && byte4 >=0)
{
*pwc= (byte1 << 12) + (byte2 << 8) + (byte3 << 4) + byte4;
diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c
index fff06ca7daa..dc1d4580959 100644
--- a/tests/mysql_client_test.c
+++ b/tests/mysql_client_test.c
@@ -5599,7 +5599,7 @@ static void test_date_dt()
static void test_pure_coverage()
{
MYSQL_STMT *stmt;
- MYSQL_BIND my_bind[1];
+ MYSQL_BIND my_bind[2];
int rc;
ulong length;
@@ -8275,7 +8275,7 @@ static void test_parse_error_and_bad_length()
DIE_UNLESS(rc);
if (!opt_silent)
fprintf(stdout, "Got error (as expected): '%s'\n", mysql_error(mysql));
- rc= mysql_real_query(mysql, "SHOW DATABASES", 100);
+ rc= mysql_real_query(mysql, STRING_WITH_LEN("SHOW DATABASES\0AAAAAAAA"));
DIE_UNLESS(rc);
if (!opt_silent)
fprintf(stdout, "Got error (as expected): '%s'\n", mysql_error(mysql));
@@ -8286,7 +8286,7 @@ static void test_parse_error_and_bad_length()
fprintf(stdout, "Got error (as expected): '%s'\n", mysql_error(mysql));
stmt= mysql_stmt_init(mysql);
DIE_UNLESS(stmt);
- rc= mysql_stmt_prepare(stmt, "SHOW DATABASES", 100);
+ rc= mysql_stmt_prepare(stmt, STRING_WITH_LEN("SHOW DATABASES\0AAAAAAA"));
DIE_UNLESS(rc != 0);
if (!opt_silent)
fprintf(stdout, "Got error (as expected): '%s'\n", mysql_stmt_error(stmt));
@@ -16272,7 +16272,8 @@ static void test_bug31669()
rc= mysql_change_user(conn, "", "", "");
DIE_UNLESS(rc);
- memset(buff, 'a', sizeof(buff));
+ memset(buff, 'a', sizeof(buff) - 1);
+ buff[sizeof(buff) - 1]= 0;
mysql_close(conn);
conn= client_connect(0, MYSQL_PROTOCOL_TCP, 0);