List:Commits« Previous MessageNext Message »
From:Alexander Nozdrin Date:December 11 2006 7:51pm
Subject:bk commit into 5.0 tree (anozdrin:1.2318) BUG#16291
View as plain text  
Below is the list of changes that have just been committed into a local
5.0 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, 2006-12-11 22:51:35+03:00, anozdrin@booka. +4 -0
  This is a preliminary patch for BUG#16291: mysqldump corrupts
  string-constants with non-ascii-chars.
  
  The fix is:
    - to store view-query in the original character set;
    - to store additional attributes -- original character sets
      (client, connection, server);
    - to use original character sets when parsing the view;
    - to add charset-columns into SHOW CREATE VIEW output;
    - to add charset-columns into I_S.VIEWS pseudo-table;
    - to update mysqldump so that it puts charset-switching statements
      before CREATE VIEW statement. They are required because now
      CREATE VIEW is in the original charset (not the mysqldump-client's
      character set).

  client/mysqldump.c@stripped, 2006-12-11 22:51:32+03:00, anozdrin@booka. +24 -3
    Switch charsets before CREATE VIEW statement.

  sql/sql_show.cc@stripped, 2006-12-11 22:51:32+03:00, anozdrin@booka. +145 -4
    1. Add charset columns into SHOW CREATE VIEW output;
    2. Add charset columns into I_S.VIEWS pseudo-table;

  sql/sql_view.cc@stripped, 2006-12-11 22:51:32+03:00, anozdrin@booka. +108 -6
    1. Save 3 charsets (client, connection, server) in view-frm file;
    2. Use view-charsets when parsing the view;
    3. Store view-query in the original charset.

  sql/table.h@stripped, 2006-12-11 22:51:32+03:00, anozdrin@booka. +4 -0
    Add attributes to store 3 view charsets (client, connection, server).

# This is a BitKeeper patch.  What follows are the unified diffs for the
# set of deltas contained in the patch.  The rest of the patch, the part
# that BitKeeper cares about, is below these diffs.
# User:	anozdrin
# Host:	booka.
# Root:	/home/alik/Documents/MySQL/devel/5.0-rt-charsets

--- 1.250/client/mysqldump.c	2006-12-11 22:51:43 +03:00
+++ 1.251/client/mysqldump.c	2006-12-11 22:51:43 +03:00
@@ -3573,8 +3573,9 @@ static my_bool get_view_structure(char *
 
 
   my_snprintf(query, sizeof(query),
-              "SELECT CHECK_OPTION, DEFINER, SECURITY_TYPE "            \
-              "FROM information_schema.views "                          \
+              "SELECT CHECK_OPTION, DEFINER, SECURITY_TYPE, "
+              "       CLIENT_CS, CONNECTION_CS, SERVER_CS "
+              "FROM information_schema.views "
               "WHERE table_name=\"%s\" AND table_schema=\"%s\"", table, db);
   if (mysql_query(mysql, query))
   {
@@ -3661,7 +3662,27 @@ static my_bool get_view_structure(char *
     }
 
     /* Dump view structure to file */
-    fprintf(sql_file, "/*!50001 %s */;\n", ds_view.str);
+
+    fprintf(sql_file,
+            "SET @saved_cs_client = @@character_set_client;\n"
+            "SET @saved_cs_results = @@character_set_results;\n"
+            "SET @saved_cs_connection = @@character_set_connection;\n"
+            "SET @saved_cs_server = @@character_set_server;\n"
+            "SET character_set_client = %s;\n"
+            "SET character_set_results = %s;\n"
+            "SET character_set_connection = %s;\n"
+            "SET character_set_server = %s;\n"
+            "/*!50001 %s */;\n"
+            "SET character_set_server = @saved_cs_client;\n"
+            "SET character_set_results = @saved_cs_results;\n"
+            "SET character_set_connection = @saved_cs_connection;\n"
+            "SET character_set_server = @saved_cs_server;\n",
+            (const char *) row[3],
+            (const char *) row[3],
+            (const char *) row[4],
+            (const char *) row[5],
+            (const char *) ds_view.str);
+
     check_io(sql_file);
     mysql_free_result(table_res);
     dynstr_free(&ds_view);

--- 1.332/sql/sql_show.cc	2006-12-11 22:51:43 +03:00
+++ 1.333/sql/sql_show.cc	2006-12-11 22:51:43 +03:00
@@ -418,6 +418,39 @@ mysqld_show_create(THD *thd, TABLE_LIST 
   }
 
   buffer.length(0);
+
+  if (table_list->view)
+  {
+    if (table_list->client_cs_name.str &&
+        table_list->connection_cs_name.str &&
+        table_list->server_cs_name.str)
+    {
+      CHARSET_INFO *client_cs=
+        get_charset_by_csname(
+          table_list->client_cs_name.str,
+          MY_CS_PRIMARY,
+          MYF(0));
+
+      if (client_cs)
+      {
+        buffer.set_charset(client_cs);
+      }
+      else
+      {
+        printf(">> Error: unknown client cs '%s'.\n",
+          (const char *) table_list->client_cs_name.str);
+      }
+    }
+    else
+    {
+      printf(">> Warning: no charset info.\n");
+    }
+  }
+  else
+  {
+    printf(">> This is not a table.\n");
+  }
+
   if ((table_list->view ?
        view_store_create_info(thd, table_list, &buffer) :
        store_create_info(thd, table_list, &buffer)))
@@ -429,6 +462,9 @@ mysqld_show_create(THD *thd, TABLE_LIST 
     field_list.push_back(new Item_empty_string("View",NAME_LEN));
     field_list.push_back(new Item_empty_string("Create View",
                                                max(buffer.length(),1024)));
+    field_list.push_back(new Item_empty_string("Client Charset", 255)); // FIXME
+    field_list.push_back(new Item_empty_string("Connection Charset", 255)); // FIXME
+    field_list.push_back(new Item_empty_string("Server Charset", 255)); // FIXME
   }
   else
   {
@@ -452,7 +488,59 @@ mysqld_show_create(THD *thd, TABLE_LIST 
     else
       protocol->store(table_list->table->alias, system_charset_info);
   }
-  protocol->store(buffer.ptr(), buffer.length(), buffer.charset());
+
+  if (table_list->view)
+  {
+    LEX_STRING client_cs_name;
+    LEX_STRING connection_cs_name;
+    LEX_STRING server_cs_name;
+
+    if (table_list->client_cs_name.str)
+    {
+      client_cs_name= table_list->client_cs_name;
+    }
+    else
+    {
+      client_cs_name.str= (char *) system_charset_info->csname;
+      client_cs_name.length= strlen(client_cs_name.str);
+    }
+
+    if (table_list->connection_cs_name.str)
+    {
+      connection_cs_name= table_list->connection_cs_name;
+    }
+    else
+    {
+      connection_cs_name.str= (char *) system_charset_info->csname;
+      connection_cs_name.length= strlen(connection_cs_name.str);
+    }
+
+    if (table_list->server_cs_name.str)
+    {
+      server_cs_name= table_list->server_cs_name;
+    }
+    else
+    {
+      server_cs_name.str= (char *) system_charset_info->csname;
+      server_cs_name.length= strlen(server_cs_name.str);
+    }
+
+    protocol->store(buffer.ptr(), buffer.length(), &my_charset_bin);
+
+    protocol->store(client_cs_name.str,
+                    client_cs_name.length,
+                    system_charset_info);
+
+    protocol->store(connection_cs_name.str,
+                    connection_cs_name.length,
+                    system_charset_info);
+
+    protocol->store(server_cs_name.str,
+                    server_cs_name.length,
+                    system_charset_info);
+  }
+  else
+    protocol->store(buffer.ptr(), buffer.length(), buffer.charset());
 
   if (protocol->write())
     DBUG_RETURN(TRUE);
@@ -692,7 +780,7 @@ append_identifier(THD *thd, String *pack
 
   if (q == EOF)
   {
-    packet->append(name, length, system_charset_info);
+    packet->append(name, length, packet->charset());
     return;
   }
 
@@ -710,7 +798,7 @@ append_identifier(THD *thd, String *pack
     uchar chr= (uchar) *name;
     length= my_mbcharlen(system_charset_info, chr);
     /*
-      my_mbcharlen can retur 0 on a wrong multibyte
+      my_mbcharlen can return 0 on a wrong multibyte
       sequence. It is possible when upgrading from 4.0,
       and identifier contains some accented characters.
       The manual says it does not work. So we'll just
@@ -720,7 +808,7 @@ append_identifier(THD *thd, String *pack
       length= 1;
     if (length == 1 && chr == (uchar) quote_char)
       packet->append(&quote_char, 1, system_charset_info);
-    packet->append(name, length, packet->charset());
+    packet->append(name, length, system_charset_info);
   }
   packet->append(&quote_char, 1, system_charset_info);
 }
@@ -1235,6 +1323,10 @@ view_store_create_info(THD *thd, TABLE_L
   */
   table->view->unit.print(buff);
 
+  /* XXX: alik
+  printf("--> buffer: '%s'\n", (const char *) buff->c_ptr());
+  */
+
   if (table->with_check != VIEW_CHECK_NONE)
   {
     if (table->with_check == VIEW_CHECK_LOCAL)
@@ -3184,6 +3276,52 @@ static int get_schema_views_record(THD *
       table->field[7]->store(STRING_WITH_LEN("DEFINER"), cs);
     else
       table->field[7]->store(STRING_WITH_LEN("INVOKER"), cs);
+
+    {
+      LEX_STRING client_cs_name;
+      LEX_STRING connection_cs_name;
+      LEX_STRING server_cs_name;
+
+      if (tables->client_cs_name.str)
+      {
+        client_cs_name= tables->client_cs_name;
+      }
+      else
+      {
+        client_cs_name.str= (char *) system_charset_info->csname;
+        client_cs_name.length= strlen(client_cs_name.str);
+      }
+
+      if (tables->connection_cs_name.str)
+      {
+        connection_cs_name= tables->connection_cs_name;
+      }
+      else
+      {
+        connection_cs_name.str= (char *) system_charset_info->csname;
+        connection_cs_name.length= strlen(connection_cs_name.str);
+      }
+
+      if (tables->server_cs_name.str)
+      {
+        server_cs_name= tables->server_cs_name;
+      }
+      else
+      {
+        server_cs_name.str= (char *) system_charset_info->csname;
+        server_cs_name.length= strlen(server_cs_name.str);
+      }
+
+      table->field[8]->store(
+        client_cs_name.str, client_cs_name.length, cs);
+
+      table->field[9]->store(
+        connection_cs_name.str, connection_cs_name.length, cs);
+
+      table->field[10]->store(
+        server_cs_name.str, server_cs_name.length, cs);
+    }
+
     if (schema_table_store_record(thd, table))
       DBUG_RETURN(1);
     if (res)
@@ -4151,6 +4289,9 @@ ST_FIELD_INFO view_fields_info[]=
   {"IS_UPDATABLE", 3, MYSQL_TYPE_STRING, 0, 0, 0},
   {"DEFINER", 77, MYSQL_TYPE_STRING, 0, 0, 0},
   {"SECURITY_TYPE", 7, MYSQL_TYPE_STRING, 0, 0, 0},
+  {"CLIENT_CS", 255, MYSQL_TYPE_STRING, 0, 0, 0}, // XXX
+  {"CONNECTION_CS", 255, MYSQL_TYPE_STRING, 0, 0, 0}, // XXX
+  {"SERVER_CS", 255, MYSQL_TYPE_STRING, 0, 0, 0}, // XXX
   {0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
 };
 

--- 1.135/sql/table.h	2006-12-11 22:51:43 +03:00
+++ 1.136/sql/table.h	2006-12-11 22:51:43 +03:00
@@ -639,6 +639,10 @@ typedef struct st_table_list
   */
   bool          prelocking_placeholder;
 
+  LEX_STRING client_cs_name;
+  LEX_STRING connection_cs_name;
+  LEX_STRING server_cs_name;
+
   void calc_md5(char *buffer);
   void set_underlying_merge();
   int view_check_option(THD *thd, bool ignore_failure);

--- 1.99/sql/sql_view.cc	2006-12-11 22:51:43 +03:00
+++ 1.100/sql/sql_view.cc	2006-12-11 22:51:43 +03:00
@@ -598,8 +598,8 @@ err:
 
 /* index of revision number in following table */
 static const int revision_number_position= 8;
-/* index of last required parameter for making view */
-static const int required_view_parameters= 10;
+/* number of required parameters for making view */
+static const int required_view_parameters= 15;
 /* number of backups */
 static const int num_view_backups= 3;
 
@@ -646,6 +646,15 @@ static File_option view_parameters[]=
  {{(char*) STRING_WITH_LEN("source")},
   my_offsetof(TABLE_LIST, source),
   FILE_OPTIONS_ESTRING},
+ {{(char*) STRING_WITH_LEN("client_cs_name")},
+  my_offsetof(TABLE_LIST, client_cs_name),
+  FILE_OPTIONS_STRING},
+ {{(char*) STRING_WITH_LEN("connection_cs_name")},
+  my_offsetof(TABLE_LIST, connection_cs_name),
+  FILE_OPTIONS_STRING},
+ {{(char*) STRING_WITH_LEN("server_cs_name")},
+  my_offsetof(TABLE_LIST, server_cs_name),
+  FILE_OPTIONS_STRING},
  {{NullS, 0},			0,
   FILE_OPTIONS_STRING}
 };
@@ -673,7 +682,7 @@ static int mysql_register_view(THD *thd,
 {
   LEX *lex= thd->lex;
   char buff[4096];
-  String str(buff,(uint32) sizeof(buff), system_charset_info);
+  String str(buff,(uint32) sizeof(buff), thd->charset()); // system_charset_info);
   char md5[MD5_BUFF_LENGTH];
   bool can_be_merged;
   char dir_buff[FN_REFLEN], file_buff[FN_REFLEN];
@@ -802,6 +811,23 @@ static int mysql_register_view(THD *thd,
       }
     }
   }
+
+  view->client_cs_name.str= (char *) thd->charset()->csname;
+  view->client_cs_name.length= strlen(view->client_cs_name.str);
+
+  view->connection_cs_name.str= (char *) thd->variables.collation_connection->csname;
+  view->connection_cs_name.length= strlen(view->connection_cs_name.str);
+
+  view->server_cs_name.str= (char *) thd->variables.collation_server->csname;
+  view->server_cs_name.length= strlen(view->server_cs_name.str);
+
+  /* XXX: alik
+  printf(">> client: '%s'; connection: '%s'; server: '%s'\n",
+    (const char *) view->client_cs_name.str,
+    (const char *) view->connection_cs_name.str,
+    (const char *) view->server_cs_name.str);
+  */
+
 loop_out:
   /*
     Check that table of main select do not used in subqueries.
@@ -863,9 +889,14 @@ bool mysql_make_view(THD *thd, File_pars
   TABLE_LIST *top_view= table->top_table();
   int res;
   bool result;
+
   DBUG_ENTER("mysql_make_view");
   DBUG_PRINT("info", ("table: 0x%lx (%s)", (ulong) table, table->table_name));
 
+  /* XXX: alik
+  printf(">> Making '%s'...\n", (const char *) table->table_name);
+  */
+
   if (table->view)
   {
     /*
@@ -973,6 +1004,14 @@ bool mysql_make_view(THD *thd, File_pars
   view_select= &lex->select_lex;
   view_select->select_number= ++thd->select_number;
   {
+    bool charset_changed= FALSE;
+
+    CHARSET_INFO *saved_client_cs;
+    CHARSET_INFO *saved_connection_cs;
+    CHARSET_INFO *saved_server_cs;
+
+    /* Change sql_mode. */
+
     ulong save_mode= thd->variables.sql_mode;
     /* switch off modes which can prevent normal parsing of VIEW
       - MODE_REAL_AS_FLOAT            affect only CREATE TABLE parsing
@@ -1000,12 +1039,75 @@ bool mysql_make_view(THD *thd, File_pars
     */
     thd->variables.sql_mode&= ~(MODE_PIPES_AS_CONCAT | MODE_ANSI_QUOTES |
                                 MODE_IGNORE_SPACE | MODE_NO_BACKSLASH_ESCAPES);
-    CHARSET_INFO *save_cs= thd->variables.character_set_client;
-    thd->variables.character_set_client= system_charset_info;
+
+    /* Change charsets. */
+
+    if (table->client_cs_name.str &&
+      table->connection_cs_name.str &&
+      table->server_cs_name.str)
+    {
+      CHARSET_INFO *client_cs=
+        get_charset_by_csname(
+          table->client_cs_name.str,
+          MY_CS_PRIMARY,
+          MYF(0));
+
+      CHARSET_INFO *connection_cs=
+        get_charset_by_csname(
+          table->connection_cs_name.str,
+          MY_CS_PRIMARY,
+          MYF(0));
+
+      CHARSET_INFO *server_cs=
+        get_charset_by_csname(
+          table->server_cs_name.str,
+          MY_CS_PRIMARY,
+          MYF(0));
+
+      if (client_cs && connection_cs && server_cs)
+      {
+        saved_client_cs= thd->variables.character_set_client;
+        saved_connection_cs= thd->variables.collation_connection;
+        saved_server_cs= thd->variables.collation_server;
+
+        thd->variables.character_set_client= client_cs;
+        thd->variables.collation_connection= connection_cs;
+        thd->variables.collation_server= server_cs;
+        thd->update_charset();
+
+        charset_changed= TRUE;
+      }
+      else
+      {
+        printf(">> Error: invalid charset specified.\n");
+      }
+    }
+    else
+    {
+      printf(">> Warning: old version -- no charset info.\n");
+    }
+
+    /* Parse the query. */
+
     res= MYSQLparse((void *)thd);
-    thd->variables.character_set_client= save_cs;
+
+    /* Restore environment. */
+
+    if (charset_changed)
+    {
+      DBUG_ASSERT(saved_client_cs);
+      DBUG_ASSERT(saved_connection_cs);
+      DBUG_ASSERT(saved_server_cs);
+
+      thd->variables.character_set_client= saved_client_cs;
+      thd->variables.collation_connection= saved_connection_cs;
+      thd->variables.collation_server= saved_server_cs;
+      thd->update_charset();
+    }
+
     thd->variables.sql_mode= save_mode;
   }
+
   if (!res && !thd->is_fatal_error)
   {
     TABLE_LIST *view_tables= lex->query_tables;
Thread
bk commit into 5.0 tree (anozdrin:1.2318) BUG#16291Alexander Nozdrin11 Dec