Skip to content

Commit 29a4e1e

Browse files
roylysengdahlerlend
authored andcommitted
Bug#35889990: Setting secondary_engine to OFF causes offload issues with executing queries from stored procedures Bug#35988564: CREATE TEMPORARY TABLE failure after Table_ref::restore_properties
The problem is that when reaching the function RapidOptimize(), the value of LEX::using_hypergraph_optimizer is not consistent with the value of the session variable use_old_optimizer. The problem is a missing setting of LEX::using_hypergraph_optimizer in the execution of a query. It was only synchronized with the hypergraph optimizer setting in preparation of a query, which is sufficient for regular statements which always perform both preparation and execution, but not for stored procedures that have separate preparation and execution. The solution is to add this setting. But this revealed another problem: sometimes execution is out of sync with the current preparation. An optimization with the hypergraph optimizer requires that the preparation is also performed with settings specific to the hypergraph optimizer. This may happen e.g if the value of the session variable use_secondary_engine is switched from "off" or "on" to "forced" either between a preparation and execution (for prepared statements) or between two executions (for prepared statements and stored procedure statements) The solution to this is to track the current preparation state versus the one desired (the optimizer switch setting). It is now checked that the value of using_hypergraph_optimizer matches the current optimizer switch setting just after opening tables and before optimizing such statements, in which case we call ask_to_reprepare(). During optimization we set using_hypergraph_optimizer according to the optimizer switch. The test rapid.pfs_secondary has an increased reprepare count because we now detect more often that an optimization requires a new preparation. In addition, a test case was added to cover the problem described in bug#35988564. Change-Id: Ibf158576ec4cd1edde655d41f7c8bf2813e208ee
1 parent 6a66479 commit 29a4e1e

11 files changed

+177
-20
lines changed

mysql-test/r/hypergraph_bugs.result

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1342,3 +1342,89 @@ EXPLAIN
13421342
-> Single-row index lookup on t1 using PRIMARY (a=5) (rows=1)
13431343

13441344
DROP TABLE t1,t2;
1345+
# Bug#5889990: Setting secondary_engine to OFF causes offload issues
1346+
CREATE TABLE t(x INT, y INT);
1347+
INSERT INTO t VALUES (1, 2), (2, 3);
1348+
ANALYZE TABLE t;
1349+
Table Op Msg_type Msg_text
1350+
test.t analyze status OK
1351+
SET optimizer_switch='hypergraph_optimizer=off';
1352+
PREPARE ps FROM
1353+
'SELECT *
1354+
FROM t AS t1 LEFT JOIN t AS t2 ON t1.x=t2.x AND t1.y IN (SELECT x FROM t)';
1355+
EXECUTE ps;
1356+
x y x y
1357+
1 2 1 2
1358+
2 3 NULL NULL
1359+
SET optimizer_switch='hypergraph_optimizer=on';
1360+
Warnings:
1361+
Warning 1287 The hypergraph optimizer is highly experimental and is meant for testing only. Do not enable it unless you are a MySQL developer.
1362+
EXECUTE ps;
1363+
x y x y
1364+
1 2 1 2
1365+
2 3 NULL NULL
1366+
SET optimizer_switch='hypergraph_optimizer=off';
1367+
EXECUTE ps;
1368+
x y x y
1369+
1 2 1 2
1370+
2 3 NULL NULL
1371+
SET optimizer_switch='hypergraph_optimizer=on';
1372+
Warnings:
1373+
Warning 1287 The hypergraph optimizer is highly experimental and is meant for testing only. Do not enable it unless you are a MySQL developer.
1374+
PREPARE ps FROM
1375+
'SELECT *
1376+
FROM t AS t1 LEFT JOIN t AS t2 ON t1.x=t2.x AND t1.y IN (SELECT x FROM t)';
1377+
EXECUTE ps;
1378+
x y x y
1379+
1 2 1 2
1380+
2 3 NULL NULL
1381+
SET optimizer_switch='hypergraph_optimizer=off';
1382+
EXECUTE ps;
1383+
x y x y
1384+
1 2 1 2
1385+
2 3 NULL NULL
1386+
DROP TABLE t;
1387+
CREATE TABLE t(x VARCHAR(100), FULLTEXT KEY (x));
1388+
INSERT INTO t VALUES ('abc'), ('xyz'), ('abc abc');
1389+
ANALYZE TABLE t;
1390+
Table Op Msg_type Msg_text
1391+
test.t analyze status OK
1392+
SET optimizer_switch='hypergraph_optimizer=on';
1393+
Warnings:
1394+
Warning 1287 The hypergraph optimizer is highly experimental and is meant for testing only. Do not enable it unless you are a MySQL developer.
1395+
PREPARE ps FROM
1396+
'SELECT x, MATCH(x) AGAINST (''abc'') AS score FROM t
1397+
GROUP BY x HAVING MATCH(x) AGAINST(''abc'') > 0';
1398+
EXECUTE ps;
1399+
x score
1400+
abc 0.031008131802082062
1401+
abc abc 0.062016263604164124
1402+
SET optimizer_switch='hypergraph_optimizer=off';
1403+
EXECUTE ps;
1404+
x score
1405+
abc 0.031008131802082062
1406+
abc abc 0.062016263604164124
1407+
SET optimizer_switch='hypergraph_optimizer=on';
1408+
Warnings:
1409+
Warning 1287 The hypergraph optimizer is highly experimental and is meant for testing only. Do not enable it unless you are a MySQL developer.
1410+
EXECUTE ps;
1411+
x score
1412+
abc 0.031008131802082062
1413+
abc abc 0.062016263604164124
1414+
SET optimizer_switch='hypergraph_optimizer=off';
1415+
PREPARE ps FROM
1416+
'SELECT x, MATCH(x) AGAINST (''abc'') AS score FROM t
1417+
GROUP BY x HAVING MATCH(x) AGAINST(''abc'') > 0';
1418+
EXECUTE ps;
1419+
x score
1420+
abc 0.031008131802082062
1421+
abc abc 0.062016263604164124
1422+
SET optimizer_switch='hypergraph_optimizer=on';
1423+
Warnings:
1424+
Warning 1287 The hypergraph optimizer is highly experimental and is meant for testing only. Do not enable it unless you are a MySQL developer.
1425+
EXECUTE ps;
1426+
x score
1427+
abc 0.031008131802082062
1428+
abc abc 0.062016263604164124
1429+
DROP TABLE t;
1430+
SET optimizer_switch='hypergraph_optimizer=default';

mysql-test/r/using_hypergraph_optimizer.result

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ COUNT(*)
7575
SELECT COUNT(*) FROM INFORMATION_SCHEMA.OPTIMIZER_TRACE
7676
WHERE TRACE LIKE '%Constructed hypergraph%';
7777
COUNT(*)
78-
1
78+
0
7979
# Case 2.a: Preparation: 'hypergraph_optimizer=off', execution: 'hypergraph_optimizer=on'
8080
SET optimizer_switch = 'hypergraph_optimizer=off';
8181
PREPARE ps_set FROM 'SET @x = (SELECT COUNT(*) FROM t)';
@@ -91,7 +91,7 @@ COUNT(*)
9191
SELECT COUNT(*) FROM INFORMATION_SCHEMA.OPTIMIZER_TRACE
9292
WHERE TRACE LIKE '%Constructed hypergraph%';
9393
COUNT(*)
94-
0
94+
1
9595
# Case 2.b: Preparation: 'hypergraph_optimizer=off', execution: 'hypergraph_optimizer=off'
9696
SET optimizer_switch = 'hypergraph_optimizer=off';
9797
EXECUTE ps_set;

mysql-test/t/hypergraph_bugs.test

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1093,3 +1093,75 @@ EXPLAIN FORMAT=TREE SELECT * FROM t1 WHERE a IN
10931093
EXPLAIN FORMAT=TREE SELECT * FROM t1 WHERE t1.a IN (SELECT 5 FROM t2);
10941094

10951095
DROP TABLE t1,t2;
1096+
1097+
--echo # Bug#5889990: Setting secondary_engine to OFF causes offload issues
1098+
1099+
CREATE TABLE t(x INT, y INT);
1100+
INSERT INTO t VALUES (1, 2), (2, 3);
1101+
ANALYZE TABLE t;
1102+
1103+
SET optimizer_switch='hypergraph_optimizer=off';
1104+
1105+
PREPARE ps FROM
1106+
'SELECT *
1107+
FROM t AS t1 LEFT JOIN t AS t2 ON t1.x=t2.x AND t1.y IN (SELECT x FROM t)';
1108+
1109+
EXECUTE ps;
1110+
1111+
SET optimizer_switch='hypergraph_optimizer=on';
1112+
1113+
EXECUTE ps;
1114+
1115+
SET optimizer_switch='hypergraph_optimizer=off';
1116+
1117+
EXECUTE ps;
1118+
1119+
SET optimizer_switch='hypergraph_optimizer=on';
1120+
1121+
PREPARE ps FROM
1122+
'SELECT *
1123+
FROM t AS t1 LEFT JOIN t AS t2 ON t1.x=t2.x AND t1.y IN (SELECT x FROM t)';
1124+
1125+
EXECUTE ps;
1126+
1127+
SET optimizer_switch='hypergraph_optimizer=off';
1128+
1129+
EXECUTE ps;
1130+
1131+
DROP TABLE t;
1132+
1133+
CREATE TABLE t(x VARCHAR(100), FULLTEXT KEY (x));
1134+
INSERT INTO t VALUES ('abc'), ('xyz'), ('abc abc');
1135+
ANALYZE TABLE t;
1136+
1137+
SET optimizer_switch='hypergraph_optimizer=on';
1138+
1139+
PREPARE ps FROM
1140+
'SELECT x, MATCH(x) AGAINST (''abc'') AS score FROM t
1141+
GROUP BY x HAVING MATCH(x) AGAINST(''abc'') > 0';
1142+
1143+
EXECUTE ps;
1144+
1145+
SET optimizer_switch='hypergraph_optimizer=off';
1146+
1147+
EXECUTE ps;
1148+
1149+
SET optimizer_switch='hypergraph_optimizer=on';
1150+
1151+
EXECUTE ps;
1152+
1153+
SET optimizer_switch='hypergraph_optimizer=off';
1154+
1155+
PREPARE ps FROM
1156+
'SELECT x, MATCH(x) AGAINST (''abc'') AS score FROM t
1157+
GROUP BY x HAVING MATCH(x) AGAINST(''abc'') > 0';
1158+
1159+
EXECUTE ps;
1160+
1161+
SET optimizer_switch='hypergraph_optimizer=on';
1162+
1163+
EXECUTE ps;
1164+
1165+
DROP TABLE t;
1166+
1167+
SET optimizer_switch='hypergraph_optimizer=default';

mysql-test/t/using_hypergraph_optimizer.test

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,8 @@ WHERE TRACE LIKE '%Constructed hypergraph%';
5656
SELECT @x;
5757

5858
# Verify that prepared SET statements use the optimizer that was active
59-
# when PREPARE was called and that the behaviour is consistent with prepared
60-
# SELECT statements
59+
# when PREPARE was called. Prepared SELECT statements use the optimizer that
60+
# is active during execution.
6161

6262
--echo # Case 1.a: Preparation: 'hypergraph_optimizer=on', execution: 'hypergraph_optimizer=on'
6363
PREPARE ps_set FROM 'SET @x = (SELECT COUNT(*) FROM t)';

sql/sp_instr.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -870,6 +870,7 @@ void sp_lex_instr::free_lex() {
870870
m_lex->sphead = nullptr;
871871
lex_end(m_lex);
872872
if (m_lex->result != nullptr) ::destroy_at(m_lex->result);
873+
m_lex->set_secondary_engine_execution_context(nullptr);
873874
m_lex->destroy();
874875
delete (st_lex_local *)m_lex;
875876

sql/sql_cmd_ddl_table.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,7 @@ bool Sql_cmd_create_table::execute(THD *thd) {
331331

332332
if (!query_expression->is_prepared()) {
333333
// Use the desired optimizer during following preparation
334+
334335
lex->set_using_hypergraph_optimizer(need_hypergraph_optimizer);
335336
}
336337
if (need_hypergraph_optimizer != lex->using_hypergraph_optimizer() &&
@@ -349,7 +350,7 @@ bool Sql_cmd_create_table::execute(THD *thd) {
349350
return false;
350351
} else {
351352
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), create_info.alias);
352-
return false;
353+
return true;
353354
}
354355
}
355356

sql/sql_lex.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -396,6 +396,7 @@ LEX::~LEX() {
396396
unit = nullptr; // Created in mem_root - no destructor
397397
query_block = nullptr;
398398
m_current_query_block = nullptr;
399+
assert(m_secondary_engine_context == nullptr);
399400
}
400401

401402
/**

sql/sql_lex.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3837,11 +3837,12 @@ struct LEX : public Query_tables_list {
38373837
bool is_explain_analyze = false;
38383838

38393839
/**
3840-
Whether the currently-running query should be (attempted) executed in
3841-
the hypergraph optimizer. This will not change after the query is
3842-
done parsing, so you can use it in any query phase to e.g. figure out
3840+
Whether the currently-running statement should be prepared and executed
3841+
with the hypergraph optimizer. This will not change after the statement is
3842+
prepared, so you can use it in any optimization phase to e.g. figure out
38433843
whether to inhibit some transformation that the hypergraph optimizer
3844-
does not properly understand yet.
3844+
does not properly understand yet. If a different optimizer is requested,
3845+
the statement must be re-prepared with the proper optimizer settings.
38453846
*/
38463847

38473848
bool using_hypergraph_optimizer() const {

sql/sql_optimizer.cc

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -691,10 +691,7 @@ bool JOIN::optimize(bool finalize_access_paths) {
691691

692692
assert(!thd->lex->using_hypergraph_optimizer());
693693
// Don't expect to get here if the hypergraph optimizer is enabled via an
694-
// optimizer switch. We only check it for regular statements. Prepared
695-
// statements and stored programs use the optimizer that was active when the
696-
// statement was prepared, and don't check the optimizer switch for each
697-
// subsequent execution.
694+
// optimizer switch. The "is_regular()" case is necessary for SET statements.
698695
assert(!thd->optimizer_switch_flag(OPTIMIZER_SWITCH_HYPERGRAPH_OPTIMIZER) ||
699696
!thd->stmt_arena->is_regular());
700697

sql/sql_prepare.cc

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1168,6 +1168,7 @@ bool Sql_cmd_create_table::prepare(THD *thd) {
11681168
}
11691169

11701170
set_prepared();
1171+
11711172
return false;
11721173
}
11731174

@@ -1908,7 +1909,6 @@ void mysqld_stmt_execute(THD *thd, Prepared_statement *stmt, bool has_new_types,
19081909
// Initially, optimize the statement for the primary storage engine.
19091910
// If an eligible secondary storage engine is found, the statement
19101911
// may be reprepared for the secondary storage engine later.
1911-
const auto saved_secondary_engine = thd->secondary_engine_optimization();
19121912
thd->set_secondary_engine_optimization(
19131913
Secondary_engine_optimization::PRIMARY_TENTATIVELY);
19141914

@@ -1923,8 +1923,6 @@ void mysqld_stmt_execute(THD *thd, Prepared_statement *stmt, bool has_new_types,
19231923
stmt->execute_loop(thd, &expanded_query, open_cursor);
19241924
}
19251925

1926-
thd->set_secondary_engine_optimization(saved_secondary_engine);
1927-
19281926
if (switch_protocol) thd->pop_protocol();
19291927

19301928
sp_cache_enforce_limit(thd->sp_proc_cache, stored_program_cache_size);
@@ -3027,7 +3025,9 @@ bool Prepared_statement::execute_loop(THD *thd, String *expanded_query,
30273025
bool general_log_temporarily_disabled = false;
30283026

30293027
// Reprepare statement unconditionally if it contains UDF references
3030-
if (m_lex->has_udf() && reprepare(thd)) return true;
3028+
if (m_lex->has_udf() && reprepare(thd)) {
3029+
return true;
3030+
}
30313031

30323032
// Reprepare statement if protocol has changed.
30333033
// Note: this is not possible in current code base, hence the assert.

0 commit comments

Comments
 (0)