Christopher van Damn
Christopher van Damn

Reputation: 71

MySql 5.7 Function UUID() default collation - Illegal mix of collations

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

Answers (2)

lyngvi
lyngvi

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

Rick James
Rick James

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

Related Questions