summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mysql-test/suite/rpl/r/rpl_autogen_query_multi_byte_char.result29
-rw-r--r--mysql-test/suite/rpl/t/rpl_autogen_query_multi_byte_char.test87
-rw-r--r--sql/log_event.cc10
-rw-r--r--sql/sql_show.cc57
-rw-r--r--sql/sql_show.h10
-rw-r--r--sql/sql_table.cc12
6 files changed, 173 insertions, 32 deletions
diff --git a/mysql-test/suite/rpl/r/rpl_autogen_query_multi_byte_char.result b/mysql-test/suite/rpl/r/rpl_autogen_query_multi_byte_char.result
new file mode 100644
index 00000000000..b03c0057a69
--- /dev/null
+++ b/mysql-test/suite/rpl/r/rpl_autogen_query_multi_byte_char.result
@@ -0,0 +1,29 @@
+include/master-slave.inc
+[connection master]
+Test case 1:- table name with one character latin name.
+SET @s:=CONCAT("CREATE TABLE `",REPEAT(CHAR(131),1),"` (a INT)");
+PREPARE STMT FROM @s;
+EXECUTE stmt;
+SET @s:=CONCAT("INSERT INTO `",REPEAT(CHAR(131),1),"` VALUES (1)");
+PREPARE STMT FROM @s;
+EXECUTE stmt;
+SET @s:=CONCAT("DROP TABLE `",REPEAT(CHAR(131),1), "`");
+PREPARE STMT FROM @s;
+EXECUTE stmt;
+Test case 2:- table name and database names with one character latin name.
+SET @s:=CONCAT("CREATE DATABASE `",REPEAT(CHAR(131),1),"`");
+PREPARE STMT FROM @s;
+EXECUTE stmt;
+SET @s:=CONCAT("CREATE TABLE `",REPEAT(CHAR(131),1),"`.`",REPEAT(CHAR(131),1),"` (a INT)");
+PREPARE STMT FROM @s;
+EXECUTE stmt;
+SET @s:=CONCAT("INSERT INTO `",REPEAT(CHAR(131),1),"`.`",REPEAT(CHAR(131),1),"` VALUES (1)");
+PREPARE STMT FROM @s;
+EXECUTE stmt;
+SET @s:=CONCAT("DROP TABLE `",REPEAT(CHAR(131),1),"`.`",REPEAT(CHAR(131),1), "`");
+PREPARE STMT FROM @s;
+EXECUTE stmt;
+SET @s:=CONCAT("DROP DATABASE `",REPEAT(CHAR(131),1),"`");
+PREPARE STMT FROM @s;
+EXECUTE stmt;
+include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/t/rpl_autogen_query_multi_byte_char.test b/mysql-test/suite/rpl/t/rpl_autogen_query_multi_byte_char.test
new file mode 100644
index 00000000000..a93fcbac82f
--- /dev/null
+++ b/mysql-test/suite/rpl/t/rpl_autogen_query_multi_byte_char.test
@@ -0,0 +1,87 @@
+###############################################################################
+# 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 contains
+# 64 latin characters (latin takes 2 bytes), server is
+# throwing an assert (M_TBLLEN < 128)
+#
+# 3) In the edge case, when db name contains 64 latin
+# characters, binlog contents are interpreted wrongly
+# which is leading to replication issues.
+#
+###############################################################################
+
+--source include/not_windows.inc
+--source include/master-slave.inc
+
+--let iter=1
+# Change iteration to 4 after fixing Bug #22280214
+while ($iter <= 2)
+{
+ --connection master
+ if ($iter == 1)
+ {
+ --echo Test case 1:- table name with one character latin name.
+ --let $tblname= REPEAT(CHAR(131),1)
+ }
+ if ($iter == 2)
+ {
+ --echo Test case 2:- table name and database names with one character latin name.
+ --let $tblname= REPEAT(CHAR(131),1),"`.`",REPEAT(CHAR(131),1)
+ --eval SET @s:=CONCAT("CREATE DATABASE `",REPEAT(CHAR(131),1),"`")
+ PREPARE STMT FROM @s; EXECUTE stmt;
+ }
+ # After fixing Bug #22280214 DATADIR LOCATION IS LIMITING
+ # IDENTIFIER MAX LENGTH, the following two tests (iter 3 and 4) can be
+ # uncommented.
+ #if ($iter == 3)
+ #{
+ # --echo Test case 3:- table name and database names with 64 latin characters name.
+ # --let $tblname= REPEAT(CHAR(131),64),"`.`", REPEAT(CHAR(131),64)
+ # --eval SET @s:=CONCAT("CREATE DATABASE `",REPEAT(CHAR(131),64),"`")
+ # PREPARE STMT FROM @s; EXECUTE stmt;
+ #}
+ #if ($iter == 4)
+ #{
+ # --echo Test case 4:- table name and database names with 64 Euro(€) characters.
+ # --let $tblname= REPEAT(CHAR(226,130,172),64),"`.`", REPEAT(CHAR(226,130,172),64)
+ # --eval SET @s:=CONCAT("CREATE DATABASE `",REPEAT(CHAR(226,130,172),64),"`")
+ # PREPARE STMT FROM @s; EXECUTE stmt;
+ #}
+ --eval SET @s:=CONCAT("CREATE TABLE `",$tblname,"` (a INT)")
+ PREPARE STMT FROM @s; EXECUTE stmt;
+ --eval SET @s:=CONCAT("INSERT INTO `",$tblname,"` VALUES (1)")
+ PREPARE STMT FROM @s; EXECUTE stmt;
+ --eval SET @s:=CONCAT("DROP TABLE `",$tblname, "`")
+ PREPARE STMT FROM @s; EXECUTE stmt;
+ if ($iter == 2)
+ {
+ --eval SET @s:=CONCAT("DROP DATABASE `",REPEAT(CHAR(131),1),"`")
+ PREPARE STMT FROM @s; EXECUTE stmt;
+ }
+ # After fixing Bug #22280214 DATADIR LOCATION IS LIMITING
+ # IDENTIFIER MAX LENGTH, the following two tests (iter 3 and 4) can be
+ # uncommented.
+ #if ($iter == 3)
+ #{
+ # --eval SET @s:=CONCAT("DROP DATABASE `",REPEAT(CHAR(131),64),"`")
+ # PREPARE STMT FROM @s; EXECUTE stmt;
+ #}
+ #if ($iter == 4)
+ #{
+ # --eval SET @s:=CONCAT("DROP DATABASE `",REPEAT(CHAR(226,130,172),64),"`")
+ # PREPARE STMT FROM @s; EXECUTE stmt;
+ #}
+ --sync_slave_with_master
+ --inc $iter
+}
+
+--source include/rpl_end.inc
diff --git a/sql/log_event.cc b/sql/log_event.cc
index 38efb2a9c6b..accb6a28dbd 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -2792,7 +2792,7 @@ Query_log_event::Query_log_event(const char* buf, uint event_len,
slave_proxy_id= thread_id = uint4korr(buf + Q_THREAD_ID_OFFSET);
exec_time = uint4korr(buf + Q_EXEC_TIME_OFFSET);
- db_len = (uint)buf[Q_DB_LEN_OFFSET]; // TODO: add a check of all *_len vars
+ db_len = (uchar)buf[Q_DB_LEN_OFFSET]; // TODO: add a check of all *_len vars
error_code = uint2korr(buf + Q_ERR_CODE_OFFSET);
/*
@@ -8960,9 +8960,9 @@ bool Table_map_log_event::write_data_body(IO_CACHE *file)
{
DBUG_ASSERT(m_dbnam != NULL);
DBUG_ASSERT(m_tblnam != NULL);
- /* We use only one byte per length for storage in event: */
- DBUG_ASSERT(m_dblen < 128);
- DBUG_ASSERT(m_tbllen < 128);
+
+ DBUG_ASSERT(m_dblen <= NAME_LEN);
+ DBUG_ASSERT(m_tbllen <= NAME_LEN);
uchar const dbuf[]= { (uchar) m_dblen };
uchar const tbuf[]= { (uchar) m_tbllen };
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);
}
diff --git a/sql/sql_show.h b/sql/sql_show.h
index 16bfc5cdb69..ad6494fd7d4 100644
--- a/sql/sql_show.h
+++ b/sql/sql_show.h
@@ -92,8 +92,14 @@ int view_store_create_info(THD *thd, TABLE_LIST *table, String *buff);
int copy_event_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table);
int get_quote_char_for_identifier(THD *thd, const char *name, uint length);
-void append_identifier(THD *thd, String *packet, const char *name,
- uint length);
+void append_identifier(THD *thd, String *packet, const char *name, uint length,
+ CHARSET_INFO *from_cs, CHARSET_INFO *to_cs);
+inline void append_identifier(THD *thd, String *packet, const char *name,
+ uint length)
+{
+ append_identifier(thd, packet, name, length, NULL, NULL);
+}
+
void mysqld_list_fields(THD *thd,TABLE_LIST *table, const char *wild);
int mysqld_dump_create_info(THD *thd, TABLE_LIST *table_list, int fd);
bool mysqld_show_create(THD *thd, TABLE_LIST *table_list);
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 0a58d9ade5b..3f64de7eac2 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -2138,11 +2138,13 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
if (thd->db == NULL || strcmp(db,thd->db) != 0
|| is_drop_tmp_if_exists_added )
{
- append_identifier(thd, built_ptr_query, db, db_len);
+ append_identifier(thd, built_ptr_query, db, db_len,
+ system_charset_info, thd->charset());
built_ptr_query->append(".");
}
append_identifier(thd, built_ptr_query, table->table_name,
- strlen(table->table_name));
+ strlen(table->table_name), system_charset_info,
+ thd->charset());
built_ptr_query->append(",");
}
/*
@@ -2204,12 +2206,14 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
*/
if (thd->db == NULL || strcmp(db,thd->db) != 0)
{
- append_identifier(thd, &built_query, db, db_len);
+ append_identifier(thd, &built_query, db, db_len,
+ system_charset_info, thd->charset());
built_query.append(".");
}
append_identifier(thd, &built_query, table->table_name,
- strlen(table->table_name));
+ strlen(table->table_name), system_charset_info,
+ thd->charset());
built_query.append(",");
}
}