diff --git a/mysql-test/main/user_var.result b/mysql-test/main/user_var.result index 8afe38398e48b..24e6c90a25dab 100644 --- a/mysql-test/main/user_var.result +++ b/mysql-test/main/user_var.result @@ -162,13 +162,13 @@ collation(@a:=_latin2'test') latin2_general_ci select coercibility(@a:=_latin2'test'); coercibility(@a:=_latin2'test') -6 +5 select collation(@a:=_latin2'test' collate latin2_bin); collation(@a:=_latin2'test' collate latin2_bin) latin2_bin select coercibility(@a:=_latin2'test' collate latin2_bin); coercibility(@a:=_latin2'test' collate latin2_bin) -6 +5 select (@a:=_latin2'test' collate latin2_bin) = _latin2'TEST'; (@a:=_latin2'test' collate latin2_bin) = _latin2'TEST' 0 diff --git a/mysql-test/main/user_var_collation.result b/mysql-test/main/user_var_collation.result new file mode 100644 index 0000000000000..c88843c5b0c02 --- /dev/null +++ b/mysql-test/main/user_var_collation.result @@ -0,0 +1,24 @@ +# +# MDEV-39530 Collation mix issue after update +# +# Reproduce the environment from the report: character_set_collations +# maps utf8mb3 to utf8mb3_uca1400_ai_ci and the connection uses that +# collation. +SET NAMES utf8mb3 COLLATE utf8mb3_uca1400_ai_ci; +SELECT @@character_set_collations, @@collation_connection; +@@character_set_collations @@collation_connection +utf8mb3=utf8mb3_uca1400_ai_ci,ucs2=ucs2_uca1400_ai_ci,utf8mb4=utf8mb4_uca1400_ai_ci,utf16=utf16_uca1400_ai_ci,utf32=utf32_uca1400_ai_ci utf8mb3_uca1400_ai_ci +CREATE TABLE file ( +`ID` int(10) unsigned NOT NULL AUTO_INCREMENT PRIMARY KEY, +`Path` varchar(800) NOT NULL DEFAULT '' +) ENGINE=MyISAM DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci; +INSERT INTO file VALUES (1,"text"); +# This query used to work in 11.4 but raises +# ER_CANT_AGGREGATE_2COLLATIONS in 12.1+ +SELECT IF((@p:=(SELECT f.Path FROM file f WHERE f.ID=1 AND f.Path REGEXP "^xx"))!="",1,2); +IF((@p:=(SELECT f.Path FROM file f WHERE f.ID=1 AND f.Path REGEXP "^xx"))!="",1,2) +2 +DROP TABLE file; +# +# End of test +# diff --git a/mysql-test/main/user_var_collation.test b/mysql-test/main/user_var_collation.test new file mode 100644 index 0000000000000..b73de1953d799 --- /dev/null +++ b/mysql-test/main/user_var_collation.test @@ -0,0 +1,26 @@ +--echo # +--echo # MDEV-39530 Collation mix issue after update +--echo # + +--echo # Reproduce the environment from the report: character_set_collations +--echo # maps utf8mb3 to utf8mb3_uca1400_ai_ci and the connection uses that +--echo # collation. +SET NAMES utf8mb3 COLLATE utf8mb3_uca1400_ai_ci; +SELECT @@character_set_collations, @@collation_connection; + +CREATE TABLE file ( + `ID` int(10) unsigned NOT NULL AUTO_INCREMENT PRIMARY KEY, + `Path` varchar(800) NOT NULL DEFAULT '' +) ENGINE=MyISAM DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci; + +INSERT INTO file VALUES (1,"text"); + +--echo # This query used to work in 11.4 but raises +--echo # ER_CANT_AGGREGATE_2COLLATIONS in 12.1+ +SELECT IF((@p:=(SELECT f.Path FROM file f WHERE f.ID=1 AND f.Path REGEXP "^xx"))!="",1,2); + +DROP TABLE file; + +--echo # +--echo # End of test +--echo # diff --git a/sql/item_func.cc b/sql/item_func.cc index fe9a2976dfbdc..22280c46c3c3c 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -4840,9 +4840,17 @@ bool Item_func_set_user_var::fix_fields(THD *thd, Item **ref) if (!m_var_entry->charset() || !null_item) m_var_entry->set_charset(args[0]->collation.derivation == DERIVATION_NUMERIC ? &my_charset_numeric : args[0]->collation.collation); + /* + A user variable assignment (e.g. @p:=expr) must expose the same collation + derivation as reading the variable back with Item_func_get_user_var, which + uses DERIVATION_USERVAR (see MDEV-35041). Using DERIVATION_COERCIBLE here + made the assignment as strong as a string literal, causing "Illegal mix of + collations" conflicts against literals that carry the (possibly different) + connection collation (MDEV-39530). + */ collation.set(m_var_entry->charset(), args[0]->collation.derivation == DERIVATION_NUMERIC ? - DERIVATION_NUMERIC : DERIVATION_COERCIBLE); + DERIVATION_NUMERIC : DERIVATION_USERVAR); switch (args[0]->result_type()) { case STRING_RESULT: case TIME_RESULT: @@ -4907,7 +4915,7 @@ Item_func_set_user_var::fix_length_and_dec(THD *thd) } else { - collation.set(DERIVATION_COERCIBLE); + collation.set(DERIVATION_USERVAR); fix_length_and_charset(args[0]->max_char_length(), args[0]->collation.collation); }