List:Commits« Previous MessageNext Message »
From:Guilhem Bichot Date:March 3 2011 9:54am
Subject:bzr commit into mysql-5.5 branch (guilhem.bichot:3358)
View as plain text  
#At file:///home/mysql_src/bzrrepos_new/bar/ based on revid:alexander.barkov@stripped

 3358 Guilhem Bichot	2011-03-03
      Suggestion of refactoring in the context of Bug 11764503 (Bug 57341)
      "Query in EXPLAIN EXTENDED shows wrong characters".
      Item_string::print() is hard to understand because of the different
      QT_ constants: in "query_type==QT_x", QT_x is explicitely included
      but the other two QT_ are implicitely excluded. The combinations
      with '||' and '&&' make this even harder. Proposal:
      - Make logic more "explicit" by changing QT_ constants to a bitmap of flags:
      QT_ORDINARY: no change,
      QT_IS -> QT_TO_SYSTEM_CHARSET | QT_WITHOUT_INTRODUCERS,
      QT_EXPLAIN -> QT_TO_SYSTEM_CHARSET.
      - Rewrite Item_string::print() using those flags
      - Comments.
      This patch shouldn't change anything as far results are concerned.
      Full test suite has been run.

    modified:
      sql/item.cc
      sql/mysqld.h
      sql/sql_parse.cc
      sql/sql_view.cc
=== modified file 'sql/item.cc'
--- a/sql/item.cc	2011-03-01 10:17:10 +0000
+++ b/sql/item.cc	2011-03-03 09:54:52 +0000
@@ -2514,8 +2514,9 @@ my_decimal *Item_float::val_decimal(my_d
 
 void Item_string::print(String *str, enum_query_type query_type)
 {
-  if ((query_type == QT_ORDINARY || query_type == QT_EXPLAIN) &&
-      is_cs_specified())
+  const bool print_introducer=
+    !(query_type & QT_WITHOUT_INTRODUCERS) && is_cs_specified();
+  if (print_introducer)
   {
     str->append('_');
     str->append(collation.collation->csname);
@@ -2523,33 +2524,52 @@ void Item_string::print(String *str, enu
 
   str->append('\'');
 
-  if (query_type == QT_EXPLAIN && is_cs_specified())
+  if (query_type & QT_TO_SYSTEM_CHARSET)
   {
-    /* Print ASCII as is, print extended characters using \xFF sequences */
-    ErrConvString tmp(str_value.ptr(), str_value.length(), &my_charset_bin);
-    str->append(tmp.ptr());
-  }
-  else if (query_type == QT_ORDINARY ||
-           my_charset_same(str_value.charset(), system_charset_info))
-  {
-    str_value.print(str);
+    if (print_introducer)
+    {
+      /*
+        Because we wrote an introducer, we must print str_value in its
+        charset, and the resulting bytes must not be changed until they
+        reach the end client.
+        But the caller is asking for system_charset_info, and may later
+        convert into character_set_results. That means two conversions: we
+        must ensure that they don't change our printed bytes.
+        So we print str_value in the least common denominator of the three
+        charsets involved: ASCII. Non-ASCII characters are printed as \xFF
+        sequences (which is ASCII too). This way, our bytes will not be
+        changed.
+      */
+      ErrConvString tmp(str_value.ptr(), str_value.length(), &my_charset_bin);
+      str->append(tmp.ptr());
+    }
+    else
+    {
+      if (my_charset_same(str_value.charset(), system_charset_info))
+        str_value.print(str); // already in system_charset_info
+      else // need to convert
+      {
+        THD *thd= current_thd;
+        LEX_STRING utf8_lex_str;
+
+        thd->convert_string(&utf8_lex_str,
+                            system_charset_info,
+                            str_value.c_ptr_safe(),
+                            str_value.length(),
+                            str_value.charset());
+
+        String utf8_str(utf8_lex_str.str,
+                        utf8_lex_str.length,
+                        system_charset_info);
+
+        utf8_str.print(str);
+      }
+    }
   }
   else
   {
-    THD *thd= current_thd;
-    LEX_STRING utf8_lex_str;
-
-    thd->convert_string(&utf8_lex_str,
-                        system_charset_info,
-                        str_value.c_ptr_safe(),
-                        str_value.length(),
-                        str_value.charset());
-
-    String utf8_str(utf8_lex_str.str,
-                    utf8_lex_str.length,
-                    system_charset_info);
-
-    utf8_str.print(str);
+    // Caller wants a result in the charset of str_value.
+    str_value.print(str);
   }
 
   str->append('\'');

=== modified file 'sql/mysqld.h'
--- a/sql/mysqld.h	2011-03-01 10:17:10 +0000
+++ b/sql/mysqld.h	2011-03-03 09:54:52 +0000
@@ -399,19 +399,16 @@ enum options_mysqld
 
 
 /**
-  Query type constants.
-
-  QT_ORDINARY -- ordinary SQL query.
-  QT_IS -- SQL query to be shown in INFORMATION_SCHEMA (in utf8 and without
-  character set introducers).
-  QT_EXPLAIN -- SQL query to be shown in EXPLAIN SELECT EXTENDED (with
-  introducers and \xFF escape sequences for extended characters)
+   Query type constants (usable as bitmap flags).
 */
 enum enum_query_type
 {
-  QT_ORDINARY,
-  QT_IS,
-  QT_EXPLAIN
+  /// Nothing specific, ordinary SQL query.
+  QT_ORDINARY= 0,
+  /// In utf8.
+  QT_TO_SYSTEM_CHARSET= (1 << 0),
+  /// Without character set introducers.
+  QT_WITHOUT_INTRODUCERS= (1 << 1)
 };
 
 /* query_id */

=== modified file 'sql/sql_parse.cc'
--- a/sql/sql_parse.cc	2011-03-01 10:17:10 +0000
+++ b/sql/sql_parse.cc	2011-03-03 09:54:52 +0000
@@ -4439,7 +4439,11 @@ static bool execute_sqlcom_select(THD *t
         char buff[1024];
         String str(buff,(uint32) sizeof(buff), system_charset_info);
         str.length(0);
-        thd->lex->unit.print(&str, QT_EXPLAIN);
+        /*
+          The warnings system requires input in utf8, @see
+          mysqld_show_warnings().
+        */
+        thd->lex->unit.print(&str, QT_TO_SYSTEM_CHARSET);
         str.append('\0');
         push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
                      ER_YES, str.ptr());

=== modified file 'sql/sql_view.cc'
--- a/sql/sql_view.cc	2011-02-08 15:47:33 +0000
+++ b/sql/sql_view.cc	2011-03-03 09:54:52 +0000
@@ -841,7 +841,8 @@ static int mysql_register_view(THD *thd,
     thd->variables.sql_mode&= ~MODE_ANSI_QUOTES;
 
     lex->unit.print(&view_query, QT_ORDINARY);
-    lex->unit.print(&is_query, QT_IS);
+    lex->unit.print(&is_query,
+                    enum_query_type(QT_TO_SYSTEM_CHARSET | QT_WITHOUT_INTRODUCERS));
 
     thd->variables.sql_mode|= sql_mode;
   }


Attachment: [text/bzr-bundle] bzr/guilhem.bichot@oracle.com-20110303095452-frwx787wv0gb4or8.bundle
Thread
bzr commit into mysql-5.5 branch (guilhem.bichot:3358) Guilhem Bichot3 Mar