Reputation: 71
Problem: MySQL's uuid() default collation does not compare to configured connnection collation.
I have a database + tables + fields created with charset: utf-8 and collation utf8_polish_ci.
The my.cnf is as follows:
init_connect='SET NAMES utf8 COLLATE utf8_polish_ci'
character-set-server=utf8
collation-server=utf8_polish_ci
character sets:
mysql> show variables like "char%";
+--------------------------+----------------------------+
| Variable_name | Value |
+--------------------------+----------------------------+
| character_set_client | utf8 |
| character_set_connection | utf8 |
| character_set_database | utf8 |
| character_set_filesystem | binary |
| character_set_results | utf8 |
| character_set_server | utf8 |
| character_set_system | utf8 |
| character_sets_dir | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+
collations:
mysql> SHOW VARIABLES LIKE 'collation%';
+----------------------+----------------+
| Variable_name | Value |
+----------------------+----------------+
| collation_connection | utf8_polish_ci |
| collation_database | utf8_polish_ci |
| collation_server | utf8_polish_ci |
+----------------------+----------------+
Now, when using the uuid()
function, following error is returned:
mysql> select replace(uuid(),'-','');
ERROR 1270 (HY000): Illegal mix of collations (utf8_general_ci,COERCIBLE), (utf8_polish_ci,COERCIBLE), (utf8_polish_ci,COERCIBLE) for operation 'replace'
This happens, due to uuid()
's default collation seems to be utf8_general_ci.
mysql> select charset(uuid()), collation(uuid());
+-----------------+-------------------+
| charset(uuid()) | collation(uuid()) |
+-----------------+-------------------+
| utf8 | utf8_general_ci |
+-----------------+-------------------+
Is there a way, to change the default collation used by uuid() so that it matches the collation_connection
?
In our environment we write SQL updates that are executed on different MySQL databases with different collations. Therefore, to force a collation by specifying it is not an option.
Upvotes: 2
Views: 1536
Reputation: 1362
I found a straightforward, if daft-looking, workaround: cast(uuid() as char)
:
Example:
MariaDB [(none)]> set collation_connection = 'utf8_polish_ci';
Query OK, 0 rows affected (0.000 sec)
# Broken
MariaDB [(none)]> select replace(uuid(), '-', '');
ERROR 1270 (HY000): Illegal mix of collations (utf8_general_ci,COERCIBLE), (utf8_polish_ci,COERCIBLE), (utf8_polish_ci,COERCIBLE) for operation 'replace'
# Working
MariaDB [(none)]> select replace(cast(uuid() as char), '-', '');
+----------------------------------------+
| replace(cast(uuid() as char), '-', '') |
+----------------------------------------+
| 0e1bc84c0ffb11ec875c0242ac140002 |
+----------------------------------------+
1 row in set (0.000 sec)
What I believe is happening here is that uuid()
is generating a string with what is ultimately an arbitrarily-selected charset+collation (utf8_general_ci
I guess). Casting it to char
converts it to a string with the connection-specified charset+collation. This should match the charset+collation of the '-' and '' literals in the query.
MariaDB 10.3 is my environment. If I'm interpreting this correctly, I suspect the collation mismatch in the output of uuid()
is a bug - it should match connection collation here - and so I expect its behavior to change eventually.
Upvotes: 1
Reputation: 142218
(This is not really an answer, but an attempt at isolating what causes the problem and what might fix it.)
Get in a DATABASE
with a totally irrelevant CHARACTER SET
and COLLATION
.
mysql> CREATE DATABASE `so40064402` /*!40100 DEFAULT CHARACTER SET ucs2 COLLATE ucs2_bin */
mysql> USE so40064402;
Database changed
Establish utf8_polish for the client:
mysql> SET NAMES utf8 COLLATE utf8_polish_ci;
Query OK, 0 rows affected (0.00 sec)
mysql> SHOW VARIABLES LIKE 'c%a%t%';
+--------------------------+----------------------------+
| Variable_name | Value |
+--------------------------+----------------------------+
| character_set_client | utf8 | -- from SET NAMES
| character_set_connection | utf8 | -- from SET NAMES
| character_set_database | ucs2 | -- from DATABASE
| character_set_filesystem | binary | -- (constant)
| character_set_results | utf8 | -- from SET NAMES
| character_set_server | utf8mb4 |
| character_set_system | utf8 | -- (constant)
| character_sets_dir | /usr/share/mysql/charsets/ |
| collation_connection | utf8_polish_ci | -- from SET NAMES
| collation_database | ucs2_bin | -- from DATABASE
| collation_server | utf8mb4_unicode_520_ci |
+--------------------------+----------------------------+
11 rows in set (0.00 sec)
mysql> select charset(uuid()), collation(uuid());
+-----------------+-------------------+
| charset(uuid()) | collation(uuid()) |
+-----------------+-------------------+
| utf8 | utf8_general_ci | -- part of the problem, but can't fix this
+-----------------+-------------------+
1 row in set (0.00 sec)
mysql> select replace(uuid(),'-','');
ERROR 1270 (HY000): Illegal mix of collations
(utf8_general_ci,COERCIBLE),
(utf8_polish_ci,COERCIBLE),
(utf8_polish_ci,COERCIBLE) for operation 'replace'
mysql>
mysql>
mysql>
mysql> SET NAMES utf8mb4 COLLATE utf8mb4_polish_ci;
Query OK, 0 rows affected (0.00 sec)
Now let's change SET NAMES
only. Now it works!?? In spite of UUID()
being utf8
!?
mysql> SHOW VARIABLES LIKE 'c%a%t%';
+--------------------------+----------------------------+
| Variable_name | Value |
+--------------------------+----------------------------+
| character_set_client | utf8mb4 | -- from SET NAMES
| character_set_connection | utf8mb4 | -- from SET NAMES
| character_set_database | ucs2 |
| character_set_filesystem | binary |
| character_set_results | utf8mb4 | -- from SET NAMES
| character_set_server | utf8mb4 |
| character_set_system | utf8 |
| character_sets_dir | /usr/share/mysql/charsets/ |
| collation_connection | utf8mb4_polish_ci | -- from SET NAMES
| collation_database | ucs2_bin |
| collation_server | utf8mb4_unicode_520_ci |
+--------------------------+----------------------------+
11 rows in set (0.00 sec)
mysql> select replace(uuid(),'-','');
+----------------------------------+
| replace(uuid(),'-','') |
+----------------------------------+
| ea841aacf83b11e8a66580fa5b3669ce |
+----------------------------------+
1 row in set (0.00 sec)
mysql>
Upvotes: 1