1
0
Fork 0
mirror of https://github.com/MariaDB/server.git synced 2025-07-29 22:50:47 +02:00

MDEV-30164 System variable for default collations

This patch adds a way to override default collations
(or "character set collations") for desired character sets.

The SQL standard says:
> Each collation known in an SQL-environment is applicable to one
> or more character sets, and for each character set, one or more
> collations are applicable to it, one of which is associated with
> it as its character set collation.

In MariaDB, character set collations has been hard-coded so far,
e.g. utf8mb4_general_ci has been a hard-coded character set collation
for utf8mb4.

This patch allows to override (globally per server, or per session)
character set collations, so for example, uca1400_ai_ci can be set as a
character set collation for Unicode character sets
(instead of compiled xxx_general_ci).

The array of overridden character set collations is stored in a new
(session and global) system variable @@character_set_collations and
can be set as a comma separated list of charset=collation pairs, e.g.:

SET @@character_set_collations='utf8mb3=uca1400_ai_ci,utf8mb4=uca1400_ai_ci';

The variable is empty by default, which mean use the hard-coded
character set collations (e.g. utf8mb4_general_ci for utf8mb4).

The variable can also be set globally by passing to the server startup command
line, and/or in my.cnf.
This commit is contained in:
Alexander Barkov 2022-12-14 18:46:27 +04:00
commit 75f25e4ca7
59 changed files with 2228 additions and 111 deletions

View file

@ -52,6 +52,7 @@
#include "sql_string.h" // needed for Rpl_filter
#include "sql_list.h" // needed for Rpl_filter
#include "rpl_filter.h"
#include "charset_collations.h"
#include "mysqld.h"

View file

@ -129,7 +129,7 @@ SET(SQL_EMBEDDED_SOURCES emb_qcache.cc libmysqld.c lib_sql.cc
../sql/sql_analyze_stmt.cc ../sql/sql_analyze_stmt.h
../sql/compat56.cc
../sql/sql_schema.cc
../sql/lex_charset.cc
../sql/lex_charset.cc ../sql/charset_collations.cc
../sql/sql_type.cc ../sql/sql_type.h
../sql/sql_mode.cc
../sql/sql_type_string.cc

View file

@ -0,0 +1,291 @@
#
# MDEV-30164 System variable for default collations
#
SET @@character_set_collations= ' utf8mb3 = utf8mb3_bin , LATIN1 = LATIN1_BIN ';
SELECT @@character_set_collations;
@@character_set_collations
latin1=latin1_bin,utf8mb3=utf8mb3_bin
SET @@character_set_collations='';
SELECT @@character_set_collations;
@@character_set_collations
SET @@character_set_collations= ',,, utf8mb3 = utf8mb3_bin , , LATIN1 = LATIN1_BIN ,,';
SELECT @@character_set_collations;
@@character_set_collations
latin1=latin1_bin,utf8mb3=utf8mb3_bin
SET @@character_set_collations='';
SELECT @@character_set_collations;
@@character_set_collations
SET @@character_set_collations= 'utf8mb3 = utf8mb3_bin LATIN1 = LATIN1_BIN ';
ERROR 42000: Variable 'character_set_collations' can't be set to the value of 'utf8mb3 = utf8mb3_bin LATIN1 = LATIN1_BIN '
SELECT @@character_set_collations;
@@character_set_collations
SET @@character_set_collations= ' 123 ';
ERROR 42000: Variable 'character_set_collations' can't be set to the value of ' 123 '
SELECT @@character_set_collations;
@@character_set_collations
SET @@character_set_collations= ' utf8mb3 ';
ERROR 42000: Variable 'character_set_collations' can't be set to the value of ' utf8mb3 '
SELECT @@character_set_collations;
@@character_set_collations
SET @@character_set_collations= ' utf8mb3 = ';
ERROR 42000: Variable 'character_set_collations' can't be set to the value of ' utf8mb3 = '
SELECT @@character_set_collations;
@@character_set_collations
SET @@character_set_collations= ' utf8mb3 = 123 ';
ERROR 42000: Variable 'character_set_collations' can't be set to the value of ' utf8mb3 = 123 '
SELECT @@character_set_collations;
@@character_set_collations
SET @@character_set_collations='utf8mb3=utf8mb3_bin';
SELECT @@character_set_collations;
@@character_set_collations
utf8mb3=utf8mb3_bin
SET @@character_set_collations='';
SET @@character_set_collations='utf8mb3=utf8mb4_general_ci';
ERROR 42000: COLLATION 'utf8mb4_general_ci' is not valid for CHARACTER SET 'utf8mb3'
SELECT @@character_set_collations;
@@character_set_collations
SET @@character_set_collations='utf8mb4=utf8mb3_general_ci';
ERROR 42000: COLLATION 'utf8mb3_general_ci' is not valid for CHARACTER SET 'utf8mb4'
SELECT @@character_set_collations;
@@character_set_collations
SET @@character_set_collations='utf8mb3=utf8mb3_general_ci';
SELECT @@character_set_collations;
@@character_set_collations
utf8mb3=utf8mb3_general_ci
SET @@character_set_collations='utf8mb4=utf8mb4_general_ci,latin1=latin1_bin';
SELECT @@character_set_collations;
@@character_set_collations
latin1=latin1_bin,utf8mb4=utf8mb4_general_ci
SET @@character_set_collations='utf8mb4=uca1400_ai_ci,latin1=uca1400_ai_ci';
ERROR 42000: COLLATION 'uca1400_ai_ci' is not valid for CHARACTER SET 'latin1'
SELECT @@character_set_collations;
@@character_set_collations
latin1=latin1_bin,utf8mb4=utf8mb4_general_ci
SELECT @@character_set_collations RLIKE 'utf8mb4=utf8mb4_general_ci' AS expect_true;
expect_true
1
SET @@character_set_collations='utf8mb4=uca1400_ai_ci';
SELECT @@character_set_collations;
@@character_set_collations
utf8mb4=utf8mb4_uca1400_ai_ci
SET NAMES utf8mb4;
SELECT @@collation_connection;
@@collation_connection
utf8mb4_uca1400_ai_ci
SELECT collation('literal');
collation('literal')
utf8mb4_uca1400_ai_ci
EXECUTE IMMEDIATE 'SELECT COLLATION(?)' USING 'literal';
COLLATION(?)
utf8mb4_uca1400_ai_ci
CREATE VIEW v1 AS SELECT 'literal', collation('literal') as cl;
SHOW CREATE VIEW v1;
View Create View character_set_client collation_connection
v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select 'literal' AS `literal`,collation('literal') AS `cl` utf8mb4 utf8mb4_uca1400_ai_ci
SELECT * FROM v1;
literal cl
literal utf8mb4_uca1400_ai_ci
DROP VIEW v1;
SET NAMES utf8mb4 COLLATE utf8mb4_general_ci;
CREATE TABLE t1 (a TEXT CHARACTER SET utf8mb4);
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` text CHARACTER SET utf8mb4 COLLATE utf8mb4_uca1400_ai_ci DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
DROP TABLE t1;
CREATE TABLE t1 (a TEXT CHARACTER SET utf8mb4 COLLATE DEFAULT);
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` text CHARACTER SET utf8mb4 COLLATE utf8mb4_uca1400_ai_ci DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
DROP TABLE t1;
CREATE TABLE t1 (a TEXT COLLATE DEFAULT) CHARACTER SET utf8mb4;
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` text DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci
DROP TABLE t1;
CREATE TABLE t1 (a TEXT) CHARACTER SET utf8mb4;
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` text DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci
DROP TABLE t1;
CREATE DATABASE db1 CHARACTER SET utf8mb4;
SHOW CREATE DATABASE db1;
Database Create Database
db1 CREATE DATABASE `db1` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_uca1400_ai_ci */
DROP DATABASE db1;
SET NAMES utf8mb4 COLLATE utf8mb4_general_ci;
SELECT
@@collation_connection AS conn,
COLLATION('a') AS lit,
COLLATION(CONCAT(1)) AS num,
COLLATION(CAST(123 AS CHAR)) AS casti,
COLLATION(_utf8mb4'a') AS litu,
COLLATION(_utf8mb4 0x62) AS lituh,
COLLATION(_utf8mb4 X'63') AS lituhs,
COLLATION(CAST(123 AS CHAR CHARACTER SET utf8mb4)) AS castic,
COLLATION(CHAR(0x61 USING utf8mb4)) AS chr,
COLLATION(CONVERT('a' USING utf8mb4)) AS conv;;
conn utf8mb4_general_ci
lit utf8mb4_general_ci
num utf8mb4_general_ci
casti utf8mb4_general_ci
litu utf8mb4_uca1400_ai_ci
lituh utf8mb4_uca1400_ai_ci
lituhs utf8mb4_uca1400_ai_ci
castic utf8mb4_uca1400_ai_ci
chr utf8mb4_uca1400_ai_ci
conv utf8mb4_uca1400_ai_ci
SET NAMES utf8mb4;
SELECT
@@collation_connection AS conn,
COLLATION('a') AS lit,
COLLATION(CONCAT(1)) AS num,
COLLATION(CAST(123 AS CHAR)) AS casti,
COLLATION(_utf8mb4'a') AS litu,
COLLATION(_utf8mb4 0x62) AS lituh,
COLLATION(_utf8mb4 X'63') AS lituhs,
COLLATION(CAST(123 AS CHAR CHARACTER SET utf8mb4)) AS castic,
COLLATION(CHAR(0x61 USING utf8mb4)) AS chr,
COLLATION(CONVERT('a' USING utf8mb4)) AS conv;;
conn utf8mb4_uca1400_ai_ci
lit utf8mb4_uca1400_ai_ci
num utf8mb4_uca1400_ai_ci
casti utf8mb4_uca1400_ai_ci
litu utf8mb4_uca1400_ai_ci
lituh utf8mb4_uca1400_ai_ci
lituhs utf8mb4_uca1400_ai_ci
castic utf8mb4_uca1400_ai_ci
chr utf8mb4_uca1400_ai_ci
conv utf8mb4_uca1400_ai_ci
SET character_set_collations='latin1=latin1_bin,utf8mb4=uca1400_ai_ci';
SHOW CHARACTER SET LIKE 'latin1';
Charset Description Default collation Maxlen
latin1 cp1252 West European latin1_bin 1
SELECT * FROM INFORMATION_SCHEMA.CHARACTER_SETS
WHERE CHARACTER_SET_NAME='latin1';
CHARACTER_SET_NAME DEFAULT_COLLATE_NAME DESCRIPTION MAXLEN
latin1 latin1_bin cp1252 West European 1
SHOW COLLATION LIKE 'latin1%';
Collation Charset Id Default Compiled Sortlen
latin1_german1_ci latin1 5 Yes 1
latin1_swedish_ci latin1 8 Yes 1
latin1_danish_ci latin1 15 Yes 1
latin1_german2_ci latin1 31 Yes 2
latin1_bin latin1 47 Yes Yes 1
latin1_general_ci latin1 48 Yes 1
latin1_general_cs latin1 49 Yes 1
latin1_spanish_ci latin1 94 Yes 1
latin1_swedish_nopad_ci latin1 1032 Yes 1
latin1_nopad_bin latin1 1071 Yes 1
SELECT COLLATION_NAME, IS_DEFAULT
FROM INFORMATION_SCHEMA.COLLATIONS
WHERE CHARACTER_SET_NAME LIKE 'latin1%';
COLLATION_NAME IS_DEFAULT
latin1_german1_ci
latin1_swedish_ci
latin1_danish_ci
latin1_german2_ci
latin1_bin Yes
latin1_general_ci
latin1_general_cs
latin1_spanish_ci
latin1_swedish_nopad_ci
latin1_nopad_bin
SELECT COLLATION_NAME, FULL_COLLATION_NAME, IS_DEFAULT
FROM INFORMATION_SCHEMA.COLLATION_CHARACTER_SET_APPLICABILITY
WHERE COLLATION_NAME LIKE 'latin1%';
COLLATION_NAME FULL_COLLATION_NAME IS_DEFAULT
latin1_german1_ci latin1_german1_ci
latin1_swedish_ci latin1_swedish_ci
latin1_danish_ci latin1_danish_ci
latin1_german2_ci latin1_german2_ci
latin1_bin latin1_bin Yes
latin1_general_ci latin1_general_ci
latin1_general_cs latin1_general_cs
latin1_spanish_ci latin1_spanish_ci
latin1_swedish_nopad_ci latin1_swedish_nopad_ci
latin1_nopad_bin latin1_nopad_bin
SHOW CHARACTER SET LIKE 'utf8mb4';
Charset Description Default collation Maxlen
utf8mb4 UTF-8 Unicode utf8mb4_uca1400_ai_ci 4
SELECT * FROM INFORMATION_SCHEMA.CHARACTER_SETS
WHERE CHARACTER_SET_NAME='utf8mb4';
CHARACTER_SET_NAME DEFAULT_COLLATE_NAME DESCRIPTION MAXLEN
utf8mb4 utf8mb4_uca1400_ai_ci UTF-8 Unicode 4
SHOW COLLATION LIKE '%uca1400_ai_ci%';
Collation Charset Id Default Compiled Sortlen
uca1400_ai_ci NULL NULL NULL Yes 8
SELECT COLLATION_NAME, IS_DEFAULT
FROM INFORMATION_SCHEMA.COLLATIONS
WHERE COLLATION_NAME LIKE '%uca1400_ai_ci%';
COLLATION_NAME IS_DEFAULT
uca1400_ai_ci NULL
SELECT COLLATION_NAME, FULL_COLLATION_NAME, IS_DEFAULT
FROM INFORMATION_SCHEMA.COLLATION_CHARACTER_SET_APPLICABILITY
WHERE COLLATION_NAME LIKE '%uca1400_ai_ci%';
COLLATION_NAME FULL_COLLATION_NAME IS_DEFAULT
uca1400_ai_ci utf8mb3_uca1400_ai_ci
uca1400_ai_ci ucs2_uca1400_ai_ci
uca1400_ai_ci utf8mb4_uca1400_ai_ci Yes
uca1400_ai_ci utf16_uca1400_ai_ci
uca1400_ai_ci utf32_uca1400_ai_ci
SET @@character_set_collations='';
PREPARE stmt FROM 'SELECT '
'COLLATION(CAST("x" AS CHAR CHARACTER SET utf8mb3)) AS a, '
'COLLATION(_utf8mb3"x") AS b';
EXECUTE stmt;
a b
utf8mb3_general_ci utf8mb3_general_ci
SET @@character_set_collations='utf8mb3=utf8mb3_bin';
EXECUTE stmt;
a b
utf8mb3_bin utf8mb3_bin
SET @@character_set_collations='utf8mb3=utf8mb3_bin';
PREPARE stmt FROM 'SELECT '
'COLLATION(CAST("x" AS CHAR CHARACTER SET utf8mb3)) AS a, '
'COLLATION(_utf8mb3"x") AS b';
EXECUTE stmt;
a b
utf8mb3_bin utf8mb3_bin
SET @@character_set_collations=DEFAULT;
EXECUTE stmt;
a b
utf8mb3_general_ci utf8mb3_general_ci
SET NAMES utf8mb3;
SET @@character_set_collations='';
PREPARE stmt FROM 'CREATE TABLE t1 '
'(a TEXT CHARACTER SET utf8mb3 COLLATE DEFAULT COLLATE utf8mb3_general_ci)';
EXECUTE stmt;
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
DROP TABLE t1;
SET @@character_set_collations='utf8mb3=utf8mb3_bin';
EXECUTE stmt;
ERROR HY000: Conflicting declarations: 'COLLATE utf8mb3_bin' and 'COLLATE utf8mb3_general_ci'
SET @@character_set_collations='';
EXECUTE stmt;
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
DROP TABLE t1;

View file

@ -0,0 +1,237 @@
--source include/have_utf8.inc
--source include/have_utf8mb4.inc
--echo #
--echo # MDEV-30164 System variable for default collations
--echo #
SET @@character_set_collations= ' utf8mb3 = utf8mb3_bin , LATIN1 = LATIN1_BIN ';
SELECT @@character_set_collations;
SET @@character_set_collations='';
SELECT @@character_set_collations;
# Relaxed redundant comma parsing
SET @@character_set_collations= ',,, utf8mb3 = utf8mb3_bin , , LATIN1 = LATIN1_BIN ,,';
SELECT @@character_set_collations;
SET @@character_set_collations='';
SELECT @@character_set_collations;
# But at least one comma must be between pairs
--error ER_WRONG_VALUE_FOR_VAR
SET @@character_set_collations= 'utf8mb3 = utf8mb3_bin LATIN1 = LATIN1_BIN ';
SELECT @@character_set_collations;
--error ER_WRONG_VALUE_FOR_VAR
SET @@character_set_collations= ' 123 ';
SELECT @@character_set_collations;
--error ER_WRONG_VALUE_FOR_VAR
SET @@character_set_collations= ' utf8mb3 ';
SELECT @@character_set_collations;
--error ER_WRONG_VALUE_FOR_VAR
SET @@character_set_collations= ' utf8mb3 = ';
SELECT @@character_set_collations;
--error ER_WRONG_VALUE_FOR_VAR
SET @@character_set_collations= ' utf8mb3 = 123 ';
SELECT @@character_set_collations;
SET @@character_set_collations='utf8mb3=utf8mb3_bin';
SELECT @@character_set_collations;
SET @@character_set_collations='';
--error ER_COLLATION_CHARSET_MISMATCH
SET @@character_set_collations='utf8mb3=utf8mb4_general_ci';
SELECT @@character_set_collations;
--error ER_COLLATION_CHARSET_MISMATCH
SET @@character_set_collations='utf8mb4=utf8mb3_general_ci';
SELECT @@character_set_collations;
SET @@character_set_collations='utf8mb3=utf8mb3_general_ci';
SELECT @@character_set_collations;
SET @@character_set_collations='utf8mb4=utf8mb4_general_ci,latin1=latin1_bin';
SELECT @@character_set_collations;
--error ER_COLLATION_CHARSET_MISMATCH
SET @@character_set_collations='utf8mb4=uca1400_ai_ci,latin1=uca1400_ai_ci';
# All or nothing is set. "Nothing" in this case because of the error on latin1.
# The "uca1400_ai_ci FOR utf8mb4" part was ignored.
SELECT @@character_set_collations;
SELECT @@character_set_collations RLIKE 'utf8mb4=utf8mb4_general_ci' AS expect_true;
SET @@character_set_collations='utf8mb4=uca1400_ai_ci';
SELECT @@character_set_collations;
SET NAMES utf8mb4;
SELECT @@collation_connection;
# We have to disable --view-protocol for the following statement.
# 'mtr --view-protocol' creates a separate connection for these statements:
# CREATE VIEW mysqltest_tmp_sp AS ...;
# DROP VIEW mysqltest_tmp_sp;
# The current @@character_set_collations does not affect this connection.
# So --view-protocol would return the hard-coded character set collation here,
# instead of utf8mb4_uca1400_ai_ci
--disable_view_protocol
SELECT collation('literal');
--enable_view_protocol
EXECUTE IMMEDIATE 'SELECT COLLATION(?)' USING 'literal';
CREATE VIEW v1 AS SELECT 'literal', collation('literal') as cl;
SHOW CREATE VIEW v1;
SELECT * FROM v1;
DROP VIEW v1;
# Override @@collation_connection to utf8mb4_general_ci.
# Make sure that CREATE statements does not use @@collation_connection.
# to detect implicit collations.
# Implicit collations are detected using @@character_set_collations!
SET NAMES utf8mb4 COLLATE utf8mb4_general_ci;
CREATE TABLE t1 (a TEXT CHARACTER SET utf8mb4);
SHOW CREATE TABLE t1;
DROP TABLE t1;
CREATE TABLE t1 (a TEXT CHARACTER SET utf8mb4 COLLATE DEFAULT);
SHOW CREATE TABLE t1;
DROP TABLE t1;
CREATE TABLE t1 (a TEXT COLLATE DEFAULT) CHARACTER SET utf8mb4;
SHOW CREATE TABLE t1;
DROP TABLE t1;
CREATE TABLE t1 (a TEXT) CHARACTER SET utf8mb4;
SHOW CREATE TABLE t1;
DROP TABLE t1;
CREATE DATABASE db1 CHARACTER SET utf8mb4;
SHOW CREATE DATABASE db1;
DROP DATABASE db1;
# Test how @@character_set_collations affects various expressions
# with implicit collations.
let query=SELECT
@@collation_connection AS conn,
COLLATION('a') AS lit,
COLLATION(CONCAT(1)) AS num,
COLLATION(CAST(123 AS CHAR)) AS casti,
COLLATION(_utf8mb4'a') AS litu,
COLLATION(_utf8mb4 0x62) AS lituh,
COLLATION(_utf8mb4 X'63') AS lituhs,
COLLATION(CAST(123 AS CHAR CHARACTER SET utf8mb4)) AS castic,
COLLATION(CHAR(0x61 USING utf8mb4)) AS chr,
COLLATION(CONVERT('a' USING utf8mb4)) AS conv;
# The below SET NAMES sets @@collation_connection to utf8mb4_general_ci.
# But @@character_set_collations still contains utf8mb4=uca1400_ai_ci.
SET NAMES utf8mb4 COLLATE utf8mb4_general_ci;
# Columns expected to print utf8mb4_general_ci
# because they use @@collation_connection:
# - String literals without introducers
# - Automatic number-to-string conversions
# - CAST(AS CHAR) - without USING
#
# Columns expected to print utf8mb4_uca1400_ai_ci
# because they use the current session default collation
# for the character set (as specified in @@collation_connection)
# - String literals with introducers
# - CAST(AS CHAR USING cs)
# - CHAR()
# - CONVERT()
--vertical_results
--eval $query;
--horizontal_results
# This sets collation_connection to utf8mb4_uca1400_ai_ci
# according to @@character_set_collations.
SET NAMES utf8mb4;
# Now all columns are expected to print utf8mb4_uca1400_ai_ci:
# - Some columns because @@collation_connection says so
# - Some columns because @@character_set_collations says so.
--vertical_results
--eval $query;
--horizontal_results
#
# INFORMATION_SCHEMA
#
SET character_set_collations='latin1=latin1_bin,utf8mb4=uca1400_ai_ci';
SHOW CHARACTER SET LIKE 'latin1';
SELECT * FROM INFORMATION_SCHEMA.CHARACTER_SETS
WHERE CHARACTER_SET_NAME='latin1';
SHOW COLLATION LIKE 'latin1%';
SELECT COLLATION_NAME, IS_DEFAULT
FROM INFORMATION_SCHEMA.COLLATIONS
WHERE CHARACTER_SET_NAME LIKE 'latin1%';
SELECT COLLATION_NAME, FULL_COLLATION_NAME, IS_DEFAULT
FROM INFORMATION_SCHEMA.COLLATION_CHARACTER_SET_APPLICABILITY
WHERE COLLATION_NAME LIKE 'latin1%';
SHOW CHARACTER SET LIKE 'utf8mb4';
SELECT * FROM INFORMATION_SCHEMA.CHARACTER_SETS
WHERE CHARACTER_SET_NAME='utf8mb4';
SHOW COLLATION LIKE '%uca1400_ai_ci%';
SELECT COLLATION_NAME, IS_DEFAULT
FROM INFORMATION_SCHEMA.COLLATIONS
WHERE COLLATION_NAME LIKE '%uca1400_ai_ci%';
SELECT COLLATION_NAME, FULL_COLLATION_NAME, IS_DEFAULT
FROM INFORMATION_SCHEMA.COLLATION_CHARACTER_SET_APPLICABILITY
WHERE COLLATION_NAME LIKE '%uca1400_ai_ci%';
#
# Prepared statements: reprepare on @@character_set_collations change.
#
SET @@character_set_collations='';
PREPARE stmt FROM 'SELECT '
'COLLATION(CAST("x" AS CHAR CHARACTER SET utf8mb3)) AS a, '
'COLLATION(_utf8mb3"x") AS b';
EXECUTE stmt;
SET @@character_set_collations='utf8mb3=utf8mb3_bin';
EXECUTE stmt;
SET @@character_set_collations='utf8mb3=utf8mb3_bin';
PREPARE stmt FROM 'SELECT '
'COLLATION(CAST("x" AS CHAR CHARACTER SET utf8mb3)) AS a, '
'COLLATION(_utf8mb3"x") AS b';
EXECUTE stmt;
SET @@character_set_collations=DEFAULT;
EXECUTE stmt;
SET NAMES utf8mb3;
SET @@character_set_collations='';
PREPARE stmt FROM 'CREATE TABLE t1 '
'(a TEXT CHARACTER SET utf8mb3 COLLATE DEFAULT COLLATE utf8mb3_general_ci)';
EXECUTE stmt;
SHOW CREATE TABLE t1;
DROP TABLE t1;
SET @@character_set_collations='utf8mb3=utf8mb3_bin';
--error ER_CONFLICTING_DECLARATIONS
EXECUTE stmt;
SET @@character_set_collations='';
EXECUTE stmt;
SHOW CREATE TABLE t1;
DROP TABLE t1;

View file

@ -0,0 +1 @@
--character-set-collations=utf8mb3=uca1400_ai_ci,latin1=latin1_bin

View file

@ -0,0 +1,85 @@
#
# MDEV-30164 System variable for default collations
#
SELECT @@global.character_set_collations;
@@global.character_set_collations
latin1=latin1_bin,utf8mb3=utf8mb3_uca1400_ai_ci
SELECT @@session.character_set_collations;
@@session.character_set_collations
latin1=latin1_bin,utf8mb3=utf8mb3_uca1400_ai_ci
SELECT COLLATION('literal');
COLLATION('literal')
latin1_bin
CREATE TABLE t1 AS SELECT 'literal' AS c1;
SELECT COLLATION_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name='t1';
COLLATION_NAME
latin1_bin
DROP TABLE t1;
SET NAMES utf8mb3;
SELECT COLLATION('literal');
COLLATION('literal')
utf8mb3_uca1400_ai_ci
CREATE TABLE t1 AS SELECT 'literal' AS c1;
SELECT COLLATION_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name='t1';
COLLATION_NAME
utf8mb3_uca1400_ai_ci
DROP TABLE t1;
SET @@session.character_set_collations='latin1=latin1_german2_ci';
SELECT @@session.character_set_collations;
@@session.character_set_collations
latin1=latin1_german2_ci
SET @@session.character_set_collations=DEFAULT;
SELECT @@session.character_set_collations;
@@session.character_set_collations
latin1=latin1_bin,utf8mb3=utf8mb3_uca1400_ai_ci
SET @@global.character_set_collations='utf8mb3=uca1400_as_ci,latin1=latin1_danish_ci';
connect con1,localhost,root,,;
connection con1;
SELECT @@session.character_set_collations;
@@session.character_set_collations
latin1=latin1_danish_ci,utf8mb3=utf8mb3_uca1400_as_ci
SELECT COLLATION('literal');
COLLATION('literal')
latin1_danish_ci
CREATE TABLE t1 AS SELECT 'literal' AS c1;
SELECT COLLATION_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name='t1';
COLLATION_NAME
latin1_danish_ci
DROP TABLE t1;
disconnect con1;
connection default;
SET @@global.character_set_collations=DEFAULT;
SELECT @@global.character_set_collations;
@@global.character_set_collations
connect con2,localhost,root,,;
connection con2;
SELECT @@session.character_set_collations;
@@session.character_set_collations
SELECT COLLATION('literal');
COLLATION('literal')
latin1_swedish_ci
CREATE TABLE t1 AS SELECT 'literal' AS c1;
SELECT COLLATION_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name='t1';
COLLATION_NAME
latin1_swedish_ci
DROP TABLE t1;
disconnect con2;
connection default;
SET @@global.character_set_collations='utf8mb3=uca1400_ai_ci,latin1=latin1_bin';
connect con3,localhost,root,,;
connection con3;
SELECT @@session.character_set_collations;
@@session.character_set_collations
latin1=latin1_bin,utf8mb3=utf8mb3_uca1400_ai_ci
SELECT COLLATION('literal');
COLLATION('literal')
latin1_bin
CREATE TABLE t1 AS SELECT 'literal' AS c1;
SELECT COLLATION_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name='t1';
COLLATION_NAME
latin1_bin
DROP TABLE t1;
disconnect con3;
connection default;

View file

@ -0,0 +1,73 @@
--source include/have_utf8.inc
--source include/have_utf8mb4.inc
--echo #
--echo # MDEV-30164 System variable for default collations
--echo #
SELECT @@global.character_set_collations;
SELECT @@session.character_set_collations;
--disable_view_protocol
SELECT COLLATION('literal');
--enable_view_protocol
CREATE TABLE t1 AS SELECT 'literal' AS c1;
SELECT COLLATION_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name='t1';
DROP TABLE t1;
SET NAMES utf8mb3;
--disable_view_protocol
SELECT COLLATION('literal');
--enable_view_protocol
CREATE TABLE t1 AS SELECT 'literal' AS c1;
SELECT COLLATION_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name='t1';
DROP TABLE t1;
SET @@session.character_set_collations='latin1=latin1_german2_ci';
SELECT @@session.character_set_collations;
SET @@session.character_set_collations=DEFAULT;
SELECT @@session.character_set_collations;
SET @@global.character_set_collations='utf8mb3=uca1400_as_ci,latin1=latin1_danish_ci';
--connect (con1,localhost,root,,)
--connection con1
SELECT @@session.character_set_collations;
--disable_view_protocol
SELECT COLLATION('literal');
--enable_view_protocol
CREATE TABLE t1 AS SELECT 'literal' AS c1;
SELECT COLLATION_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name='t1';
DROP TABLE t1;
--disconnect con1
--connection default
SET @@global.character_set_collations=DEFAULT;
SELECT @@global.character_set_collations;
--connect (con2,localhost,root,,)
--connection con2
SELECT @@session.character_set_collations;
--disable_view_protocol
SELECT COLLATION('literal');
--enable_view_protocol
CREATE TABLE t1 AS SELECT 'literal' AS c1;
SELECT COLLATION_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name='t1';
DROP TABLE t1;
--disconnect con2
--connection default
# Set back to the command line value, to avoid mtr internal check failure.
SET @@global.character_set_collations='utf8mb3=uca1400_ai_ci,latin1=latin1_bin';
--connect (con3,localhost,root,,)
--connection con3
SELECT @@session.character_set_collations;
--disable_view_protocol
SELECT COLLATION('literal');
--enable_view_protocol
CREATE TABLE t1 AS SELECT 'literal' AS c1;
SELECT COLLATION_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name='t1';
DROP TABLE t1;
--disconnect con3
--connection default

View file

@ -0,0 +1,19 @@
#
# MDEV-30164 System variable for default collations
#
SET @@character_set_collations= CONVERT('latin1=latin1_bin,utf8mb3=utf8mb3_bin' USING utf32);
SELECT @@character_set_collations;
@@character_set_collations
latin1=latin1_bin,utf8mb3=utf8mb3_bin
SET @@character_set_collations=_utf32'';
SELECT @@character_set_collations;
@@character_set_collations
SET @@character_set_collations= CONVERT('utf32=utf32_bin' USING utf32);
SELECT @@character_set_collations;
@@character_set_collations
utf32=utf32_bin
SET @@character_set_collations='';
SELECT @@character_set_collations;
@@character_set_collations

View file

@ -0,0 +1,16 @@
--source include/have_utf8.inc
--source include/have_utf32.inc
--echo #
--echo # MDEV-30164 System variable for default collations
--echo #
SET @@character_set_collations= CONVERT('latin1=latin1_bin,utf8mb3=utf8mb3_bin' USING utf32);
SELECT @@character_set_collations;
SET @@character_set_collations=_utf32'';
SELECT @@character_set_collations;
SET @@character_set_collations= CONVERT('utf32=utf32_bin' USING utf32);
SELECT @@character_set_collations;
SET @@character_set_collations='';
SELECT @@character_set_collations;

View file

@ -1819,6 +1819,7 @@ SET CHARACTER SET utf8;
SHOW VARIABLES LIKE 'character\_set\_%';
Variable_name Value
character_set_client utf8mb3
character_set_collations
character_set_connection latin1
character_set_database latin1
character_set_filesystem binary

View file

@ -1844,6 +1844,7 @@ SET CHARACTER SET utf8mb4;
SHOW VARIABLES LIKE 'character\_set\_%';
Variable_name Value
character_set_client utf8mb4
character_set_collations
character_set_connection latin1
character_set_database latin1
character_set_filesystem binary

View file

@ -1676,6 +1676,7 @@ SET CHARACTER SET utf8mb4;
SHOW VARIABLES LIKE 'character\_set\_%';
Variable_name Value
character_set_client utf8mb4
character_set_collations
character_set_connection latin1
character_set_database latin1
character_set_filesystem binary

View file

@ -1802,6 +1802,7 @@ SET CHARACTER SET utf8mb4;
SHOW VARIABLES LIKE 'character\_set\_%';
Variable_name Value
character_set_client utf8mb4
character_set_collations
character_set_connection latin1
character_set_database latin1
character_set_filesystem binary

View file

@ -1809,6 +1809,7 @@ SET CHARACTER SET utf8mb4;
SHOW VARIABLES LIKE 'character\_set\_%';
Variable_name Value
character_set_client utf8mb4
character_set_collations
character_set_connection latin1
character_set_database latin1
character_set_filesystem binary

View file

@ -564,6 +564,7 @@ SET @@session.sql_mode=#/*!*/;
SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/;
/*!\C latin1 *//*!*/;
SET @@session.character_set_client=latin1,@@session.collation_connection=8,@@session.collation_server=#/*!*/;
SET @@session.character_set_collations=''/*!*/;
SET @@session.lc_time_names=0/*!*/;
SET @@session.collation_database=DEFAULT/*!*/;
create table t1 (a varchar(64) character set utf8)

View file

@ -144,6 +144,8 @@ The following specify which files/extra groups are read (specified before remain
Don't ignore client side character set value sent during
handshake.
(Defaults to on; use --skip-character-set-client-handshake to disable.)
--character-set-collations=name
Overrides for character set default collations.
--character-set-filesystem=name
Set the filesystem character set.
-C, --character-set-server=name
@ -1574,6 +1576,7 @@ binlog-row-metadata NO_LOG
binlog-stmt-cache-size 32768
bulk-insert-buffer-size 8388608
character-set-client-handshake TRUE
character-set-collations
character-set-filesystem binary
character-sets-dir MYSQL_CHARSETSDIR/
chroot (No default value)

View file

@ -1934,7 +1934,6 @@ START TRANSACTION
# at #
#010909 4:46:40 server id 1 end_log_pos # CRC32 XXX Query thread_id=# exec_time=# error_code=0 xid=<xid>
SET TIMESTAMP=1000000000/*!*/;
SET @@session.time_zone='SYSTEM'/*!*/;
COMMIT
/*!*/;
# at #
@ -2320,6 +2319,7 @@ DROP TABLE `t1` /* generated by server */
# at #
#010909 4:46:40 server id 1 end_log_pos # CRC32 XXX Query thread_id=# exec_time=# error_code=0 xid=<xid>
SET TIMESTAMP=1000000000/*!*/;
SET @@session.character_set_collations=''/*!*/;
CREATE TABLE t1 (c37 NATIONAL CHAR)
/*!*/;
# at #
@ -2378,6 +2378,7 @@ DROP TABLE `t1` /* generated by server */
# at #
#010909 4:46:40 server id 1 end_log_pos # CRC32 XXX Query thread_id=# exec_time=# error_code=0 xid=<xid>
SET TIMESTAMP=1000000000/*!*/;
SET @@session.character_set_collations=''/*!*/;
CREATE TABLE t1 (c38 NATIONAL CHAR(0))
/*!*/;
# at #
@ -2436,6 +2437,7 @@ DROP TABLE `t1` /* generated by server */
# at #
#010909 4:46:40 server id 1 end_log_pos # CRC32 XXX Query thread_id=# exec_time=# error_code=0 xid=<xid>
SET TIMESTAMP=1000000000/*!*/;
SET @@session.character_set_collations=''/*!*/;
CREATE TABLE t1 (c39 NATIONAL CHAR(1))
/*!*/;
# at #
@ -2494,6 +2496,7 @@ DROP TABLE `t1` /* generated by server */
# at #
#010909 4:46:40 server id 1 end_log_pos # CRC32 XXX Query thread_id=# exec_time=# error_code=0 xid=<xid>
SET TIMESTAMP=1000000000/*!*/;
SET @@session.character_set_collations=''/*!*/;
CREATE TABLE t1 (c40 NATIONAL CHAR(255))
/*!*/;
# at #
@ -2576,6 +2579,7 @@ DROP TABLE `t1` /* generated by server */
# at #
#010909 4:46:40 server id 1 end_log_pos # CRC32 XXX Query thread_id=# exec_time=# error_code=0 xid=<xid>
SET TIMESTAMP=1000000000/*!*/;
SET @@session.character_set_collations=''/*!*/;
CREATE TABLE t1 (c41 CHAR CHARACTER SET UCS2)
/*!*/;
# at #
@ -2634,6 +2638,7 @@ DROP TABLE `t1` /* generated by server */
# at #
#010909 4:46:40 server id 1 end_log_pos # CRC32 XXX Query thread_id=# exec_time=# error_code=0 xid=<xid>
SET TIMESTAMP=1000000000/*!*/;
SET @@session.character_set_collations=''/*!*/;
CREATE TABLE t1 (c42 CHAR(0) CHARACTER SET UCS2)
/*!*/;
# at #
@ -2692,6 +2697,7 @@ DROP TABLE `t1` /* generated by server */
# at #
#010909 4:46:40 server id 1 end_log_pos # CRC32 XXX Query thread_id=# exec_time=# error_code=0 xid=<xid>
SET TIMESTAMP=1000000000/*!*/;
SET @@session.character_set_collations=''/*!*/;
CREATE TABLE t1 (c43 CHAR(1) CHARACTER SET UCS2)
/*!*/;
# at #
@ -2750,6 +2756,7 @@ DROP TABLE `t1` /* generated by server */
# at #
#010909 4:46:40 server id 1 end_log_pos # CRC32 XXX Query thread_id=# exec_time=# error_code=0 xid=<xid>
SET TIMESTAMP=1000000000/*!*/;
SET @@session.character_set_collations=''/*!*/;
CREATE TABLE t1 (c44 CHAR(255) CHARACTER SET UCS2)
/*!*/;
# at #
@ -3064,6 +3071,7 @@ DROP TABLE `t1` /* generated by server */
# at #
#010909 4:46:40 server id 1 end_log_pos # CRC32 XXX Query thread_id=# exec_time=# error_code=0 xid=<xid>
SET TIMESTAMP=1000000000/*!*/;
SET @@session.character_set_collations=''/*!*/;
CREATE TABLE t1 (c49 NATIONAL VARCHAR(0))
/*!*/;
# at #
@ -3122,6 +3130,7 @@ DROP TABLE `t1` /* generated by server */
# at #
#010909 4:46:40 server id 1 end_log_pos # CRC32 XXX Query thread_id=# exec_time=# error_code=0 xid=<xid>
SET TIMESTAMP=1000000000/*!*/;
SET @@session.character_set_collations=''/*!*/;
CREATE TABLE t1 (c50 NATIONAL VARCHAR(1))
/*!*/;
# at #
@ -3180,6 +3189,7 @@ DROP TABLE `t1` /* generated by server */
# at #
#010909 4:46:40 server id 1 end_log_pos # CRC32 XXX Query thread_id=# exec_time=# error_code=0 xid=<xid>
SET TIMESTAMP=1000000000/*!*/;
SET @@session.character_set_collations=''/*!*/;
CREATE TABLE t1 (c51 NATIONAL VARCHAR(255))
/*!*/;
# at #
@ -3262,6 +3272,7 @@ DROP TABLE `t1` /* generated by server */
# at #
#010909 4:46:40 server id 1 end_log_pos # CRC32 XXX Query thread_id=# exec_time=# error_code=0 xid=<xid>
SET TIMESTAMP=1000000000/*!*/;
SET @@session.character_set_collations=''/*!*/;
CREATE TABLE t1 (c52 NATIONAL VARCHAR(261))
/*!*/;
# at #
@ -3344,6 +3355,7 @@ DROP TABLE `t1` /* generated by server */
# at #
#010909 4:46:40 server id 1 end_log_pos # CRC32 XXX Query thread_id=# exec_time=# error_code=0 xid=<xid>
SET TIMESTAMP=1000000000/*!*/;
SET @@session.character_set_collations=''/*!*/;
CREATE TABLE t1 (c53 VARCHAR(0) CHARACTER SET ucs2)
/*!*/;
# at #
@ -3402,6 +3414,7 @@ DROP TABLE `t1` /* generated by server */
# at #
#010909 4:46:40 server id 1 end_log_pos # CRC32 XXX Query thread_id=# exec_time=# error_code=0 xid=<xid>
SET TIMESTAMP=1000000000/*!*/;
SET @@session.character_set_collations=''/*!*/;
CREATE TABLE t1 (c54 VARCHAR(1) CHARACTER SET ucs2)
/*!*/;
# at #
@ -3460,6 +3473,7 @@ DROP TABLE `t1` /* generated by server */
# at #
#010909 4:46:40 server id 1 end_log_pos # CRC32 XXX Query thread_id=# exec_time=# error_code=0 xid=<xid>
SET TIMESTAMP=1000000000/*!*/;
SET @@session.character_set_collations=''/*!*/;
CREATE TABLE t1 (c55 VARCHAR(255) CHARACTER SET ucs2)
/*!*/;
# at #
@ -3518,6 +3532,7 @@ DROP TABLE `t1` /* generated by server */
# at #
#010909 4:46:40 server id 1 end_log_pos # CRC32 XXX Query thread_id=# exec_time=# error_code=0 xid=<xid>
SET TIMESTAMP=1000000000/*!*/;
SET @@session.character_set_collations=''/*!*/;
CREATE TABLE t1 (c56 VARCHAR(261) CHARACTER SET ucs2)
/*!*/;
# at #
@ -4656,6 +4671,7 @@ DROP TABLE `t1` /* generated by server */
# at #
#010909 4:46:40 server id 1 end_log_pos # CRC32 XXX Query thread_id=# exec_time=# error_code=0 xid=<xid>
SET TIMESTAMP=1000000000/*!*/;
SET @@session.character_set_collations=''/*!*/;
CREATE TABLE t1 (c67 TINYTEXT CHARACTER SET UCS2)
/*!*/;
# at #
@ -4714,6 +4730,7 @@ DROP TABLE `t1` /* generated by server */
# at #
#010909 4:46:40 server id 1 end_log_pos # CRC32 XXX Query thread_id=# exec_time=# error_code=0 xid=<xid>
SET TIMESTAMP=1000000000/*!*/;
SET @@session.character_set_collations=''/*!*/;
CREATE TABLE t1 (c70 TEXT CHARACTER SET UCS2)
/*!*/;
# at #
@ -4772,6 +4789,7 @@ DROP TABLE `t1` /* generated by server */
# at #
#010909 4:46:40 server id 1 end_log_pos # CRC32 XXX Query thread_id=# exec_time=# error_code=0 xid=<xid>
SET TIMESTAMP=1000000000/*!*/;
SET @@session.character_set_collations=''/*!*/;
CREATE TABLE t1 (c73 MEDIUMTEXT CHARACTER SET UCS2)
/*!*/;
# at #
@ -4830,6 +4848,7 @@ DROP TABLE `t1` /* generated by server */
# at #
#010909 4:46:40 server id 1 end_log_pos # CRC32 XXX Query thread_id=# exec_time=# error_code=0 xid=<xid>
SET TIMESTAMP=1000000000/*!*/;
SET @@session.character_set_collations=''/*!*/;
CREATE TABLE t1 (c76 LONGTEXT CHARACTER SET UCS2)
/*!*/;
# at #

View file

@ -2275,6 +2275,7 @@ SET @@session.sql_mode=0/*!*/;
SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/;
/*!\C utf8mb3 *//*!*/;
SET @@session.character_set_client=utf8mb3,@@session.collation_connection=33,@@session.collation_server=X/*!*/;
SET @@session.character_set_collations=''/*!*/;
SET @@session.lc_time_names=0/*!*/;
SET @@session.collation_database=DEFAULT/*!*/;
CREATE TABLE t1 (
@ -5284,6 +5285,7 @@ SET @@session.sql_mode=0/*!*/;
SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/;
/*!\C utf8mb3 *//*!*/;
SET @@session.character_set_client=utf8mb3,@@session.collation_connection=33,@@session.collation_server=X/*!*/;
SET @@session.character_set_collations=''/*!*/;
SET @@session.lc_time_names=0/*!*/;
SET @@session.collation_database=DEFAULT/*!*/;
CREATE TABLE t1 (
@ -5684,6 +5686,7 @@ SET @@session.sql_mode=0/*!*/;
SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/;
/*!\C utf8mb3 *//*!*/;
SET @@session.character_set_client=utf8mb3,@@session.collation_connection=33,@@session.collation_server=X/*!*/;
SET @@session.character_set_collations=''/*!*/;
SET @@session.lc_time_names=0/*!*/;
SET @@session.collation_database=DEFAULT/*!*/;
CREATE TABLE t1 (
@ -5698,6 +5701,7 @@ c_1_n INT -- row number
# at #
#010909 4:46:40 server id 1 end_log_pos # CRC32 XXX Query thread_id=# exec_time=# error_code=0 xid=<xid>
SET TIMESTAMP=1000000000/*!*/;
SET @@session.character_set_collations=''/*!*/;
CREATE TABLE t2 (
c_2_1 DATE,
c_2_2 VARCHAR(255),
@ -5710,6 +5714,7 @@ c_2_n INT -- row number
# at #
#010909 4:46:40 server id 1 end_log_pos # CRC32 XXX Query thread_id=# exec_time=# error_code=0 xid=<xid>
SET TIMESTAMP=1000000000/*!*/;
SET @@session.character_set_collations=''/*!*/;
CREATE TABLE t3 (
c_3_1 DATE,
c_3_2 VARCHAR(255),
@ -6322,6 +6327,7 @@ SET @@session.sql_mode=0/*!*/;
SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/;
/*!\C utf8mb3 *//*!*/;
SET @@session.character_set_client=utf8mb3,@@session.collation_connection=33,@@session.collation_server=X/*!*/;
SET @@session.character_set_collations=''/*!*/;
SET @@session.lc_time_names=0/*!*/;
SET @@session.collation_database=DEFAULT/*!*/;
CREATE TABLE t1 (

View file

@ -2273,6 +2273,7 @@ SET @@session.sql_mode=0/*!*/;
SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/;
/*!\C utf8mb3 *//*!*/;
SET @@session.character_set_client=utf8mb3,@@session.collation_connection=33,@@session.collation_server=X/*!*/;
SET @@session.character_set_collations=''/*!*/;
SET @@session.lc_time_names=0/*!*/;
SET @@session.collation_database=DEFAULT/*!*/;
CREATE TABLE t1 (
@ -2547,7 +2548,6 @@ START TRANSACTION
# at #
#010909 4:46:40 server id 1 end_log_pos # CRC32 XXX Query thread_id=# exec_time=# error_code=0 xid=<xid>
SET TIMESTAMP=1000000000/*!*/;
SET @@session.time_zone='SYSTEM'/*!*/;
COMMIT
/*!*/;
# at #
@ -5305,6 +5305,7 @@ SET @@session.sql_mode=0/*!*/;
SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/;
/*!\C utf8mb3 *//*!*/;
SET @@session.character_set_client=utf8mb3,@@session.collation_connection=33,@@session.collation_server=X/*!*/;
SET @@session.character_set_collations=''/*!*/;
SET @@session.lc_time_names=0/*!*/;
SET @@session.collation_database=DEFAULT/*!*/;
CREATE TABLE t1 (
@ -5711,6 +5712,7 @@ SET @@session.sql_mode=0/*!*/;
SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/;
/*!\C utf8mb3 *//*!*/;
SET @@session.character_set_client=utf8mb3,@@session.collation_connection=33,@@session.collation_server=X/*!*/;
SET @@session.character_set_collations=''/*!*/;
SET @@session.lc_time_names=0/*!*/;
SET @@session.collation_database=DEFAULT/*!*/;
CREATE TABLE t1 (
@ -5725,6 +5727,7 @@ c_1_n INT -- row number
# at #
#010909 4:46:40 server id 1 end_log_pos # CRC32 XXX Query thread_id=# exec_time=# error_code=0 xid=<xid>
SET TIMESTAMP=1000000000/*!*/;
SET @@session.character_set_collations=''/*!*/;
CREATE TABLE t2 (
c_2_1 DATE,
c_2_2 VARCHAR(255),
@ -5737,6 +5740,7 @@ c_2_n INT -- row number
# at #
#010909 4:46:40 server id 1 end_log_pos # CRC32 XXX Query thread_id=# exec_time=# error_code=0 xid=<xid>
SET TIMESTAMP=1000000000/*!*/;
SET @@session.character_set_collations=''/*!*/;
CREATE TABLE t3 (
c_3_1 DATE,
c_3_2 VARCHAR(255),
@ -6359,6 +6363,7 @@ SET @@session.sql_mode=0/*!*/;
SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/;
/*!\C utf8mb3 *//*!*/;
SET @@session.character_set_client=utf8mb3,@@session.collation_connection=33,@@session.collation_server=X/*!*/;
SET @@session.character_set_collations=''/*!*/;
SET @@session.lc_time_names=0/*!*/;
SET @@session.collation_database=DEFAULT/*!*/;
CREATE TABLE t1 (

View file

@ -151,6 +151,7 @@ SET @@session.sql_mode=1411383296/*!*/;
SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/;
/*!\C latin1 *//*!*/;
SET @@session.character_set_client=X,@@session.collation_connection=X,@@session.collation_server=X/*!*/;
SET @@session.character_set_collations=''/*!*/;
SET @@session.lc_time_names=0/*!*/;
SET @@session.collation_database=DEFAULT/*!*/;
CREATE TABLE t1 (
@ -164,6 +165,7 @@ c2 VARCHAR(20)
# at #
#010909 4:46:40 server id 1 end_log_pos # CRC32 XXX Query thread_id=# exec_time=# error_code=0 xid=<xid>
SET TIMESTAMP=1000000000/*!*/;
SET @@session.character_set_collations=''/*!*/;
CREATE TABLE t2 (
c1 INT,
c2 VARCHAR(20)

View file

@ -97,6 +97,7 @@ SET @@session.sql_mode=1411383296/*!*/;
SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/;
/*!\C utf8mb3 *//*!*/;
SET @@session.character_set_client=X,@@session.collation_connection=X,@@session.collation_server=X/*!*/;
SET @@session.character_set_collations=''/*!*/;
SET @@session.lc_time_names=0/*!*/;
SET @@session.collation_database=DEFAULT/*!*/;
CREATE TABLE t1 (a VARCHAR(10) CHARACTER SET utf8)

View file

@ -99,6 +99,7 @@ SET @@session.sql_mode=1411383296/*!*/;
SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/;
/*!\C utf8mb3 *//*!*/;
SET @@session.character_set_client=X,@@session.collation_connection=X,@@session.collation_server=X/*!*/;
SET @@session.character_set_collations=''/*!*/;
SET @@session.lc_time_names=0/*!*/;
SET @@session.collation_database=DEFAULT/*!*/;
CREATE TABLE t1 (a VARCHAR(10) CHARACTER SET utf8)
@ -126,6 +127,7 @@ START TRANSACTION
# at #
#YYMMDD HH:MM:SS server id # end_log_pos # CRC32 XXX Query thread_id=# exec_time=# error_code=0 xid=<xid>
SET TIMESTAMP=XXX/*!*/;
SET @@session.character_set_collations=''/*!*/;
INSERT INTO t1 VALUES ('ä(i2)')
/*!*/;
# at #
@ -171,6 +173,7 @@ START TRANSACTION
# at #
#YYMMDD HH:MM:SS server id # end_log_pos # CRC32 XXX Query thread_id=# exec_time=# error_code=0 xid=<xid>
SET TIMESTAMP=XXX/*!*/;
SET @@session.character_set_collations=''/*!*/;
INSERT INTO t1 VALUES ('ä(p2)')
/*!*/;
# at #

View file

@ -0,0 +1,193 @@
RESET MASTER;
SET timestamp=1000000000;
#
# MDEV-30164 System variable for default collations
#
SET character_set_collations='utf8mb3=utf8mb3_bin,ucs2=ucs2_bin';
CREATE TABLE t1 (a VARCHAR(20));
DROP TABLE t1;
CREATE TABLE t1 (a VARCHAR(20) CHARACTER SET utf8mb4);
DROP TABLE t1;
CREATE TABLE t1 (a VARCHAR(20) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin);
DROP TABLE t1;
CREATE TABLE t1 (a VARCHAR(20) CHARACTER SET utf8mb3);
INSERT INTO t1 VALUES ('a00');
INSERT INTO t1 VALUES (_utf8mb3'a01-utf8mb3');
INSERT INTO t1 VALUES (_utf8mb4'a01-utf8mb4');
PREPARE stmt FROM 'INSERT INTO t1 VALUES (?)';
EXECUTE stmt USING _utf8mb3'a02-utf8mb3';
EXECUTE stmt USING _utf8mb4'a02-utf8mb4';
EXECUTE stmt USING CONVERT('a03-utf8mb3' USING utf8mb3);
EXECUTE stmt USING CONVERT('a03-utf8mb4' USING utf8mb4);
EXECUTE stmt USING IF(0,CONVERT('a04-utf8mb3' USING utf8mb3),CONVERT('a03-utf8mb4' USING utf8mb4));
EXECUTE stmt USING IF(1,CONVERT('a04-utf8mb3' USING utf8mb3),CONVERT('a03-utf8mb4' USING utf8mb4));
DEALLOCATE PREPARE stmt;
DROP TABLE t1;
PREPARE stmt FROM 'CREATE TABLE t1 (a VARCHAR(20) CHARACTER SET utf8mb4)';
EXECUTE stmt;
DROP TABLE t1;
DEALLOCATE PREPARE stmt;
PREPARE stmt FROM 'CREATE TABLE t1 (a VARCHAR(20) CHARACTER SET utf8mb3)';
EXECUTE stmt;
DROP TABLE t1;
DEALLOCATE PREPARE stmt;
EXECUTE IMMEDIATE 'CREATE TABLE t1 (a VARCHAR(20) CHARACTER SET utf8mb4)';
DROP TABLE t1;
EXECUTE IMMEDIATE 'CREATE TABLE t1 (a VARCHAR(20) CHARACTER SET utf8mb3)';
DROP TABLE t1;
FLUSH LOGS;
--- ---- ---
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/;
/*!40019 SET @@session.max_delayed_threads=0*/;
/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
DELIMITER /*!*/;
ROLLBACK/*!*/;
use `test`/*!*/;
SET TIMESTAMP=1000000000/*!*/;
SET @@session.pseudo_thread_id=999999999/*!*/;
SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=0, @@session.unique_checks=1, @@session.autocommit=1, @@session.check_constraint_checks=1, @@session.sql_if_exists=0, @@session.explicit_defaults_for_timestamp=1, @@session.system_versioning_insert_history=0/*!*/;
SET @@session.sql_mode=#/*!*/;
SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/;
/*!\C latin1 *//*!*/;
SET @@session.character_set_client=latin1,@@session.collation_connection=8,@@session.collation_server=#/*!*/;
SET @@session.lc_time_names=0/*!*/;
SET @@session.collation_database=DEFAULT/*!*/;
CREATE TABLE t1 (a VARCHAR(20))
/*!*/;
SET TIMESTAMP=1000000000/*!*/;
DROP TABLE `t1` /* generated by server */
/*!*/;
SET TIMESTAMP=1000000000/*!*/;
SET @@session.character_set_collations='utf8mb3=utf8mb3_bin,ucs2=ucs2_bin'/*!*/;
CREATE TABLE t1 (a VARCHAR(20) CHARACTER SET utf8mb4)
/*!*/;
SET TIMESTAMP=1000000000/*!*/;
DROP TABLE `t1` /* generated by server */
/*!*/;
SET TIMESTAMP=1000000000/*!*/;
CREATE TABLE t1 (a VARCHAR(20) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin)
/*!*/;
SET TIMESTAMP=1000000000/*!*/;
DROP TABLE `t1` /* generated by server */
/*!*/;
SET TIMESTAMP=1000000000/*!*/;
SET @@session.character_set_collations='utf8mb3=utf8mb3_bin,ucs2=ucs2_bin'/*!*/;
CREATE TABLE t1 (a VARCHAR(20) CHARACTER SET utf8mb3)
/*!*/;
START TRANSACTION
/*!*/;
SET TIMESTAMP=1000000000/*!*/;
INSERT INTO t1 VALUES ('a00')
/*!*/;
SET TIMESTAMP=1000000000/*!*/;
COMMIT
/*!*/;
START TRANSACTION
/*!*/;
SET TIMESTAMP=1000000000/*!*/;
SET @@session.character_set_collations='utf8mb3=utf8mb3_bin,ucs2=ucs2_bin'/*!*/;
INSERT INTO t1 VALUES (_utf8mb3'a01-utf8mb3')
/*!*/;
SET TIMESTAMP=1000000000/*!*/;
COMMIT
/*!*/;
START TRANSACTION
/*!*/;
SET TIMESTAMP=1000000000/*!*/;
SET @@session.character_set_collations='utf8mb3=utf8mb3_bin,ucs2=ucs2_bin'/*!*/;
INSERT INTO t1 VALUES (_utf8mb4'a01-utf8mb4')
/*!*/;
SET TIMESTAMP=1000000000/*!*/;
COMMIT
/*!*/;
START TRANSACTION
/*!*/;
SET TIMESTAMP=1000000000/*!*/;
SET @@session.character_set_collations='utf8mb3=utf8mb3_bin,ucs2=ucs2_bin'/*!*/;
INSERT INTO t1 VALUES ('a02-utf8mb3')
/*!*/;
SET TIMESTAMP=1000000000/*!*/;
COMMIT
/*!*/;
START TRANSACTION
/*!*/;
SET TIMESTAMP=1000000000/*!*/;
SET @@session.character_set_collations='utf8mb3=utf8mb3_bin,ucs2=ucs2_bin'/*!*/;
INSERT INTO t1 VALUES ('a02-utf8mb4')
/*!*/;
SET TIMESTAMP=1000000000/*!*/;
COMMIT
/*!*/;
START TRANSACTION
/*!*/;
SET TIMESTAMP=1000000000/*!*/;
SET @@session.character_set_collations='utf8mb3=utf8mb3_bin,ucs2=ucs2_bin'/*!*/;
INSERT INTO t1 VALUES ('a03-utf8mb3')
/*!*/;
SET TIMESTAMP=1000000000/*!*/;
COMMIT
/*!*/;
START TRANSACTION
/*!*/;
SET TIMESTAMP=1000000000/*!*/;
SET @@session.character_set_collations='utf8mb3=utf8mb3_bin,ucs2=ucs2_bin'/*!*/;
INSERT INTO t1 VALUES ('a03-utf8mb4')
/*!*/;
SET TIMESTAMP=1000000000/*!*/;
COMMIT
/*!*/;
START TRANSACTION
/*!*/;
SET TIMESTAMP=1000000000/*!*/;
SET @@session.character_set_collations='utf8mb3=utf8mb3_bin,ucs2=ucs2_bin'/*!*/;
INSERT INTO t1 VALUES ('a03-utf8mb4')
/*!*/;
SET TIMESTAMP=1000000000/*!*/;
COMMIT
/*!*/;
START TRANSACTION
/*!*/;
SET TIMESTAMP=1000000000/*!*/;
SET @@session.character_set_collations='utf8mb3=utf8mb3_bin,ucs2=ucs2_bin'/*!*/;
INSERT INTO t1 VALUES ('a04-utf8mb3')
/*!*/;
SET TIMESTAMP=1000000000/*!*/;
COMMIT
/*!*/;
SET TIMESTAMP=1000000000/*!*/;
DROP TABLE `t1` /* generated by server */
/*!*/;
SET TIMESTAMP=1000000000/*!*/;
SET @@session.character_set_collations='utf8mb3=utf8mb3_bin,ucs2=ucs2_bin'/*!*/;
CREATE TABLE t1 (a VARCHAR(20) CHARACTER SET utf8mb4)
/*!*/;
SET TIMESTAMP=1000000000/*!*/;
DROP TABLE `t1` /* generated by server */
/*!*/;
SET TIMESTAMP=1000000000/*!*/;
SET @@session.character_set_collations='utf8mb3=utf8mb3_bin,ucs2=ucs2_bin'/*!*/;
CREATE TABLE t1 (a VARCHAR(20) CHARACTER SET utf8mb3)
/*!*/;
SET TIMESTAMP=1000000000/*!*/;
DROP TABLE `t1` /* generated by server */
/*!*/;
SET TIMESTAMP=1000000000/*!*/;
SET @@session.character_set_collations='utf8mb3=utf8mb3_bin,ucs2=ucs2_bin'/*!*/;
CREATE TABLE t1 (a VARCHAR(20) CHARACTER SET utf8mb4)
/*!*/;
SET TIMESTAMP=1000000000/*!*/;
DROP TABLE `t1` /* generated by server */
/*!*/;
SET TIMESTAMP=1000000000/*!*/;
SET @@session.character_set_collations='utf8mb3=utf8mb3_bin,ucs2=ucs2_bin'/*!*/;
CREATE TABLE t1 (a VARCHAR(20) CHARACTER SET utf8mb3)
/*!*/;
SET TIMESTAMP=1000000000/*!*/;
DROP TABLE `t1` /* generated by server */
/*!*/;
DELIMITER ;
# End of log file
ROLLBACK /* added by mysqlbinlog */;
/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=0*/;

View file

@ -0,0 +1,77 @@
-- source include/have_utf8.inc
-- source include/have_utf8mb4.inc
-- source include/have_ucs2.inc
-- source include/have_binlog_format_statement.inc
-- source include/have_log_bin.inc
--disable_query_log
CALL mtr.add_suppression("Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT");
--enable_query_log
RESET MASTER;
SET timestamp=1000000000;
--echo #
--echo # MDEV-30164 System variable for default collations
--echo #
SET character_set_collations='utf8mb3=utf8mb3_bin,ucs2=ucs2_bin';
CREATE TABLE t1 (a VARCHAR(20));
DROP TABLE t1;
CREATE TABLE t1 (a VARCHAR(20) CHARACTER SET utf8mb4);
DROP TABLE t1;
CREATE TABLE t1 (a VARCHAR(20) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin);
DROP TABLE t1;
CREATE TABLE t1 (a VARCHAR(20) CHARACTER SET utf8mb3);
INSERT INTO t1 VALUES ('a00');
INSERT INTO t1 VALUES (_utf8mb3'a01-utf8mb3');
INSERT INTO t1 VALUES (_utf8mb4'a01-utf8mb4');
PREPARE stmt FROM 'INSERT INTO t1 VALUES (?)';
EXECUTE stmt USING _utf8mb3'a02-utf8mb3';
EXECUTE stmt USING _utf8mb4'a02-utf8mb4';
EXECUTE stmt USING CONVERT('a03-utf8mb3' USING utf8mb3);
EXECUTE stmt USING CONVERT('a03-utf8mb4' USING utf8mb4);
EXECUTE stmt USING IF(0,CONVERT('a04-utf8mb3' USING utf8mb3),CONVERT('a03-utf8mb4' USING utf8mb4));
EXECUTE stmt USING IF(1,CONVERT('a04-utf8mb3' USING utf8mb3),CONVERT('a03-utf8mb4' USING utf8mb4));
DEALLOCATE PREPARE stmt;
DROP TABLE t1;
PREPARE stmt FROM 'CREATE TABLE t1 (a VARCHAR(20) CHARACTER SET utf8mb4)';
EXECUTE stmt;
DROP TABLE t1;
DEALLOCATE PREPARE stmt;
PREPARE stmt FROM 'CREATE TABLE t1 (a VARCHAR(20) CHARACTER SET utf8mb3)';
EXECUTE stmt;
DROP TABLE t1;
DEALLOCATE PREPARE stmt;
EXECUTE IMMEDIATE 'CREATE TABLE t1 (a VARCHAR(20) CHARACTER SET utf8mb4)';
DROP TABLE t1;
EXECUTE IMMEDIATE 'CREATE TABLE t1 (a VARCHAR(20) CHARACTER SET utf8mb3)';
DROP TABLE t1;
### Starting master-bin.000002
FLUSH LOGS;
--disable_query_log
SELECT "--- ---- ---" as "";
--enable_query_log
let $MYSQLD_DATADIR= `select @@datadir`;
--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
--replace_regex /SQL_LOAD_MB-[0-9a-f]+-[0-9a-f]+/SQL_LOAD_MB-#-#/ /@@session.sql_mode=\d+/@@session.sql_mode=#/ /collation_server=\d+/collation_server=#/
--exec $MYSQL_BINLOG --short-form --local-load=$MYSQLTEST_VARDIR/tmp/ $MYSQLD_DATADIR/master-bin.000001

View file

@ -0,0 +1,83 @@
include/master-slave.inc
[connection master]
#
# MDEV-30164 System variable for default collations
#
connection master;
SET @@character_set_collations='utf8mb3=uca1400_ai_ci,'
'utf8mb4=uca1400_ai_ci,'
'ucs2=uca1400_ai_ci,'
'utf16=uca1400_ai_ci,'
'utf32=uca1400_ai_ci';
connection master;
CREATE TABLE t1 AS SELECT CHAR(0x61 USING utf8mb4);
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`CHAR(0x61 USING utf8mb4)` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_uca1400_ai_ci DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
connection slave;
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`CHAR(0x61 USING utf8mb4)` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_uca1400_ai_ci DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
connection master;
DROP TABLE t1;
connection slave;
connection master;
CREATE TABLE t1 AS SELECT CONVERT('a' USING utf8mb4);
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`CONVERT('a' USING utf8mb4)` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_uca1400_ai_ci DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
connection slave;
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`CONVERT('a' USING utf8mb4)` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_uca1400_ai_ci DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
connection master;
DROP TABLE t1;
connection slave;
connection master;
CREATE TABLE t1 (
c0 TEXT CHARACTER SET utf8mb3,
c1 TEXT CHARACTER SET utf8mb4,
c2 TEXT CHARACTER SET utf16,
c3 TEXT CHARACTER SET utf32,
c4 TEXT CHARACTER SET ucs2
);
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`c0` text CHARACTER SET utf8mb3 COLLATE utf8mb3_uca1400_ai_ci DEFAULT NULL,
`c1` text CHARACTER SET utf8mb4 COLLATE utf8mb4_uca1400_ai_ci DEFAULT NULL,
`c2` text CHARACTER SET utf16 COLLATE utf16_uca1400_ai_ci DEFAULT NULL,
`c3` text CHARACTER SET utf32 COLLATE utf32_uca1400_ai_ci DEFAULT NULL,
`c4` text CHARACTER SET ucs2 COLLATE ucs2_uca1400_ai_ci DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
connection slave;
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`c0` text CHARACTER SET utf8mb3 COLLATE utf8mb3_uca1400_ai_ci DEFAULT NULL,
`c1` text CHARACTER SET utf8mb4 COLLATE utf8mb4_uca1400_ai_ci DEFAULT NULL,
`c2` text CHARACTER SET utf16 COLLATE utf16_uca1400_ai_ci DEFAULT NULL,
`c3` text CHARACTER SET utf32 COLLATE utf32_uca1400_ai_ci DEFAULT NULL,
`c4` text CHARACTER SET ucs2 COLLATE ucs2_uca1400_ai_ci DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
connection master;
DROP TABLE t1;
connection slave;
connection master;
CREATE DATABASE db1 CHARACTER SET utf8mb4;
connection slave;
SHOW CREATE DATABASE db1;
Database Create Database
db1 CREATE DATABASE `db1` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_uca1400_ai_ci */
connection master;
DROP DATABASE db1;
connection slave;
include/rpl_end.inc

View file

@ -52,7 +52,7 @@ SET TIMESTAMP=1293832861.123456/*!*/;
SET @@session.time_zone='+03:00'/*!*/;
insert t1 (b,c) values (now(6), now(6))
/*!*/;
SET TIMESTAMP=1293832861.123456/*!*/;
SET TIMESTAMP=1293832861/*!*/;
COMMIT
/*!*/;
START TRANSACTION
@ -68,7 +68,7 @@ START TRANSACTION
SET TIMESTAMP=1643756522.654321/*!*/;
insert t1 (b,c) values (now(), now())
/*!*/;
SET TIMESTAMP=1643756522.654321/*!*/;
SET TIMESTAMP=1643756522/*!*/;
COMMIT
/*!*/;
START TRANSACTION
@ -76,7 +76,7 @@ START TRANSACTION
SET TIMESTAMP=1643756522.654321/*!*/;
insert t1 (b,c) values (0,0)
/*!*/;
SET TIMESTAMP=1643756522.654321/*!*/;
SET TIMESTAMP=1643756522/*!*/;
COMMIT
/*!*/;
START TRANSACTION
@ -84,7 +84,7 @@ START TRANSACTION
SET TIMESTAMP=1643756522.654321/*!*/;
insert t1 (a,b,c) values (0,0,now(6))
/*!*/;
SET TIMESTAMP=1643756522.654321/*!*/;
SET TIMESTAMP=1643756522/*!*/;
COMMIT
/*!*/;
SET TIMESTAMP=1643756522/*!*/;

View file

@ -0,0 +1,60 @@
--source include/have_binlog_format_row.inc
--source include/master-slave.inc
--echo #
--echo # MDEV-30164 System variable for default collations
--echo #
--connection master
SET @@character_set_collations='utf8mb3=uca1400_ai_ci,'
'utf8mb4=uca1400_ai_ci,'
'ucs2=uca1400_ai_ci,'
'utf16=uca1400_ai_ci,'
'utf32=uca1400_ai_ci';
--connection master
CREATE TABLE t1 AS SELECT CHAR(0x61 USING utf8mb4);
SHOW CREATE TABLE t1;
--sync_slave_with_master
SHOW CREATE TABLE t1;
--connection master
DROP TABLE t1;
--sync_slave_with_master
--connection master
CREATE TABLE t1 AS SELECT CONVERT('a' USING utf8mb4);
SHOW CREATE TABLE t1;
--sync_slave_with_master
SHOW CREATE TABLE t1;
--connection master
DROP TABLE t1;
--sync_slave_with_master
--connection master
CREATE TABLE t1 (
c0 TEXT CHARACTER SET utf8mb3,
c1 TEXT CHARACTER SET utf8mb4,
c2 TEXT CHARACTER SET utf16,
c3 TEXT CHARACTER SET utf32,
c4 TEXT CHARACTER SET ucs2
);
SHOW CREATE TABLE t1;
--sync_slave_with_master
SHOW CREATE TABLE t1;
--connection master
DROP TABLE t1;
--sync_slave_with_master
--connection master
CREATE DATABASE db1 CHARACTER SET utf8mb4;
--sync_slave_with_master
SHOW CREATE DATABASE db1;
--connection master
DROP DATABASE db1;
--sync_slave_with_master
--source include/rpl_end.inc

View file

@ -502,6 +502,16 @@ NUMERIC_BLOCK_SIZE NULL
ENUM_VALUE_LIST NULL
READ_ONLY NO
COMMAND_LINE_ARGUMENT NULL
VARIABLE_NAME CHARACTER_SET_COLLATIONS
VARIABLE_SCOPE SESSION
VARIABLE_TYPE VARCHAR
VARIABLE_COMMENT Overrides for character set default collations
NUMERIC_MIN_VALUE NULL
NUMERIC_MAX_VALUE NULL
NUMERIC_BLOCK_SIZE NULL
ENUM_VALUE_LIST NULL
READ_ONLY NO
COMMAND_LINE_ARGUMENT NULL
VARIABLE_NAME CHARACTER_SET_CONNECTION
VARIABLE_SCOPE SESSION
VARIABLE_TYPE ENUM

View file

@ -542,6 +542,16 @@ NUMERIC_BLOCK_SIZE NULL
ENUM_VALUE_LIST NULL
READ_ONLY NO
COMMAND_LINE_ARGUMENT NULL
VARIABLE_NAME CHARACTER_SET_COLLATIONS
VARIABLE_SCOPE SESSION
VARIABLE_TYPE VARCHAR
VARIABLE_COMMENT Overrides for character set default collations
NUMERIC_MIN_VALUE NULL
NUMERIC_MAX_VALUE NULL
NUMERIC_BLOCK_SIZE NULL
ENUM_VALUE_LIST NULL
READ_ONLY NO
COMMAND_LINE_ARGUMENT NULL
VARIABLE_NAME CHARACTER_SET_CONNECTION
VARIABLE_SCOPE SESSION
VARIABLE_TYPE ENUM

View file

@ -166,7 +166,7 @@ SET (SQL_SOURCE
semisync.cc semisync_master.cc semisync_slave.cc
semisync_master_ack_receiver.cc
sql_schema.cc
lex_charset.cc
lex_charset.cc charset_collations.cc
sql_type.cc sql_mode.cc sql_type_json.cc
sql_type_string.cc
sql_type_geom.cc

117
sql/charset_collations.cc Normal file
View file

@ -0,0 +1,117 @@
/* Copyright (c) 2023, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
#include "my_global.h"
#include "my_sys.h"
#include "lex_charset.h"
#include "mysqld_error.h"
#include "charset_collations.h"
#include "simple_tokenizer.h"
bool Charset_collation_map_st::insert_or_replace(
const Lex_exact_charset &charset,
const Lex_extended_collation &collation,
bool error_on_conflicting_duplicate)
{
Lex_exact_charset_opt_extended_collate res(charset);
Sql_used used;
if (res.merge_collation_override(&used, *this, collation))
return true;
if (error_on_conflicting_duplicate)
{
const Elem_st *dup;
if ((dup= find_elem_by_charset_id(charset.charset_info()->number)) &&
dup->to() != res.collation().charset_info())
{
my_error(ER_CONFLICTING_DECLARATIONS, MYF(0),
"", dup->to()->coll_name.str,
"", res.collation().charset_info()->coll_name.str);
return true;
}
}
return insert_or_replace(Elem(charset.charset_info(),
res.collation().charset_info()));
}
bool Charset_collation_map_st::insert_or_replace(
const LEX_CSTRING &cs_name,
const LEX_CSTRING &cl_name,
bool error_on_conflicting_duplicate,
myf utf8_flag)
{
char charset_name_c[MY_CS_CHARACTER_SET_NAME_SIZE + 1/*for '\0'*/];
strmake(charset_name_c, cs_name.str, cs_name.length);
CHARSET_INFO *cs= get_charset_by_csname(charset_name_c,
MY_CS_PRIMARY, utf8_flag);
if (!cs)
{
my_error(ER_UNKNOWN_CHARACTER_SET, MYF(0), charset_name_c);
return true;
}
char collation_name_c[MY_CS_COLLATION_NAME_SIZE + 1/*for '\0'*/];
strmake(collation_name_c, cl_name.str, cl_name.length);
Lex_exact_collation tmpec(&my_charset_bin);
Lex_extended_collation tmp(tmpec);
if (tmp.set_by_name(collation_name_c, utf8_flag))
return true;
return insert_or_replace(Lex_exact_charset(cs), tmp,
error_on_conflicting_duplicate);
}
bool Charset_collation_map_st::from_text(const LEX_CSTRING &str, myf utf8_flag)
{
init();
Simple_tokenizer stream(str.str, str.length);
/*
Allow relaxed comma parsing:
SET @@character_set_collations=
',,,utf8mb3 = utf8mb3_bin,,latin1 = latin1_bin,,,';
It makes it easier for the user to edit the value
using SQL functions CONCAT or REGEXP_REPLACE.
*/
for ( ; ; )
{
LEX_CSTRING charset_name= stream.get_ident();
if (charset_name.length)
{
if (stream.get_char('='))
return true;
LEX_CSTRING collation_name= stream.get_ident();
if (!collation_name.length)
return true;
/*
Don't allow duplicate conflicting declarations within the same string:
SET @@var='utf8mb3=utf8mb3_general_ci,utf8mb3=utf8mb3_bin';
*/
if (insert_or_replace(charset_name, collation_name,
true/*err on dup*/, utf8_flag))
return true;
}
if (!stream.get_char(','))
continue;
if (stream.eof())
return false;
return true;
}
return false;
}

247
sql/charset_collations.h Normal file
View file

@ -0,0 +1,247 @@
/* Copyright (c) 2023, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
#ifndef LEX_CHARSET_COLLATIONS_INCLUDED
#define LEX_CHARSET_COLLATIONS_INCLUDED
#include "sql_used.h"
struct Charset_collation_map_st
{
public:
struct Elem_st
{
protected:
CHARSET_INFO *m_from; // From a character set
CHARSET_INFO *m_to; // To a collation
static size_t print_lex_string(char *dst, const LEX_CSTRING &str)
{
memcpy(dst, str.str, str.length);
return str.length;
}
public:
/*
Size in text format: 'utf8mb4=utf8mb4_unicode_ai_ci'
*/
static constexpr size_t text_size_max()
{
return MY_CS_CHARACTER_SET_NAME_SIZE + 1 +
MY_CS_COLLATION_NAME_SIZE;
}
CHARSET_INFO *from() const
{
return m_from;
}
CHARSET_INFO *to() const
{
return m_to;
}
void set_to(CHARSET_INFO *cl)
{
m_to= cl;
}
size_t print(char *dst) const
{
const char *dst0= dst;
dst+= print_lex_string(dst, m_from->cs_name);
*dst++= '=';
dst+= print_lex_string(dst, m_to->coll_name);
return (size_t) (dst - dst0);
}
int cmp_by_charset_id(const Elem_st &rhs) const
{
return m_from->number < rhs.m_from->number ? -1 :
m_from->number > rhs.m_from->number ? +1 : 0;
}
};
class Elem: public Elem_st
{
public:
Elem(CHARSET_INFO *from, CHARSET_INFO *to)
{
m_from= from;
m_to= to;
}
};
protected:
Elem_st m_element[8]; // Should be enough for now
uint m_count;
uint m_version;
static int cmp_by_charset_id(const void *a, const void *b)
{
return static_cast<const Elem_st*>(a)->
cmp_by_charset_id(*static_cast<const Elem_st*>(b));
}
void sort()
{
qsort(m_element, m_count, sizeof(Elem_st), cmp_by_charset_id);
}
const Elem_st *find_elem_by_charset_id(uint id) const
{
if (!m_count)
return NULL;
int first= 0, last= ((int) m_count) - 1;
for ( ; first <= last; )
{
const int middle= (first + last) / 2;
DBUG_ASSERT(middle >= 0);
DBUG_ASSERT(middle < (int) m_count);
const uint middle_id= m_element[middle].from()->number;
if (middle_id == id)
return &m_element[middle];
if (middle_id < id)
first= middle + 1;
else
last= middle - 1;
}
return NULL;
}
bool insert(const Elem_st &elem)
{
DBUG_ASSERT(elem.from()->state & MY_CS_PRIMARY);
if (m_count >= array_elements(m_element))
return true;
m_element[m_count]= elem;
m_count++;
sort();
return false;
}
bool insert_or_replace(const Elem_st &elem)
{
DBUG_ASSERT(elem.from()->state & MY_CS_PRIMARY);
const Elem_st *found= find_elem_by_charset_id(elem.from()->number);
if (found)
{
const_cast<Elem_st*>(found)->set_to(elem.to());
return false;
}
return insert(elem);
}
public:
void init()
{
m_count= 0;
m_version= 0;
}
uint count() const
{
return m_count;
}
uint version() const
{
return m_version;
}
void set(const Charset_collation_map_st &rhs, uint version_increment)
{
uint version= m_version;
*this= rhs;
m_version= version + version_increment;
}
const Elem_st & operator[](uint pos) const
{
DBUG_ASSERT(pos < m_count);
return m_element[pos];
}
bool insert_or_replace(const class Lex_exact_charset &cs,
const class Lex_extended_collation &cl,
bool error_on_conflicting_duplicate);
bool insert_or_replace(const LEX_CSTRING &cs,
const LEX_CSTRING &cl,
bool error_on_conflicting_duplicate,
myf utf8_flag);
CHARSET_INFO *get_collation_for_charset(Sql_used *used,
CHARSET_INFO *cs) const
{
DBUG_ASSERT(cs->state & MY_CS_PRIMARY);
const Elem_st *elem= find_elem_by_charset_id(cs->number);
used->used|= Sql_used::CHARACTER_SET_COLLATIONS_USED;
if (elem)
return elem->to();
return cs;
}
size_t text_format_nbytes_needed() const
{
return (Elem_st::text_size_max() + 1/* for ',' */) * m_count;
}
size_t print(char *dst, size_t nbytes_available) const
{
const char *dst0= dst;
const char *end= dst + nbytes_available;
for (uint i= 0; i < m_count; i++)
{
if (Elem_st::text_size_max() + 1/* for ',' */ > (size_t) (end - dst))
break;
if (i > 0)
*dst++= ',';
dst+= m_element[i].print(dst);
}
return dst - dst0;
}
static constexpr size_t binary_size_max()
{
return 1/*count*/ + 4 * array_elements(m_element);
}
size_t to_binary(char *dst) const
{
const char *dst0= dst;
*dst++= (char) (uchar) m_count;
for (uint i= 0; i < m_count; i++)
{
int2store(dst, (uint16) m_element[i].from()->number);
dst+= 2;
int2store(dst, (uint16) m_element[i].to()->number);
dst+= 2;
}
return (size_t) (dst - dst0);
}
size_t from_binary(const char *src, size_t srclen)
{
const char *src0= src;
init();
if (!srclen)
return 0; // Empty
uint count= (uchar) *src++;
if (srclen < 1 + 4 * count)
return 0;
for (uint i= 0; i < count; i++, src+= 4)
{
CHARSET_INFO *cs, *cl;
if (!(cs= get_charset(uint2korr(src), MYF(0))) ||
!(cl= get_charset(uint2korr(src + 2), MYF(0))))
{
/*
Unpacking from binary format happens on the slave side.
If for some reasons the slave does not know about a
character set or a collation, just skip the pair here.
This pair might not even be needed.
*/
continue;
}
insert_or_replace(Elem(cs, cl));
}
return src - src0;
}
bool from_text(const LEX_CSTRING &str, myf utf8_flag);
};
#endif // LEX_CHARSET_COLLATIONS_INCLUDED

View file

@ -5340,7 +5340,9 @@ public:
- find a _bin collation if the BINARY comparison style was specified, e.g.:
CREATE TABLE t1 (a VARCHAR(10) BINARY) CHARSET utf8;
*/
bool prepare_charset_for_string(const Column_derived_attributes *dattr);
bool prepare_charset_for_string(Sql_used *used,
const Charset_collation_map_st &map,
const Column_derived_attributes *dattr);
/**
Prepare a SET/ENUM field.
@ -5495,10 +5497,11 @@ public:
bool check_vcol_for_key(THD *thd) const;
void set_charset_collation_attrs(const
void set_charset_collation_attrs(Sql_used *used,
const Charset_collation_map_st &map, const
Lex_column_charset_collation_attrs_st &lc)
{
charset= lc.charset_info();
charset= lc.charset_info(used, map);
if (lc.is_contextually_typed_collation())
flags|= CONTEXT_COLLATION_FLAG;
else

View file

@ -2366,32 +2366,42 @@ struct Table_specification_st: public HA_CREATE_INFO,
convert_charset_collation.init();
}
bool add_table_option_convert_charset(CHARSET_INFO *cs)
bool add_table_option_convert_charset(Sql_used *used,
const Charset_collation_map_st &map,
CHARSET_INFO *cs)
{
// cs can be NULL, e.g.: ALTER TABLE t1 CONVERT TO CHARACTER SET DEFAULT;
used_fields|= (HA_CREATE_USED_CHARSET | HA_CREATE_USED_DEFAULT_CHARSET);
return cs ?
convert_charset_collation.merge_exact_charset(Lex_exact_charset(cs)) :
convert_charset_collation.merge_exact_charset(used, map,
Lex_exact_charset(cs)) :
convert_charset_collation.merge_charset_default();
}
bool add_table_option_convert_collation(const Lex_extended_collation_st &cl)
bool add_table_option_convert_collation(Sql_used *used,
const Charset_collation_map_st &map,
const Lex_extended_collation_st &cl)
{
used_fields|= (HA_CREATE_USED_CHARSET | HA_CREATE_USED_DEFAULT_CHARSET);
return convert_charset_collation.merge_collation(cl);
return convert_charset_collation.merge_collation(used, map, cl);
}
bool add_table_option_default_charset(CHARSET_INFO *cs)
bool add_table_option_default_charset(Sql_used *used,
const Charset_collation_map_st &map,
CHARSET_INFO *cs)
{
// cs can be NULL, e.g.: CREATE TABLE t1 (..) CHARACTER SET DEFAULT;
used_fields|= HA_CREATE_USED_DEFAULT_CHARSET;
return cs ?
default_charset_collation.merge_exact_charset(Lex_exact_charset(cs)) :
default_charset_collation.merge_exact_charset(used, map,
Lex_exact_charset(cs)) :
default_charset_collation.merge_charset_default();
}
bool add_table_option_default_collation(const Lex_extended_collation_st &cl)
bool add_table_option_default_collation(Sql_used *used,
const Charset_collation_map_st &map,
const Lex_extended_collation_st &cl)
{
used_fields|= HA_CREATE_USED_DEFAULT_CHARSET;
return default_charset_collation.merge_collation(cl);
return default_charset_collation.merge_collation(used, map, cl);
}
bool resolve_to_charset_collation_context(THD *thd,

View file

@ -3785,10 +3785,12 @@ public:
}
bool set(const Type_handler *handler,
const Lex_length_and_dec_st & length_and_dec,
Sql_used *used,
const Charset_collation_map_st &map,
const Lex_column_charset_collation_attrs_st &cscl,
CHARSET_INFO *defcs)
{
CHARSET_INFO *tmp= cscl.resolved_to_character_set(defcs);
CHARSET_INFO *tmp= cscl.resolved_to_character_set(used, map, defcs);
if (!tmp)
return true;
set(handler, length_and_dec, tmp);

View file

@ -3830,7 +3830,9 @@ bool Item_func_set_collation::fix_length_and_dec(THD *thd)
if (agg_arg_charsets_for_string_result(collation, args, 1))
return true;
Lex_exact_charset_opt_extended_collate cl(collation.collation, true);
if (cl.merge_collation_override(m_set_collation))
if (cl.merge_collation_override(thd,
thd->variables.character_set_collations,
m_set_collation))
return true;
collation.set(cl.collation().charset_info(), DERIVATION_EXPLICIT,
args[0]->collation.repertoire);

View file

@ -925,7 +925,10 @@ int Json_table_column::set(THD *thd, enum_type ctype, const LEX_CSTRING &path,
return set(thd, ctype, path, nullptr);
CHARSET_INFO *tmp;
if (!(tmp= cl.resolved_to_character_set(&my_charset_utf8mb4_general_ci)))
if (!(tmp= cl.resolved_to_character_set(
thd,
thd->variables.character_set_collations,
&my_charset_utf8mb4_general_ci)))
return 1;
return set(thd, ctype, path, tmp);
}

View file

@ -197,7 +197,9 @@ Lex_context_collation::raise_if_not_equal(const Lex_context_collation &cl) const
CREATE DATABASE db1 COLLATE DEFAULT CHARACTER SET latin1;
*/
bool Lex_exact_charset_opt_extended_collate::
merge_context_collation_override(const Lex_context_collation &cl)
merge_context_collation_override(Sql_used *used,
const Charset_collation_map_st &map,
const Lex_context_collation &cl)
{
DBUG_ASSERT(m_ci);
@ -215,7 +217,7 @@ bool Lex_exact_charset_opt_extended_collate::
// COLLATE DEFAULT
if (cl.is_contextually_typed_collate_default())
{
CHARSET_INFO *ci= find_default_collation();
CHARSET_INFO *ci= find_mapped_default_collation(used, map);
DBUG_ASSERT(ci);
if (!ci)
return true;
@ -238,7 +240,9 @@ bool Lex_exact_charset_opt_extended_collate::
}
bool Lex_extended_collation_st::merge_exact_charset(const Lex_exact_charset &cs)
bool Lex_extended_collation_st::merge_exact_charset(Sql_used *used,
const Charset_collation_map_st &map,
const Lex_exact_charset &cs)
{
switch (m_type) {
case TYPE_EXACT:
@ -250,7 +254,7 @@ bool Lex_extended_collation_st::merge_exact_charset(const Lex_exact_charset &cs)
{
// COLLATE DEFAULT .. CHARACTER SET latin1
Lex_exact_charset_opt_extended_collate tmp(cs);
if (tmp.merge_context_collation(Lex_context_collation(m_ci)))
if (tmp.merge_context_collation(used, map, Lex_context_collation(m_ci)))
return true;
*this= Lex_extended_collation(tmp.collation());
return false;
@ -419,7 +423,7 @@ CHARSET_INFO *Lex_exact_charset_opt_extended_collate::find_bin_collation() const
CHARSET_INFO *
Lex_exact_charset_opt_extended_collate::find_default_collation() const
Lex_exact_charset_opt_extended_collate::find_compiled_default_collation() const
{
// See comments in find_bin_collation()
DBUG_ASSERT(m_ci->cs_name.length !=4 || memcmp(m_ci->cs_name.str, "utf8", 4));
@ -447,6 +451,17 @@ Lex_exact_charset_opt_extended_collate::find_default_collation() const
}
CHARSET_INFO *
Lex_exact_charset_opt_extended_collate::
find_mapped_default_collation(Sql_used *used,
const Charset_collation_map_st &map) const
{
CHARSET_INFO *cs= find_compiled_default_collation();
if (!cs)
return nullptr;
return map.get_collation_for_charset(used, cs);
}
/*
Resolve an empty or a contextually typed collation according to the
upper level default character set (and optionally a collation), e.g.:
@ -459,7 +474,9 @@ Lex_exact_charset_opt_extended_collate::find_default_collation() const
"def" is the upper level CHARACTER SET clause (e.g. of a table)
*/
CHARSET_INFO *Lex_exact_charset_extended_collation_attrs_st::
resolved_to_character_set(CHARSET_INFO *def) const
resolved_to_character_set(Sql_used *used,
const Charset_collation_map_st &map,
CHARSET_INFO *def) const
{
DBUG_ASSERT(def);
@ -467,6 +484,10 @@ CHARSET_INFO *Lex_exact_charset_extended_collation_attrs_st::
case TYPE_EMPTY:
return def;
case TYPE_CHARACTER_SET:
{
DBUG_ASSERT(m_ci);
return map.get_collation_for_charset(used, m_ci);
}
case TYPE_CHARACTER_SET_COLLATE_EXACT:
case TYPE_COLLATE_EXACT:
DBUG_ASSERT(m_ci);
@ -474,7 +495,7 @@ CHARSET_INFO *Lex_exact_charset_extended_collation_attrs_st::
case TYPE_COLLATE_CONTEXTUALLY_TYPED:
{
Lex_exact_charset_opt_extended_collate tmp(def, true);
if (tmp.merge_context_collation_override(Lex_context_collation(m_ci)))
if (tmp.merge_context_collation_override(used, map, Lex_context_collation(m_ci)))
return NULL;
return tmp.collation().charset_info();
}
@ -526,7 +547,9 @@ bool Lex_exact_charset_extended_collation_attrs_st::
bool Lex_exact_charset_extended_collation_attrs_st::
merge_context_collation(const Lex_context_collation &cl)
merge_context_collation(Sql_used *used,
const Charset_collation_map_st &map,
const Lex_context_collation &cl)
{
switch (m_type) {
case TYPE_EMPTY:
@ -540,7 +563,7 @@ bool Lex_exact_charset_extended_collation_attrs_st::
{
// CHARACTER SET latin1 .. COLLATE DEFAULT
Lex_exact_charset_opt_extended_collate tmp(m_ci, false);
if (tmp.merge_context_collation(cl))
if (tmp.merge_context_collation(used, map, cl))
return true;
*this= Lex_exact_charset_extended_collation_attrs(tmp);
return false;
@ -582,24 +605,29 @@ bool Lex_exact_charset_opt_extended_collate::
bool Lex_exact_charset_opt_extended_collate::
merge_context_collation(const Lex_context_collation &cl)
merge_context_collation(Sql_used *used,
const Charset_collation_map_st &map,
const Lex_context_collation &cl)
{
// CHARACTER SET latin1 [COLLATE latin1_bin] .. COLLATE DEFAULT
if (m_with_collate)
return Lex_exact_collation(m_ci).
raise_if_conflicts_with_context_collation(cl, false);
return merge_context_collation_override(cl);
return merge_context_collation_override(used, map, cl);
}
bool Lex_exact_charset_extended_collation_attrs_st::
merge_collation(const Lex_extended_collation_st &cl)
merge_collation(Sql_used *used,
const Charset_collation_map_st &map,
const Lex_extended_collation_st &cl)
{
switch (cl.type()) {
case Lex_extended_collation_st::TYPE_EXACT:
return merge_exact_collation(Lex_exact_collation(cl.charset_info()));
case Lex_extended_collation_st::TYPE_CONTEXTUALLY_TYPED:
return merge_context_collation(Lex_context_collation(cl.charset_info()));
return merge_context_collation(used, map,
Lex_context_collation(cl.charset_info()));
}
DBUG_ASSERT(0);
return false;
@ -613,7 +641,9 @@ bool Lex_exact_charset_extended_collation_attrs_st::
@param cs - The "CHARACTER SET exact_charset_name".
*/
bool Lex_exact_charset_extended_collation_attrs_st::
merge_exact_charset(const Lex_exact_charset &cs)
merge_exact_charset(Sql_used *used,
const Charset_collation_map_st &map,
const Lex_exact_charset &cs)
{
DBUG_ASSERT(cs.charset_info());
@ -643,7 +673,7 @@ bool Lex_exact_charset_extended_collation_attrs_st::
// COLLATE DEFAULT .. CHARACTER SET cs
{
Lex_exact_charset_opt_extended_collate tmp(cs);
if (tmp.merge_context_collation(Lex_context_collation(m_ci)))
if (tmp.merge_context_collation(used, map, Lex_context_collation(m_ci)))
return true;
*this= Lex_exact_charset_extended_collation_attrs(tmp);
return false;
@ -664,11 +694,14 @@ bool Lex_extended_charset_extended_collation_attrs_st::merge_charset_default()
bool Lex_extended_charset_extended_collation_attrs_st::
merge_exact_charset(const Lex_exact_charset &cs)
merge_exact_charset(Sql_used *used,
const Charset_collation_map_st &map,
const Lex_exact_charset &cs)
{
if (m_charset_order == CHARSET_TYPE_EMPTY)
m_charset_order= CHARSET_TYPE_EXACT;
return Lex_exact_charset_extended_collation_attrs_st::merge_exact_charset(cs);
return Lex_exact_charset_extended_collation_attrs_st::
merge_exact_charset(used, map, cs);
}
@ -691,13 +724,16 @@ bool Lex_extended_charset_extended_collation_attrs_st::
CHARSET_INFO *
Lex_extended_charset_extended_collation_attrs_st::
resolved_to_context(const Charset_collation_context &ctx) const
resolved_to_context(Sql_used *used,
const Charset_collation_map_st &map,
const Charset_collation_context &ctx) const
{
if (Lex_opt_context_charset_st::is_empty())
{
// Without CHARACTER SET DEFAULT
return Lex_exact_charset_extended_collation_attrs_st::
resolved_to_character_set(ctx.collate_default().charset_info());
resolved_to_character_set(used, map,
ctx.collate_default().charset_info());
}
// With CHARACTER SET DEFAULT
@ -767,8 +803,9 @@ Lex_extended_charset_extended_collation_attrs_st::
ALTER DATABASE db1 COLLATE DEFAULT CHARACTER SET DEFAULT;
*/
return Lex_exact_charset_extended_collation_attrs_st::
resolved_to_character_set(ctx.charset_default().
collation().charset_info());
resolved_to_character_set(used, map,
ctx.charset_default().
collation().charset_info());
}
DBUG_ASSERT(0);
return NULL;

View file

@ -16,6 +16,7 @@
#ifndef LEX_CHARSET_INCLUDED
#define LEX_CHARSET_INCLUDED
#include "charset_collations.h"
/*
An extention for Charset_loader_mysys,
@ -296,7 +297,9 @@ public:
bool set_by_name(const char *name, myf my_flags); // e.g. MY_UTF8_IS_UTF8MB3
bool raise_if_conflicts_with_context_collation(const Lex_context_collation &)
const;
bool merge_exact_charset(const Lex_exact_charset &rhs);
bool merge_exact_charset(Sql_used *used,
const Charset_collation_map_st &map,
const Lex_exact_charset &rhs);
bool merge_exact_collation(const Lex_exact_collation &rhs);
bool merge(const Lex_extended_collation_st &rhs);
};
@ -347,7 +350,10 @@ public:
}
bool with_collate() const { return m_with_collate; }
CHARSET_INFO *find_bin_collation() const;
CHARSET_INFO *find_default_collation() const;
CHARSET_INFO *find_compiled_default_collation() const;
CHARSET_INFO *find_mapped_default_collation(
Sql_used *used,
const Charset_collation_map_st &map) const;
bool raise_if_charsets_differ(const Lex_exact_charset &cs) const;
bool raise_if_not_applicable(const Lex_exact_collation &cl) const;
/*
@ -355,18 +361,23 @@ public:
So the full syntax looks like:
CHARACTER SET cs [COLLATE cl] ... COLLATE cl2
*/
bool merge_collation(const Lex_extended_collation_st &cl)
bool merge_collation(Sql_used *used,
const Charset_collation_map_st &map,
const Lex_extended_collation_st &cl)
{
switch (cl.type()) {
case Lex_extended_collation_st::TYPE_EXACT:
return merge_exact_collation(Lex_exact_collation(cl.charset_info()));
case Lex_extended_collation_st::TYPE_CONTEXTUALLY_TYPED:
return merge_context_collation(Lex_context_collation(cl.charset_info()));
return merge_context_collation(used, map,
Lex_context_collation(cl.charset_info()));
}
DBUG_ASSERT(0);
return false;
}
bool merge_collation_override(const Lex_extended_collation_st &cl)
bool merge_collation_override(Sql_used *used,
const Charset_collation_map_st &map,
const Lex_extended_collation_st &cl)
{
switch (cl.type()) {
case Lex_extended_collation_st::TYPE_EXACT:
@ -374,7 +385,7 @@ public:
Lex_exact_collation(cl.charset_info()));
case Lex_extended_collation_st::TYPE_CONTEXTUALLY_TYPED:
return merge_context_collation_override(
Lex_context_collation(cl.charset_info()));
used, map, Lex_context_collation(cl.charset_info()));
}
DBUG_ASSERT(0);
return false;
@ -383,8 +394,12 @@ public:
Add a context collation:
CHARACTER SET cs [COLLATE cl] ... COLLATE DEFAULT
*/
bool merge_context_collation(const Lex_context_collation &cl);
bool merge_context_collation_override(const Lex_context_collation &cl);
bool merge_context_collation(Sql_used *used,
const Charset_collation_map_st &map,
const Lex_context_collation &cl);
bool merge_context_collation_override(Sql_used *used,
const Charset_collation_map_st &map,
const Lex_context_collation &cl);
/*
Add an exact collation:
CHARACTER SET cs [COLLATE cl] ... COLLATE latin1_bin
@ -399,7 +414,7 @@ public:
{
if ((m_ci->state & MY_CS_PRIMARY))
return Lex_exact_charset(m_ci);
return Lex_exact_charset(find_default_collation());
return Lex_exact_charset(find_compiled_default_collation());
}
};
@ -507,11 +522,13 @@ public:
m_ci= cs.charset_info();
m_type= TYPE_CHARACTER_SET;
}
bool set_charset_collate_default(const Lex_exact_charset &cs)
bool set_charset_collate_default(Sql_used *used,
const Charset_collation_map_st &map,
const Lex_exact_charset &cs)
{
CHARSET_INFO *ci;
if (!(ci= Lex_exact_charset_opt_extended_collate(cs).
find_default_collation()))
find_mapped_default_collation(used, map)))
return true;
m_ci= ci;
m_type= TYPE_CHARACTER_SET_COLLATE_EXACT;
@ -544,6 +561,21 @@ public:
{
return m_ci;
}
CHARSET_INFO *charset_info(Sql_used *used,
const Charset_collation_map_st &map) const
{
switch (m_type)
{
case TYPE_CHARACTER_SET:
return map.get_collation_for_charset(used, m_ci);
case TYPE_EMPTY:
case TYPE_CHARACTER_SET_COLLATE_EXACT:
case TYPE_COLLATE_CONTEXTUALLY_TYPED:
case TYPE_COLLATE_EXACT:
break;
}
return m_ci;
}
Type type() const
{
return m_type;
@ -552,7 +584,9 @@ public:
{
return m_type == TYPE_COLLATE_CONTEXTUALLY_TYPED;
}
CHARSET_INFO *resolved_to_character_set(CHARSET_INFO *cs) const;
CHARSET_INFO *resolved_to_character_set(Sql_used *used,
const Charset_collation_map_st &map,
CHARSET_INFO *cs) const;
/*
Merge the column CHARACTER SET clause to:
- an exact collation name
@ -561,15 +595,17 @@ public:
"cl" corresponds to the COLLATE clause
*/
bool merge_column_charset_clause_and_collate_clause(
Sql_used *used,
const Charset_collation_map_st &map,
const Lex_exact_charset_extended_collation_attrs_st &cl)
{
switch (cl.type()) {
case TYPE_EMPTY:
return false;
case TYPE_COLLATE_EXACT:
return merge_exact_collation(Lex_exact_collation(cl.charset_info()));
return merge_exact_collation(Lex_exact_collation(cl.m_ci));
case TYPE_COLLATE_CONTEXTUALLY_TYPED:
return merge_context_collation(Lex_context_collation(cl.charset_info()));
return merge_context_collation(used, map, Lex_context_collation(cl.m_ci));
case TYPE_CHARACTER_SET:
case TYPE_CHARACTER_SET_COLLATE_EXACT:
break;
@ -584,6 +620,8 @@ public:
in an independent COLLATE clause in a column attribute.
*/
bool merge_column_collate_clause_and_collate_clause(
Sql_used *used,
const Charset_collation_map_st &map,
const Lex_exact_charset_extended_collation_attrs_st &cl)
{
DBUG_ASSERT(m_type != TYPE_CHARACTER_SET);
@ -591,9 +629,9 @@ public:
case TYPE_EMPTY:
return false;
case TYPE_COLLATE_EXACT:
return merge_exact_collation(Lex_exact_collation(cl.charset_info()));
return merge_exact_collation(Lex_exact_collation(cl.m_ci));
case TYPE_COLLATE_CONTEXTUALLY_TYPED:
return merge_context_collation(Lex_context_collation(cl.charset_info()));
return merge_context_collation(used, map, Lex_context_collation(cl.m_ci));
case TYPE_CHARACTER_SET:
case TYPE_CHARACTER_SET_COLLATE_EXACT:
break;
@ -601,10 +639,16 @@ public:
DBUG_ASSERT(0);
return false;
}
bool merge_exact_charset(const Lex_exact_charset &cs);
bool merge_exact_charset(Sql_used *used,
const Charset_collation_map_st &map,
const Lex_exact_charset &cs);
bool merge_exact_collation(const Lex_exact_collation &cl);
bool merge_context_collation(const Lex_context_collation &cl);
bool merge_collation(const Lex_extended_collation_st &cl);
bool merge_context_collation(Sql_used *used,
const Charset_collation_map_st &map,
const Lex_context_collation &cl);
bool merge_collation(Sql_used *used,
const Charset_collation_map_st &map,
const Lex_extended_collation_st &cl);
};
@ -713,9 +757,13 @@ public:
}
bool raise_if_charset_conflicts_with_default(
const Lex_exact_charset_opt_extended_collate &def) const;
CHARSET_INFO *resolved_to_context(const Charset_collation_context &ctx) const;
CHARSET_INFO *resolved_to_context(Sql_used *used,
const Charset_collation_map_st &map,
const Charset_collation_context &ctx) const;
bool merge_charset_default();
bool merge_exact_charset(const Lex_exact_charset &cs);
bool merge_exact_charset(Sql_used *used,
const Charset_collation_map_st &map,
const Lex_exact_charset &cs);
};

View file

@ -1330,6 +1330,7 @@ code_name(int code)
case Q_HRNOW: return "Q_HRNOW";
case Q_XID: return "XID";
case Q_GTID_FLAGS3: return "Q_GTID_FLAGS3";
case Q_CHARACTER_SET_COLLATIONS: return "Q_CHARACTER_SET_COLLATIONS";
}
sprintf(buf, "CODE#%d", code);
return buf;
@ -1375,7 +1376,8 @@ Query_log_event::Query_log_event(const uchar *buf, uint event_len,
Log_event_type event_type)
:Log_event(buf, description_event), data_buf(0), query(NullS),
db(NullS), catalog_len(0), status_vars_len(0),
flags2_inited(0), sql_mode_inited(0), charset_inited(0), flags2(0),
flags2_inited(0), sql_mode_inited(0), charset_inited(0),
character_set_collations({0,0}), flags2(0),
auto_increment_increment(1), auto_increment_offset(1),
time_zone_len(0), lc_time_names_number(0), charset_database_number(0),
table_map_for_update(0), xid(0), gtid_flags_extra(0),
@ -1480,6 +1482,17 @@ Query_log_event::Query_log_event(const uchar *buf, uint event_len,
pos+= 6;
break;
}
case Q_CHARACTER_SET_COLLATIONS:
{
const uchar *pos0= pos;
CHECK_SPACE(pos, end, 1);
uint16 count= *pos++;
CHECK_SPACE(pos, end, count * 4);
pos+= count * 4;
character_set_collations= Lex_cstring((const char *) pos0,
(const char *) pos);
break;
}
case Q_TIME_ZONE_CODE:
{
if (get_str_len_and_pointer(&pos, &time_zone_str, &time_zone_len, end))

View file

@ -40,6 +40,7 @@
#include <functional>
#include <memory>
#include <map>
#include <lex_charset.h>
#ifdef MYSQL_CLIENT
#include "sql_const.h"
@ -225,7 +226,8 @@ class String;
packet (i.e. a query) sent from client to master;
First, an auxiliary log_event status vars estimation:
*/
#define MAX_SIZE_LOG_EVENT_STATUS (1 + 4 /* type, flags2 */ + \
#define MAX_SIZE_LOG_EVENT_STATUS (uint) \
(1 + 4 /* type, flags2 */ + \
1 + 8 /* type, sql_mode */ + \
1 + 1 + 255 /* type, length, catalog */ + \
1 + 4 /* type, auto_increment */ + \
@ -237,7 +239,10 @@ class String;
1 + 4 /* type, master_data_written */ + \
1 + 3 /* type, sec_part of NOW() */ + \
1 + 16 + 1 + 60/* type, user_len, user, host_len, host */ + \
1 + 2 + 8 /* type, flags3, seq_no */)
1 + 2 + 8 /* type, flags3, seq_no */ + \
1 + Charset_collation_map_st::binary_size_max() \
/* type, map */ \
)
#define MAX_LOG_EVENT_HEADER ( /* in order of Query_log_event::write */ \
LOG_EVENT_HEADER_LEN + /* write_header */ \
QUERY_HEADER_LEN + /* write_data */ \
@ -319,6 +324,8 @@ class String;
#define Q_XID 129
#define Q_GTID_FLAGS3 130
#define Q_CHARACTER_SET_COLLATIONS 131
/* Intvar event post-header */
/* Intvar event data */
@ -2131,6 +2138,8 @@ public:
bool sql_mode_inited;
bool charset_inited;
LEX_CSTRING character_set_collations;
uint32 flags2;
sql_mode_t sql_mode;
ulong auto_increment_increment, auto_increment_offset;

View file

@ -1982,6 +1982,38 @@ bool Query_log_event::print_query_header(IO_CACHE* file,
memcpy(print_event_info->charset, charset, 6);
print_event_info->charset_inited= 1;
}
if (character_set_collations.length)
{
Charset_collation_map_st map;
size_t length= map.from_binary(character_set_collations.str,
character_set_collations.length);
if (length == character_set_collations.length)
{
Binary_string str;
size_t nbytes= map.text_format_nbytes_needed();
if (str.alloc(nbytes))
goto err;
size_t text_length= map.print((char*) str.ptr(), nbytes);
str.length(text_length);
/*
my_b_printf() does not seem to support '%.*s'
so append a \0 terminator.
*/
str.append_char('\0');
if (my_b_printf(file, "SET @@session.character_set_collations='%s'%s\n",
str.ptr(), print_event_info->delimiter))
goto err;
}
else
{
if (my_b_printf(file,
"/* SET @@session.character_set_collations='%s' */\n",
"<format not recognized>"))
goto err;
}
}
if (time_zone_len)
{
if (memcmp(print_event_info->time_zone_str,

View file

@ -1164,6 +1164,14 @@ bool Query_log_event::write()
int2store(start+2, auto_increment_offset);
start+= 4;
}
if (thd && (thd->used & THD::CHARACTER_SET_COLLATIONS_USED))
{
*start++= Q_CHARACTER_SET_COLLATIONS;
size_t len= thd->variables.character_set_collations.to_binary((char*)start);
start+= len;
}
if (charset_inited)
{
*start++= Q_CHARSET_CODE;
@ -1946,6 +1954,17 @@ int Query_log_event::do_apply_event(rpl_group_info *rgi,
thd->variables.sql_mode=
(sql_mode_t) ((thd->variables.sql_mode & MODE_NO_DIR_IN_CREATE) |
(sql_mode & ~(sql_mode_t) MODE_NO_DIR_IN_CREATE));
size_t cslen= thd->variables.character_set_collations.from_binary(
character_set_collations.str,
character_set_collations.length);
if (cslen != character_set_collations.length)
{
// Fatal: either a broken even, or an unknown collation ID
thd->variables.character_set_collations.init();
goto compare_errors; // QQ: report an error here?
}
if (charset_inited)
{
rpl_sql_thread_info *sql_info= thd->system_thread_info.rpl_sql_info;

View file

@ -351,6 +351,7 @@ char *enforced_storage_engine=NULL;
char *gtid_pos_auto_engines;
plugin_ref *opt_gtid_pos_auto_plugins;
static char compiled_default_collation_name[]= MYSQL_DEFAULT_COLLATION_NAME;
static const char *character_set_collations_str= "";
Thread_cache thread_cache;
static bool binlog_format_used= false;
LEX_STRING opt_init_connect, opt_init_slave;
@ -4288,6 +4289,18 @@ static int init_common_variables()
*/
myf utf8_flag= global_system_variables.old_behavior &
OLD_MODE_UTF8_IS_UTF8MB3 ? MY_UTF8_IS_UTF8MB3 : 0;
if (character_set_collations_str[0])
{
Lex_cstring_strlen str(character_set_collations_str);
if (global_system_variables.character_set_collations.
from_text(str, utf8_flag))
{
sql_print_error(ER_DEFAULT(ER_WRONG_VALUE_FOR_VAR),
"character_set_collations", character_set_collations_str);
}
}
for (;;)
{
char *next_character_set_name= strchr(default_character_set_name, ',');
@ -4306,7 +4319,13 @@ static int init_common_variables()
return 1; // Eof of the list
}
else
{
Sql_used used;
default_charset_info= global_system_variables.character_set_collations.
get_collation_for_charset(&used,
default_charset_info);
break;
}
}
if (default_collation_name)
@ -6520,6 +6539,9 @@ struct my_option my_long_options[]=
{"collation-server", 0, "Set the default collation.",
&default_collation_name, &default_collation_name,
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
{"character-set-collations", 0, "Overrides for character set default collations.",
&character_set_collations_str, &character_set_collations_str,
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
{"console", OPT_CONSOLE, "Write error output on screen; don't remove the console window on windows.",
&opt_console, &opt_console, 0, GET_BOOL, NO_ARG, 0, 0, 0,
0, 0, 0},

85
sql/simple_tokenizer.h Normal file
View file

@ -0,0 +1,85 @@
/* Copyright (c) 2023, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
#ifndef SIMPLE_TOKENIZER_INCLUDED
#define SIMPLE_TOKENIZER_INCLUDED
class Simple_tokenizer
{
const char *m_ptr;
const char *m_end;
public:
Simple_tokenizer(const char *str, size_t length)
:m_ptr(str), m_end(str + length)
{ }
const char *ptr() const
{
return m_ptr;
}
bool eof() const
{
return m_ptr >= m_end;
}
void get_spaces()
{
for ( ; !eof(); m_ptr++)
{
if (m_ptr[0] != ' ')
break;
}
}
bool is_ident_start(char ch) const
{
return (ch >= 'a' && ch <= 'z') ||
(ch >= 'A' && ch <= 'Z') ||
ch == '_';
}
bool is_ident_body(char ch) const
{
return is_ident_start(ch) ||
(ch >= '0' && ch <= '9');
}
bool is_ident_start() const
{
return !eof() && is_ident_start(*m_ptr);
}
bool is_ident_body() const
{
return !eof() && is_ident_body(*m_ptr);
}
LEX_CSTRING get_ident()
{
get_spaces();
if (!is_ident_start())
return {m_ptr,0};
const char *start= m_ptr++;
for ( ; is_ident_body(); m_ptr++)
{ }
LEX_CSTRING res= {start, (size_t) (m_ptr - start)};
return res;
}
bool get_char(char ch)
{
get_spaces();
if (eof() || *m_ptr != ch)
return true;
m_ptr++;
return false;
}
};
#endif // SIMPLE_TOKENIZER_INCLUDED

View file

@ -637,7 +637,7 @@ THD::THD(my_thread_id id, bool is_wsrep_applier)
protocol_text(this), protocol_binary(this), initial_status_var(0),
m_current_stage_key(0), m_psi(0),
in_sub_stmt(0), log_all_errors(0),
binlog_unsafe_warning_flags(0), used(0),
binlog_unsafe_warning_flags(0),
current_stmt_binlog_format(BINLOG_FORMAT_MIXED),
bulk_param(0),
table_map_for_update(0),

View file

@ -24,6 +24,7 @@
#include "dur_prop.h"
#include <waiting_threads.h>
#include "sql_const.h"
#include "sql_used.h"
#include <mysql/plugin_audit.h>
#include "log.h"
#include "rpl_tblmap.h"
@ -886,6 +887,8 @@ typedef struct system_variables
vers_asof_timestamp_t vers_asof_timestamp;
my_bool binlog_alter_two_phase;
Charset_collation_map_st character_set_collations;
} SV;
/**
@ -2603,6 +2606,7 @@ struct thd_async_state
*/
class THD: public THD_count, /* this must be first */
public Sql_used,
public Statement,
/*
This is to track items changed during execution of a prepared
@ -2925,12 +2929,6 @@ public:
*/
uint32 binlog_unsafe_warning_flags;
typedef uint used_t;
enum { RAND_USED=1, TIME_ZONE_USED=2, QUERY_START_SEC_PART_USED=4,
THREAD_SPECIFIC_USED=8 };
used_t used;
#ifndef MYSQL_CLIENT
binlog_cache_mngr * binlog_setup_trx_data();
/*

View file

@ -801,6 +801,9 @@ bool thd_init_client_charset(THD *thd, uint cs_number)
cs->cs_name.str);
return true;
}
Sql_used used;
cs= global_system_variables.character_set_collations.
get_collation_for_charset(&used, cs);
thd->org_charset= cs;
thd->update_charset(cs,cs,cs);
}

View file

@ -4465,19 +4465,23 @@ public:
bool add_alter_list(LEX_CSTRING par_name, Virtual_column_info *expr,
bool par_exists);
bool add_alter_list(LEX_CSTRING name, LEX_CSTRING new_name, bool exists);
bool add_alter_list_item_convert_to_charset(CHARSET_INFO *cs)
bool add_alter_list_item_convert_to_charset(Sql_used *used,
const Charset_collation_map_st &map,
CHARSET_INFO *cs)
{
if (create_info.add_table_option_convert_charset(cs))
if (create_info.add_table_option_convert_charset(used, map, cs))
return true;
alter_info.flags|= ALTER_CONVERT_TO;
return false;
}
bool
add_alter_list_item_convert_to_charset(CHARSET_INFO *cs,
add_alter_list_item_convert_to_charset(Sql_used *used,
const Charset_collation_map_st &map,
CHARSET_INFO *cs,
const Lex_extended_collation_st &cl)
{
if (create_info.add_table_option_convert_charset(cs) ||
create_info.add_table_option_convert_collation(cl))
if (create_info.add_table_option_convert_charset(used, map, cs) ||
create_info.add_table_option_convert_collation(used, map, cl))
return true;
alter_info.flags|= ALTER_CONVERT_TO;
return false;

View file

@ -5812,6 +5812,32 @@ finish:
}
thd->reset_kill_query();
}
/*
Binary logging is now done. Unset the "used" flags to avoid
flags leaking to the next event (and to the COMMIT statement
in the end of the current event).
Example:
Suppose a non-default collation (in @@character_set_collations)
was used during the statement, the mysqlbinlog output for
the current statement will contain a sequence like this:
SET character_set_collations='utf8mb3=utf8mb3_bin';
INSERT INTO t1 VALUES (_utf8mb3'test');
COMMIT;
The statment (INSERT in this example) is already in binlog at this point, and the
and the "SET character_set_collations" is written inside a
Q_CHARACTER_SET_COLLATIONS chunk in its log entry header.
The flag CHARACTER_SET_COLLATIONS_USED is not needed any more.
The COMMIT can be printed without "SET character_set_collations".
The same logic applies to the other _USED flags.
*/
thd->used= 0;
if (unlikely(thd->is_error()) ||
(thd->variables.option_bits & OPTION_MASTER_SQL_ERROR))
{

View file

@ -226,6 +226,20 @@ private:
*/
MEM_ROOT main_mem_root;
sql_mode_t m_sql_mode;
THD::used_t m_prepare_time_thd_used_flags;
uint m_prepare_time_charset_collation_map_version;
bool check_charset_collation_map_version(THD *thd,
Reprepare_observer *observer)
{
if ((m_prepare_time_thd_used_flags & THD::CHARACTER_SET_COLLATIONS_USED) &&
m_prepare_time_charset_collation_map_version !=
thd->variables.character_set_collations.version())
{
observer->report_error(thd);
return true;
}
return false;
}
private:
bool set_db(const LEX_CSTRING *db);
bool set_parameters(String *expanded_query,
@ -3891,7 +3905,9 @@ Prepared_statement::Prepared_statement(THD *thd_arg)
iterations(0),
start_param(0),
read_types(0),
m_sql_mode(thd->variables.sql_mode)
m_sql_mode(thd->variables.sql_mode),
m_prepare_time_thd_used_flags(0),
m_prepare_time_charset_collation_map_version(0)
{
init_sql_alloc(key_memory_prepared_statement_main_mem_root,
&main_mem_root, thd_arg->variables.query_alloc_block_size,
@ -4274,6 +4290,9 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len)
}
// The same format as for triggers to compare
hr_prepare_time= my_hrtime();
m_prepare_time_thd_used_flags= thd->used;
m_prepare_time_charset_collation_map_version=
thd->variables.character_set_collations.version();
DBUG_RETURN(error);
}
@ -4829,6 +4848,13 @@ Prepared_statement::swap_prepared_statement(Prepared_statement *copy)
/* Ditto */
swap_variables(LEX_CSTRING, db, copy->db);
swap_variables(uint,
m_prepare_time_charset_collation_map_version,
copy->m_prepare_time_charset_collation_map_version);
swap_variables(THD::used_t,
m_prepare_time_thd_used_flags,
copy->m_prepare_time_thd_used_flags);
DBUG_ASSERT(param_count == copy->param_count);
DBUG_ASSERT(thd == copy->thd);
last_error[0]= '\0';
@ -4872,6 +4898,9 @@ bool Prepared_statement::execute(String *expanded_query, bool open_cursor)
LEX_CSTRING stmt_db_name= db;
if (check_charset_collation_map_version(thd, thd->m_reprepare_observer))
return true;
status_var_increment(thd->status_var.com_stmt_execute);
if (flags & (uint) IS_IN_USE)
@ -4989,6 +5018,15 @@ bool Prepared_statement::execute(String *expanded_query, bool open_cursor)
MYSQL_QUERY_EXEC_START(thd->query(), thd->thread_id, thd->get_db(),
&thd->security_ctx->priv_user[0],
(char *) thd->security_ctx->host_or_ip, 1);
/*
Some thd->used flags are set only during PREPARE.
For example CHARACTER_SET_COLLATIONS_USED is in most cases
set during parsing only.
Mix PREPARE time thd->used flags to EXECUTE time thd->used flags,
e.g. to have the log event header write an optional chunk with
the @@character_set_collations map.
*/
thd->used|= m_prepare_time_thd_used_flags;
error= mysql_execute_command(thd, true);
MYSQL_QUERY_EXEC_DONE(error);
thd->update_server_status();

View file

@ -6257,7 +6257,9 @@ int fill_schema_charsets(THD *thd, TABLE_LIST *tables, COND *cond)
const char *comment;
restore_record(table, s->default_values);
table->field[0]->store(&tmp_cs->cs_name, scs);
table->field[1]->store(&tmp_cs->coll_name, scs);
CHARSET_INFO *def_cl= thd->variables.character_set_collations.
get_collation_for_charset(thd, tmp_cs);
table->field[1]->store(&def_cl->coll_name, scs);
comment= tmp_cs->comment ? tmp_cs->comment : "";
table->field[2]->store(comment, strlen(comment), scs);
table->field[3]->store((longlong) tmp_cs->mbmaxlen, TRUE);
@ -6360,6 +6362,8 @@ int fill_schema_collation(THD *thd, TABLE_LIST *tables, COND *cond)
(tmp_cs->state & MY_CS_HIDDEN) ||
!(tmp_cs->state & MY_CS_PRIMARY))
continue;
CHARSET_INFO *def_cl= thd->variables.character_set_collations.
get_collation_for_charset(thd, tmp_cs);
for (cl= all_charsets;
cl < all_charsets + array_elements(all_charsets) ;
cl ++)
@ -6400,7 +6404,7 @@ int fill_schema_collation(THD *thd, TABLE_LIST *tables, COND *cond)
table->field[2]->store((longlong) tmp_cl->number, TRUE);
table->field[3]->set_notnull(); // IS_DEFAULT
table->field[3]->store(
Show::Yes_or_empty::value(tmp_cl->default_flag()), scs);
Show::Yes_or_empty::value(def_cl == tmp_cl), scs);
}
table->field[4]->store(
Show::Yes_or_empty::value(tmp_cl->compiled_flag()), scs);
@ -6428,6 +6432,8 @@ int fill_schema_coll_charset_app(THD *thd, TABLE_LIST *tables, COND *cond)
if (!tmp_cs || !(tmp_cs->state & MY_CS_AVAILABLE) ||
!(tmp_cs->state & MY_CS_PRIMARY))
continue;
CHARSET_INFO *def_cl= thd->variables.character_set_collations.
get_collation_for_charset(thd, tmp_cs);
for (cl= all_charsets;
cl < all_charsets + array_elements(all_charsets) ;
cl ++)
@ -6447,7 +6453,7 @@ int fill_schema_coll_charset_app(THD *thd, TABLE_LIST *tables, COND *cond)
table->field[2]->store(full_collation_name, scs);
table->field[3]->store(tmp_cl->number);
table->field[4]->store(
Show::Yes_or_empty::value(tmp_cl->default_flag()), scs);
Show::Yes_or_empty::value(def_cl == tmp_cl), scs);
if (schema_table_store_record(thd, table))
return 1;
}

View file

@ -2201,10 +2201,12 @@ bool check_duplicates_in_interval(const char *set_or_name,
Generates an error to the diagnostics area in case of a failure.
*/
bool Column_definition::
prepare_charset_for_string(const Column_derived_attributes *dattr)
prepare_charset_for_string(Sql_used *used,
const Charset_collation_map_st &map,
const Column_derived_attributes *dattr)
{
CHARSET_INFO *tmp= charset_collation_attrs().
resolved_to_character_set(dattr->charset());
resolved_to_character_set(used, map, dattr->charset());
if (!tmp)
return true;
charset= tmp;
@ -12535,7 +12537,8 @@ bool HA_CREATE_INFO::
// Make sure we don't do double resolution in direct SQL execution
DBUG_ASSERT(!default_table_charset || thd->stmt_arena->is_stmt_execute());
if (!(default_table_charset=
default_cscl.resolved_to_context(ctx)))
default_cscl.resolved_to_context(thd,
thd->variables.character_set_collations, ctx)))
return true;
}
@ -12547,7 +12550,8 @@ bool HA_CREATE_INFO::
DBUG_ASSERT(!alter_table_convert_to_charset ||
thd->stmt_arena->is_stmt_execute());
if (!(alter_table_convert_to_charset=
convert_cscl.resolved_to_context(ctx)))
convert_cscl.resolved_to_context(thd,
thd->variables.character_set_collations, ctx)))
return true;
}
return false;

View file

@ -2718,7 +2718,9 @@ Type_handler::Column_definition_set_attributes(THD *thd,
column_definition_type_t type)
const
{
def->set_charset_collation_attrs(attr.charset_collation_attrs());
def->set_charset_collation_attrs(thd,
thd->variables.character_set_collations,
attr.charset_collation_attrs());
def->set_length_and_dec(attr);
return false;
}
@ -3026,7 +3028,9 @@ bool Type_handler_null::
*derived_attr)
const
{
def->prepare_charset_for_string(derived_attr);
def->prepare_charset_for_string(thd,
thd->variables.character_set_collations,
derived_attr);
def->create_length_to_internal_length_null();
return false;
}
@ -3108,7 +3112,10 @@ bool Type_handler_typelib::
*derived_attr)
const
{
return def->prepare_charset_for_string(derived_attr) ||
return def->prepare_charset_for_string(thd,
thd->variables.
character_set_collations,
derived_attr) ||
def->prepare_stage1_typelib(thd, mem_root, type);
}
@ -3122,7 +3129,10 @@ bool Type_handler_string_result::
*derived_attr)
const
{
return def->prepare_charset_for_string(derived_attr) ||
return def->prepare_charset_for_string(thd,
thd->variables.
character_set_collations,
derived_attr) ||
def->prepare_stage1_string(thd, mem_root);
}

33
sql/sql_used.h Normal file
View file

@ -0,0 +1,33 @@
/* Copyright (c) 2023, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
#ifndef SQL_USED_INCLUDED
#define SQL_USED_INCLUDED
class Sql_used
{
public:
typedef uint used_t;
enum { RAND_USED=1, TIME_ZONE_USED=2, QUERY_START_SEC_PART_USED=4,
THREAD_SPECIFIC_USED=8,
CHARACTER_SET_COLLATIONS_USED= 16
};
used_t used;
Sql_used()
:used(0)
{ }
};
#endif // SQL_USED_INCLUDED

View file

@ -5565,7 +5565,8 @@ versioning_option:
default_charset:
opt_default charset opt_equal charset_name_or_default
{
if (unlikely(Lex->create_info.add_table_option_default_charset($4)))
if (unlikely(Lex->create_info.add_table_option_default_charset(
thd, thd->variables.character_set_collations, $4)))
MYSQL_YYABORT;
}
;
@ -5574,7 +5575,8 @@ default_collation:
opt_default COLLATE_SYM opt_equal collation_name_or_default
{
Table_specification_st *cinfo= &Lex->create_info;
if (unlikely(cinfo->add_table_option_default_collation($4)))
if (unlikely(cinfo->add_table_option_default_collation(
thd, thd->variables.character_set_collations, $4)))
MYSQL_YYABORT;
}
;
@ -5827,9 +5829,12 @@ field_type_or_serial:
field_def
{
auto tmp= $1.charset_collation_attrs();
if (tmp.merge_column_charset_clause_and_collate_clause($3))
if (tmp.merge_column_charset_clause_and_collate_clause(
thd, thd->variables.character_set_collations, $3))
MYSQL_YYABORT;
Lex->last_field->set_charset_collation_attrs(tmp);
Lex->last_field->set_charset_collation_attrs(
thd, thd->variables.character_set_collations,
tmp);
}
| SERIAL_SYM
{
@ -5867,7 +5872,8 @@ field_def:
| attribute_list compressed_deprecated_column_attribute { $$= $1; }
| attribute_list compressed_deprecated_column_attribute attribute_list
{
if (($$= $1).merge_column_collate_clause_and_collate_clause($3))
if (($$= $1).merge_column_collate_clause_and_collate_clause(
thd, thd->variables.character_set_collations, $3))
MYSQL_YYABORT;
}
| opt_generated_always AS virtual_column_func
@ -6347,8 +6353,9 @@ opt_precision:
attribute_list:
attribute_list attribute
{
if (($$= $1).merge_column_collate_clause_and_collate_clause($2))
MYSQL_YYABORT;
if (($$= $1).merge_column_collate_clause_and_collate_clause(
thd, thd->variables.character_set_collations, $2))
MYSQL_YYABORT;
}
| attribute
;
@ -6575,11 +6582,17 @@ binary:
}
| charset_or_alias COLLATE_SYM DEFAULT
{
$$.set_charset_collate_default(Lex_exact_charset($1));
$$.set_charset_collate_default(
thd,
thd->variables.character_set_collations,
Lex_exact_charset($1));
}
| charset_or_alias COLLATE_SYM collation_name
{
if ($3.merge_exact_charset(Lex_exact_charset($1)))
if ($3.merge_exact_charset(
thd,
thd->variables.character_set_collations,
Lex_exact_charset($1)))
MYSQL_YYABORT;
$$= Lex_exact_charset_extended_collation_attrs($3);
}
@ -7660,13 +7673,15 @@ alter_list_item:
}
| CONVERT_SYM TO_SYM charset charset_name_or_default
{
if (Lex->add_alter_list_item_convert_to_charset($4))
if (Lex->add_alter_list_item_convert_to_charset(
thd, thd->variables.character_set_collations, $4))
MYSQL_YYABORT;
}
| CONVERT_SYM TO_SYM charset charset_name_or_default
COLLATE_SYM collation_name_or_default
{
if (Lex->add_alter_list_item_convert_to_charset($4, $6))
if (Lex->add_alter_list_item_convert_to_charset(
thd, thd->variables.character_set_collations, $4, $6))
MYSQL_YYABORT;
}
| create_table_options_space_separated
@ -9542,7 +9557,9 @@ temporal_dyncol_type:
string_dyncol_type:
char opt_binary
{
if ($$.set(DYN_COL_STRING, $2, thd->variables.collation_connection))
if ($$.set(DYN_COL_STRING, thd,
thd->variables.character_set_collations,
$2, thd->variables.collation_connection))
MYSQL_YYABORT;
}
| nchar
@ -9721,6 +9738,8 @@ column_default_non_parenthesized_expr:
}
| CONVERT_SYM '(' expr USING charset_name ')'
{
$5= thd->variables.character_set_collations.
get_collation_for_charset(thd, $5);
$$= new (thd->mem_root) Item_func_conv_charset(thd, $3, $5);
if (unlikely($$ == NULL))
MYSQL_YYABORT;
@ -9873,6 +9892,8 @@ function_call_keyword:
}
| CHAR_SYM '(' expr_list USING charset_name ')'
{
$5= thd->variables.character_set_collations.
get_collation_for_charset(thd, $5);
$$= new (thd->mem_root) Item_func_char(thd, *$3, $5);
if (unlikely($$ == NULL))
MYSQL_YYABORT;
@ -11174,19 +11195,22 @@ cast_type:
{ $$.set(&type_handler_long_blob, $2, &my_charset_bin); }
| CHAR_SYM opt_field_length opt_binary
{
if ($$.set(&type_handler_long_blob, $2, $3,
if ($$.set(&type_handler_long_blob,
$2, thd, thd->variables.character_set_collations, $3,
thd->variables.collation_connection))
MYSQL_YYABORT;
}
| VARCHAR field_length opt_binary
{
if ($$.set(&type_handler_long_blob, $2, $3,
if ($$.set(&type_handler_long_blob,
$2, thd, thd->variables.character_set_collations, $3,
thd->variables.collation_connection))
MYSQL_YYABORT;
}
| VARCHAR2_ORACLE_SYM field_length opt_binary
{
if ($$.set(&type_handler_long_blob, $2, $3,
if ($$.set(&type_handler_long_blob,
$2, thd, thd->variables.character_set_collations, $3,
thd->variables.collation_connection))
MYSQL_YYABORT;
}
@ -14839,6 +14863,8 @@ text_literal:
}
| UNDERSCORE_CHARSET TEXT_STRING
{
$1= thd->variables.character_set_collations.
get_collation_for_charset(thd, $1);
if (unlikely(!($$= thd->make_string_literal_charset($2, $1))))
MYSQL_YYABORT;
}
@ -14978,6 +15004,8 @@ literal:
Item_string_with_introducer *item_str;
LEX_CSTRING tmp;
$2->get_value(&tmp);
$1= thd->variables.character_set_collations.
get_collation_for_charset(thd, $1);
/*
Pass NULL as name. Name will be set in the "select_item" rule and
will include the introducer and the original hex/bin notation.
@ -16694,7 +16722,11 @@ option_value_no_option_type:
{
CHARSET_INFO *def= global_system_variables.character_set_client;
Lex_exact_charset_opt_extended_collate tmp($2 ? $2 : def, false);
if (Lex->set_names($1.pos(), tmp, yychar == YYEMPTY))
Lex_extended_collation_st cl;
cl.set_collate_default();
if (tmp.merge_collation(thd, thd->variables.
character_set_collations, cl) ||
Lex->set_names($1.pos(), tmp, yychar == YYEMPTY))
MYSQL_YYABORT;
}
| NAMES_SYM charset_name_or_default
@ -16702,7 +16734,8 @@ option_value_no_option_type:
{
CHARSET_INFO *def= global_system_variables.character_set_client;
Lex_exact_charset_opt_extended_collate tmp($2 ? $2 : def, false);
if (tmp.merge_collation($4) ||
if (tmp.merge_collation(thd, thd->variables.
character_set_collations, $4) ||
Lex->set_names($1.pos(), tmp, yychar == YYEMPTY))
MYSQL_YYABORT;
}

View file

@ -773,10 +773,13 @@ public:
m_ci= cs;
Lex_length_and_dec_st::reset();
}
bool set(int type, const Lex_column_charset_collation_attrs_st &collation,
bool set(int type,
Sql_used *used,
const Charset_collation_map_st &map,
const Lex_column_charset_collation_attrs_st &collation,
CHARSET_INFO *charset)
{
CHARSET_INFO *tmp= collation.resolved_to_character_set(charset);
CHARSET_INFO *tmp= collation.resolved_to_character_set(used, map, charset);
if (!tmp)
return true;
set(type, tmp);

View file

@ -438,6 +438,14 @@ static bool update_auto_increment_increment (sys_var *self, THD *thd, enum_var_t
#endif /* WITH_WSREP */
static Sys_var_charset_collation_map Sys_character_set_collations(
"character_set_collations",
"Overrides for character set default collations",
SESSION_VAR(character_set_collations),
NO_CMD_LINE, NOT_IN_BINLOG);
static Sys_var_double Sys_analyze_sample_percentage(
"analyze_sample_percentage",
"Percentage of rows from the table ANALYZE TABLE will sample "
@ -819,7 +827,7 @@ static bool check_charset(sys_var *self, THD *thd, set_var *var)
((thd->variables.pseudo_slave_mode || thd->slave_thread) &&
(var->save_result.ptr=
Lex_exact_charset_opt_extended_collate(cs, true).
find_default_collation())))
find_compiled_default_collation())))
return false;
}
my_error(ER_UNKNOWN_CHARACTER_SET, MYF(0), llstr(csno, buff));

View file

@ -2994,3 +2994,104 @@ public:
virtual const uchar *global_value_ptr(THD *thd, const LEX_CSTRING *base) const
{ return value_ptr(thd, global_var(vers_asof_timestamp_t)); }
};
class Sys_var_charset_collation_map: public sys_var
{
public:
Sys_var_charset_collation_map(const char *name_arg, const char *comment,
int flag_args, ptrdiff_t off, size_t size,
CMD_LINE getopt,
enum binlog_status_enum binlog_status_arg)
:sys_var(&all_sys_vars, name_arg, comment,
flag_args, off, getopt.id, getopt.arg_type,
SHOW_CHAR,
DEFAULT(0), nullptr, binlog_status_arg,
nullptr, nullptr, nullptr)
{
option.var_type|= GET_STR;
}
private:
static bool charset_collation_map_from_item(Charset_collation_map_st *map,
Item *item,
myf utf8_flag)
{
String *value, buffer;
if (!(value= item->val_str_ascii(&buffer)))
return true;
return map->from_text(value->to_lex_cstring(), utf8_flag);
}
static const uchar *make_value_ptr(THD *thd,
const Charset_collation_map_st &map)
{
size_t nbytes= map.text_format_nbytes_needed();
char *buf= (char *) thd->alloc(nbytes + 1);
size_t length= map.print(buf, nbytes);
buf[length]= '\0';
return (uchar *) buf;
}
private:
bool do_check(THD *thd, set_var *var) override
{
Charset_collation_map_st *map= (Charset_collation_map_st*)
thd->alloc(sizeof(Charset_collation_map_st));
if (!map || charset_collation_map_from_item(map, var->value,
thd->get_utf8_flag()))
return true;
var->save_result.ptr= map;
return false;
}
void session_save_default(THD *thd, set_var *var) override
{
thd->variables.character_set_collations.set(
global_system_variables.character_set_collations, 1);
}
void global_save_default(THD *thd, set_var *var) override
{
global_system_variables.character_set_collations.init();
}
bool session_update(THD *thd, set_var *var) override
{
if (!var->value)
{
session_save_default(thd, var);
return false;
}
thd->variables.character_set_collations.
set(*(Charset_collation_map_st*) var->save_result.ptr, 1);
return false;
}
bool global_update(THD *thd, set_var *var) override
{
if (!var->value)
{
global_save_default(thd, var);
return false;
}
global_system_variables.character_set_collations=
*(Charset_collation_map_st*) var->save_result.ptr;
return false;
}
const uchar *
session_value_ptr(THD *thd, const LEX_CSTRING *base) const override
{
return make_value_ptr(thd, thd->variables.character_set_collations);
}
const uchar *
global_value_ptr(THD *thd, const LEX_CSTRING *base) const override
{
return make_value_ptr(thd, global_system_variables.
character_set_collations);
}
};