List:Commits« Previous MessageNext Message »
From:Alexander Nozdrin Date:September 28 2007 9:31pm
Subject:bk commit into 5.1 tree (anozdrin:1.2613) BUG#30472
View as plain text  
Below is the list of changes that have just been committed into a local
5.1 repository of alik. When alik does a push these changes will
be propagated to the main repository and, within 24 hours after the
push, to the public repository.
For information on how to access the public repository
see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html

ChangeSet@stripped, 2007-09-28 23:30:54+04:00, anozdrin@station. +5 -0
  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@stripped, 2007-09-28 23:30:52+04:00, anozdrin@station. +4 -0
    Declare a function, used in libmysql.c and client.c.

  libmysql/libmysql.c@stripped, 2007-09-28 23:30:52+04:00, anozdrin@station. +25 -1
    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@stripped, 2007-09-28 23:30:52+04:00, anozdrin@station.
+2 -2
    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@stripped, 2007-09-28 23:30:52+04:00, anozdrin@station. +13 -1
    Switch character set in COM_CHANGE_USER.

  tests/mysql_client_test.c@stripped, 2007-09-28 23:30:52+04:00, anozdrin@station. +174 -2
    Test case for BUG#30472.

diff -Nrup a/client/client_priv.h b/client/client_priv.h
--- a/client/client_priv.h	2007-08-04 05:44:45 +04:00
+++ b/client/client_priv.h	2007-09-28 23:30:52 +04:00
@@ -82,3 +82,7 @@ enum options_client
   OPT_DEBUG_INFO, OPT_DEBUG_CHECK, OPT_COLUMN_TYPES, OPT_ERROR_LOG_FILE,
   OPT_WRITE_BINLOG, OPT_MAX_CLIENT_OPTION
 };
+
+C_MODE_START
+extern int mysql_init_character_set(MYSQL *mysql);
+C_MODE_END
diff -Nrup a/libmysql/libmysql.c b/libmysql/libmysql.c
--- a/libmysql/libmysql.c	2007-08-25 12:43:10 +04:00
+++ b/libmysql/libmysql.c	2007-09-28 23:30:52 +04:00
@@ -685,14 +685,25 @@ int cli_read_change_user_result(MYSQL *m
   return 0;
 }
 
-
 my_bool	STDCALL mysql_change_user(MYSQL *mysql, const char *user,
 				  const char *passwd, const char *db)
 {
   char buff[512],*end=buff;
   int rc;
+  CHARSET_INFO *saved_cs= mysql->charset;
+
   DBUG_ENTER("mysql_change_user");
 
+  /* Get the connection-default character set. */
+
+  if (mysql_init_character_set(mysql))
+  {
+    mysql->charset= saved_cs;
+    DBUG_RETURN(TRUE);
+  }
+
+  /* Use an empty string instead of NULL. */
+
   if (!user)
     user="";
   if (!passwd)
@@ -721,6 +732,14 @@ my_bool	STDCALL mysql_change_user(MYSQL 
   /* Add database if needed */
   end= strmov(end, db ? db : "") + 1;
 
+  /* Add character set number. */
+
+  if (mysql->server_capabilities & CLIENT_SECURE_CONNECTION)
+  {
+    *end= (uchar) mysql->charset->number;
+    ++end;
+  }
+
   /* Write authentication package */
   simple_command(mysql,COM_CHANGE_USER, (uchar*) buff, (ulong) (end-buff), 1);
 
@@ -743,6 +762,11 @@ my_bool	STDCALL mysql_change_user(MYSQL 
     mysql->passwd=my_strdup(passwd,MYF(MY_WME));
     mysql->db=    db ? my_strdup(db,MYF(MY_WME)) : 0;
   }
+  else
+  {
+    mysql->charset= saved_cs;
+  }
+
   DBUG_RETURN(rc);
 }
 
diff -Nrup a/mysql-test/t/mysql_client_test.test b/mysql-test/t/mysql_client_test.test
--- a/mysql-test/t/mysql_client_test.test	2006-10-04 18:33:24 +04:00
+++ b/mysql-test/t/mysql_client_test.test	2007-09-28 23:30:52 +04:00
@@ -8,8 +8,8 @@
 # server or run mysql-test-run --debug mysql_client_test and check
 # var/log/mysql_client_test.trace
 
---exec echo "$MYSQL_CLIENT_TEST" > $MYSQLTEST_VARDIR/log/mysql_client_test.log
2>&1
---exec $MYSQL_CLIENT_TEST --getopt-ll-test=25600M >>
$MYSQLTEST_VARDIR/log/mysql_client_test.log 2>&1
+--exec echo "$MYSQL_CLIENT_TEST" > $MYSQLTEST_VARDIR/log/mysql_client_test.out.log
2>&1
+--exec $MYSQL_CLIENT_TEST --getopt-ll-test=25600M >>
$MYSQLTEST_VARDIR/log/mysql_client_test.out.log 2>&1
 
 # End of 4.1 tests
 echo ok;
diff -Nrup a/sql/sql_parse.cc b/sql/sql_parse.cc
--- a/sql/sql_parse.cc	2007-09-28 15:42:35 +04:00
+++ b/sql/sql_parse.cc	2007-09-28 23:30:52 +04:00
@@ -876,7 +876,13 @@ bool dispatch_command(enum enum_server_c
       my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
       break;
     }
-    db_length= packet_end - db - 1; /* do not count the trailing '\0'  */
+    db_length= strlen(db);
+
+    uint cs_number= 0;
+
+    if (db + db_length < packet_end)
+      cs_number= (uchar) *(db + db_length + 1);
+
     /* Convert database name to utf8 */
     db_buff[copy_and_convert(db_buff, sizeof(db_buff)-1,
                              system_charset_info, db, db_length,
@@ -921,6 +927,12 @@ bool dispatch_command(enum enum_server_c
 #endif /* NO_EMBEDDED_ACCESS_CHECKS */
       x_free((uchar*) save_db);
       x_free((uchar*)  save_security_ctx.user);
+
+      if (cs_number)
+      {
+        thd_init_client_charset(thd, cs_number);
+        thd->update_charset();
+      }
     }
     break;
   }
diff -Nrup a/tests/mysql_client_test.c b/tests/mysql_client_test.c
--- a/tests/mysql_client_test.c	2007-09-28 15:42:35 +04:00
+++ b/tests/mysql_client_test.c	2007-09-28 23:30:52 +04:00
@@ -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 */
@@ -16650,6 +16652,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 }
 };
 
Thread
bk commit into 5.1 tree (anozdrin:1.2613) BUG#30472Alexander Nozdrin28 Sep
  • Re: bk commit into 5.1 tree (anozdrin:1.2613) BUG#30472Konstantin Osipov28 Sep