summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoranozdrin/alik@ibm. <>2007-07-12 12:49:39 +0400
committeranozdrin/alik@ibm. <>2007-07-12 12:49:39 +0400
commit3f2e94c401b87dd14b17307dab88e15067a24322 (patch)
treebad8ca7dc824a2eae76369d7f7183cc94cdf1c9a
parent08e7d2d3128ec4d5313b0a481020ad6687ced9f9 (diff)
downloadmariadb-git-3f2e94c401b87dd14b17307dab88e15067a24322.tar.gz
Fix for 5.1 for BUG#10491: Server returns data as charset binary
SHOW CREATE TABLE or SELECT FROM I_S. This is the last patch for this bug, which depends on the big CS patch and was pending. The problem was that SHOW CREATE statements returned original queries in the binary character set. That could cause the query to be unreadable. The fix is to use original character_set_client when sending the original query to the client. In order to preserve the query in mysqldump, 'binary' character set results should be set when issuing SHOW CREATE statement. If either source or destination character set is 'binary' , no conversion is performed. The idea is that since the source character set is no longer 'binary', we fix the destination character set to still produce valid dumps.
-rw-r--r--client/mysqldump.c43
-rw-r--r--mysql-test/r/show_check.result39
-rw-r--r--mysql-test/t/show_check.test64
-rw-r--r--sql/events.cc3
-rw-r--r--sql/sp_head.cc3
-rw-r--r--sql/sql_show.cc12
6 files changed, 160 insertions, 4 deletions
diff --git a/client/mysqldump.c b/client/mysqldump.c
index 812a158048e..11be212ec3b 100644
--- a/client/mysqldump.c
+++ b/client/mysqldump.c
@@ -1201,6 +1201,20 @@ static void restore_time_zone(FILE *sql_file,
(const char *) delimiter);
}
+
+static int switch_character_set_results(MYSQL *mysql, const char *cs_name)
+{
+ char query_buffer[QUERY_LENGTH];
+ size_t query_length;
+
+ query_length= my_snprintf(query_buffer,
+ sizeof (query_buffer),
+ "SET SESSION character_set_results = '%s'",
+ (const char *) cs_name);
+
+ return mysql_real_query(mysql, query_buffer, query_length);
+}
+
/*
Open a new .sql file to dump the table or view into
@@ -1706,6 +1720,9 @@ static uint dump_events_for_db(char *db)
if (fetch_db_collation(db_name_buff, db_cl_name, sizeof (db_cl_name)))
DBUG_RETURN(1);
+ if (switch_character_set_results(mysql, "binary"))
+ DBUG_RETURN(1);
+
while ((event_list_row= mysql_fetch_row(event_list_res)) != NULL)
{
event_name= quote_name(event_list_row[1], name_buff, 0);
@@ -1774,6 +1791,9 @@ static uint dump_events_for_db(char *db)
} /* end of list of events */
fprintf(sql_file, "DELIMITER ;\n");
fprintf(sql_file, "/*!50106 SET TIME_ZONE= @save_time_zone */ ;\n");
+
+ if (switch_character_set_results(mysql, default_charset))
+ DBUG_RETURN(1);
}
mysql_free_result(event_list_res);
@@ -1853,6 +1873,9 @@ static uint dump_routines_for_db(char *db)
if (fetch_db_collation(db_name_buff, db_cl_name, sizeof (db_cl_name)))
DBUG_RETURN(1);
+ if (switch_character_set_results(mysql, "binary"))
+ DBUG_RETURN(1);
+
/* 0, retrieve and dump functions, 1, procedures */
for (i= 0; i <= 1; i++)
{
@@ -1990,6 +2013,9 @@ static uint dump_routines_for_db(char *db)
mysql_free_result(routine_list_res);
} /* end of for i (0 .. 1) */
+ if (switch_character_set_results(mysql, default_charset))
+ DBUG_RETURN(1);
+
if (lock_tables)
VOID(mysql_query_with_error_report(mysql, 0, "UNLOCK TABLES"));
DBUG_RETURN(0);
@@ -2542,6 +2568,9 @@ static void dump_triggers_for_table(char *table, char *db_name)
if (fetch_db_collation(db_name, db_cl_name, sizeof (db_cl_name)))
DBUG_VOID_RETURN;
+ if (switch_character_set_results(mysql, "binary"))
+ DBUG_VOID_RETURN;
+
/* Dump triggers. */
while ((row= mysql_fetch_row(result)))
@@ -2637,6 +2666,9 @@ static void dump_triggers_for_table(char *table, char *db_name)
mysql_free_result(result);
+ if (switch_character_set_results(mysql, default_charset))
+ DBUG_VOID_RETURN;
+
/*
make sure to set back opt_compatible mode to
original value
@@ -4390,14 +4422,22 @@ static my_bool get_view_structure(char *table, char* db)
result_table= quote_name(table, table_buff, 1);
opt_quoted_table= quote_name(table, table_buff2, 0);
+ if (switch_character_set_results(mysql, "binary"))
+ DBUG_RETURN(1);
+
my_snprintf(query, sizeof(query), "SHOW CREATE TABLE %s", result_table);
+
if (mysql_query_with_error_report(mysql, &table_res, query))
+ {
+ switch_character_set_results(mysql, default_charset);
DBUG_RETURN(0);
+ }
/* Check if this is a view */
field= mysql_fetch_field_direct(table_res, 0);
if (strcmp(field->name, "View") != 0)
{
+ switch_character_set_results(mysql, default_charset);
verbose_msg("-- It's base table, skipped\n");
DBUG_RETURN(0);
}
@@ -4540,6 +4580,9 @@ static my_bool get_view_structure(char *table, char* db)
dynstr_free(&ds_view);
}
+ if (switch_character_set_results(mysql, default_charset))
+ DBUG_RETURN(1);
+
/* If a separate .sql file was opened, close it now */
if (sql_file != md_result_file)
{
diff --git a/mysql-test/r/show_check.result b/mysql-test/r/show_check.result
index 9ef10865cd7..c89f386623b 100644
--- a/mysql-test/r/show_check.result
+++ b/mysql-test/r/show_check.result
@@ -1282,4 +1282,43 @@ t1_bi CREATE DEFINER=`root`@`localhost` TRIGGER t1_bi BEFORE INSERT ON t1 FOR E
DROP TABLE t1;
DROP PROCEDURE p1;
DEALLOCATE PREPARE stmt1;
+set names koi8r;
+DROP VIEW IF EXISTS v1;
+DROP PROCEDURE IF EXISTS p1;
+DROP FUNCTION IF EXISTS f1;
+DROP TABLE IF EXISTS t1;
+DROP EVENT IF EXISTS ev1;
+CREATE VIEW v1 AS SELECT 'ΤΕΣΤ' AS test;
+CREATE PROCEDURE p1() SELECT 'ΤΕΣΤ' AS test;
+CREATE FUNCTION f1() RETURNS CHAR(10) RETURN 'ΤΕΣΤ';
+CREATE TABLE t1(c1 CHAR(10));
+CREATE TRIGGER t1_bi BEFORE INSERT ON t1
+FOR EACH ROW
+SET NEW.c1 = 'ΤΕΣΤ';
+CREATE EVENT ev1 ON SCHEDULE AT '2030-01-01 00:00:00' DO SELECT 'ΤΕΣΤ' AS test;
+set names utf8;
+SHOW CREATE VIEW v1;
+View Create View character_set_client collation_connection
+v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select _koi8r'тСст' AS `test` koi8r koi8r_general_ci
+SHOW CREATE PROCEDURE p1;
+Procedure sql_mode Create Procedure character_set_client collation_connection Database Collation
+p1 CREATE DEFINER=`root`@`localhost` PROCEDURE `p1`()
+SELECT 'тСст' AS test koi8r koi8r_general_ci latin1_swedish_ci
+SHOW CREATE FUNCTION f1;
+Function sql_mode Create Function character_set_client collation_connection Database Collation
+f1 CREATE DEFINER=`root`@`localhost` FUNCTION `f1`() RETURNS char(10) CHARSET latin1
+RETURN 'тСст' koi8r koi8r_general_ci latin1_swedish_ci
+SHOW CREATE TRIGGER t1_bi;
+Trigger sql_mode SQL Original Statement character_set_client collation_connection Database Collation
+t1_bi CREATE DEFINER=`root`@`localhost` TRIGGER t1_bi BEFORE INSERT ON t1
+FOR EACH ROW
+SET NEW.c1 = 'тСст' koi8r koi8r_general_ci latin1_swedish_ci
+SHOW CREATE EVENT ev1;
+Event sql_mode time_zone Create Event character_set_client collation_connection Database Collation
+ev1 SYSTEM CREATE EVENT `ev1` ON SCHEDULE AT '2030-01-01 00:00:00' ON COMPLETION NOT PRESERVE ENABLE DO SELECT 'тСст' AS test koi8r koi8r_general_ci latin1_swedish_ci
+DROP VIEW v1;
+DROP PROCEDURE p1;
+DROP FUNCTION f1;
+DROP TABLE t1;
+DROP EVENT ev1;
End of 5.1 tests
diff --git a/mysql-test/t/show_check.test b/mysql-test/t/show_check.test
index 341c9039390..2f474d0335b 100644
--- a/mysql-test/t/show_check.test
+++ b/mysql-test/t/show_check.test
@@ -897,4 +897,68 @@ DROP TABLE t1;
DROP PROCEDURE p1;
DEALLOCATE PREPARE stmt1;
+#
+# BUG#10491: Server returns data as charset binary SHOW CREATE TABLE or SELECT
+# FROM INFORMATION_SCHEMA.
+#
+# Before the change performed to fix the bug, the metadata of the output of
+# SHOW CREATE statements would always describe the result as 'binary'. That
+# would ensure that the result is never converted to character_set_client
+# (which was essential to mysqldump). Now we return to the client the actual
+# character set of the object -- which is character_set_client of the
+# connection that issues the CREATE statement, and this triggers an automatic
+# conversion to character_set_results of the connection that issues SHOW CREATE
+# statement.
+#
+# This test demonstrates that this conversion indeed is taking place.
+#
+
+# Prepare: create objects in a one character set.
+
+set names koi8r;
+
+--disable_warnings
+DROP VIEW IF EXISTS v1;
+DROP PROCEDURE IF EXISTS p1;
+DROP FUNCTION IF EXISTS f1;
+DROP TABLE IF EXISTS t1;
+DROP EVENT IF EXISTS ev1;
+--enable_warnings
+
+CREATE VIEW v1 AS SELECT 'ΤΕΣΤ' AS test;
+
+CREATE PROCEDURE p1() SELECT 'ΤΕΣΤ' AS test;
+
+CREATE FUNCTION f1() RETURNS CHAR(10) RETURN 'ΤΕΣΤ';
+
+CREATE TABLE t1(c1 CHAR(10));
+CREATE TRIGGER t1_bi BEFORE INSERT ON t1
+ FOR EACH ROW
+ SET NEW.c1 = 'ΤΕΣΤ';
+
+CREATE EVENT ev1 ON SCHEDULE AT '2030-01-01 00:00:00' DO SELECT 'ΤΕΣΤ' AS test;
+
+# Test: switch the character set and show that SHOW CREATE output is
+# automatically converted to the new character_set_client.
+
+set names utf8;
+
+SHOW CREATE VIEW v1;
+
+SHOW CREATE PROCEDURE p1;
+
+SHOW CREATE FUNCTION f1;
+
+SHOW CREATE TRIGGER t1_bi;
+
+SHOW CREATE EVENT ev1;
+
+# Cleanup.
+
+DROP VIEW v1;
+DROP PROCEDURE p1;
+DROP FUNCTION f1;
+DROP TABLE t1;
+DROP EVENT ev1;
+
--echo End of 5.1 tests
diff --git a/sql/events.cc b/sql/events.cc
index e48daeca63d..8d32580816f 100644
--- a/sql/events.cc
+++ b/sql/events.cc
@@ -717,7 +717,8 @@ send_show_create_event(THD *thd, Event_timed *et, Protocol *protocol)
protocol->store(et->name.str, et->name.length, system_charset_info);
protocol->store(sql_mode.str, sql_mode.length, system_charset_info);
protocol->store(tz_name->ptr(), tz_name->length(), system_charset_info);
- protocol->store(show_str.c_ptr(), show_str.length(), &my_charset_bin);
+ protocol->store(show_str.c_ptr(), show_str.length(),
+ et->creation_ctx->get_client_cs());
protocol->store(et->creation_ctx->get_client_cs()->csname,
strlen(et->creation_ctx->get_client_cs()->csname),
system_charset_info);
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index f0cc5204749..d3a9787ee2b 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -2260,7 +2260,8 @@ sp_head::show_create_routine(THD *thd, int type)
protocol->store(sql_mode.str, sql_mode.length, system_charset_info);
if (full_access)
- protocol->store(m_defstr.str, m_defstr.length, &my_charset_bin);
+ protocol->store(m_defstr.str, m_defstr.length,
+ m_creation_ctx->get_client_cs());
else
protocol->store_null();
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index f66897df671..04374c1d1c1 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -639,7 +639,8 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list)
if (table_list->view)
{
- protocol->store(buffer.ptr(), buffer.length(), &my_charset_bin);
+ protocol->store(buffer.ptr(), buffer.length(),
+ table_list->view_creation_ctx->get_client_cs());
protocol->store(table_list->view_creation_ctx->get_client_cs()->csname,
system_charset_info);
@@ -5983,6 +5984,8 @@ static bool show_create_trigger_impl(THD *thd,
LEX_STRING trg_connection_cl_name;
LEX_STRING trg_db_cl_name;
+ CHARSET_INFO *trg_client_cs;
+
/*
TODO: Check privileges here. This functionality will be added by
implementation of the following WL items:
@@ -6008,6 +6011,11 @@ static bool show_create_trigger_impl(THD *thd,
trg_sql_mode,
&trg_sql_mode_str);
+ /* Resolve trigger client character set. */
+
+ if (resolve_charset(trg_client_cs_name.str, NULL, &trg_client_cs))
+ return TRUE;
+
/* Send header. */
fields.push_back(new Item_empty_string("Trigger", NAME_LEN));
@@ -6054,7 +6062,7 @@ static bool show_create_trigger_impl(THD *thd,
p->store(trg_sql_original_stmt.str,
trg_sql_original_stmt.length,
- &my_charset_bin);
+ trg_client_cs);
p->store(trg_client_cs_name.str,
trg_client_cs_name.length,