summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mysql-test/r/sp-ucs2.result108
-rw-r--r--mysql-test/t/sp-ucs2.test120
-rw-r--r--sql/mysql_priv.h2
-rw-r--r--sql/sp.cc5
-rw-r--r--sql/sql_parse.cc34
-rw-r--r--sql/sql_yacc.yy118
6 files changed, 353 insertions, 34 deletions
diff --git a/mysql-test/r/sp-ucs2.result b/mysql-test/r/sp-ucs2.result
index ce6be5b0a65..3806a84a849 100644
--- a/mysql-test/r/sp-ucs2.result
+++ b/mysql-test/r/sp-ucs2.result
@@ -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'
diff --git a/mysql-test/t/sp-ucs2.test b/mysql-test/t/sp-ucs2.test
index 7dd88b04871..0480d8f0799 100644
--- a/mysql-test/t/sp-ucs2.test
+++ b/mysql-test/t/sp-ucs2.test
@@ -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 ;|
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index 7413c18fdd8..b95e5e50f5a 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -858,6 +858,8 @@ bool check_string_char_length(LEX_STRING *str, const char *err_msg,
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);
diff --git a/sql/sp.cc b/sql/sp.cc
index 5898e553320..6c268e87711 100644
--- a/sql/sp.cc
+++ b/sql/sp.cc
@@ -693,6 +693,11 @@ sp_returns_type(THD *thd, String &result, sp_head *sp)
{
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;
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 08af00bb024..3b99d0e4c5f 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -7951,3 +7951,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;
+}
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index e21ef0040fa..05283718162 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -1172,7 +1172,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
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
@@ -1297,7 +1297,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
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
@@ -2259,7 +2259,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;
@@ -2296,7 +2296,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;
@@ -2376,7 +2376,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;
@@ -4835,14 +4835,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;
}
;
@@ -5360,6 +5360,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
{
@@ -5442,11 +5464,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))))
@@ -5455,8 +5487,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:
@@ -5464,20 +5528,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 */
@@ -13666,7 +13716,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;