Main patch MDEV-27896 Wrong result upon COLLATE latin1_bin CHARACTER SET latin1 on the table or the database level

Also fixes
MDEV-27782 Wrong columns when using table level `CHARACTER SET utf8mb4 COLLATE DEFAULT`
MDEV-28644 Unexpected error on ALTER TABLE t1 CONVERT TO CHARACTER SET utf8mb3, DEFAULT CHARACTER SET utf8mb4
This commit is contained in:
Alexander Barkov 2022-05-17 12:52:23 +04:00
parent 89adedcb9f
commit 208addf484
25 changed files with 3255 additions and 206 deletions

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,366 @@
--source include/have_utf8mb4.inc
CREATE TABLE t0 (a VARCHAR(64));
INSERT INTO t0 VALUES
('CHARACTER SET DEFAULT'),
('CHARACTER SET latin1'),
('CHARACTER SET utf8mb4'),
('COLLATE DEFAULT'),
('COLLATE utf8mb4_bin'),
('COLLATE latin1_swedish_ci'),
('COLLATE latin1_bin');
CREATE TABLE clauses
(
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
cl1 VARCHAR(64) NOT NULL,
cl2 VARCHAR(64) NOT NULL,
cl3 VARCHAR(64) NOT NULL,
clause_count INT GENERATED ALWAYS AS ((cl1<>'') + (cl2<>'') + (cl3<>'')),
clauses TEXT GENERATED ALWAYS AS (CONCAT(cl1,
IF(cl2='','',' '), cl2,
IF(cl3='','',' '), cl3))
);
# No clauses
INSERT INTO clauses (cl1, cl2, cl3)
SELECT '' AS cl1, '' AS cl2, '' AS cl3;
# One clause
INSERT INTO clauses (cl1, cl2, cl3)
SELECT t0.a AS cl1, '' AS cl2, '' AS cl3
FROM t0;
# Two clauses
INSERT INTO clauses (cl1, cl2, cl3)
SELECT t0.a AS cl1, t2.a AS cl2, '' AS cl3
FROM t0 t0, t0 t2;
# Three clauses
INSERT INTO clauses (cl1, cl2, cl3)
SELECT t0.a AS cl1, t2.a AS cl2, t3.a AS cl3
FROM t0 t0, t0 t2, t0 t3;
DROP TABLE t0;
CREATE TABLE results_template
(
id INT NOT NULL PRIMARY KEY,
result TEXT NOT NULL
);
DELIMITER $$;
CREATE PROCEDURE diff_result_tables_stat(table1 VARCHAR(64),
table2 VARCHAR(64),
cond VARCHAR(128))
BEGIN
DECLARE query_counts TEXT DEFAULT
'SELECT '
' COUNT(*),'
' SUM(t1.result=t2.result),'
' SUM(t1.result<>t2.result) '
'FROM table1 t1 JOIN table2 t2 USING (id)/*$(WHERE)*/';
SET query_counts=REPLACE(query_counts, 'table1', table1);
SET query_counts=REPLACE(query_counts, 'table2', table2);
IF (cond<>'')
THEN
SET query_counts=REPLACE(query_counts, '/*$(WHERE)*/', CONCAT('WHERE ',cond));
END IF;
EXECUTE IMMEDIATE query_counts;
END;
$$
DELIMITER ;$$
DELIMITER $$;
CREATE PROCEDURE diff_result_tables_records(table1 VARCHAR(64),
table2 VARCHAR(64),
cond VARCHAR(128))
BEGIN
DECLARE query_records TEXT DEFAULT
'SELECT '
' '''' AS ``,'
' clauses.clauses AS attrs,'
' t1.result AS `aaa`,'
' t2.result AS `bbb` '
' FROM table1 t1'
' JOIN table2 t2 USING (id)'
' JOIN clauses USING (id) '
' WHERE t1.result<>t2.result /*$(COND)*/ ORDER BY t1.id';
SET query_records=REPLACE(query_records, 'table1', table1);
SET query_records=REPLACE(query_records, 'table2', table2);
IF (cond<>'')
THEN
SET query_records=REPLACE(query_records, '/*$(COND)*/', CONCAT('AND ',cond));
END IF;
EXECUTE IMMEDIATE query_records;
END;
$$
DELIMITER ;$$
DELIMITER $$;
CREATE PROCEDURE diff_result_tables(table1 VARCHAR(64),
table2 VARCHAR(64),
cond VARCHAR(128))
BEGIN
CALL diff_result_tables_stat(table1, table2, cond);
CALL diff_result_tables_records(table1, table2, cond);
END;
$$
DELIMITER ;$$
DELIMITER $$;
CREATE PROCEDURE exec(query_bootstrap TEXT,
query_pattern TEXT,
query_cleanup TEXT,
id INT,
clauses TEXT)
BEGIN
DECLARE query TEXT DEFAULT REPLACE(query_pattern, '/*CSCL*/',clauses);
DECLARE result TEXT DEFAULT NULL;
DECLARE CONTINUE HANDLER FOR
1064, /*ER_PARSE_ERROR*/
1302, /*ER_CONFLICTING_DECLARATIONS*/
1253 /*ER_COLLATION_CHARSET_MISMATCH*/
BEGIN
GET DIAGNOSTICS CONDITION 1 result=MESSAGE_TEXT;
SET result=CONCAT('ERROR: ', result);
END;
IF query_bootstrap<>''
THEN
EXECUTE IMMEDIATE query_bootstrap;
END IF;
EXECUTE IMMEDIATE query;
IF result IS NULL
THEN
IF query_pattern LIKE '%DATABASE%'
THEN
SET result=(SELECT CONCAT('CHARACTER SET ', DEFAULT_CHARACTER_SET_NAME,
' COLLATE ', DEFAULT_COLLATION_NAME)
FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME='db1');
ELSE
SET result=(SELECT CONCAT('CHARACTER SET ', SUBSTRING_INDEX(TABLE_COLLATION,'_',1),
' COLLATE ', TABLE_COLLATION)
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME='t1' AND TABLE_SCHEMA='test1');
END IF;
END IF;
INSERT INTO results (id, result) VALUES (id, result);
IF query_cleanup<>''
THEN
EXECUTE IMMEDIATE query_cleanup;
END IF;
END;
$$
DELIMITER ;$$
DELIMITER $$;
CREATE PROCEDURE show_results(query TEXT, clause_count_arg INT)
BEGIN
SELECT '' AS ``, CONCAT(clause_count_arg, ' clauses') AS `TEST:`;
SELECT '' AS ``, COUNT(*) AS `TOTAL`
FROM results JOIN clauses USING (id)
WHERE clauses.clause_count=clause_count_arg;
-- Display erroneous results
SELECT '' AS ``, COUNT(*) AS `ERROR`
FROM results JOIN clauses USING (id)
WHERE clauses.clause_count=clause_count_arg
AND result RLIKE '^ERROR';
SELECT '' AS ``, query, clauses AS attrs, result
FROM results JOIN clauses USING (id)
WHERE clauses.clause_count=clause_count_arg
AND result RLIKE '^ERROR' ORDER BY id;
-- Display successfull results
SELECT '' AS ``, COUNT(*) AS `OK`
FROM results JOIN clauses USING (id)
WHERE clauses.clause_count=clause_count_arg
AND result NOT RLIKE '^ERROR';
SELECT '' AS ``, query, clauses AS attrs, result
FROM results JOIN clauses USING (id)
WHERE clauses.clause_count=clause_count_arg
AND result NOT RLIKE '^ERROR' ORDER BY id;
END;
$$
DELIMITER ;$$
DELIMITER $$;
CREATE PROCEDURE run(query_bootstrap TEXT,
query TEXT,
query_cleanup TEXT,
clause_count_arg INT)
BEGIN
FOR rec IN (SELECT * FROM clauses WHERE clause_count=clause_count_arg)
DO
CALL exec(query_bootstrap, query, query_cleanup, rec.id, rec.clauses);
END FOR;
END;
$$
DELIMITER ;$$
DELIMITER $$;
CREATE PROCEDURE run_all(query_bootstrap TEXT, query TEXT, query_cleanup TEXT)
BEGIN
DECLARE msg TEXT;
DECLARE count_results INT;
DECLARE count_clauses INT;
FOR i IN 0..3
DO
CALL run(query_bootstrap, query, query_cleanup, i);
END FOR;
SET count_clauses=(SELECT COUNT(*) FROM clauses);
SET count_results=(SELECT COUNT(*) FROM results);
IF (count_results<>count_clauses)
THEN
SET msg=CONCAT('Got ', count_results,' rows in `results`; ',
'Expected ', count_clauses, ' rows');
SIGNAL SQLSTATE '45000'
SET MYSQL_ERRNO=30001,
MESSAGE_TEXT=msg;
END IF;
END;
$$
DELIMITER ;$$
DELIMITER $$;
CREATE PROCEDURE show_results_all(query TEXT)
BEGIN
FOR i IN 0..3
DO
CALL show_results(query, i);
END FOR;
END;
$$
DELIMITER ;$$
--vertical_results
--echo #
--echo # Running CREATE DATABASE tests
--echo # Displaying all results
--echo #
SET @@collation_server=utf8mb4_unicode_ci;
CREATE TABLE results LIKE results_template;
CALL run_all('','CREATE DATABASE db1 /*CSCL*/', 'DROP DATABASE IF EXISTS db1');
CALL show_results_all('CREATE DATABASE');
ALTER TABLE results RENAME TO results_create_db;
--echo #
--echo # Running ALTER DATABASE tests
--echo #
CREATE TABLE results LIKE results_template;
CALL run_all('CREATE DATABASE db1 CHARACTER SET utf8mb3 COLLATE utf8mb3_unicode_ci',
'ALTER DATABASE db1 COMMENT '''' /*CSCL*/',
'DROP DATABASE db1');
ALTER TABLE results RENAME TO results_alter_db;
--echo # Displaying results that differ in CREATE DATABASE and ALTER DATABASE
--echo # Only queries with no clauses or with COLLATE DEFAULT alone
--echo # (without any other COLLATE or CHARACTER SET clauses)
--echo # should differ:
--echo # CREATE DATABASE db1 COMMENT '' [COLLATE DEFAULT]; -- means @@collation_server
--echo # ALTER DATABASE db1 COMMENT '' COLLATE DEFAULT; -- means "the default collation of the current character set of db1"
--echo # ALTER DATABASE db1 COMMENT ''; -- means "keep the current db1 collation"
CALL diff_result_tables('results_create_db', 'results_alter_db', '');
--echo #
--echo # Running CREATE TABLE tests
--echo #
CREATE DATABASE test1 COLLATE utf8mb4_unicode_ci;
CREATE TABLE results LIKE results_template;
CALL run_all('',
'CREATE TABLE test1.t1 (a int) /*CSCL*/',
'DROP TABLE IF EXISTS test1.t1');
ALTER TABLE results RENAME TO results_create_table;
--echo # Expect no difference to CREATE DATABASE
CALL diff_result_tables('results_create_db', 'results_create_table', '');
DROP DATABASE test1;
--echo #
--echo # Running ALTER TABLE tests
--echo #
CREATE DATABASE test1 COLLATE utf8mb4_unicode_ci;
CREATE TABLE results LIKE results_template;
CALL run_all('CREATE TABLE test1.t1(a INT) CHARACTER SET utf8mb3 COLLATE utf8mb3_unicode_ci',
'ALTER TABLE test1.t1 COMMENT '''' /*CSCL*/',
'DROP TABLE test1.t1');
ALTER TABLE results RENAME TO results_alter_table;
--echo # Only queries with no clauses or with COLLATE DEFAULT alone
--echo # (without any other COLLATE or CHARACTER SET clauses)
--echo # should differ:
--echo # CREATE TABLE test1.t1 COMMENT '' [COLLATE DEFAULT]; -- means "the default collation of the database test1"
--echo # ALTER TABLE test1.t1 COMMENT '' COLLATE DEFAULT; -- means "the default collation of the current character set of test1.t1"
--echo # ALTER TABLE test1.t1 COMMENT ''; -- means "keep the current collation of test.t1"
CALL diff_result_tables('results_create_table', 'results_alter_table', '');
#SELECT result FROM (
#(SELECT * FROM results_create_table)
#EXCEPT
#(SELECT * FROM results_alter_table)) t1;
DROP DATABASE test1;
--echo #
--echo # Running ALTER TABLE CONVERT TO tests
--echo #
CREATE DATABASE test1 COLLATE utf8mb4_unicode_ci;
CREATE TABLE results LIKE results_template;
CALL run_all('CREATE TABLE test1.t1(a INT) CHARACTER SET utf8mb3 COLLATE utf8mb3_unicode_ci',
'ALTER TABLE test1.t1 CONVERT TO /*CSCL*/',
'DROP TABLE test1.t1');
ALTER TABLE results RENAME TO results_convert_table;
--echo # CONVERT TO COLLATE (without CHARACTER SET) is not supported yet
CALL diff_result_tables_stat('results_alter_table', 'results_convert_table','');
--echo # Everything that did not fail on syntax error
--echo # should give equal results with ALTER TABLE DEFAULT CHARACTER SET
--echo # Expect 0 non-equal results:
CALL diff_result_tables('results_alter_table', 'results_convert_table',
't2.result NOT RLIKE ''SQL syntax''');
DROP DATABASE test1;
--horizontal_results
DROP PROCEDURE show_results_all;
DROP PROCEDURE run_all;
DROP PROCEDURE show_results;
DROP PROCEDURE exec;
DROP PROCEDURE run;
DROP PROCEDURE diff_result_tables;
DROP PROCEDURE diff_result_tables_stat;
DROP PROCEDURE diff_result_tables_records;
DROP TABLE clauses;
DROP TABLE results_template;
DROP TABLE results_create_db;
DROP TABLE results_alter_db;
DROP TABLE results_create_table;
DROP TABLE results_alter_table;
DROP TABLE results_convert_table;

View File

@ -0,0 +1,106 @@
#
# MDEV-27896 Wrong result upon COLLATE latin1_bin CHARACTER SET latin1 on the table or the database level
#
CREATE DATABASE db1 COLLATE latin1_bin CHARACTER SET latin1;
SHOW CREATE DATABASE db1;
Database Create Database
db1 CREATE DATABASE `db1` /*!40100 DEFAULT CHARACTER SET latin1 COLLATE latin1_bin */
DROP DATABASE db1;
CREATE VIEW cscl AS
SELECT
DEFAULT_CHARACTER_SET_NAME,
DEFAULT_COLLATION_NAME
FROM
INFORMATION_SCHEMA.SCHEMATA
WHERE
SCHEMA_NAME='db1';
SET collation_server=utf8mb4_unicode_ci;
CREATE DATABASE db1 COMMENT 'test';
SELECT * FROM cscl;
DEFAULT_CHARACTER_SET_NAME DEFAULT_COLLATION_NAME
utf8mb4 utf8mb4_unicode_ci
DROP DATABASE db1;
CREATE DATABASE db1 COLLATE DEFAULT;
SELECT * FROM cscl;
DEFAULT_CHARACTER_SET_NAME DEFAULT_COLLATION_NAME
utf8mb4 utf8mb4_general_ci
DROP DATABASE db1;
CREATE DATABASE db1 COLLATE latin1_bin;
SELECT * FROM cscl;
DEFAULT_CHARACTER_SET_NAME DEFAULT_COLLATION_NAME
latin1 latin1_bin
DROP DATABASE db1;
CREATE DATABASE db1 CHARACTER SET latin1;
SELECT * FROM cscl;
DEFAULT_CHARACTER_SET_NAME DEFAULT_COLLATION_NAME
latin1 latin1_swedish_ci
DROP DATABASE db1;
CREATE DATABASE db1 CHARACTER SET latin1 COLLATE DEFAULT;
SELECT * FROM cscl;
DEFAULT_CHARACTER_SET_NAME DEFAULT_COLLATION_NAME
latin1 latin1_swedish_ci
DROP DATABASE db1;
CREATE DATABASE db1 CHARACTER SET latin1 COLLATE latin1_bin;
SELECT * FROM cscl;
DEFAULT_CHARACTER_SET_NAME DEFAULT_COLLATION_NAME
latin1 latin1_bin
DROP DATABASE db1;
CREATE DATABASE db1 COLLATE DEFAULT CHARACTER SET latin1;
SELECT * FROM cscl;
DEFAULT_CHARACTER_SET_NAME DEFAULT_COLLATION_NAME
latin1 latin1_swedish_ci
DROP DATABASE db1;
CREATE DATABASE db1 COLLATE latin1_bin CHARACTER SET latin1;
SELECT * FROM cscl;
DEFAULT_CHARACTER_SET_NAME DEFAULT_COLLATION_NAME
latin1 latin1_bin
DROP DATABASE db1;
CREATE DATABASE db1 CHARACTER SET DEFAULT;
SELECT * FROM cscl;
DEFAULT_CHARACTER_SET_NAME DEFAULT_COLLATION_NAME
utf8mb4 utf8mb4_general_ci
DROP DATABASE db1;
CREATE DATABASE db1 CHARACTER SET DEFAULT CHARACTER SET DEFAULT;
SELECT * FROM cscl;
DEFAULT_CHARACTER_SET_NAME DEFAULT_COLLATION_NAME
utf8mb4 utf8mb4_general_ci
DROP DATABASE db1;
CREATE DATABASE db1 CHARACTER SET DEFAULT COLLATE DEFAULT;
SELECT * FROM cscl;
DEFAULT_CHARACTER_SET_NAME DEFAULT_COLLATION_NAME
utf8mb4 utf8mb4_general_ci
DROP DATABASE db1;
CREATE DATABASE db1 COLLATE DEFAULT CHARACTER SET DEFAULT;
SELECT * FROM cscl;
DEFAULT_CHARACTER_SET_NAME DEFAULT_COLLATION_NAME
utf8mb4 utf8mb4_general_ci
DROP DATABASE db1;
CREATE DATABASE db1 CHARACTER SET DEFAULT CHARACTER SET utf8mb4;
SELECT * FROM cscl;
DEFAULT_CHARACTER_SET_NAME DEFAULT_COLLATION_NAME
utf8mb4 utf8mb4_general_ci
DROP DATABASE db1;
CREATE DATABASE db1 CHARACTER SET utf8mb4 CHARACTER SET DEFAULT;
SELECT * FROM cscl;
DEFAULT_CHARACTER_SET_NAME DEFAULT_COLLATION_NAME
utf8mb4 utf8mb4_general_ci
DROP DATABASE db1;
CREATE DATABASE db1 CHARACTER SET DEFAULT CHARACTER SET latin1;
ERROR HY000: Conflicting declarations: 'CHARACTER SET DEFAULT (utf8mb4)' and 'CHARACTER SET latin1'
CREATE DATABASE db1 CHARACTER SET latin1 CHARACTER SET DEFAULT;
ERROR HY000: Conflicting declarations: 'CHARACTER SET latin1' and 'CHARACTER SET DEFAULT (utf8mb4)'
CREATE DATABASE db1 CHARACTER SET DEFAULT COLLATE latin1_bin;
ERROR 42000: COLLATION 'latin1_bin' is not valid for CHARACTER SET 'utf8mb4'
CREATE DATABASE db1 COLLATE latin1_bin CHARACTER SET DEFAULT;
ERROR 42000: COLLATION 'latin1_bin' is not valid for CHARACTER SET 'utf8mb4'
CREATE DATABASE db1 CHARACTER SET DEFAULT COLLATE utf8mb4_bin;
SELECT * FROM cscl;
DEFAULT_CHARACTER_SET_NAME DEFAULT_COLLATION_NAME
utf8mb4 utf8mb4_bin
DROP DATABASE db1;
CREATE DATABASE db1 COLLATE utf8mb4_bin CHARACTER SET DEFAULT;
SELECT * FROM cscl;
DEFAULT_CHARACTER_SET_NAME DEFAULT_COLLATION_NAME
utf8mb4 utf8mb4_bin
DROP DATABASE db1;
DROP VIEW cscl;

View File

@ -0,0 +1,96 @@
--source include/have_utf8mb4.inc
--echo #
--echo # MDEV-27896 Wrong result upon COLLATE latin1_bin CHARACTER SET latin1 on the table or the database level
--echo #
CREATE DATABASE db1 COLLATE latin1_bin CHARACTER SET latin1;
SHOW CREATE DATABASE db1;
DROP DATABASE db1;
CREATE VIEW cscl AS
SELECT
DEFAULT_CHARACTER_SET_NAME,
DEFAULT_COLLATION_NAME
FROM
INFORMATION_SCHEMA.SCHEMATA
WHERE
SCHEMA_NAME='db1';
SET collation_server=utf8mb4_unicode_ci;
CREATE DATABASE db1 COMMENT 'test';
SELECT * FROM cscl;
DROP DATABASE db1;
CREATE DATABASE db1 COLLATE DEFAULT;
SELECT * FROM cscl;
DROP DATABASE db1;
CREATE DATABASE db1 COLLATE latin1_bin;
SELECT * FROM cscl;
DROP DATABASE db1;
CREATE DATABASE db1 CHARACTER SET latin1;
SELECT * FROM cscl;
DROP DATABASE db1;
CREATE DATABASE db1 CHARACTER SET latin1 COLLATE DEFAULT;
SELECT * FROM cscl;
DROP DATABASE db1;
CREATE DATABASE db1 CHARACTER SET latin1 COLLATE latin1_bin;
SELECT * FROM cscl;
DROP DATABASE db1;
CREATE DATABASE db1 COLLATE DEFAULT CHARACTER SET latin1;
SELECT * FROM cscl;
DROP DATABASE db1;
CREATE DATABASE db1 COLLATE latin1_bin CHARACTER SET latin1;
SELECT * FROM cscl;
DROP DATABASE db1;
CREATE DATABASE db1 CHARACTER SET DEFAULT;
SELECT * FROM cscl;
DROP DATABASE db1;
CREATE DATABASE db1 CHARACTER SET DEFAULT CHARACTER SET DEFAULT;
SELECT * FROM cscl;
DROP DATABASE db1;
CREATE DATABASE db1 CHARACTER SET DEFAULT COLLATE DEFAULT;
SELECT * FROM cscl;
DROP DATABASE db1;
CREATE DATABASE db1 COLLATE DEFAULT CHARACTER SET DEFAULT;
SELECT * FROM cscl;
DROP DATABASE db1;
CREATE DATABASE db1 CHARACTER SET DEFAULT CHARACTER SET utf8mb4;
SELECT * FROM cscl;
DROP DATABASE db1;
CREATE DATABASE db1 CHARACTER SET utf8mb4 CHARACTER SET DEFAULT;
SELECT * FROM cscl;
DROP DATABASE db1;
--error ER_CONFLICTING_DECLARATIONS
CREATE DATABASE db1 CHARACTER SET DEFAULT CHARACTER SET latin1;
--error ER_CONFLICTING_DECLARATIONS
CREATE DATABASE db1 CHARACTER SET latin1 CHARACTER SET DEFAULT;
--error ER_COLLATION_CHARSET_MISMATCH
CREATE DATABASE db1 CHARACTER SET DEFAULT COLLATE latin1_bin;
--error ER_COLLATION_CHARSET_MISMATCH
CREATE DATABASE db1 COLLATE latin1_bin CHARACTER SET DEFAULT;
CREATE DATABASE db1 CHARACTER SET DEFAULT COLLATE utf8mb4_bin;
SELECT * FROM cscl;
DROP DATABASE db1;
CREATE DATABASE db1 COLLATE utf8mb4_bin CHARACTER SET DEFAULT;
SELECT * FROM cscl;
DROP DATABASE db1;
DROP VIEW cscl;

View File

@ -0,0 +1,27 @@
#
# MDEV-27896 Wrong result upon `COLLATE latin1_bin CHARACTER SET latin1` on the table or the database level
#
CREATE TABLE t1 (a CHAR) COLLATE latin1_bin CHARACTER SET latin1;
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` char(1) COLLATE latin1_bin DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_bin
DROP TABLE t1;
#
# MDEV-27782 Wrong columns when using table level `CHARACTER SET utf8mb4 COLLATE DEFAULT`
#
CREATE TABLE t1 (a CHAR(10)) CHARACTER SET latin1 COLLATE DEFAULT;
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` char(10) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
DROP TABLE t1;
CREATE TABLE t1 (a CHAR(10)) CHARACTER SET utf8mb4 COLLATE DEFAULT;
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` char(10) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4
DROP TABLE t1;

View File

@ -0,0 +1,22 @@
--source include/have_utf8mb4.inc
--echo #
--echo # MDEV-27896 Wrong result upon `COLLATE latin1_bin CHARACTER SET latin1` on the table or the database level
--echo #
CREATE TABLE t1 (a CHAR) COLLATE latin1_bin CHARACTER SET latin1;
SHOW CREATE TABLE t1;
DROP TABLE t1;
--echo #
--echo # MDEV-27782 Wrong columns when using table level `CHARACTER SET utf8mb4 COLLATE DEFAULT`
--echo #
CREATE TABLE t1 (a CHAR(10)) CHARACTER SET latin1 COLLATE DEFAULT;
SHOW CREATE TABLE t1;
DROP TABLE t1;
CREATE TABLE t1 (a CHAR(10)) CHARACTER SET utf8mb4 COLLATE DEFAULT;
SHOW CREATE TABLE t1;
DROP TABLE t1;

View File

@ -78,37 +78,113 @@ ALTER DATABASE `` DEFAULT CHARACTER SET latin2;
ERROR 42000: Incorrect database name ''
USE test;
#
# Start of 10.0 tests
# End of 10.0 tests
#
#
# Start of 10.9 tests
#
#
# MDEV-7387 Alter table xxx CHARACTER SET utf8, CONVERT TO CHARACTER SET latin1 should fail
# MDEV-28644 Unexpected error on ALTER TABLE t1 CONVERT TO CHARACTER SET utf8mb3, DEFAULT CHARACTER SET utf8mb4
#
CREATE DATABASE tmp DEFAULT CHARACTER SET latin5;
USE tmp;
CREATE TABLE t1 (a VARCHAR(10)) CHARACTER SET DEFAULT, CHARACTER SET utf8;
ERROR HY000: Conflicting declarations: 'CHARACTER SET DEFAULT' and 'CHARACTER SET utf8mb3'
ERROR HY000: Conflicting declarations: 'CHARACTER SET DEFAULT (latin5)' and 'CHARACTER SET utf8mb3'
CREATE TABLE t1 (a VARCHAR(10)) CHARACTER SET utf8, CHARACTER SET DEFAULT;
ERROR HY000: Conflicting declarations: 'CHARACTER SET utf8mb3' and 'CHARACTER SET DEFAULT'
ERROR HY000: Conflicting declarations: 'CHARACTER SET utf8mb3' and 'CHARACTER SET DEFAULT (latin5)'
CREATE TABLE t1 (a VARCHAR(10)) CHARACTER SET utf8, CHARACTER SET utf8;
DROP TABLE t1;
CREATE TABLE t1 (a VARCHAR(10)) CHARACTER SET DEFAULT, CHARACTER SET DEFAULT;
DROP TABLE t1;
CREATE TABLE t1 (a VARCHAR(10) CHARACTER SET latin1, b VARCHAR(10) CHARACTER SET utf8);
ALTER TABLE t1 CONVERT TO CHARACTER SET utf8, CHARACTER SET latin1;
ERROR HY000: Conflicting declarations: 'CHARACTER SET utf8mb3' and 'CHARACTER SET latin1'
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` varchar(10) CHARACTER SET utf8mb3 DEFAULT NULL,
`b` varchar(10) CHARACTER SET utf8mb3 DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
ALTER TABLE t1 CONVERT TO CHARACTER SET utf8, CHARACTER SET DEFAULT;
ERROR HY000: Conflicting declarations: 'CHARACTER SET utf8mb3' and 'CHARACTER SET DEFAULT'
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` varchar(10) CHARACTER SET utf8mb3 DEFAULT NULL,
`b` varchar(10) CHARACTER SET utf8mb3 DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin5
ALTER TABLE t1 CONVERT TO CHARACTER SET latin1, CHARACTER SET utf8;
ERROR HY000: Conflicting declarations: 'CHARACTER SET latin1' and 'CHARACTER SET utf8mb3'
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` varchar(10) CHARACTER SET latin1 DEFAULT NULL,
`b` varchar(10) CHARACTER SET latin1 DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb3
ALTER TABLE t1 CONVERT TO CHARACTER SET latin1, CHARACTER SET DEFAULT;
ERROR HY000: Conflicting declarations: 'CHARACTER SET latin1' and 'CHARACTER SET DEFAULT'
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` varchar(10) CHARACTER SET latin1 DEFAULT NULL,
`b` varchar(10) CHARACTER SET latin1 DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin5
ALTER TABLE t1 CONVERT TO CHARACTER SET DEFAULT, CHARACTER SET utf8;
ERROR HY000: Conflicting declarations: 'CHARACTER SET latin5' and 'CHARACTER SET utf8mb3'
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` varchar(10) CHARACTER SET latin5 DEFAULT NULL,
`b` varchar(10) CHARACTER SET latin5 DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb3
ALTER TABLE t1 CONVERT TO CHARACTER SET DEFAULT, CHARACTER SET latin1;
ERROR HY000: Conflicting declarations: 'CHARACTER SET latin5' and 'CHARACTER SET latin1'
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` varchar(10) CHARACTER SET latin5 DEFAULT NULL,
`b` varchar(10) CHARACTER SET latin5 DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
ALTER TABLE t1 CHARACTER SET latin1, CONVERT TO CHARACTER SET utf8;
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` varchar(10) CHARACTER SET utf8mb3 DEFAULT NULL,
`b` varchar(10) CHARACTER SET utf8mb3 DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
ALTER TABLE t1 CHARACTER SET DEFAULT, CONVERT TO CHARACTER SET utf8;
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` varchar(10) CHARACTER SET utf8mb3 DEFAULT NULL,
`b` varchar(10) CHARACTER SET utf8mb3 DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin5
ALTER TABLE t1 CHARACTER SET utf8, CONVERT TO CHARACTER SET latin1;
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` varchar(10) CHARACTER SET latin1 DEFAULT NULL,
`b` varchar(10) CHARACTER SET latin1 DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb3
ALTER TABLE t1 CHARACTER SET DEFAULT, CONVERT TO CHARACTER SET latin1;
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` varchar(10) CHARACTER SET latin1 DEFAULT NULL,
`b` varchar(10) CHARACTER SET latin1 DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin5
ALTER TABLE t1 CHARACTER SET utf8, CONVERT TO CHARACTER SET DEFAULT;
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` varchar(10) CHARACTER SET latin5 DEFAULT NULL,
`b` varchar(10) CHARACTER SET latin5 DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb3
ALTER TABLE t1 CHARACTER SET latin1, CONVERT TO CHARACTER SET DEFAULT;
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` varchar(10) CHARACTER SET latin5 DEFAULT NULL,
`b` varchar(10) CHARACTER SET latin5 DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
DROP TABLE t1;
DROP DATABASE tmp;
USE test;
#
# End of 10.0 tests
# End of 10.9 tests
#

View File

@ -108,11 +108,16 @@ ALTER DATABASE `` DEFAULT CHARACTER SET latin2;
USE test;
--echo #
--echo # Start of 10.0 tests
--echo # End of 10.0 tests
--echo #
--echo #
--echo # Start of 10.9 tests
--echo #
--echo #
--echo # MDEV-7387 Alter table xxx CHARACTER SET utf8, CONVERT TO CHARACTER SET latin1 should fail
--echo # MDEV-28644 Unexpected error on ALTER TABLE t1 CONVERT TO CHARACTER SET utf8mb3, DEFAULT CHARACTER SET utf8mb4
--echo #
CREATE DATABASE tmp DEFAULT CHARACTER SET latin5;
USE tmp;
@ -125,23 +130,48 @@ DROP TABLE t1;
CREATE TABLE t1 (a VARCHAR(10)) CHARACTER SET DEFAULT, CHARACTER SET DEFAULT;
DROP TABLE t1;
CREATE TABLE t1 (a VARCHAR(10) CHARACTER SET latin1, b VARCHAR(10) CHARACTER SET utf8);
--error ER_CONFLICTING_DECLARATIONS
ALTER TABLE t1 CONVERT TO CHARACTER SET utf8, CHARACTER SET latin1;
--error ER_CONFLICTING_DECLARATIONS
SHOW CREATE TABLE t1;
ALTER TABLE t1 CONVERT TO CHARACTER SET utf8, CHARACTER SET DEFAULT;
--error ER_CONFLICTING_DECLARATIONS
SHOW CREATE TABLE t1;
ALTER TABLE t1 CONVERT TO CHARACTER SET latin1, CHARACTER SET utf8;
--error ER_CONFLICTING_DECLARATIONS
SHOW CREATE TABLE t1;
ALTER TABLE t1 CONVERT TO CHARACTER SET latin1, CHARACTER SET DEFAULT;
--error ER_CONFLICTING_DECLARATIONS
SHOW CREATE TABLE t1;
ALTER TABLE t1 CONVERT TO CHARACTER SET DEFAULT, CHARACTER SET utf8;
--error ER_CONFLICTING_DECLARATIONS
SHOW CREATE TABLE t1;
ALTER TABLE t1 CONVERT TO CHARACTER SET DEFAULT, CHARACTER SET latin1;
SHOW CREATE TABLE t1;
ALTER TABLE t1 CHARACTER SET latin1, CONVERT TO CHARACTER SET utf8;
SHOW CREATE TABLE t1;
ALTER TABLE t1 CHARACTER SET DEFAULT, CONVERT TO CHARACTER SET utf8;
SHOW CREATE TABLE t1;
ALTER TABLE t1 CHARACTER SET utf8, CONVERT TO CHARACTER SET latin1;
SHOW CREATE TABLE t1;
ALTER TABLE t1 CHARACTER SET DEFAULT, CONVERT TO CHARACTER SET latin1;
SHOW CREATE TABLE t1;
ALTER TABLE t1 CHARACTER SET utf8, CONVERT TO CHARACTER SET DEFAULT;
SHOW CREATE TABLE t1;
ALTER TABLE t1 CHARACTER SET latin1, CONVERT TO CHARACTER SET DEFAULT;
SHOW CREATE TABLE t1;
DROP TABLE t1;
DROP DATABASE tmp;
USE test;
--echo #
--echo # End of 10.0 tests
--echo # End of 10.9 tests
--echo #

View File

@ -7921,24 +7921,6 @@ int ha_abort_transaction(THD *bf_thd, THD *victim_thd, my_bool signal)
#endif /* WITH_WSREP */
bool HA_CREATE_INFO::check_conflicting_charset_declarations(CHARSET_INFO *cs)
{
if ((used_fields & HA_CREATE_USED_DEFAULT_CHARSET) &&
/* DEFAULT vs explicit, or explicit vs DEFAULT */
(((default_table_charset == NULL) != (cs == NULL)) ||
/* Two different explicit character sets */
(default_table_charset && cs &&
!my_charset_same(default_table_charset, cs))))
{
my_error(ER_CONFLICTING_DECLARATIONS, MYF(0),
"CHARACTER SET ", default_table_charset ?
default_table_charset->cs_name.str : "DEFAULT",
"CHARACTER SET ", cs ? cs->cs_name.str : "DEFAULT");
return true;
}
return false;
}
/* Remove all indexes for a given table from global index statistics */
static

View File

@ -2289,33 +2289,6 @@ struct HA_CREATE_INFO: public Table_scope_and_contents_source_st,
Schema_specification_st::init();
alter_info= NULL;
}
bool check_conflicting_charset_declarations(CHARSET_INFO *cs);
bool add_table_option_default_charset(CHARSET_INFO *cs)
{
// cs can be NULL, e.g.: CREATE TABLE t1 (..) CHARACTER SET DEFAULT;
if (check_conflicting_charset_declarations(cs))
return true;
default_table_charset= cs;
used_fields|= HA_CREATE_USED_DEFAULT_CHARSET;
return false;
}
bool add_alter_list_item_convert_to_charset(CHARSET_INFO *cs)
{
/*
cs cannot be NULL, as sql_yacc.yy translates
CONVERT TO CHARACTER SET DEFAULT
to
CONVERT TO CHARACTER SET <character-set-of-the-current-database>
TODO: Shouldn't we postpone resolution of DEFAULT until the
character set of the table owner database is loaded from its db.opt?
*/
DBUG_ASSERT(cs);
if (check_conflicting_charset_declarations(cs))
return true;
alter_table_convert_to_charset= default_table_charset= cs;
used_fields|= (HA_CREATE_USED_CHARSET | HA_CREATE_USED_DEFAULT_CHARSET);
return false;
}
ulong table_options_with_row_type()
{
if (row_type == ROW_TYPE_DYNAMIC || row_type == ROW_TYPE_PAGE)
@ -2323,6 +2296,10 @@ struct HA_CREATE_INFO: public Table_scope_and_contents_source_st,
else
return table_options;
}
bool resolve_to_charset_collation_context(THD *thd,
const Lex_table_charset_collation_attrs_st &default_cscl,
const Lex_table_charset_collation_attrs_st &convert_cscl,
const Charset_collation_context &ctx);
};
@ -2333,16 +2310,23 @@ struct HA_CREATE_INFO: public Table_scope_and_contents_source_st,
struct Table_specification_st: public HA_CREATE_INFO,
public DDL_options_st
{
Lex_table_charset_collation_attrs_st default_charset_collation;
Lex_table_charset_collation_attrs_st convert_charset_collation;
// Deep initialization
void init()
{
HA_CREATE_INFO::init();
DDL_options_st::init();
default_charset_collation.init();
convert_charset_collation.init();
}
void init(DDL_options_st::Options options_arg)
{
HA_CREATE_INFO::init();
DDL_options_st::init(options_arg);
default_charset_collation.init();
convert_charset_collation.init();
}
/*
Quick initialization, for parser.
@ -2354,6 +2338,46 @@ struct Table_specification_st: public HA_CREATE_INFO,
{
HA_CREATE_INFO::options= 0;
DDL_options_st::init();
default_charset_collation.init();
convert_charset_collation.init();
}
bool add_table_option_convert_charset(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_charset_default();
}
bool add_table_option_convert_collation(const Lex_extended_collation_st &cl)
{
used_fields|= (HA_CREATE_USED_CHARSET | HA_CREATE_USED_DEFAULT_CHARSET);
return convert_charset_collation.merge_collation(cl);
}
bool add_table_option_default_charset(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_charset_default();
}
bool add_table_option_default_collation(const Lex_extended_collation_st &cl)
{
used_fields|= HA_CREATE_USED_DEFAULT_CHARSET;
return default_charset_collation.merge_collation(cl);
}
bool resolve_to_charset_collation_context(THD *thd,
const Charset_collation_context &ctx)
{
return HA_CREATE_INFO::
resolve_to_charset_collation_context(thd,
default_charset_collation,
convert_charset_collation,
ctx);
}
};

View File

@ -37,6 +37,22 @@ raise_ER_CONFLICTING_DECLARATIONS(const char *clause1,
}
static void
raise_ER_CONFLICTING_DECLARATIONS(const char *clause1,
const char *name1,
const char *name1_part2,
const char *clause2,
const char *name2,
bool reverse_order)
{
char def[MY_CS_NAME_SIZE * 2];
my_snprintf(def, sizeof(def), "%s (%s)", name1, name1_part2);
raise_ER_CONFLICTING_DECLARATIONS(clause1, def,
clause2, name2,
reverse_order);
}
bool Lex_exact_charset::raise_if_not_equal(const Lex_exact_charset &rhs) const
{
if (m_ci == rhs.m_ci)
@ -537,3 +553,124 @@ bool Lex_exact_charset_extended_collation_attrs_st::
DBUG_ASSERT(0);
return false;
}
bool Lex_extended_charset_extended_collation_attrs_st::merge_charset_default()
{
if (m_charset_order == CHARSET_TYPE_EMPTY)
m_charset_order= CHARSET_TYPE_CONTEXT;
Lex_opt_context_charset_st::merge_charset_default();
return false;
}
bool Lex_extended_charset_extended_collation_attrs_st::
merge_exact_charset(const Lex_exact_charset &cs)
{
m_had_charset_exact= true;
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);
}
bool Lex_extended_charset_extended_collation_attrs_st::
raise_if_charset_conflicts_with_default(
const Lex_exact_charset_opt_extended_collate &def) const
{
DBUG_ASSERT(m_charset_order != CHARSET_TYPE_EMPTY || is_empty());
if (!my_charset_same(def.collation().charset_info(), m_ci))
{
raise_ER_CONFLICTING_DECLARATIONS("CHARACTER SET ", "DEFAULT",
def.collation().charset_info()->cs_name.str,
"CHARACTER SET ", m_ci->cs_name.str,
m_charset_order == CHARSET_TYPE_EXACT);
return true;
}
return false;
}
CHARSET_INFO *
Lex_extended_charset_extended_collation_attrs_st::
resolved_to_context(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());
}
// With CHARACTER SET DEFAULT
switch (type()) {
case TYPE_EMPTY:
// CHARACTER SET DEFAULT;
return ctx.charset_default().charset().charset_info();
case TYPE_CHARACTER_SET:
// CHARACTER SET DEFAULT CHARACTER SET cs_exact
if (raise_if_charset_conflicts_with_default(ctx.charset_default()))
{
/*
A possible scenario:
SET character_set_server=utf8mb4;
CREATE DATABASE db1 CHARACTER SET latin1 CHARACTER SET DEFAULT;
*/
return NULL;
}
return m_ci;
case TYPE_COLLATE_EXACT:
{
/*
CREATE DATABASE db1
COLLATE cl_exact
[ CHARACTER SET cs_exact ]
CHARACTER SET DEFAULT;
*/
if (m_had_charset_exact &&
raise_if_charset_conflicts_with_default(ctx.charset_default()))
{
/*
A possible scenario:
SET character_set_server=utf8mb4;
CREATE DATABASE db1
COLLATE latin1_bin
CHARACTER SET latin1
CHARACTER SET DEFAULT;
*/
return NULL;
}
/*
Now check that "COLLATE cl_exact" does not conflict with
CHARACTER SET DEFAULT.
*/
if (ctx.charset_default().
raise_if_not_applicable(Lex_exact_collation(m_ci)))
{
/*
A possible scenario:
SET character_set_server=utf8mb4;
CREATE DATABASE db1
COLLATE latin1_bin
CHARACTER SET DEFAULT;
*/
return NULL;
}
return m_ci;
}
case TYPE_COLLATE_CONTEXTUALLY_TYPED:
/*
Both CHARACTER SET and COLLATE are contextual:
ALTER DATABASE db1 CHARACTER SET DEFAULT COLLATE DEFAULT;
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());
}
DBUG_ASSERT(0);
return NULL;
}

View File

@ -37,6 +37,41 @@ public:
};
/*
An optional contextually typed character set:
[ CHARACTER SET DEFAULT ]
*/
class Lex_opt_context_charset_st
{
/*
Currently we support only DEFAULT as a possible value.
So "bool" is enough.
*/
bool m_had_charset_default;
public:
void init()
{
m_had_charset_default= false;
}
void merge_charset_default()
{
/*
Ok to specify CHARACTER SET DEFAULT multiple times.
No error raised here.
*/
m_had_charset_default= true;
}
bool is_empty() const
{
return !m_had_charset_default;
}
bool is_contextually_typed_charset_default() const
{
return m_had_charset_default;
}
};
/*
A contextually typed collation, e.g.:
COLLATE DEFAULT
@ -407,6 +442,132 @@ public:
};
class Charset_collation_context
{
/*
Although the goal of m_charset_default is to store the meaning
of CHARACTER SET DEFAULT, it does not necessarily point to a
default collation of CHARACTER SET DEFAULT. It can point to its any
arbitrary collation.
For performance purposes we don't need to find the default
collation at the instantiation time of "this", because:
- m_charset_default may not be even needed during the resolution
- when it's needed, in many cases it's passed to my_charset_same(),
which does not need the default collation again.
Note, m_charset_default and m_collate_default are not necessarily equal.
- The default value for CHARACTER SET is taken from the upper level:
CREATE DATABASE db1 CHARACTER SET DEFAULT; <-- @@character_set_server
ALTER DATABASE db1 CHARACTER SET DEFAULT; <-- @@character_set_server
- The default value for COLLATE is taken from the upper level for CREATE:
CREATE DATABASE db1 COLLATE DEFAULT; <-- @@collation_server
CREATE TABLE db1.t1 COLLATE DEFAULT; <-- character set of "db1"
- The default value for COLLATE is taken from the same level for ALTER:
ALTER DATABASE db1 COLLATE DEFAULT; <-- the default collation of the
current db1 character set
ALTER TABLE db1.t1 COLLATE DEFAULT; <-- the default collation of the
current db1.t1 character set
*/
// comes from the upper level
Lex_exact_charset_opt_extended_collate m_charset_default;
// comes from the upper or the current level
Lex_exact_collation m_collate_default;
public:
Charset_collation_context(CHARSET_INFO *charset_default,
CHARSET_INFO *collate_default)
:m_charset_default(charset_default,
!(charset_default->state & MY_CS_PRIMARY)),
m_collate_default(collate_default)
{ }
const Lex_exact_charset_opt_extended_collate charset_default() const
{
return m_charset_default;
}
const Lex_exact_collation collate_default() const
{
return m_collate_default;
}
};
/*
A universal container. It can store at the same time:
- CHARACTER SET DEFAULT
- CHARACTER SET cs_exact
- COLLATE {cl_exact|cl_context}
All three parts can co-exist.
All three parts are optional.
Parts can come in any arbitrary order, e.g:
CHARACTER SET DEFAULT [CHARACTER SET latin1] COLLATE latin1_bin
CHARACTER SET latin1 CHARACTER SET DEFAULT COLLATE latin1_bin
COLLATE latin1_bin [CHARACTER SET latin1] CHARACTER SET DEFAULT
COLLATE latin1_bin CHARACTER SET DEFAULT [CHARACTER SET latin1]
*/
class Lex_extended_charset_extended_collation_attrs_st:
public Lex_opt_context_charset_st,
public Lex_exact_charset_extended_collation_attrs_st
{
enum charset_type_t
{
CHARSET_TYPE_EMPTY,
CHARSET_TYPE_CONTEXT,
CHARSET_TYPE_EXACT
};
/*
Which part came first:
- CHARACTER SET DEFAULT or
- CHARACTER SET cs_exact
e.g. to produce error messages preserving the user typed
order of CHARACTER SET clauses in case of conflicts.
*/
charset_type_t m_charset_order;
/*
The parent class Lex_exact_charset_extended_collation_attrs_st
does not let know if a "COLLATE cl_exact" was used in combination with
"CHARACTER SET cs_exact" or just alone.
Here we need to distinguish:
- CHARACTER SET cs_exact COLLATE cl_exact, or
- COLLATE cl_exact CHARACTER SET cs_exact
versus just:
- COLLATE cl_exact
to produce better error messages in case of conflicts.
So let's add a flag member:
*/
bool m_had_charset_exact;
public:
void init()
{
Lex_opt_context_charset_st::init();
Lex_exact_charset_extended_collation_attrs_st::init();
m_charset_order= CHARSET_TYPE_EMPTY;
m_had_charset_exact= false;
}
void init(const Lex_exact_charset_opt_extended_collate &c)
{
Lex_opt_context_charset_st::init();
Lex_exact_charset_extended_collation_attrs_st::init(c);
m_charset_order= CHARSET_TYPE_EXACT;
m_had_charset_exact= true;
}
bool is_empty() const
{
return Lex_opt_context_charset_st::is_empty() &&
Lex_exact_charset_extended_collation_attrs_st::is_empty();
}
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;
bool merge_charset_default();
bool merge_exact_charset(const Lex_exact_charset &cs);
};
class Lex_exact_charset_extended_collation_attrs:
public Lex_exact_charset_extended_collation_attrs_st
{
@ -456,6 +617,23 @@ public:
};
class Lex_extended_charset_extended_collation_attrs:
public Lex_extended_charset_extended_collation_attrs_st
{
public:
Lex_extended_charset_extended_collation_attrs()
{
init();
}
explicit Lex_extended_charset_extended_collation_attrs(
const Lex_exact_charset_opt_extended_collate &c)
{
init(c);
}
};
using Lex_column_charset_collation_attrs_st =
Lex_exact_charset_extended_collation_attrs_st;
@ -463,4 +641,11 @@ using Lex_column_charset_collation_attrs =
Lex_exact_charset_extended_collation_attrs;
using Lex_table_charset_collation_attrs_st =
Lex_extended_charset_extended_collation_attrs_st;
using Lex_table_charset_collation_attrs =
Lex_extended_charset_extended_collation_attrs;
#endif // LEX_CHARSET_INCLUDED

View File

@ -922,7 +922,7 @@ bool partition_info::vers_set_hist_part(THD *thd, uint *create_count)
bool vers_create_partitions(THD *thd, TABLE_LIST* tl, uint num_parts)
{
bool result= true;
HA_CREATE_INFO create_info;
Table_specification_st create_info;
Alter_info alter_info;
partition_info *save_part_info= thd->work_part_info;
Query_tables_list save_query_tables;

View File

@ -411,7 +411,7 @@ bool Sql_cmd_alter_table::execute(THD *thd)
referenced from this structure will be modified.
@todo move these into constructor...
*/
HA_CREATE_INFO create_info(lex->create_info);
Table_specification_st create_info(lex->create_info);
Alter_info alter_info(lex->alter_info, thd->mem_root);
create_info.alter_info= &alter_info;
privilege_t priv(NO_ACL);

View File

@ -56,6 +56,7 @@
#include "sp_rcontext.h"
#include "sp_cache.h"
#include "sql_show.h" // append_identifier
#include "sql_db.h" // get_default_db_collation
#include "transaction.h"
#include "sql_select.h" /* declares create_tmp_table() */
#include "debug_sync.h"
@ -8296,3 +8297,27 @@ THD_list_iterator *THD_list_iterator::iterator()
{
return &server_threads;
}
Charset_collation_context
THD::charset_collation_context_alter_db(const char *db)
{
return Charset_collation_context(variables.collation_server,
get_default_db_collation(this, db));
}
Charset_collation_context
THD::charset_collation_context_create_table_in_db(const char *db)
{
CHARSET_INFO *cs= get_default_db_collation(this, db);
return Charset_collation_context(cs, cs);
}
Charset_collation_context
THD::charset_collation_context_alter_table(const TABLE_SHARE *s)
{
return Charset_collation_context(get_default_db_collation(this, s->db.str),
s->table_charset);
}

View File

@ -5521,6 +5521,19 @@ public:
MY_UTF8_IS_UTF8MB3 : 0);
}
Charset_collation_context
charset_collation_context_create_db() const
{
return Charset_collation_context(variables.collation_server,
variables.collation_server);
}
Charset_collation_context
charset_collation_context_alter_db(const char *db);
Charset_collation_context
charset_collation_context_create_table_in_db(const char *db);
Charset_collation_context
charset_collation_context_alter_table(const TABLE_SHARE *s);
/**
Save current lex to the output parameter and reset it to point to
main_lex. This method is called from mysql_client_binlog_statement()
@ -6140,6 +6153,7 @@ public:
m_plock(NULL), exit_done(0),
saved_tmp_table_share(0)
{
DBUG_ASSERT(create_info->default_table_charset);
bzero(&ddl_log_state_create, sizeof(ddl_log_state_create));
bzero(&ddl_log_state_rm, sizeof(ddl_log_state_rm));
}

View File

@ -943,6 +943,7 @@ exit:
int mysql_create_db(THD *thd, const LEX_CSTRING *db, DDL_options_st options,
const Schema_specification_st *create_info)
{
DBUG_ASSERT(create_info->default_table_charset);
/*
As mysql_create_db_internal() may modify Db_create_info structure passed
to it, we need to use a copy to make execution prepared statement- safe.
@ -958,6 +959,7 @@ int mysql_create_db(THD *thd, const LEX_CSTRING *db, DDL_options_st options,
bool mysql_alter_db(THD *thd, const LEX_CSTRING *db,
const Schema_specification_st *create_info)
{
DBUG_ASSERT(create_info->default_table_charset);
/*
As mysql_alter_db_internal() may modify Db_create_info structure passed
to it, we need to use a copy to make execution prepared statement- safe.

View File

@ -4408,6 +4408,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)
{
if (create_info.add_table_option_convert_charset(cs))
return true;
alter_info.flags|= ALTER_CONVERT_TO;
return false;
}
bool
add_alter_list_item_convert_to_charset(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))
return true;
alter_info.flags|= ALTER_CONVERT_TO;
return false;
}
void set_command(enum_sql_command command,
DDL_options_st options)
{

View File

@ -43,9 +43,7 @@
// mysql_alter_db,
// check_db_dir_existence,
// my_dbopt_cleanup
#include "sql_table.h" // mysql_create_like_table,
// mysql_create_table,
// mysql_alter_table,
#include "sql_table.h" // mysql_alter_table,
// mysql_backup_table,
// mysql_restore_table
#include "sql_reload.h" // reload_acl_and_cache
@ -4190,7 +4188,7 @@ mysql_execute_command(THD *thd, bool is_called_from_prepared_stmt)
*/
{
/* Prepare stack copies to be re-execution safe */
HA_CREATE_INFO create_info;
Table_specification_st create_info;
Alter_info alter_info(lex->alter_info, thd->mem_root);
if (unlikely(thd->is_fatal_error)) /* out of memory creating alter_info */
@ -4200,10 +4198,9 @@ mysql_execute_command(THD *thd, bool is_called_from_prepared_stmt)
if (check_one_table_access(thd, INDEX_ACL, all_tables))
goto error; /* purecov: inspected */
bzero((char*) &create_info, sizeof(create_info));
create_info.init();
create_info.db_type= 0;
create_info.row_type= ROW_TYPE_NOT_USED;
create_info.default_table_charset= thd->variables.collation_database;
create_info.alter_info= &alter_info;
WSREP_TO_ISOLATION_BEGIN(first_table->db.str, first_table->table_name.str, NULL);
@ -5162,6 +5159,10 @@ mysql_execute_command(THD *thd, bool is_called_from_prepared_stmt)
&lex->name))
break;
if ((res= lex->create_info.resolve_to_charset_collation_context(thd,
thd->charset_collation_context_create_db())))
break;
WSREP_TO_ISOLATION_BEGIN(lex->name.str, NULL, NULL);
res= mysql_create_db(thd, &lex->name,
@ -5223,6 +5224,10 @@ mysql_execute_command(THD *thd, bool is_called_from_prepared_stmt)
if (prepare_db_action(thd, ALTER_ACL, db))
break;
if ((res= lex->create_info.resolve_to_charset_collation_context(thd,
thd->charset_collation_context_alter_db(lex->name.str))))
break;
WSREP_TO_ISOLATION_BEGIN(db->str, NULL, NULL);
res= mysql_alter_db(thd, db, &lex->create_info);
@ -10472,40 +10477,6 @@ bool parse_sql(THD *thd, Parser_state *parser_state,
*/
/**
Check and merge "CHARACTER SET cs [ COLLATE cl ]" clause
@param cs character set pointer.
@param cl collation pointer.
Check if collation "cl" is applicable to character set "cs".
If "cl" is NULL (e.g. when COLLATE clause is not specified),
then simply "cs" is returned.
@return Error status.
@retval NULL, if "cl" is not applicable to "cs".
@retval pointer to merged CHARSET_INFO on success.
*/
CHARSET_INFO*
merge_charset_and_collation(CHARSET_INFO *cs, CHARSET_INFO *cl)
{
if (cl)
{
if (!my_charset_same(cs, cl))
{
my_error(ER_COLLATION_CHARSET_MISMATCH, MYF(0), cl->coll_name.str,
cs->cs_name.str);
return NULL;
}
return cl;
}
return cs;
}
void LEX::mark_first_table_as_inserting()
{
TABLE_LIST *t= first_select_lex()->table_list.first;

View File

@ -78,7 +78,6 @@ bool check_string_char_length(const LEX_CSTRING *str, uint err_msg,
size_t max_char_length, CHARSET_INFO *cs,
bool no_error);
bool check_ident_length(const LEX_CSTRING *ident);
CHARSET_INFO* merge_charset_and_collation(CHARSET_INFO *cs, CHARSET_INFO *cl);
bool check_host_name(LEX_CSTRING *str);
bool check_identifier_name(LEX_CSTRING *str, uint max_char_length,
uint err_code, const char *param_for_err_msg);

View File

@ -195,7 +195,8 @@ static bool check_exchange_partition(TABLE *table, TABLE *part_table)
bool compare_table_with_partition(THD *thd, TABLE *table, TABLE *part_table,
partition_element *part_elem, uint part_id)
{
HA_CREATE_INFO table_create_info, part_create_info;
HA_CREATE_INFO table_create_info;
Table_specification_st part_create_info;
Alter_info part_alter_info;
Alter_table_ctx part_alter_ctx; // Not used
DBUG_ENTER("compare_table_with_partition");

View File

@ -3874,38 +3874,6 @@ bool validate_comment_length(THD *thd, LEX_CSTRING *comment, size_t max_len,
}
/*
Set table default charset, if not set
SYNOPSIS
set_table_default_charset()
create_info Table create information
DESCRIPTION
If the table character set was not given explicitly,
let's fetch the database default character set and
apply it to the table.
*/
static void set_table_default_charset(THD *thd, HA_CREATE_INFO *create_info,
const LEX_CSTRING &db)
{
/*
If the table character set was not given explicitly,
let's fetch the database default character set and
apply it to the table.
*/
if (!create_info->default_table_charset)
{
Schema_specification_st db_info;
load_db_opt_by_name(thd, db.str, &db_info);
create_info->default_table_charset= db_info.default_table_charset;
}
}
/*
Extend long VARCHAR fields to blob & prepare field if it's a blob
@ -4064,14 +4032,14 @@ handler *mysql_create_frm_image(THD *thd, const LEX_CSTRING &db,
handler *file;
DBUG_ENTER("mysql_create_frm_image");
DBUG_ASSERT(create_info->default_table_charset);
if (!alter_info->create_list.elements)
{
my_error(ER_TABLE_MUST_HAVE_COLUMNS, MYF(0));
DBUG_RETURN(NULL);
}
set_table_default_charset(thd, create_info, db);
db_options= create_info->table_options_with_row_type();
if (unlikely(!(file= get_new_handler((TABLE_SHARE*) 0, thd->mem_root,
@ -4345,6 +4313,7 @@ err:
@retval -1 table existed but IF NOT EXISTS was used
*/
static
int create_table_impl(THD *thd,
DDL_LOG_STATE *ddl_log_state_create,
DDL_LOG_STATE *ddl_log_state_rm,
@ -4365,6 +4334,8 @@ int create_table_impl(THD *thd,
DBUG_PRINT("enter", ("db: '%s' table: '%s' tmp: %d path: %s",
db.str, table_name.str, internal_tmp_table, path.str));
DBUG_ASSERT(create_info->default_table_charset);
/* Easy check for ddl logging if we are creating a temporary table */
if (create_info->tmp_table())
{
@ -4703,6 +4674,8 @@ int mysql_create_table_no_lock(THD *thd,
LEX_CSTRING cpath;
LEX_CUSTRING frm= {0,0};
DBUG_ASSERT(create_info->default_table_charset);
if (create_info->tmp_table())
path_length= build_tmptable_filename(thd, path, sizeof(path));
else
@ -4771,6 +4744,8 @@ int mysql_create_table_no_lock(THD *thd,
close of thread tables.
*/
static
bool mysql_create_table(THD *thd, TABLE_LIST *create_table,
Table_specification_st *create_info,
Alter_info *alter_info)
@ -4784,6 +4759,8 @@ bool mysql_create_table(THD *thd, TABLE_LIST *create_table,
bool result;
DBUG_ENTER("mysql_create_table");
DBUG_ASSERT(create_info->default_table_charset);
DBUG_ASSERT(create_table == thd->lex->query_tables);
bzero(&ddl_log_state_create, sizeof(ddl_log_state_create));
@ -5222,6 +5199,7 @@ mysql_rename_table(handlerton *base, const LEX_CSTRING *old_db,
TRUE error
*/
static
bool mysql_create_like_table(THD* thd, TABLE_LIST* table,
TABLE_LIST* src_table,
Table_specification_st *create_info)
@ -5296,6 +5274,14 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table,
local_create_info.db_type= src_table->table->s->db_type();
local_create_info.row_type= src_table->table->s->row_type;
local_create_info.alter_info= &local_alter_info;
/*
This statement:
CREATE TABLE t1 LIKE t2
does not support table charset/collation clauses.
No needs to copy. Assert they are empty.
*/
DBUG_ASSERT(create_info->default_charset_collation.is_empty());
DBUG_ASSERT(create_info->convert_charset_collation.is_empty());
if (mysql_prepare_alter_table(thd, src_table->table, &local_create_info,
&local_alter_info, &local_alter_ctx))
goto err;
@ -7949,7 +7935,7 @@ void append_drop_column(THD *thd, String *str, Field *field)
bool
mysql_prepare_alter_table(THD *thd, TABLE *table,
HA_CREATE_INFO *create_info,
Table_specification_st *create_info,
Alter_info *alter_info,
Alter_table_ctx *alter_ctx)
{
@ -8015,8 +8001,11 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
create_info->max_rows= table->s->max_rows;
if (!(used_fields & HA_CREATE_USED_AVG_ROW_LENGTH))
create_info->avg_row_length= table->s->avg_row_length;
if (!(used_fields & HA_CREATE_USED_DEFAULT_CHARSET))
create_info->default_table_charset= table->s->table_charset;
if (create_info->resolve_to_charset_collation_context(thd,
thd->charset_collation_context_alter_table(table->s)))
DBUG_RETURN(true);
if (!(used_fields & HA_CREATE_USED_AUTO) && table->found_next_number_field)
{
/* Table has an autoincrement, copy value to new table */
@ -9774,7 +9763,7 @@ static uint64 get_start_alter_id(THD *thd)
bool mysql_alter_table(THD *thd, const LEX_CSTRING *new_db,
const LEX_CSTRING *new_name,
HA_CREATE_INFO *create_info,
Table_specification_st *create_info,
TABLE_LIST *table_list,
Alter_info *alter_info,
uint order_num, ORDER *order, bool ignore,
@ -10367,7 +10356,7 @@ do_continue:;
DBUG_RETURN(true);
}
set_table_default_charset(thd, create_info, alter_ctx.db);
DBUG_ASSERT(create_info->default_table_charset);
if (create_info->check_fields(thd, alter_info,
table_list->table_name, table_list->db) ||
@ -11787,7 +11776,7 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to,
bool mysql_recreate_table(THD *thd, TABLE_LIST *table_list, bool table_copy)
{
HA_CREATE_INFO create_info;
Table_specification_st create_info;
Alter_info alter_info;
TABLE_LIST *next_table= table_list->next_global;
DBUG_ENTER("mysql_recreate_table");
@ -11799,9 +11788,8 @@ bool mysql_recreate_table(THD *thd, TABLE_LIST *table_list, bool table_copy)
/* hide following tables from open_tables() */
table_list->next_global= NULL;
bzero((char*) &create_info, sizeof(create_info));
create_info.init();
create_info.row_type=ROW_TYPE_NOT_USED;
create_info.default_table_charset=default_charset_info;
create_info.alter_info= &alter_info;
/* Force alter table to recreate table */
alter_info.flags= (ALTER_CHANGE_COLUMN | ALTER_RECREATE);
@ -12058,6 +12046,11 @@ bool Sql_cmd_create_table_like::execute(THD *thd)
const bool used_engine= lex->create_info.used_fields & HA_CREATE_USED_ENGINE;
DBUG_ASSERT((m_storage_engine_name.str != NULL) == used_engine);
if (lex->create_info.resolve_to_charset_collation_context(thd,
thd->charset_collation_context_create_table_in_db(first_table->db.str)))
DBUG_RETURN(true);
if (used_engine)
{
if (resolve_storage_engine_with_error(thd, &lex->create_info.db_type,
@ -12130,19 +12123,9 @@ bool Sql_cmd_create_table_like::execute(THD *thd)
*/
if (!(create_info.used_fields & HA_CREATE_USED_ENGINE))
create_info.use_default_db_type(thd);
/*
If we are using SET CHARSET without DEFAULT, add an implicit
DEFAULT to not confuse old users. (This may change).
*/
if ((create_info.used_fields &
(HA_CREATE_USED_DEFAULT_CHARSET | HA_CREATE_USED_CHARSET)) ==
HA_CREATE_USED_CHARSET)
{
create_info.used_fields&= ~HA_CREATE_USED_CHARSET;
create_info.used_fields|= HA_CREATE_USED_DEFAULT_CHARSET;
create_info.default_table_charset= create_info.alter_table_convert_to_charset;
create_info.alter_table_convert_to_charset= 0;
}
DBUG_ASSERT(!(create_info.used_fields & HA_CREATE_USED_CHARSET));
DBUG_ASSERT(create_info.convert_charset_collation.is_empty());
/*
If we are a slave, we should add OR REPLACE if we don't have
@ -12368,3 +12351,46 @@ bool Sql_cmd_create_table_like::execute(THD *thd)
end_with_restore_list:
DBUG_RETURN(res);
}
bool HA_CREATE_INFO::
resolve_to_charset_collation_context(THD *thd,
const Lex_table_charset_collation_attrs_st &default_cscl_arg,
const Lex_table_charset_collation_attrs_st &convert_cscl,
const Charset_collation_context &ctx)
{
/*
If CONVERT TO clauses are specified only (without table default clauses),
then we copy CONVERT TO clauses to default clauses, so e.g:
CONVERT TO CHARACTER SET utf8mb4
means
CONVERT TO CHARACTER SET utf8mb4, DEFAULT CHARACTER SET utf8mb4
*/
Lex_table_charset_collation_attrs_st default_cscl=
!convert_cscl.is_empty() && default_cscl_arg.is_empty() ?
convert_cscl : default_cscl_arg;
if (default_cscl.is_empty())
default_table_charset= ctx.collate_default().charset_info();
else
{
// 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)))
return true;
}
if (convert_cscl.is_empty())
alter_table_convert_to_charset= NULL;
else
{
// Make sure we don't do double resolution in direct SQL execution
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)))
return true;
}
return false;
}

View File

@ -19,6 +19,7 @@
#include <my_sys.h> // pthread_mutex_t
#include "m_string.h" // LEX_CUSTRING
#include "lex_charset.h"
#define ERROR_INJECT(code) \
((DBUG_IF("crash_" code) && (DBUG_SUICIDE(), 0)) || \
@ -90,9 +91,6 @@ void build_lower_case_table_filename(char *buff, size_t bufflen,
const LEX_CSTRING *table,
uint flags);
uint build_tmptable_filename(THD* thd, char *buff, size_t bufflen);
bool mysql_create_table(THD *thd, TABLE_LIST *create_table,
Table_specification_st *create_info,
Alter_info *alter_info);
bool add_keyword_to_query(THD *thd, String *result, const LEX_CSTRING *keyword,
const LEX_CSTRING *add);
@ -156,14 +154,14 @@ int mysql_discard_or_import_tablespace(THD *thd,
bool discard);
bool mysql_prepare_alter_table(THD *thd, TABLE *table,
HA_CREATE_INFO *create_info,
Table_specification_st *create_info,
Alter_info *alter_info,
Alter_table_ctx *alter_ctx);
bool mysql_trans_prepare_alter_copy_data(THD *thd);
bool mysql_trans_commit_alter_copy_data(THD *thd);
bool mysql_alter_table(THD *thd, const LEX_CSTRING *new_db,
const LEX_CSTRING *new_name,
HA_CREATE_INFO *create_info,
Table_specification_st *create_info,
TABLE_LIST *table_list,
Alter_info *alter_info,
uint order_num, ORDER *order, bool ignore,
@ -173,9 +171,6 @@ bool mysql_compare_tables(TABLE *table,
HA_CREATE_INFO *create_info,
bool *metadata_equal);
bool mysql_recreate_table(THD *thd, TABLE_LIST *table_list, bool table_copy);
bool mysql_create_like_table(THD *thd, TABLE_LIST *table,
TABLE_LIST *src_table,
Table_specification_st *create_info);
bool mysql_rename_table(handlerton *base, const LEX_CSTRING *old_db,
const LEX_CSTRING *old_name, const LEX_CSTRING *new_db,
const LEX_CSTRING *new_name, LEX_CUSTRING *id,

View File

@ -2369,7 +2369,6 @@ create:
If the table exists, we should either not create it or replace it
*/
lex->query_tables->open_strategy= TABLE_LIST::OPEN_STUB;
lex->create_info.default_table_charset= NULL;
lex->name= null_clex_str;
lex->create_last_non_select_table= lex->last_table();
lex->inc_select_stack_outer_barrier();
@ -2512,9 +2511,7 @@ create:
}
| create_or_replace DATABASE opt_if_not_exists ident
{
Lex->create_info.default_table_charset= NULL;
Lex->create_info.schema_comment= NULL;
Lex->create_info.used_fields= 0;
Lex->create_info.init();
}
opt_create_database_options
{
@ -5533,17 +5530,9 @@ default_charset:
default_collation:
opt_default COLLATE_SYM opt_equal collation_name_or_default
{
HA_CREATE_INFO *cinfo= &Lex->create_info;
bool is_exact= $4.type() == Lex_extended_collation_st::TYPE_EXACT;
CHARSET_INFO *cl= is_exact ? $4.charset_info() : NULL;
if (unlikely((cinfo->used_fields & HA_CREATE_USED_DEFAULT_CHARSET) &&
cinfo->default_table_charset && cl &&
!(cl= merge_charset_and_collation(cinfo->default_table_charset,
cl))))
Table_specification_st *cinfo= &Lex->create_info;
if (unlikely(cinfo->add_table_option_default_collation($4)))
MYSQL_YYABORT;
Lex->create_info.default_table_charset= cl;
Lex->create_info.used_fields|= HA_CREATE_USED_DEFAULT_CHARSET;
}
;
@ -6955,9 +6944,7 @@ alter:
}
| ALTER DATABASE ident_or_empty
{
Lex->create_info.default_table_charset= NULL;
Lex->create_info.schema_comment= NULL;
Lex->create_info.used_fields= 0;
Lex->create_info.init();
if (Lex->main_select_push(true))
MYSQL_YYABORT;
}
@ -6973,8 +6960,7 @@ alter:
}
| ALTER DATABASE COMMENT_SYM opt_equal TEXT_STRING_sys
{
Lex->create_info.default_table_charset= NULL;
Lex->create_info.used_fields= 0;
Lex->create_info.init();
Lex->create_info.schema_comment= thd->make_clex_string($5);
Lex->create_info.used_fields|= HA_CREATE_USED_COMMENT;
}
@ -7619,29 +7605,14 @@ alter_list_item:
}
| CONVERT_SYM TO_SYM charset charset_name_or_default
{
if (!$4)
{
$4= thd->variables.collation_database;
}
if (unlikely(Lex->create_info.add_alter_list_item_convert_to_charset($4)))
if (Lex->add_alter_list_item_convert_to_charset($4))
MYSQL_YYABORT;
Lex->alter_info.flags|= ALTER_CONVERT_TO;
}
| CONVERT_SYM TO_SYM charset charset_name_or_default
COLLATE_SYM collation_name_or_default
{
if (!$4)
{
$4= thd->variables.collation_database;
}
bool is_exact= $6.type() == Lex_extended_collation_st::TYPE_EXACT;
CHARSET_INFO *cl= is_exact ? $6.charset_info() : $4;
if (unlikely(!my_charset_same($4,cl)))
my_yyabort_error((ER_COLLATION_CHARSET_MISMATCH, MYF(0),
cl->coll_name.str, $4->cs_name.str));
if (unlikely(Lex->create_info.add_alter_list_item_convert_to_charset(cl)))
if (Lex->add_alter_list_item_convert_to_charset($4, $6))
MYSQL_YYABORT;
Lex->alter_info.flags|= ALTER_CONVERT_TO;
}
| create_table_options_space_separated
{

View File

@ -45,6 +45,7 @@
#include "ha_sequence.h"
#include "sql_show.h"
#include "opt_trace.h"
#include "sql_db.h" // get_default_db_collation
/* For MySQL 5.7 virtual fields */
#define MYSQL57_GENERATED_FIELD 128
@ -3503,6 +3504,19 @@ int TABLE_SHARE::init_from_sql_statement_string(THD *thd, bool write,
else
thd->set_n_backup_active_arena(arena, &backup);
/*
THD::reset_db() does not set THD::db_charset,
so it keeps pointing to the character set and collation
of the current database, rather than the database of the
new initialized table. After reset_db() the result of
get_default_db_collation() can be wrong. The latter is
used inside charset_collation_context_create_table_in_db().
Let's initialize ctx before calling reset_db().
This makes sure the db.opt file to be loaded properly when needed.
*/
Charset_collation_context
ctx(thd->charset_collation_context_create_table_in_db(db.str));
thd->reset_db(&db);
lex_start(thd);
@ -3510,6 +3524,9 @@ int TABLE_SHARE::init_from_sql_statement_string(THD *thd, bool write,
sql_unusable_for_discovery(thd, hton, sql_copy))))
goto ret;
if (thd->lex->create_info.resolve_to_charset_collation_context(thd, ctx))
DBUG_RETURN(true);
thd->lex->create_info.db_type= hton;
#ifdef WITH_PARTITION_STORAGE_ENGINE
thd->work_part_info= 0; // For partitioning