From f800d9353d3f5c6ab9986c43fe6137eff010b41b Mon Sep 17 00:00:00 2001 From: Mohamed Date: Fri, 16 Jan 2026 17:58:42 +0200 Subject: [PATCH] MDEV-37442 Illegal mix of collations in mariadb-dump --system=user --- client/mysqldump.cc | 20 +++---- .../main/mysqldump-system-collation.result | 33 ++++++++++++ .../main/mysqldump-system-collation.test | 53 +++++++++++++++++++ 3 files changed, 97 insertions(+), 9 deletions(-) create mode 100644 mysql-test/main/mysqldump-system-collation.result create mode 100644 mysql-test/main/mysqldump-system-collation.test diff --git a/client/mysqldump.cc b/client/mysqldump.cc index 811bf73ab9088..000973f60ceff 100644 --- a/client/mysqldump.cc +++ b/client/mysqldump.cc @@ -4925,10 +4925,10 @@ static int dump_all_users_roles_and_grants() "SELECT CONCAT(QUOTE(u.user), '@', QUOTE(u.Host)) AS u " "FROM mysql.user u " " /*!80001 LEFT JOIN mysql.role_edges e " - " ON u.user=e.from_user " - " AND u.host=e.from_host " + " ON u.user=e.from_user COLLATE utf8mb4_bin " + " AND u.host=e.from_host COLLATE utf8mb4_bin " " WHERE e.from_user IS NULL */" - " /*M!100005 WHERE is_role='N' */")) + " /*M!100005 WHERE BINARY is_role='N' */")) return 1; while ((row= mysql_fetch_row(tableres))) { @@ -4995,7 +4995,7 @@ static int dump_all_users_roles_and_grants() " (SELECT 1 as n, roles_mapping.*" " FROM mysql.roles_mapping" " JOIN mysql.user USING (user,host)" - " WHERE is_role='N'" + " WHERE BINARY is_role='N'" " AND Admin_option='Y'" " UNION SELECT c.n+1, r.*" " FROM create_role_order c" @@ -5017,8 +5017,8 @@ static int dump_all_users_roles_and_grants() " (SELECT 1 AS n," " re.*" " FROM mysql.role_edges re" - " JOIN mysql.user u ON re.TO_HOST=u.HOST" - " AND re.TO_USER = u.USER" + " JOIN mysql.user u ON re.TO_HOST=u.HOST COLLATE utf8mb4_bin" + " AND re.TO_USER = u.USER COLLATE utf8mb4_bin" " LEFT JOIN mysql.role_edges re2 ON re.TO_USER=re2.FROM_USER" " AND re2.TO_HOST=re2.FROM_HOST" " WHERE re2.FROM_USER IS NULL" @@ -5061,13 +5061,15 @@ static int dump_all_users_roles_and_grants() if (maria_roles_exist && mysql_query_with_error_report(mysql, &tableres, "select IF(default_role='', 'NONE', QUOTE(default_role)) as r," "concat(QUOTE(User), '@', QUOTE(Host)) as u FROM mysql.user " - "/*M!100005 WHERE is_role='N' */")) + "/*M!100005 WHERE BINARY is_role='N' */")) return 1; if (mysql_roles_exist && mysql_query_with_error_report(mysql, &tableres, "SELECT IF(DEFAULT_ROLE_HOST IS NULL, 'NONE', CONCAT(QUOTE(DEFAULT_ROLE_USER)," " '@', QUOTE(DEFAULT_ROLE_HOST))) as r," " CONCAT(QUOTE(mu.USER),'@',QUOTE(mu.HOST)) as u " - "FROM mysql.user mu LEFT JOIN mysql.default_roles using (USER, HOST)")) + "FROM mysql.user mu LEFT JOIN mysql.default_roles dr" + " ON mu.USER = dr.USER COLLATE utf8mb4_bin" + " AND mu.HOST = dr.HOST COLLATE utf8mb4_bin")) { mysql_free_result(tableres); return 1; @@ -5086,7 +5088,7 @@ static int dump_all_users_roles_and_grants() "SELECT DISTINCT QUOTE(m.role) AS r " " FROM mysql.roles_mapping m" " JOIN mysql.user u ON u.user = m.role" - " WHERE is_role='Y'" + " WHERE BINARY is_role='Y'" " AND Admin_option='Y'" " ORDER BY m.role")) return 1; diff --git a/mysql-test/main/mysqldump-system-collation.result b/mysql-test/main/mysqldump-system-collation.result new file mode 100644 index 0000000000000..416f7b81c607b --- /dev/null +++ b/mysql-test/main/mysqldump-system-collation.result @@ -0,0 +1,33 @@ +# +# MDEV-37442: Illegal mix of collations during "mariadb-dump --system=user" +# +# After upgrading MariaDB (e.g. 11.2 -> 11.8), the mysql.user view +# retains the old default utf8mb4 collation while the connection uses +# the new one, causing collation mismatch errors in mysqldump --system=user. +# +SET @view_body = (SELECT VIEW_DEFINITION FROM INFORMATION_SCHEMA.VIEWS +WHERE TABLE_SCHEMA='mysql' AND TABLE_NAME='user'); +CREATE ROLE test_role_37442; +CREATE USER test_user_37442; +GRANT test_role_37442 TO test_user_37442; +SET DEFAULT ROLE test_role_37442 FOR test_user_37442; +ALTER TABLE mysql.roles_mapping ORDER BY Host, User, Role; +SET @save_collation = @@collation_connection; +SET collation_connection = 'utf8mb4_general_ci'; +SET @recreate_sql = CONCAT( +"CREATE OR REPLACE DEFINER='mariadb.sys'@'localhost' ", +"SQL SECURITY DEFINER VIEW mysql.user AS ", @view_body); +PREPARE stmt FROM @recreate_sql; +EXECUTE stmt; +DEALLOCATE PREPARE stmt; +SET collation_connection = @save_collation; +# mysqldump --system=user should succeed despite collation mismatch +# Cleanup +DROP USER test_user_37442; +DROP ROLE test_role_37442; +SET @recreate_sql = CONCAT( +"CREATE OR REPLACE DEFINER='mariadb.sys'@'localhost' ", +"SQL SECURITY DEFINER VIEW mysql.user AS ", @view_body); +PREPARE stmt FROM @recreate_sql; +EXECUTE stmt; +DEALLOCATE PREPARE stmt; diff --git a/mysql-test/main/mysqldump-system-collation.test b/mysql-test/main/mysqldump-system-collation.test new file mode 100644 index 0000000000000..24693dba1fd73 --- /dev/null +++ b/mysql-test/main/mysqldump-system-collation.test @@ -0,0 +1,53 @@ +--source include/not_embedded.inc + +--echo # +--echo # MDEV-37442: Illegal mix of collations during "mariadb-dump --system=user" +--echo # +--echo # After upgrading MariaDB (e.g. 11.2 -> 11.8), the mysql.user view +--echo # retains the old default utf8mb4 collation while the connection uses +--echo # the new one, causing collation mismatch errors in mysqldump --system=user. +--echo # + +# Save the mysql.user view definition to recreate it later +SET @view_body = (SELECT VIEW_DEFINITION FROM INFORMATION_SCHEMA.VIEWS + WHERE TABLE_SCHEMA='mysql' AND TABLE_NAME='user'); + +# Create roles so that role-related code paths in mysqldump are exercised +CREATE ROLE test_role_37442; +CREATE USER test_user_37442; +GRANT test_role_37442 TO test_user_37442; +SET DEFAULT ROLE test_role_37442 FOR test_user_37442; +ALTER TABLE mysql.roles_mapping ORDER BY Host, User, Role; + +# Recreate the mysql.user view with utf8mb4_general_ci collation +# to simulate a view created before the default collation changed +SET @save_collation = @@collation_connection; +SET collation_connection = 'utf8mb4_general_ci'; +SET @recreate_sql = CONCAT( + "CREATE OR REPLACE DEFINER='mariadb.sys'@'localhost' ", + "SQL SECURITY DEFINER VIEW mysql.user AS ", @view_body); +PREPARE stmt FROM @recreate_sql; +EXECUTE stmt; +DEALLOCATE PREPARE stmt; + +# Restore connection collation to the current default (utf8mb4_uca1400_ai_ci) +# This creates the mismatch: view uses utf8mb4_general_ci, connection uses +# utf8mb4_uca1400_ai_ci +SET collation_connection = @save_collation; + +--echo # mysqldump --system=user should succeed despite collation mismatch +--exec $MYSQL_DUMP --skip-comments --system=user > $MYSQLTEST_VARDIR/tmp/mdev37442.sql + +--echo # Cleanup +DROP USER test_user_37442; +DROP ROLE test_role_37442; + +# Restore the mysql.user view with current collation +SET @recreate_sql = CONCAT( + "CREATE OR REPLACE DEFINER='mariadb.sys'@'localhost' ", + "SQL SECURITY DEFINER VIEW mysql.user AS ", @view_body); +PREPARE stmt FROM @recreate_sql; +EXECUTE stmt; +DEALLOCATE PREPARE stmt; + +--remove_file $MYSQLTEST_VARDIR/tmp/mdev37442.sql