summaryrefslogtreecommitdiff
path: root/sql/sql_show.cc
diff options
context:
space:
mode:
authorVenkatesh Duggirala <venkatesh.duggirala@oracle.com>2015-12-01 15:38:11 +0530
committerVenkatesh Duggirala <venkatesh.duggirala@oracle.com>2015-12-01 15:38:11 +0530
commit2735f0b92020c8ac4bd07d7ea843a0946b19e8ad (patch)
treef698248dc83ac973eec6eb91e6b3994b019b3fea /sql/sql_show.cc
parent08e929388b2cea170f6a44e9c8669f9c0f636808 (diff)
downloadmariadb-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.cc57
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(&quote_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(&quote_char, 1, system_charset_info);
- packet->append(name, length, system_charset_info);
+ packet->append(to_name, to_length, system_charset_info);
}
packet->append(&quote_char, 1, system_charset_info);
}