diff options
author | Sergei Golubchik <sergii@pisem.net> | 2013-04-12 01:01:18 +0200 |
---|---|---|
committer | Sergei Golubchik <sergii@pisem.net> | 2013-04-12 01:01:18 +0200 |
commit | ce926c90accc6ca36c62f0b954e651d89db66da8 (patch) | |
tree | 737c9571a90e6e1f07be30d8bdc64c2f06d6fbf3 | |
parent | 5ae72bb73cceafe5062be3827dbe3b4f488a7a73 (diff) | |
parent | ea4a417a8d456e8e09b6b4306f22c7c20b3e594c (diff) | |
download | mariadb-git-ce926c90accc6ca36c62f0b954e651d89db66da8.tar.gz |
5.3 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-- | mysql-test/r/fulltext_derived_4316.result | 8 | ||||
-rw-r--r-- | mysql-test/t/fulltext_derived_4316.test | 14 | ||||
-rw-r--r-- | sql-common/client.c | 6 | ||||
-rw-r--r-- | sql/item_func.cc | 29 | ||||
-rw-r--r-- | sql/multi_range_read.cc | 2 | ||||
-rw-r--r-- | sql/opt_range.cc | 11 | ||||
-rw-r--r-- | sql/slave.cc | 19 | ||||
-rw-r--r-- | sql/sql_base.cc | 1 | ||||
-rw-r--r-- | sql/sql_select.cc | 5 | ||||
-rw-r--r-- | sql/sql_show.cc | 6 | ||||
-rw-r--r-- | strings/ctype-utf8.c | 8 | ||||
-rw-r--r-- | tests/mysql_client_test.c | 9 |
15 files changed, 205 insertions, 108 deletions
diff --git a/client/mysqlbinlog.cc b/client/mysqlbinlog.cc index 2dae59af9ea..387413cc5aa 100644 --- a/client/mysqlbinlog.cc +++ b/client/mysqlbinlog.cc @@ -818,6 +818,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. @@ -1130,86 +1212,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: print_skip_replication_statement(print_event_info, ev); diff --git a/include/my_global.h b/include/my_global.h index 09a3a0a6efd..fcfc052d191 100644 --- a/include/my_global.h +++ b/include/my_global.h @@ -390,7 +390,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 c0f350d2bcf..4a28e145546 100644 --- a/include/mysql_com.h +++ b/include/mysql_com.h @@ -34,6 +34,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/mysql-test/r/fulltext_derived_4316.result b/mysql-test/r/fulltext_derived_4316.result new file mode 100644 index 00000000000..141202c9842 --- /dev/null +++ b/mysql-test/r/fulltext_derived_4316.result @@ -0,0 +1,8 @@ +create table t1 (ft text) engine=myisam; +insert into t1 values ('test1'),('test2'); +select distinct match(ft) against("test1" in boolean mode) from +(select distinct ft from t1) as t; +match(ft) against("test1" in boolean mode) +1 +0 +drop table t1; diff --git a/mysql-test/t/fulltext_derived_4316.test b/mysql-test/t/fulltext_derived_4316.test new file mode 100644 index 00000000000..ecf4a0e7722 --- /dev/null +++ b/mysql-test/t/fulltext_derived_4316.test @@ -0,0 +1,14 @@ +# +# MATCH on the derived tables +# + +# +# MDEV-4316 MariaDB server crash with signal 11 +# + +create table t1 (ft text) engine=myisam; +insert into t1 values ('test1'),('test2'); +select distinct match(ft) against("test1" in boolean mode) from + (select distinct ft from t1) as t; +drop table t1; + diff --git a/sql-common/client.c b/sql-common/client.c index 3119236ef2d..976c09d7a70 100644 --- a/sql-common/client.c +++ b/sql-common/client.c @@ -3414,6 +3414,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/item_func.cc b/sql/item_func.cc index 84161021a2b..62f8990aa8c 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -5990,15 +5990,12 @@ void Item_func_match::init_search(bool no_order) { DBUG_ENTER("Item_func_match::init_search"); + if (!table->file->get_table()) // the handler isn't opened yet + DBUG_VOID_RETURN; + /* Check if init_search() has been called before */ if (ft_handler) { - /* - We should reset ft_handler as it is cleaned up - on destruction of FT_SELECT object - (necessary in case of re-execution of subquery). - TODO: FT_SELECT should not clean up ft_handler. - */ if (join_key) table->file->ft_handler= ft_handler; DBUG_VOID_RETURN; @@ -6007,10 +6004,10 @@ void Item_func_match::init_search(bool no_order) if (key == NO_SUCH_KEY) { List<Item> fields; - fields.push_back(new Item_string(" ",1, cmp_collation.collation)); - for (uint i=1; i < arg_count; i++) + fields.push_back(new Item_string(" ", 1, cmp_collation.collation)); + for (uint i= 1; i < arg_count; i++) fields.push_back(args[i]); - concat_ws=new Item_func_concat_ws(fields); + concat_ws= new Item_func_concat_ws(fields); /* Above function used only to get value and do not need fix_fields for it: Item_string - basic constant @@ -6022,10 +6019,10 @@ void Item_func_match::init_search(bool no_order) if (master) { - join_key=master->join_key=join_key|master->join_key; + join_key= master->join_key= join_key | master->join_key; master->init_search(no_order); - ft_handler=master->ft_handler; - join_key=master->join_key; + ft_handler= master->ft_handler; + join_key= master->join_key; DBUG_VOID_RETURN; } @@ -6035,7 +6032,7 @@ void Item_func_match::init_search(bool no_order) if (!(ft_tmp=key_item()->val_str(&value))) { ft_tmp= &value; - value.set("",0,cmp_collation.collation); + value.set("", 0, cmp_collation.collation); } if (ft_tmp->charset() != cmp_collation.collation) @@ -6048,7 +6045,11 @@ void Item_func_match::init_search(bool no_order) if (join_key && !no_order) flags|=FT_SORTED; - ft_handler=table->file->ft_init_ext(flags, key, ft_tmp); + + if (key != NO_SUCH_KEY) + thd_proc_info(table->in_use, "FULLTEXT initialization"); + + ft_handler= table->file->ft_init_ext(flags, key, ft_tmp); if (join_key) table->file->ft_handler=ft_handler; diff --git a/sql/multi_range_read.cc b/sql/multi_range_read.cc index 800602fe9e1..175405790b5 100644 --- a/sql/multi_range_read.cc +++ b/sql/multi_range_read.cc @@ -1648,7 +1648,7 @@ int DsMrr_impl::dsmrr_explain_info(uint mrr_mode, char *str, size_t size) uint used_str_len= strlen(used_str); uint copy_len= min(used_str_len, size); - memcpy(str, used_str, size); + memcpy(str, used_str, copy_len); return copy_len; } return 0; diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 3f49e1664f0..823699d14b1 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -132,7 +132,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; /* @@ -7368,8 +7373,10 @@ static SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param,COND *cond) DBUG_RETURN(tree); } /* Here when simple cond */ - if (cond->const_item() && !cond->is_expensive()) + if (cond->const_item()) { + if (cond->is_expensive()) + DBUG_RETURN(0); /* During the cond->val_int() evaluation we can come across a subselect item which may allocate memory on the thd->mem_root and assumes diff --git a/sql/slave.cc b/sql/slave.cc index 16ef754c058..0a162f6fbaa 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -1216,6 +1216,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"); /* @@ -1236,20 +1237,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; @@ -1470,10 +1471,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, @@ -1536,7 +1537,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/sql/sql_base.cc b/sql/sql_base.cc index 46b936a6b21..a02294236f7 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -9477,7 +9477,6 @@ int init_ftfuncs(THD *thd, SELECT_LEX *select_lex, bool no_order) List_iterator<Item_func_match> li(*(select_lex->ftfunc_list)); Item_func_match *ifm; DBUG_PRINT("info",("Performing FULLTEXT search")); - thd_proc_info(thd, "FULLTEXT initialization"); while ((ifm=li++)) ifm->init_search(no_order); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 5eb182b32f4..a1d8d3c62e2 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -10401,6 +10401,11 @@ bool JOIN_TAB::preread_init() preread_init_done= TRUE; if (select && select->quick) select->quick->replace_handler(table->file); + + /* init ftfuns for just initialized derived table */ + if (table->fulltext_searched) + init_ftfuncs(join->thd, join->select_lex, test(join->order)); + return FALSE; } diff --git a/sql/sql_show.cc b/sql/sql_show.cc index e4b83a68a68..055dfa95b8b 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -7241,20 +7241,20 @@ TABLE *create_schema_table(THD *thd, TABLE_LIST *table_list) break; case MYSQL_TYPE_DATE: if (!(item=new Item_return_date_time(fields_info->field_name, - MAX_DATE_WIDTH, + strlen(fields_info->field_name), fields_info->field_type))) DBUG_RETURN(0); break; case MYSQL_TYPE_TIME: if (!(item=new Item_return_date_time(fields_info->field_name, - MAX_TIME_FULL_WIDTH, + strlen(fields_info->field_name), fields_info->field_type))) DBUG_RETURN(0); break; case MYSQL_TYPE_TIMESTAMP: case MYSQL_TYPE_DATETIME: if (!(item=new Item_return_date_time(fields_info->field_name, - MAX_DATETIME_WIDTH, + strlen(fields_info->field_name), fields_info->field_type))) DBUG_RETURN(0); break; diff --git a/strings/ctype-utf8.c b/strings/ctype-utf8.c index 88bab1fac76..b113d9f3b92 100644 --- a/strings/ctype-utf8.c +++ b/strings/ctype-utf8.c @@ -4353,6 +4353,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) @@ -4374,7 +4378,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) @@ -4399,7 +4403,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 f348ec4515b..f3f25a4ec90 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -6204,7 +6204,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; @@ -8880,7 +8880,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)); @@ -8891,7 +8891,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)); @@ -16926,7 +16926,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); |