From 20b08f4705a1f526b0e746ec5dcd065364971c03 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 28 Sep 2007 23:30:54 +0400 Subject: Patch for BUG#30472: libmysql doesn't reset charset, insert_id after succ. mysql_change_user() call. See also WL 4066. This bug reveals two problems: - the problem on the client side which was described originally; - the problem in protocol / the server side: connection context on client and server should be like after mysql_real_connect() and be consistent. The server however just resets character set variables to the global defaults. The fix seems to be as follows: - extend the protocol so that the client be able to send character set information in COM_CHANGE_USER command; - change the server so that it understands client character set in the command; - change the client: - reset character set to the default value (which has been read from the configuration); - send character set in COM_CHANGE_USER command. client/client_priv.h: Declare a function, used in libmysql.c and client.c. libmysql/libmysql.c: 1. Reset character set on the client in mysql_change_user(). 2. Send character set to the server in COM_CHANGE_USER command. mysql-test/t/mysql_client_test.test: mysql_client_test.log is used by the test suite. Use mysql_client_test.out.log to collect mysql_client_test real output. sql/sql_parse.cc: Switch character set in COM_CHANGE_USER. tests/mysql_client_test.c: Test case for BUG#30472. --- tests/mysql_client_test.c | 176 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 174 insertions(+), 2 deletions(-) (limited to 'tests') diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index 93a85f44919..eff8df8109a 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -119,6 +119,8 @@ static void client_disconnect(void); #define DIE_UNLESS(expr) \ ((void) ((expr) ? 0 : (die(__FILE__, __LINE__, #expr), 0))) +#define DIE_IF(expr) \ + ((void) ((expr) ? (die(__FILE__, __LINE__, #expr), 0) : 0)) #define DIE(expr) \ die(__FILE__, __LINE__, #expr) @@ -177,8 +179,8 @@ if (stmt == 0) \ DIE_UNLESS(stmt == 0);\ } -#define mytest(x) if (!x) {myerror(NULL);DIE_UNLESS(FALSE);} -#define mytest_r(x) if (x) {myerror(NULL);DIE_UNLESS(FALSE);} +#define mytest(x) if (!(x)) {myerror(NULL);DIE_UNLESS(FALSE);} +#define mytest_r(x) if ((x)) {myerror(NULL);DIE_UNLESS(FALSE);} /* A workaround for Sun Forte 5.6 on Solaris x86 */ @@ -16649,6 +16651,175 @@ static void test_bug29306() DBUG_VOID_RETURN; } +/* + Bug#30472: libmysql doesn't reset charset, insert_id after succ. + mysql_change_user() call row insertions. +*/ + +static void bug30472_retrieve_charset_info(MYSQL *con, + char *character_set_name, + char *character_set_client, + char *character_set_results, + char *collation_connection) +{ + MYSQL_RES *rs; + MYSQL_ROW row; + + /* Get the cached client character set name. */ + + strcpy(character_set_name, mysql_character_set_name(con)); + + /* Retrieve server character set information. */ + + DIE_IF(mysql_query(con, "SHOW VARIABLES LIKE 'character_set_client'")); + DIE_UNLESS(rs= mysql_store_result(con)); + DIE_UNLESS(row= mysql_fetch_row(rs)); + strcpy(character_set_client, row[1]); + mysql_free_result(rs); + + DIE_IF(mysql_query(con, "SHOW VARIABLES LIKE 'character_set_results'")); + DIE_UNLESS(rs= mysql_store_result(con)); + DIE_UNLESS(row= mysql_fetch_row(rs)); + strcpy(character_set_results, row[1]); + mysql_free_result(rs); + + DIE_IF(mysql_query(con, "SHOW VARIABLES LIKE 'collation_connection'")); + DIE_UNLESS(rs= mysql_store_result(con)); + DIE_UNLESS(row= mysql_fetch_row(rs)); + strcpy(collation_connection, row[1]); + mysql_free_result(rs); +} + +static void test_bug30472() +{ + MYSQL con; + + char character_set_name_1[MY_CS_NAME_SIZE]; + char character_set_client_1[MY_CS_NAME_SIZE]; + char character_set_results_1[MY_CS_NAME_SIZE]; + char collation_connnection_1[MY_CS_NAME_SIZE]; + + char character_set_name_2[MY_CS_NAME_SIZE]; + char character_set_client_2[MY_CS_NAME_SIZE]; + char character_set_results_2[MY_CS_NAME_SIZE]; + char collation_connnection_2[MY_CS_NAME_SIZE]; + + char character_set_name_3[MY_CS_NAME_SIZE]; + char character_set_client_3[MY_CS_NAME_SIZE]; + char character_set_results_3[MY_CS_NAME_SIZE]; + char collation_connnection_3[MY_CS_NAME_SIZE]; + + char character_set_name_4[MY_CS_NAME_SIZE]; + char character_set_client_4[MY_CS_NAME_SIZE]; + char character_set_results_4[MY_CS_NAME_SIZE]; + char collation_connnection_4[MY_CS_NAME_SIZE]; + + /* Create a new connection. */ + + DIE_UNLESS(mysql_init(&con)); + + DIE_UNLESS(mysql_real_connect(&con, + opt_host, + opt_user, + opt_password, + opt_db ? opt_db : "test", + opt_port, + opt_unix_socket, + CLIENT_FOUND_ROWS)); + + /* Retrieve character set information. */ + + bug30472_retrieve_charset_info(&con, + character_set_name_1, + character_set_client_1, + character_set_results_1, + collation_connnection_1); + + /* Switch client character set. */ + + DIE_IF(mysql_set_character_set(&con, "utf8")); + + /* Retrieve character set information. */ + + bug30472_retrieve_charset_info(&con, + character_set_name_2, + character_set_client_2, + character_set_results_2, + collation_connnection_2); + + /* + Check that + 1) character set has been switched and + 2) new character set is different from the original one. + */ + + DIE_UNLESS(strcmp(character_set_name_2, "utf8") == 0); + DIE_UNLESS(strcmp(character_set_client_2, "utf8") == 0); + DIE_UNLESS(strcmp(character_set_results_2, "utf8") == 0); + DIE_UNLESS(strcmp(collation_connnection_2, "utf8_general_ci") == 0); + + DIE_UNLESS(strcmp(character_set_name_1, character_set_name_2) != 0); + DIE_UNLESS(strcmp(character_set_client_1, character_set_client_2) != 0); + DIE_UNLESS(strcmp(character_set_results_1, character_set_results_2) != 0); + DIE_UNLESS(strcmp(collation_connnection_1, collation_connnection_2) != 0); + + /* Call mysql_change_user() with the same username, password, database. */ + + DIE_IF(mysql_change_user(&con, + opt_user, + opt_password, + opt_db ? opt_db : "test")); + + /* Retrieve character set information. */ + + bug30472_retrieve_charset_info(&con, + character_set_name_3, + character_set_client_3, + character_set_results_3, + collation_connnection_3); + + /* Check that character set information has been reset. */ + + DIE_UNLESS(strcmp(character_set_name_1, character_set_name_3) == 0); + DIE_UNLESS(strcmp(character_set_client_1, character_set_client_3) == 0); + DIE_UNLESS(strcmp(character_set_results_1, character_set_results_3) == 0); + DIE_UNLESS(strcmp(collation_connnection_1, collation_connnection_3) == 0); + + /* Change connection-default character set in the client. */ + + con.options.charset_name= my_strdup("utf8", MYF(MY_FAE)); + + /* + Call mysql_change_user() in order to check that new connection will + have UTF8 character set on the client and on the server. + */ + + DIE_IF(mysql_change_user(&con, + opt_user, + opt_password, + opt_db ? opt_db : "test")); + + /* Retrieve character set information. */ + + bug30472_retrieve_charset_info(&con, + character_set_name_4, + character_set_client_4, + character_set_results_4, + collation_connnection_4); + + /* Check that we have UTF8 on the server and on the client. */ + + DIE_UNLESS(strcmp(character_set_name_4, "utf8") == 0); + DIE_UNLESS(strcmp(character_set_client_4, "utf8") == 0); + DIE_UNLESS(strcmp(character_set_results_4, "utf8") == 0); + DIE_UNLESS(strcmp(collation_connnection_4, "utf8_general_ci") == 0); + + /* That's it. Cleanup. */ + + mysql_close(&con); +} + + /* Read and parse arguments and MySQL options from my.cnf */ @@ -16943,6 +17114,7 @@ static struct my_tests_st my_tests[]= { { "test_bug29692", test_bug29692 }, { "test_bug29306", test_bug29306 }, { "test_change_user", test_change_user }, + { "test_bug30472", test_bug30472 }, { 0, 0 } }; -- cgit v1.2.1