Skip to content

Commit eba7cd0

Browse files
author
Oystein Grovlen
committed
Bug#25650399: DOWNGRADE FROM MYSQL 8.0 TO 5.7 WILL CRASH SERVER
MySQL 8.0 adds a generated column to the two tables mysql.server_cost and mysql.engine_cost. MySQL 5.7 fails if system tables contain generated columns. Hence, downgrade to 5.7 will not work when cost tables contain generated columns from 8.0. This patch is for 5.7 and backports fix to read_cost_constants() from 8.0. mysql_system_tables_fix.sql is changed to remove columns should they exist. This will make mysql_upgrade, if run during downgrade, restore these tables to its original form. sql/opt_costconstantcache.cc In order for resolving of generated column to work correctly when opening cost tables, lex_start() must be called. scripts/mysql_system_tables_fix.sql Add SQL code to remove the columns from 8.0 should they exist. scripts/mysql_system_tables.sql Specify only non-default values in insert statements for cost tables. This way mysql_upgrade does not give errors if extra columns exist. mysql-test/t/opt_costmodel_downgrade.test mysql-test/r/opt_costmodel_downgrade.result Test to verfiy that 5.7 does not crash should generated columns exist in cost tables. Also verifies that running mysql_upgrade will remove the columns.
1 parent d15e4c2 commit eba7cd0

5 files changed

+121
-24
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
2+
Bug#25650399: DOWNGRADE FROM MYSQL 8.0 WITH WL#10128 TO 5.7
3+
WILL CRASH SERVER
4+
5+
ALTER TABLE mysql.server_cost
6+
ADD COLUMN default_value FLOAT GENERATED ALWAYS AS (cost_name) VIRTUAL;
7+
ALTER TABLE mysql.engine_cost
8+
ADD COLUMN default_value FLOAT GENERATED ALWAYS AS (cost_name) VIRTUAL;
9+
FLUSH OPTIMIZER_COSTS;
10+
mysql.columns_priv OK
11+
mysql.db OK
12+
mysql.engine_cost OK
13+
mysql.event OK
14+
mysql.func OK
15+
mysql.general_log OK
16+
mysql.gtid_executed OK
17+
mysql.help_category OK
18+
mysql.help_keyword OK
19+
mysql.help_relation OK
20+
mysql.help_topic OK
21+
mysql.innodb_index_stats OK
22+
mysql.innodb_table_stats OK
23+
mysql.ndb_binlog_index OK
24+
mysql.plugin OK
25+
mysql.proc OK
26+
mysql.procs_priv OK
27+
mysql.proxies_priv OK
28+
mysql.server_cost OK
29+
mysql.servers OK
30+
mysql.slave_master_info OK
31+
mysql.slave_relay_log_info OK
32+
mysql.slave_worker_info OK
33+
mysql.slow_log OK
34+
mysql.tables_priv OK
35+
mysql.time_zone OK
36+
mysql.time_zone_leap_second OK
37+
mysql.time_zone_name OK
38+
mysql.time_zone_transition OK
39+
mysql.time_zone_transition_type OK
40+
mysql.user OK
41+
mtr.global_suppressions OK
42+
mtr.test_suppressions OK
43+
sys.sys_config OK
44+
SELECT * FROM mysql.server_cost;
45+
cost_name cost_value last_update comment
46+
disk_temptable_create_cost NULL # NULL
47+
disk_temptable_row_cost NULL # NULL
48+
key_compare_cost NULL # NULL
49+
memory_temptable_create_cost NULL # NULL
50+
memory_temptable_row_cost NULL # NULL
51+
row_evaluate_cost NULL # NULL
52+
SELECT * FROM mysql.engine_cost;
53+
engine_name device_type cost_name cost_value last_update comment
54+
default 0 io_block_read_cost NULL # NULL
55+
default 0 memory_block_read_cost NULL # NULL
+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
-- source include/no_valgrind_without_big.inc
2+
-- source include/mysql_upgrade_preparation.inc
3+
4+
--echo
5+
--echo Bug#25650399: DOWNGRADE FROM MYSQL 8.0 WITH WL#10128 TO 5.7
6+
--echo WILL CRASH SERVER
7+
--echo
8+
9+
# Add columns and check that upgrade script drops them
10+
ALTER TABLE mysql.server_cost
11+
ADD COLUMN default_value FLOAT GENERATED ALWAYS AS (cost_name) VIRTUAL;
12+
ALTER TABLE mysql.engine_cost
13+
ADD COLUMN default_value FLOAT GENERATED ALWAYS AS (cost_name) VIRTUAL;
14+
15+
# This will crash server without fix
16+
FLUSH OPTIMIZER_COSTS;
17+
18+
--exec $MYSQL_UPGRADE --skip-verbose --force 2>&1
19+
20+
# Mask out the content of the last_update column
21+
--replace_column 3 #
22+
SELECT * FROM mysql.server_cost;
23+
--replace_column 5 #
24+
SELECT * FROM mysql.engine_cost;
25+
26+
--source include/mysql_upgrade_cleanup.inc

scripts/mysql_system_tables.sql

+8-22
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
-- Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved.
1+
-- Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
22
--
33
-- This program is free software; you can redistribute it and/or modify
44
-- it under the terms of the GNU General Public License as published by
@@ -226,23 +226,10 @@ CREATE TABLE IF NOT EXISTS server_cost (
226226
PRIMARY KEY (cost_name)
227227
) ENGINE=InnoDB CHARACTER SET=utf8 COLLATE=utf8_general_ci STATS_PERSISTENT=0;
228228

229-
INSERT IGNORE INTO server_cost VALUES
230-
("row_evaluate_cost", DEFAULT, CURRENT_TIMESTAMP, DEFAULT);
231-
232-
INSERT IGNORE INTO server_cost VALUES
233-
("key_compare_cost", DEFAULT, CURRENT_TIMESTAMP, DEFAULT);
234-
235-
INSERT IGNORE INTO server_cost VALUES
236-
("memory_temptable_create_cost", DEFAULT, CURRENT_TIMESTAMP, DEFAULT);
237-
238-
INSERT IGNORE INTO server_cost VALUES
239-
("memory_temptable_row_cost", DEFAULT, CURRENT_TIMESTAMP, DEFAULT);
240-
241-
INSERT IGNORE INTO server_cost VALUES
242-
("disk_temptable_create_cost", DEFAULT, CURRENT_TIMESTAMP, DEFAULT);
243-
244-
INSERT IGNORE INTO server_cost VALUES
245-
("disk_temptable_row_cost", DEFAULT, CURRENT_TIMESTAMP, DEFAULT);
229+
INSERT IGNORE INTO server_cost(cost_name) VALUES
230+
("row_evaluate_cost"), ("key_compare_cost"),
231+
("memory_temptable_create_cost"), ("memory_temptable_row_cost"),
232+
("disk_temptable_create_cost"), ("disk_temptable_row_cost");
246233

247234
-- Engine cost constants
248235

@@ -256,10 +243,9 @@ CREATE TABLE IF NOT EXISTS engine_cost (
256243
PRIMARY KEY (cost_name, engine_name, device_type)
257244
) ENGINE=InnoDB CHARACTER SET=utf8 COLLATE=utf8_general_ci STATS_PERSISTENT=0;
258245

259-
INSERT IGNORE INTO engine_cost VALUES
260-
("default", 0, "memory_block_read_cost", DEFAULT, CURRENT_TIMESTAMP, DEFAULT);
261-
INSERT IGNORE INTO engine_cost VALUES
262-
("default", 0, "io_block_read_cost", DEFAULT, CURRENT_TIMESTAMP, DEFAULT);
246+
INSERT IGNORE INTO engine_cost(engine_name, device_type, cost_name) VALUES
247+
("default", 0, "memory_block_read_cost"),
248+
("default", 0, "io_block_read_cost");
263249

264250
--
265251
-- PERFORMANCE SCHEMA INSTALLATION

scripts/mysql_system_tables_fix.sql

+28-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
-- Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
1+
-- Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
22
--
33
-- This program is free software; you can redistribute it and/or modify
44
-- it under the terms of the GNU General Public License as published by
@@ -939,3 +939,30 @@ SET @str = IF(@had_distributed_proxies_priv > 0, @cmd, "SET @dummy = 0");
939939
PREPARE stmt FROM @str;
940940
EXECUTE stmt;
941941
DROP PREPARE stmt;
942+
943+
--
944+
-- MySQL 8.0 adds default_value column to cost tables
945+
-- In case of downgrade to 5.7, remove these columns
946+
--
947+
948+
-- Drop column default_value from mysql.server_cost if it exists
949+
SET @have_server_cost_default =
950+
(SELECT COUNT(column_name) FROM information_schema.columns
951+
WHERE table_schema = 'mysql' AND table_name = 'server_cost' AND
952+
column_name = 'default_value');
953+
SET @cmd="ALTER TABLE mysql.server_cost DROP COLUMN default_value";
954+
SET @str = IF(@have_server_cost_default > 0, @cmd, "SET @dummy = 0");
955+
PREPARE stmt FROM @str;
956+
EXECUTE stmt;
957+
DROP PREPARE stmt;
958+
959+
-- Drop column default_value from mysql.engine_cost if it exists
960+
SET @have_engine_cost_default =
961+
(SELECT COUNT(column_name) FROM information_schema.columns
962+
WHERE table_schema = 'mysql' AND table_name = 'engine_cost' AND
963+
column_name = 'default_value');
964+
SET @cmd="ALTER TABLE mysql.engine_cost DROP COLUMN default_value";
965+
SET @str = IF(@have_engine_cost_default > 0, @cmd, "SET @dummy = 0");
966+
PREPARE stmt FROM @str;
967+
EXECUTE stmt;
968+
DROP PREPARE stmt;

sql/opt_costconstantcache.cc

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
2+
Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
33
44
This program is free software; you can redistribute it and/or modify
55
it under the terms of the GNU General Public License as published by
@@ -28,6 +28,7 @@
2828
#include "records.h" // READ_RECORD
2929
#include "sql_base.h" // open_and_lock_tables
3030
#include "sql_class.h" // THD
31+
#include "sql_lex.h" // lex_start/lex_end
3132
#include "sql_string.h" // String
3233
#include "table.h" // TABLE
3334
#include "thr_lock.h" // TL_READ
@@ -434,6 +435,7 @@ static void read_cost_constants(Cost_model_constants* cost_constants)
434435
DBUG_ASSERT(thd);
435436
thd->thread_stack= pointer_cast<char*>(&thd);
436437
thd->store_globals();
438+
lex_start(thd);
437439

438440
TABLE_LIST tables[2];
439441
tables[0].init_one_table(C_STRING_WITH_LEN("mysql"),
@@ -462,6 +464,7 @@ static void read_cost_constants(Cost_model_constants* cost_constants)
462464

463465
trans_commit_stmt(thd);
464466
close_thread_tables(thd);
467+
lex_end(thd->lex);
465468

466469
// Delete the locally created THD
467470
delete thd;

0 commit comments

Comments
 (0)