From e42f4e31990d7741e7c375f1102c4584a507c05f Mon Sep 17 00:00:00 2001 From: Alexander Barkov <bar@mariadb.org> Date: Wed, 3 Sep 2014 16:31:47 +0400 Subject: [PATCH] MDEV-6688 Illegal mix of collation with bit string B'01100001' --- mysql-test/r/ctype_utf8.result | 12 +++++ mysql-test/t/ctype_utf8.test | 10 +++++ sql/item.h | 52 ++++++++++++++-------- sql/sql_yacc.yy | 80 ++++++---------------------------- 4 files changed, 71 insertions(+), 83 deletions(-) diff --git a/mysql-test/r/ctype_utf8.result b/mysql-test/r/ctype_utf8.result index d768550e2c6..8a3fcd9dc0d 100644 --- a/mysql-test/r/ctype_utf8.result +++ b/mysql-test/r/ctype_utf8.result @@ -5996,5 +5996,17 @@ id select_type table type possible_keys key key_len ref rows Extra DEALLOCATE PREPARE stmt; DROP TABLE t1; # +# MDEV-6688 Illegal mix of collation with bit string B'01100001' +# +CREATE TABLE t1 (a VARCHAR(10) CHARACTER SET latin1, b INT); +INSERT INTO t1 VALUES ('a',1); +SELECT CONCAT(a, IF(b>10, _utf8 X'61', _utf8 X'61')) FROM t1; +CONCAT(a, IF(b>10, _utf8 X'61', _utf8 X'61')) +aa +SELECT CONCAT(a, IF(b>10, _utf8 X'61', _utf8 B'01100001')) FROM t1; +CONCAT(a, IF(b>10, _utf8 X'61', _utf8 B'01100001')) +aa +DROP TABLE t1; +# # End of 10.0 tests # diff --git a/mysql-test/t/ctype_utf8.test b/mysql-test/t/ctype_utf8.test index 0ccdfe8aacf..75630cf9cd5 100644 --- a/mysql-test/t/ctype_utf8.test +++ b/mysql-test/t/ctype_utf8.test @@ -1710,6 +1710,16 @@ EXECUTE stmt USING @arg; DEALLOCATE PREPARE stmt; DROP TABLE t1; +--echo # +--echo # MDEV-6688 Illegal mix of collation with bit string B'01100001' +--echo # +CREATE TABLE t1 (a VARCHAR(10) CHARACTER SET latin1, b INT); +INSERT INTO t1 VALUES ('a',1); +SELECT CONCAT(a, IF(b>10, _utf8 X'61', _utf8 X'61')) FROM t1; +SELECT CONCAT(a, IF(b>10, _utf8 X'61', _utf8 B'01100001')) FROM t1; +DROP TABLE t1; + + --echo # --echo # End of 10.0 tests --echo # diff --git a/sql/item.h b/sql/item.h index 3d60794061b..814ec121803 100644 --- a/sql/item.h +++ b/sql/item.h @@ -2711,6 +2711,23 @@ class Item_static_float_func :public Item_float class Item_string :public Item_basic_constant { + bool m_cs_specified; +protected: + /** + Set the value of m_cs_specified attribute. + + m_cs_specified attribute shows whether character-set-introducer was + explicitly specified in the original query for this text literal or + not. The attribute makes sense (is used) only for views. + + This operation is to be called from the parser during parsing an input + query. + */ + inline void set_cs_specified(bool cs_specified) + { + m_cs_specified= cs_specified; + } + public: Item_string(const char *str,uint length, CHARSET_INFO *cs, Derivation dv= DERIVATION_COERCIBLE, @@ -2860,21 +2877,6 @@ class Item_string :public Item_basic_constant return m_cs_specified; } - /** - Set the value of m_cs_specified attribute. - - m_cs_specified attribute shows whether character-set-introducer was - explicitly specified in the original query for this text literal or - not. The attribute makes sense (is used) only for views. - - This operation is to be called from the parser during parsing an input - query. - */ - inline void set_cs_specified(bool cs_specified) - { - m_cs_specified= cs_specified; - } - String *check_well_formed_result(bool send_error) { return Item::check_well_formed_result(&str_value, send_error); } @@ -2906,8 +2908,24 @@ class Item_string :public Item_basic_constant } return MYSQL_TYPE_STRING; // Not a temporal literal } -private: - bool m_cs_specified; +}; + + +class Item_string_with_introducer :public Item_string +{ +public: + Item_string_with_introducer(const char *str, uint length, CHARSET_INFO *cs) + :Item_string(str, length, cs) + { + set_repertoire_from_value(); + set_cs_specified(true); + } + Item_string_with_introducer(const String *str, CHARSET_INFO *tocs) + :Item_string(str->ptr(), str->length(), tocs) + { + set_repertoire_from_value(); + set_cs_specified(true); + } }; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index ef71369ac66..ecef9d8841a 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1648,7 +1648,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %type <lex_str> IDENT IDENT_QUOTED TEXT_STRING DECIMAL_NUM FLOAT_NUM NUM LONG_NUM - HEX_NUM HEX_STRING hex_num_or_string + HEX_NUM HEX_STRING LEX_HOSTNAME ULONGLONG_NUM field_ident select_alias ident ident_or_text IDENT_sys TEXT_STRING_sys TEXT_STRING_literal NCHAR_STRING opt_component key_cache_name @@ -1666,7 +1666,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); remember_name remember_end opt_db text_or_password %type <string> - text_string opt_gconcat_separator + text_string hex_or_bin_String opt_gconcat_separator %type <num> type type_with_opt_collate int_type real_type order_dir lock_option @@ -6517,11 +6517,6 @@ now_or_signed_literal: { $$=$1; } ; -hex_num_or_string: - HEX_NUM {} - | HEX_STRING {} - ; - charset: CHAR_SYM SET {} | CHARSET {} @@ -13253,14 +13248,10 @@ text_literal: } | UNDERSCORE_CHARSET TEXT_STRING { - Item_string *str= new (thd->mem_root) Item_string($2.str, + $$= new (thd->mem_root) Item_string_with_introducer($2.str, $2.length, $1); - if (str == NULL) + if ($$ == NULL) MYSQL_YYABORT; - str->set_repertoire_from_value(); - str->set_cs_specified(TRUE); - - $$= str; } | text_literal TEXT_STRING_literal { @@ -13289,7 +13280,12 @@ text_string: if ($$ == NULL) MYSQL_YYABORT; } - | HEX_NUM + | hex_or_bin_String { $$= $1; } + ; + + +hex_or_bin_String: + HEX_NUM { Item *tmp= new (thd->mem_root) Item_hex_hybrid($1.str, $1.length); if (tmp == NULL) @@ -13394,60 +13390,12 @@ literal: if ($$ == NULL) MYSQL_YYABORT; } - | UNDERSCORE_CHARSET hex_num_or_string + | UNDERSCORE_CHARSET hex_or_bin_String { - Item *tmp= new (thd->mem_root) Item_hex_string($2.str, $2.length); - if (tmp == NULL) + Item_string_with_introducer *item_str; + item_str= new (thd->mem_root) Item_string_with_introducer($2, $1); + if (!item_str || !item_str->check_well_formed_result(true)) MYSQL_YYABORT; - /* - it is OK only emulate fix_fieds, because we need only - value of constant - */ - tmp->quick_fix_field(); - String *str= tmp->val_str((String*) 0); - - Item_string *item_str; - item_str= new (thd->mem_root) - Item_string(NULL, /* name will be set in select_item */ - str ? str->ptr() : "", - str ? str->length() : 0, - $1); - if (!item_str || - !item_str->check_well_formed_result(true)) - { - MYSQL_YYABORT; - } - - item_str->set_repertoire_from_value(); - item_str->set_cs_specified(TRUE); - - $$= item_str; - } - | UNDERSCORE_CHARSET BIN_NUM - { - Item *tmp= new (thd->mem_root) Item_bin_string($2.str, $2.length); - if (tmp == NULL) - MYSQL_YYABORT; - /* - it is OK only emulate fix_fieds, because we need only - value of constant - */ - tmp->quick_fix_field(); - String *str= tmp->val_str((String*) 0); - - Item_string *item_str; - item_str= new (thd->mem_root) - Item_string(NULL, /* name will be set in select_item */ - str ? str->ptr() : "", - str ? str->length() : 0, - $1); - if (!item_str || - !item_str->check_well_formed_result(true)) - { - MYSQL_YYABORT; - } - - item_str->set_cs_specified(TRUE); $$= item_str; } -- 2.30.9