diff options
author | Venkatesh Duggirala <venkatesh.duggirala@oracle.com> | 2015-12-01 15:38:11 +0530 |
---|---|---|
committer | Venkatesh Duggirala <venkatesh.duggirala@oracle.com> | 2015-12-01 15:38:11 +0530 |
commit | 2735f0b92020c8ac4bd07d7ea843a0946b19e8ad (patch) | |
tree | f698248dc83ac973eec6eb91e6b3994b019b3fea /sql/sql_show.cc | |
parent | 08e929388b2cea170f6a44e9c8669f9c0f636808 (diff) | |
download | mariadb-git-2735f0b92020c8ac4bd07d7ea843a0946b19e8ad.tar.gz |
Bug#21205695 DROP TABLE MAY CAUSE SLAVES TO BREAK
Problem:
========
1) Drop table queries are re-generated by server
before writing the events(queries) into binlog
for various reasons. If table name/db name contains
a non regular characters (like latin characters),
the generated query is wrong. Hence it breaks the
replication.
2) In the edge case, when table name/db name contains
64 characters, server is throwing an assert
assert(M_TBLLEN < 128)
3) In the edge case, when db name contains 64 latin
characters, binlog content is interpreted badly
which is leading replication failure.
Analysis & Fix :
================
1) Parser reads the table name from the query and converts
it to standard charset(utf8) and stores it in table_name variable.
When drop table query is regenerated with the same table_name
variable, it should be converted back to the original charset
from standard charset(utf8).
2) Latin character takes two bytes for each character. Limit
of the identifier is 64. SYSTEM_CHARSET_MBMAXLEN is set to '3'.
So there is a possiblity that tablename/dbname contains 3 * 64.
Hence assert is changed to
(M_TBLLEN <= NAME_CHAR_LEN*SYSTEM_CHARSET_MBMAXLEN)
3) db_len in the binlog event header is taking 1 byte.
db_len is ranged from 0 to 192 bytes (3 * 64).
While reading the db_len from the event, server
is casting to uint instead of uchar which is leading
to bad db_len. This problem is fixed by changing the
cast type to uchar.
Diffstat (limited to 'sql/sql_show.cc')
-rw-r--r-- | sql/sql_show.cc | 57 |
1 files changed, 36 insertions, 21 deletions
diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 5da9f43d793..c936ea69a97 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -949,29 +949,44 @@ static const char *require_quotes(const char *name, uint name_length) } -/* - Quote the given identifier if needed and append it to the target string. - If the given identifier is empty, it will be quoted. - - SYNOPSIS - append_identifier() - thd thread handler - packet target string - name the identifier to be appended - name_length length of the appending identifier +/** + Convert and quote the given identifier if needed and append it to the + target string. If the given identifier is empty, it will be quoted. + @thd thread handler + @packet target string + @name the identifier to be appended + @length length of the appending identifier + @param from_cs Charset information about the input string + @param to_cs Charset information about the target string */ void -append_identifier(THD *thd, String *packet, const char *name, uint length) +append_identifier(THD *thd, String *packet, const char *name, uint length, + CHARSET_INFO *from_cs, CHARSET_INFO *to_cs) { const char *name_end; char quote_char; int q; - q= thd ? get_quote_char_for_identifier(thd, name, length) : '`'; + CHARSET_INFO *cs_info= system_charset_info; + const char *to_name= name; + size_t to_length= length; + String to_string(name,length, from_cs); + + if (from_cs != NULL && to_cs != NULL && from_cs != to_cs) + thd->convert_string(&to_string, from_cs, to_cs); + + if (to_cs != NULL) + { + to_name= to_string.c_ptr(); + to_length= to_string.length(); + cs_info= to_cs; + } + + q= thd ? get_quote_char_for_identifier(thd, to_name, to_length) : '`'; if (q == EOF) { - packet->append(name, length, packet->charset()); + packet->append(to_name, to_length, packet->charset()); return; } @@ -980,14 +995,14 @@ append_identifier(THD *thd, String *packet, const char *name, uint length) it's a keyword */ - (void) packet->reserve(length*2 + 2); + (void) packet->reserve(to_length*2 + 2); quote_char= (char) q; packet->append("e_char, 1, system_charset_info); - for (name_end= name+length ; name < name_end ; name+= length) + for (name_end= to_name+to_length ; to_name < name_end ; to_name+= to_length) { - uchar chr= (uchar) *name; - length= my_mbcharlen(system_charset_info, chr); + uchar chr= (uchar) *to_name; + to_length= my_mbcharlen(cs_info, chr); /* my_mbcharlen can return 0 on a wrong multibyte sequence. It is possible when upgrading from 4.0, @@ -995,11 +1010,11 @@ append_identifier(THD *thd, String *packet, const char *name, uint length) The manual says it does not work. So we'll just change length to 1 not to hang in the endless loop. */ - if (!length) - length= 1; - if (length == 1 && chr == (uchar) quote_char) + if (!to_length) + to_length= 1; + if (to_length == 1 && chr == (uchar) quote_char) packet->append("e_char, 1, system_charset_info); - packet->append(name, length, system_charset_info); + packet->append(to_name, to_length, system_charset_info); } packet->append("e_char, 1, system_charset_info); } |