MySQL Lists are EOL. Please join:

List:Commits« Previous MessageNext Message »
From:Alexander Barkov Date:October 30 2009 4:58am
Subject:bzr commit into mysql-5.5-next-mr branch (bar:2912) Bug#17903 Bug#24690
View as plain text  
#At file:///home/bar/mysql-bzr/mysql-next-mr-b24690/ based on revid:bar@stripped

 2912 Alexander Barkov	2009-10-30
      #
      # Bug#24690 Stored functions: RETURNing UTF8 strings
      # do not return UTF8_UNICODE_CI collation
      #
      # Bug#17903: cast to char results in binary
      # Regression. The character set was not being properly initialized
      # for CAST() with a type like CHAR(2) BINARY, which resulted in
      # incorrect results or even a server crash.
      #
      
      Backporting from mysql-6.0-codebase.
      
      mysql-test/r/sp-ucs2.result:
      mysql-test/t/sp-ucs2.test:
      
        Adding tests
      
      sql/mysql_priv.h:
        Adding prototype
      
      sql/sp.cc
        Remember COLLATE clause for non-default collations
      
      sql/sql_parse.cc
        Adding a new helper function
      
      sql/sql_yacc.yy
        - Allow "CHARACTER SET cs COLLATE cl" in
          SP parameters, RETURNS, DECLARE
        - Minor reorganization for "ASCII" and "UNICODE"
          related rules, to make the code more readable,
          also to allow these aliases:
          * "VARCHAR(10) ASCII BINARY"   -> CHARACTER SET latin1 COLLATE latin1_bin
          * "VARCHAR(10) BINARY ASCII"   -> CHARACTER SET latin1 COLLATE latin1_bin
          * "VARCHAR(10) UNICODE BINARY" -> CHARACTER SET ucs2 COLLATE ucs2_bin
          * "VARCHAR(10) BINARY UNICODE" -> CHARACTER SET ucs2 COLLATE ucs2_bin
          Previously these four aliases returned the error
          "This version of MySQL does not yet support return value collation".
      
      Note:
      
         This patch allows  "VARCHAR(10) CHARACTER SET cs COLLATE cl"
         and the above four aliases.
      
         "VARCHAR(10) COLLATE cl" is still not allowed
         i.e. when COLLATE is given without CHARACTER SET.
         If we want to support this, we need an architecture decision
         which character set to use by default.

    modified:
      mysql-test/r/sp-ucs2.result
      mysql-test/t/sp-ucs2.test
      sql/mysql_priv.h
      sql/sp.cc
      sql/sql_parse.cc
      sql/sql_yacc.yy
=== modified file 'mysql-test/r/sp-ucs2.result'
--- a/mysql-test/r/sp-ucs2.result	2007-02-19 10:57:06 +0000
+++ b/mysql-test/r/sp-ucs2.result	2009-10-30 04:57:46 +0000
@@ -12,3 +12,111 @@ a
 foo string
 drop function bug17615|
 drop table t3|
+CREATE FUNCTION f(f1 VARCHAR(64) CHARACTER SET ucs2 COLLATE ucs2_unicode_ci)
+RETURNS VARCHAR(64) CHARACTER SET ucs2 COLLATE ucs2_danish_ci
+BEGIN
+DECLARE f2 VARCHAR(64) CHARACTER SET ucs2 COLLATE ucs2_swedish_ci;
+DECLARE f3 VARCHAR(64) CHARACTER SET ucs2 COLLATE ucs2_bin;
+SET f1= concat(collation(f1), ' ', collation(f2), ' ', collation(f3));
+RETURN f1;
+END|
+SELECT f('a')|
+f('a')
+ucs2_unicode_ci ucs2_swedish_ci ucs2_bin
+SELECT collation(f('a'))|
+collation(f('a'))
+ucs2_danish_ci
+DROP FUNCTION f|
+CREATE FUNCTION f()
+RETURNS VARCHAR(64) UNICODE BINARY
+BEGIN
+RETURN '';
+END|
+SHOW CREATE FUNCTION f;
+DROP FUNCTION f;
+CREATE FUNCTION f()
+RETURNS VARCHAR(64) BINARY UNICODE
+BEGIN
+RETURN '';
+END|
+Function	sql_mode	Create Function	character_set_client	collation_connection	Database Collation
+f		CREATE DEFINER=`root`@`localhost` FUNCTION `f`() RETURNS varchar(64) CHARSET ucs2 COLLATE ucs2_bin
+BEGIN
+RETURN '';
+END	latin1	latin1_swedish_ci	latin1_swedish_ci
+SHOW CREATE FUNCTION f;
+DROP FUNCTION f;
+#
+# Testing keywords ASCII + BINARY
+#
+CREATE FUNCTION f()
+RETURNS VARCHAR(64) ASCII BINARY
+BEGIN
+RETURN '';
+END|
+Function	sql_mode	Create Function	character_set_client	collation_connection	Database Collation
+f		CREATE DEFINER=`root`@`localhost` FUNCTION `f`() RETURNS varchar(64) CHARSET ucs2 COLLATE ucs2_bin
+BEGIN
+RETURN '';
+END	latin1	latin1_swedish_ci	latin1_swedish_ci
+SHOW CREATE FUNCTION f;
+DROP FUNCTION f;
+CREATE FUNCTION f()
+RETURNS VARCHAR(64) BINARY ASCII
+BEGIN
+RETURN '';
+END|
+Function	sql_mode	Create Function	character_set_client	collation_connection	Database Collation
+f		CREATE DEFINER=`root`@`localhost` FUNCTION `f`() RETURNS varchar(64) CHARSET latin1 COLLATE latin1_bin
+BEGIN
+RETURN '';
+END	latin1	latin1_swedish_ci	latin1_swedish_ci
+SHOW CREATE FUNCTION f;
+DROP FUNCTION f;
+#
+# Testing COLLATE in OUT parameter
+#
+CREATE PROCEDURE p1(IN  f1 VARCHAR(64) CHARACTER SET ucs2 COLLATE ucs2_czech_ci,
+OUT f2 VARCHAR(64) CHARACTER SET ucs2 COLLATE ucs2_polish_ci)
+BEGIN
+SET f2= f1;
+SET f2= concat(collation(f1), ' ', collation(f2));
+END|
+Function	sql_mode	Create Function	character_set_client	collation_connection	Database Collation
+f		CREATE DEFINER=`root`@`localhost` FUNCTION `f`() RETURNS varchar(64) CHARSET latin1 COLLATE latin1_bin
+BEGIN
+RETURN '';
+END	latin1	latin1_swedish_ci	latin1_swedish_ci
+CREATE FUNCTION f1()
+RETURNS VARCHAR(64) CHARACTER SET ucs2
+BEGIN
+DECLARE f1 VARCHAR(64) CHARACTER SET ucs2;
+DECLARE f2 VARCHAR(64) CHARACTER SET ucs2;
+SET f1='str';
+CALL p1(f1, f2);
+RETURN f2;
+END|
+SELECT f1()|
+f1()
+ucs2_czech_ci ucs2_polish_ci
+DROP PROCEDURE p1|
+DROP FUNCTION f1|
+CREATE FUNCTION f(f1 VARCHAR(64) COLLATE ucs2_unicode_ci)
+RETURNS VARCHAR(64) CHARACTER SET ucs2
+BEGIN
+RETURN 'str';
+END|
+ERROR 42000: This version of MySQL doesn't yet support 'COLLATE with no CHARACTER SET in SP parameters, RETURNS, DECLARE'
+CREATE FUNCTION f(f1 VARCHAR(64) CHARACTER SET ucs2)
+RETURNS VARCHAR(64) COLLATE ucs2_unicode_ci
+BEGIN
+RETURN 'str';
+END|
+ERROR 42000: This version of MySQL doesn't yet support 'COLLATE with no CHARACTER SET in SP parameters, RETURNS, DECLARE'
+CREATE FUNCTION f(f1 VARCHAR(64) CHARACTER SET ucs2)
+RETURNS VARCHAR(64) CHARACTER SET ucs2
+BEGIN
+DECLARE f2 VARCHAR(64) COLLATE ucs2_unicode_ci;
+RETURN 'str';
+END|
+ERROR 42000: This version of MySQL doesn't yet support 'COLLATE with no CHARACTER SET in SP parameters, RETURNS, DECLARE'

=== modified file 'mysql-test/t/sp-ucs2.test'
--- a/mysql-test/t/sp-ucs2.test	2007-02-19 10:57:06 +0000
+++ b/mysql-test/t/sp-ucs2.test	2009-10-30 04:57:46 +0000
@@ -25,4 +25,124 @@ drop function bug17615|
 drop table t3|
 
 
+#
+# Testing COLLATE clause in
+# - IN parameter
+# - RETURNS
+# - DELCARE
+#
+
+CREATE FUNCTION f(f1 VARCHAR(64) CHARACTER SET ucs2 COLLATE ucs2_unicode_ci)
+  RETURNS VARCHAR(64) CHARACTER SET ucs2 COLLATE ucs2_danish_ci
+BEGIN
+  DECLARE f2 VARCHAR(64) CHARACTER SET ucs2 COLLATE ucs2_swedish_ci;
+  DECLARE f3 VARCHAR(64) CHARACTER SET ucs2 COLLATE ucs2_bin;
+  SET f1= concat(collation(f1), ' ', collation(f2), ' ', collation(f3));
+  RETURN f1;
+END|
+SELECT f('a')|
+SELECT collation(f('a'))|
+DROP FUNCTION f|
+
+#
+# Testing keywords UNICODE + BINARY
+#
+CREATE FUNCTION f()
+  RETURNS VARCHAR(64) UNICODE BINARY
+BEGIN
+  RETURN '';
+END|
+SHOW CREATE FUNCTION f;
+DROP FUNCTION f;
+
+CREATE FUNCTION f()
+  RETURNS VARCHAR(64) BINARY UNICODE
+BEGIN
+  RETURN '';
+END|
+SHOW CREATE FUNCTION f;
+DROP FUNCTION f;
+
+
+#
+# Testing keywords ASCII + BINARY
+#
+CREATE FUNCTION f()
+  RETURNS VARCHAR(64) ASCII BINARY
+BEGIN
+  RETURN '';
+END|
+SHOW CREATE FUNCTION f;
+DROP FUNCTION f;
+
+CREATE FUNCTION f()
+  RETURNS VARCHAR(64) BINARY ASCII
+BEGIN
+  RETURN '';
+END|
+SHOW CREATE FUNCTION f;
+DROP FUNCTION f;
+
+#
+# Testing COLLATE in OUT parameter
+#
+
+CREATE PROCEDURE p1(IN  f1 VARCHAR(64) CHARACTER SET ucs2 COLLATE ucs2_czech_ci,
+                    OUT f2 VARCHAR(64) CHARACTER SET ucs2 COLLATE ucs2_polish_ci)
+BEGIN
+  SET f2= f1;
+  SET f2= concat(collation(f1), ' ', collation(f2));
+END|
+
+
+CREATE FUNCTION f1()
+  RETURNS VARCHAR(64) CHARACTER SET ucs2
+BEGIN
+  DECLARE f1 VARCHAR(64) CHARACTER SET ucs2;
+  DECLARE f2 VARCHAR(64) CHARACTER SET ucs2;
+  SET f1='str';
+  CALL p1(f1, f2);
+  RETURN f2;
+END|
+
+
+SELECT f1()|
+DROP PROCEDURE p1|
+DROP FUNCTION f1|
+
+
+#
+# COLLATE with no CHARACTER SET in IN param
+#
+--error ER_NOT_SUPPORTED_YET
+CREATE FUNCTION f(f1 VARCHAR(64) COLLATE ucs2_unicode_ci)
+  RETURNS VARCHAR(64) CHARACTER SET ucs2
+BEGIN
+  RETURN 'str';
+END|
+
+
+#
+# COLLATE with no CHARACTER SET in RETURNS
+#
+--error ER_NOT_SUPPORTED_YET
+CREATE FUNCTION f(f1 VARCHAR(64) CHARACTER SET ucs2)
+  RETURNS VARCHAR(64) COLLATE ucs2_unicode_ci
+BEGIN
+  RETURN 'str';
+END|
+
+
+#
+# COLLATE with no CHARACTER SET in DECLARE
+#
+--error ER_NOT_SUPPORTED_YET
+CREATE FUNCTION f(f1 VARCHAR(64) CHARACTER SET ucs2)
+  RETURNS VARCHAR(64) CHARACTER SET ucs2
+BEGIN
+  DECLARE f2 VARCHAR(64) COLLATE ucs2_unicode_ci;
+  RETURN 'str';
+END|
+
+
 delimiter ;|

=== modified file 'sql/mysql_priv.h'
--- a/sql/mysql_priv.h	2009-10-22 22:30:28 +0000
+++ b/sql/mysql_priv.h	2009-10-30 04:57:46 +0000
@@ -858,6 +858,8 @@ bool check_string_char_length(LEX_STRING
                               bool no_error);
 bool check_host_name(LEX_STRING *str);
 
+CHARSET_INFO *merge_charset_and_collation(CHARSET_INFO *cs, CHARSET_INFO *cl);
+
 bool parse_sql(THD *thd,
                Parser_state *parser_state,
                Object_creation_ctx *creation_ctx);

=== modified file 'sql/sp.cc'
--- a/sql/sp.cc	2009-09-10 09:18:29 +0000
+++ b/sql/sp.cc	2009-10-30 04:57:46 +0000
@@ -693,6 +693,11 @@ sp_returns_type(THD *thd, String &result
   {
     result.append(STRING_WITH_LEN(" CHARSET "));
     result.append(field->charset()->csname);
+    if (!(field->charset()->state & MY_CS_PRIMARY))
+    {
+      result.append(STRING_WITH_LEN(" COLLATE "));
+      result.append(field->charset()->name);
+    }
   }
 
   delete field;

=== modified file 'sql/sql_parse.cc'
--- a/sql/sql_parse.cc	2009-10-22 22:30:28 +0000
+++ b/sql/sql_parse.cc	2009-10-30 04:57:46 +0000
@@ -7939,3 +7939,37 @@ bool parse_sql(THD *thd,
 /**
   @} (end of group Runtime_Environment)
 */
+
+
+
+/**
+  Check and merge "CHARACTER SET cs [ COLLATE cl ]" clause
+
+  @param cs character set pointer.
+  @param cl collation pointer.
+
+  Check if collation "cl" is applicable to character set "cs".
+
+  If "cl" is NULL (e.g. when COLLATE clause is not specified),
+  then simply "cs" is returned.
+  
+  @return Error status.
+    @retval NULL, if "cl" is not applicable to "cs".
+    @retval pointer to merged CHARSET_INFO on success.
+*/
+
+
+CHARSET_INFO*
+merge_charset_and_collation(CHARSET_INFO *cs, CHARSET_INFO *cl)
+{
+  if (cl)
+  {
+    if (!my_charset_same(cs, cl))
+    {
+      my_error(ER_COLLATION_CHARSET_MISMATCH, MYF(0), cl->name, cs->csname);
+      return NULL;
+    }
+    return cl;
+  }
+  return cs;
+}

=== modified file 'sql/sql_yacc.yy'
--- a/sql/sql_yacc.yy	2009-10-22 22:30:28 +0000
+++ b/sql/sql_yacc.yy	2009-10-30 04:57:46 +0000
@@ -1170,7 +1170,7 @@ bool my_yyoverflow(short **a, YYSTYPE **
         text_string opt_gconcat_separator
 
 %type <num>
-        type int_type real_type order_dir lock_option
+        type type_with_opt_collate int_type real_type order_dir lock_option
         udf_type if_exists opt_local opt_table_options table_options
         table_option opt_if_not_exists opt_no_write_to_binlog
         delete_option opt_temporary all_or_any opt_distinct
@@ -1295,7 +1295,7 @@ bool my_yyoverflow(short **a, YYSTYPE **
         handler
         opt_precision opt_ignore opt_column opt_restrict
         grant revoke set lock unlock string_list field_options field_option
-        field_opt_list opt_binary table_lock_list table_lock
+        field_opt_list opt_binary ascii unicode table_lock_list table_lock
         ref_list opt_on_delete opt_on_delete_list opt_on_delete_item use
         opt_delete_options opt_delete_option varchar nchar nvarchar
         opt_outer table_list table_name table_alias_ref_list table_alias_ref
@@ -2257,7 +2257,7 @@ sp_init_param:
         ;
 
 sp_fdparam:
-          ident sp_init_param type
+          ident sp_init_param type_with_opt_collate
           {
             LEX *lex= Lex;
             sp_pcontext *spc= lex->spcont;
@@ -2294,7 +2294,7 @@ sp_pdparams:
         ;
 
 sp_pdparam:
-          sp_opt_inout sp_init_param ident type
+          sp_opt_inout sp_init_param ident type_with_opt_collate
           {
             LEX *lex= Lex;
             sp_pcontext *spc= lex->spcont;
@@ -2374,7 +2374,7 @@ sp_decl:
             lex->sphead->reset_lex(YYTHD);
             lex->spcont->declare_var_boundary($2);
           }
-          type
+          type_with_opt_collate
           sp_opt_default
           {
             THD *thd= YYTHD;
@@ -4833,14 +4833,14 @@ default_collation:
             HA_CREATE_INFO *cinfo= &Lex->create_info;
             if ((cinfo->used_fields & HA_CREATE_USED_DEFAULT_CHARSET) &&
                  cinfo->default_table_charset && $4 &&
-                 !my_charset_same(cinfo->default_table_charset,$4))
-              {
-                my_error(ER_COLLATION_CHARSET_MISMATCH, MYF(0),
-                         $4->name, cinfo->default_table_charset->csname);
-                MYSQL_YYABORT;
-              }
-              Lex->create_info.default_table_charset= $4;
-              Lex->create_info.used_fields|= HA_CREATE_USED_DEFAULT_CHARSET;
+                 !($4= merge_charset_and_collation(cinfo->default_table_charset,
+                                                   $4)))
+            {
+              MYSQL_YYABORT;
+            }
+
+            Lex->create_info.default_table_charset= $4;
+            Lex->create_info.used_fields|= HA_CREATE_USED_DEFAULT_CHARSET;
           }
         ;
 
@@ -5358,6 +5358,28 @@ attribute:
           }
         ;
 
+
+type_with_opt_collate:
+        type opt_collate
+        {
+          $$= $1;
+
+          if (Lex->charset) /* Lex->charset is scanned in "type" */
+          {
+            if (!(Lex->charset= merge_charset_and_collation(Lex->charset, $2)))
+              MYSQL_YYABORT;
+          }
+          else if ($2)
+          {
+            my_error(ER_NOT_SUPPORTED_YET, MYF(0),
+                     "COLLATE with no CHARACTER SET "
+                     "in SP parameters, RETURNS, DECLARE");
+            MYSQL_YYABORT;
+          }
+        }
+        ;
+
+
 now_or_signed_literal:
           NOW_SYM optional_braces
           {
@@ -5440,11 +5462,21 @@ opt_default:
         | DEFAULT {}
         ;
 
-opt_binary:
-          /* empty */ { Lex->charset=NULL; }
-        | ASCII_SYM opt_bin_mod { Lex->charset=&my_charset_latin1; }
-        | BYTE_SYM { Lex->charset=&my_charset_bin; }
-        | UNICODE_SYM opt_bin_mod
+
+ascii:
+          ASCII_SYM { Lex->charset= &my_charset_latin1; }
+        | BINARY ASCII_SYM
+          {
+            Lex->charset= &my_charset_latin1_bin;
+          }
+        | ASCII_SYM BINARY
+          {
+            Lex->charset= &my_charset_latin1_bin;
+          }
+        ;
+
+unicode:
+          UNICODE_SYM
           {
             if (!(Lex->charset=get_charset_by_csname("ucs2",
                                                      MY_CS_PRIMARY,MYF(0))))
@@ -5453,8 +5485,40 @@ opt_binary:
               MYSQL_YYABORT;
             }
           }
+        | UNICODE_SYM BINARY
+          {
+            if (!(Lex->charset=get_charset_by_name("ucs2_bin", MYF(0))))
+            {
+              my_error(ER_UNKNOWN_COLLATION, MYF(0), "ucs2_bin");
+              MYSQL_YYABORT;
+            }
+          }
+        | BINARY UNICODE_SYM
+          {
+            if (!(Lex->charset=get_charset_by_name("ucs2_bin", MYF(0))))
+            {
+              my_error(ER_UNKNOWN_COLLATION, MYF(0), "ucs2_bin");
+              MYSQL_YYABORT;
+            }
+          }
+        ;
+
+opt_binary:
+          /* empty */ { Lex->charset=NULL; }
+        | ascii
+        | unicode
+        | BYTE_SYM { Lex->charset=&my_charset_bin; }
         | charset charset_name opt_bin_mod { Lex->charset=$2; }
-        | BINARY opt_bin_charset { Lex->type|= BINCMP_FLAG; }
+        | BINARY
+          {
+            Lex->charset= NULL;
+            Lex->type|= BINCMP_FLAG;
+          }
+        | BINARY charset charset_name
+          {
+            Lex->charset= $3;
+            Lex->type|= BINCMP_FLAG;
+          }
         ;
 
 opt_bin_mod:
@@ -5462,20 +5526,6 @@ opt_bin_mod:
         | BINARY { Lex->type|= BINCMP_FLAG; }
         ;
 
-opt_bin_charset:
-          /* empty */ { Lex->charset= NULL; }
-        | ASCII_SYM { Lex->charset=&my_charset_latin1; }
-        | UNICODE_SYM
-          {
-            if (!(Lex->charset=get_charset_by_csname("ucs2",
-                                                     MY_CS_PRIMARY,MYF(0))))
-            {
-              my_error(ER_UNKNOWN_CHARACTER_SET, MYF(0), "ucs2");
-              MYSQL_YYABORT;
-            }
-          }
-        | charset charset_name { Lex->charset=$2; }
-        ;
 
 opt_primary:
           /* empty */
@@ -13665,7 +13715,7 @@ sf_tail:
             lex->interval_list.empty();
             lex->type= 0;
           }
-          type /* $11 */
+          type_with_opt_collate /* $11 */
           { /* $12 */
             LEX *lex= Lex;
             sp_head *sp= lex->sphead;


Attachment: [text/bzr-bundle] bzr/bar@mysql.com-20091030045746-apknku9pv4n4o7x6.bundle
Thread
bzr commit into mysql-5.5-next-mr branch (bar:2912) Bug#17903 Bug#24690Alexander Barkov30 Oct