diff --git a/mysql-test/main/ctype_collate.result b/mysql-test/main/ctype_collate.result index e5fc353f1dba1..dc00cc028c521 100644 --- a/mysql-test/main/ctype_collate.result +++ b/mysql-test/main/ctype_collate.result @@ -808,3 +808,25 @@ ts 2024-01-26 21:38:02 drop table t1; # End of 10.6 tests +# +# 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 12.3 tests diff --git a/mysql-test/main/ctype_collate.test b/mysql-test/main/ctype_collate.test index 7a5fbdc74719b..a9433dc6f9dde 100644 --- a/mysql-test/main/ctype_collate.test +++ b/mysql-test/main/ctype_collate.test @@ -378,3 +378,28 @@ select * from t1 order by ts collate utf8_bin; drop table t1; --echo # End of 10.6 tests + +--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 # End of 12.3 tests 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/sql/item_func.cc b/sql/item_func.cc index fe9a2976dfbdc..7b55c62aea7ab 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: