diff options
author | Sergei Golubchik <sergii@pisem.net> | 2013-04-11 19:35:39 +0200 |
---|---|---|
committer | Sergei Golubchik <sergii@pisem.net> | 2013-04-11 19:35:39 +0200 |
commit | bfc6fa8c94f550f311b00c0d63372f3b75cf4b9b (patch) | |
tree | 01f9700b021029f4d6b878a3a0feab7ab8b8a458 | |
parent | b7f6c7432add38b8c31c1c962be7a43a6e8fbb33 (diff) | |
parent | 8296959c73534c54296096152fce9406d8b81a02 (diff) | |
download | mariadb-git-bfc6fa8c94f550f311b00c0d63372f3b75cf4b9b.tar.gz |
5.2 merge
-rw-r--r-- | client/mysqlbinlog.cc | 167 | ||||
-rw-r--r-- | include/my_global.h | 3 | ||||
-rw-r--r-- | include/mysql_com.h | 25 | ||||
-rw-r--r-- | sql-common/client.c | 6 | ||||
-rw-r--r-- | sql/opt_range.cc | 7 | ||||
-rw-r--r-- | sql/slave.cc | 19 | ||||
-rw-r--r-- | strings/ctype-utf8.c | 8 | ||||
-rw-r--r-- | tests/mysql_client_test.c | 9 |
8 files changed, 156 insertions, 88 deletions
diff --git a/client/mysqlbinlog.cc b/client/mysqlbinlog.cc index de44ef5d927..134334aef37 100644 --- a/client/mysqlbinlog.cc +++ b/client/mysqlbinlog.cc @@ -780,6 +780,88 @@ 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(); + + /* + If there is a kept Annotate event and all corresponding + rbr-events were filtered away, the Annotate event was not + freed and it is just the time to do it. + */ + free_annotate_event(); + + /* + 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. @@ -1081,86 +1163,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(); - - /* - If there is a kept Annotate event and all corresponding - rbr-events were filtered away, the Annotate event was not - freed and it is just the time to do it. - */ - free_annotate_event(); - - /* - 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 da6c918ff4d..41ab8bc518d 100644 --- a/include/my_global.h +++ b/include/my_global.h @@ -498,7 +498,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 d811b79889b..29869254171 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 e18af7d85b4..6cd6e25ee15 100644 --- a/sql-common/client.c +++ b/sql-common/client.c @@ -2947,6 +2947,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 af47578e8e3..a112f16dd3c 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -125,7 +125,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 436e52e64fe..a40b7cdcc48 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -874,6 +874,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"); /* @@ -894,20 +895,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; @@ -1113,10 +1114,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, @@ -1177,7 +1178,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 8b6da8f27c2..5b57d28afff 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); |