Skip to content

Commit 51a6f13

Browse files
author
Mia Primorac
committed
WL#16235 - offload secondary-engine queries that insert into tables with
triggers - MySQL server part This patch adds a new member to Query_tables_list, has_stored_functions. This variable is used instead of uses_stored_routines() check in all the places that check offloads for the secondary engine. To streamline updating this variable, an additional stored-routine type argument is added to sp_add_used_routine. As a consequence, we now don't block offload of select queries from insert into select statements to secondary engine even when the destination table has a defined trigger. Change-Id: I59662ab8e87a893a50de8d25b76108322a244b6e
1 parent f5b31c0 commit 51a6f13

File tree

6 files changed

+48
-22
lines changed

6 files changed

+48
-22
lines changed

sql/sp.cc

+12-5
Original file line numberDiff line numberDiff line change
@@ -1695,6 +1695,8 @@ bool sp_exist_routines(THD *thd, Table_ref *routines, bool is_proc) {
16951695
@param name_length Length of the routine name.
16961696
@param belong_to_view Uppermost view which uses this routine
16971697
(0 if routine is not used by view)
1698+
@param type Routine type (one of FUNCTION/PROCEDURE/
1699+
TRIGGER ...)
16981700
16991701
@note
17001702
Will also add element to end of 'Query_tables_list::sroutines_list' list.
@@ -1716,7 +1718,8 @@ static bool sp_add_used_routine(Query_tables_list *prelocking_ctx,
17161718
Query_arena *arena, const uchar *key,
17171719
size_t key_length, size_t db_length,
17181720
const char *name, size_t name_length,
1719-
Table_ref *belong_to_view) {
1721+
Table_ref *belong_to_view,
1722+
Sroutine_hash_entry::entry_type type) {
17201723
if (prelocking_ctx->sroutines == nullptr) {
17211724
prelocking_ctx->sroutines.reset(
17221725
new malloc_unordered_map<std::string, Sroutine_hash_entry *>(
@@ -1746,6 +1749,9 @@ static bool sp_add_used_routine(Query_tables_list *prelocking_ctx,
17461749
prelocking_ctx->sroutines_list.link_in_list(rn, &rn->next);
17471750
rn->belong_to_view = belong_to_view;
17481751
rn->m_cache_version = 0;
1752+
if (type == Sroutine_hash_entry::entry_type::FUNCTION) {
1753+
prelocking_ctx->has_stored_functions = true;
1754+
}
17491755
return true;
17501756
}
17511757
return false;
@@ -1810,8 +1816,9 @@ bool sp_add_used_routine(Query_tables_list *prelocking_ctx, Query_arena *arena,
18101816
*/
18111817
key_length +=
18121818
my_casedn_str(system_charset_info, (char *)(key) + key_length) + 1;
1813-
} else
1819+
} else {
18141820
key_length += db_length + 1;
1821+
}
18151822

18161823
switch (name_normalize_type) {
18171824
case Sp_name_normalize_type::LEAVE_AS_IS:
@@ -1860,7 +1867,7 @@ bool sp_add_used_routine(Query_tables_list *prelocking_ctx, Query_arena *arena,
18601867
}
18611868

18621869
if (sp_add_used_routine(prelocking_ctx, arena, key, key_length, db_length,
1863-
name, name_length, belong_to_view)) {
1870+
name, name_length, belong_to_view, type)) {
18641871
if (own_routine) {
18651872
prelocking_ctx->sroutines_list_own_last =
18661873
prelocking_ctx->sroutines_list.next;
@@ -1922,7 +1929,7 @@ void sp_update_stmt_used_routines(
19221929
(void)sp_add_used_routine(prelocking_ctx, thd->stmt_arena,
19231930
pointer_cast<const uchar *>(rt->m_key),
19241931
rt->m_key_length, rt->m_db_length, rt->name(),
1925-
rt->name_length(), belong_to_view);
1932+
rt->name_length(), belong_to_view, rt->type());
19261933
}
19271934
}
19281935

@@ -1947,7 +1954,7 @@ void sp_update_stmt_used_routines(THD *thd, Query_tables_list *prelocking_ctx,
19471954
(void)sp_add_used_routine(prelocking_ctx, thd->stmt_arena,
19481955
pointer_cast<const uchar *>(rt->m_key),
19491956
rt->m_key_length, rt->m_db_length, rt->name(),
1950-
rt->name_length(), belong_to_view);
1957+
rt->name_length(), belong_to_view, rt->type());
19511958
}
19521959

19531960
/**

sql/sql_base.cc

+17-10
Original file line numberDiff line numberDiff line change
@@ -6892,18 +6892,25 @@ static bool open_secondary_engine_tables(THD *thd, uint flags) {
68926892

68936893
// Replace the TABLE objects in the Table_ref with secondary tables.
68946894
Open_table_context ot_ctx(thd, flags | MYSQL_OPEN_SECONDARY_ENGINE);
6895-
Table_ref *tl = lex->query_tables;
6895+
Table_ref *tr = lex->query_tables;
68966896
// For INSERT INTO SELECT and CTAS statements, the table to insert into does
68976897
// not have to have a secondary engine. This table is always first in the list
68986898
if ((lex->sql_command == SQLCOM_INSERT_SELECT ||
68996899
lex->sql_command == SQLCOM_CREATE_TABLE) &&
6900-
tl != nullptr)
6901-
tl = tl->next_global;
6902-
for (; tl != nullptr; tl = tl->next_global) {
6903-
if (tl->is_placeholder()) continue;
6904-
TABLE *primary_table = tl->table;
6905-
tl->table = nullptr;
6906-
if (open_table(thd, tl, &ot_ctx)) {
6900+
tr != nullptr) {
6901+
tr = tr->next_global;
6902+
}
6903+
// Re-open the tables belonging to the query, but not those belonging to
6904+
// associated triggers (query_tables_own_last will point to the boundary).
6905+
for (; tr != nullptr && (lex->query_tables_own_last == nullptr ||
6906+
tr != lex->query_tables_own_last[0]);
6907+
tr = tr->next_global) {
6908+
if (tr->is_placeholder()) {
6909+
continue;
6910+
}
6911+
TABLE *primary_table = tr->table;
6912+
tr->table = nullptr;
6913+
if (open_table(thd, tr, &ot_ctx)) {
69076914
if (!thd->is_error()) {
69086915
/*
69096916
open_table() has not registered any error, implying that we can
@@ -6916,8 +6923,8 @@ static bool open_secondary_engine_tables(THD *thd, uint flags) {
69166923
}
69176924
return true;
69186925
}
6919-
assert(tl->table->s->is_secondary_engine());
6920-
tl->table->file->ha_set_primary_handler(primary_table->file);
6926+
assert(tr->table->s->is_secondary_engine());
6927+
tr->table->file->ha_set_primary_handler(primary_table->file);
69216928
}
69226929

69236930
// Prepare the secondary engine for executing the statement.

sql/sql_lex.cc

+1
Original file line numberDiff line numberDiff line change
@@ -3657,6 +3657,7 @@ void Query_tables_list::reset_query_tables_list(bool init) {
36573657
sroutines_list.clear();
36583658
sroutines_list_own_last = sroutines_list.next;
36593659
sroutines_list_own_elements = 0;
3660+
has_stored_functions = false;
36603661
binlog_stmt_flags = 0;
36613662
stmt_accessed_table_flag = 0;
36623663
lock_tables_state = LTS_NOT_LOCKED;

sql/sql_lex.h

+6-1
Original file line numberDiff line numberDiff line change
@@ -2660,6 +2660,11 @@ class Query_tables_list {
26602660
Sroutine_hash_entry **sroutines_list_own_last;
26612661
uint sroutines_list_own_elements;
26622662

2663+
/**
2664+
Does this LEX context have any stored functions
2665+
*/
2666+
bool has_stored_functions;
2667+
26632668
/**
26642669
Locking state of tables in this particular statement.
26652670
@@ -3185,7 +3190,7 @@ class Query_tables_list {
31853190
}
31863191

31873192
/**
3188-
true if the parsed tree contains references to stored procedures
3193+
true if the parsed tree contains references to stored procedures, triggers
31893194
or functions, false otherwise
31903195
*/
31913196
bool uses_stored_routines() const { return sroutines_list.elements != 0; }

sql/sql_select.cc

+4-6
Original file line numberDiff line numberDiff line change
@@ -313,8 +313,8 @@ static bool equal_engines(const LEX_CSTRING &engine1,
313313
// engine.
314314
const MYSQL_LEX_CSTRING *get_eligible_secondary_engine_from(const LEX *lex) {
315315
// Don't use secondary storage engines for statements that call stored
316-
// routines.
317-
if (lex->uses_stored_routines()) return nullptr;
316+
// functions.
317+
if (lex->has_stored_functions) return nullptr;
318318
// Now check if the opened tables are available in a secondary
319319
// storage engine. Only use the secondary tables if all the tables
320320
// have a secondary tables, and they are all in the same secondary
@@ -430,11 +430,9 @@ void find_and_set_offload_fail_reason(const LEX *lex) {
430430
// check known unsupported features and raise a specific offload error.
431431
std::string err_msg{};
432432
const Table_ref *tref = nullptr;
433-
if (lex->uses_stored_routines() ||
434-
(lex->m_sql_cmd != nullptr && lex->m_sql_cmd->is_part_of_sp()) ||
435-
lex->thd->sp_runtime_ctx != nullptr) {
433+
if (lex->has_stored_functions) {
436434
// We don't support secondary storage engine execution,
437-
// if the query has statements that call stored routines.
435+
// if the query has statements that call stored functions.
438436
err_msg =
439437
"Statements that reference stored functions are not supported in "
440438
"secondary engines.";

sql/trigger.cc

+8
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,12 @@ bool Trigger::execute(THD *thd) {
394394

395395
thd->reset_sub_statement_state(&statement_state, SUB_STMT_TRIGGER);
396396

397+
Secondary_engine_optimization saved_state =
398+
thd->secondary_engine_optimization();
399+
400+
thd->set_secondary_engine_optimization(
401+
Secondary_engine_optimization::PRIMARY_TENTATIVELY);
402+
397403
/*
398404
Reset current_query_block before call execute_trigger() and
399405
restore it after return from one. This way error is set
@@ -407,6 +413,8 @@ bool Trigger::execute(THD *thd) {
407413

408414
thd->restore_sub_statement_state(&statement_state);
409415

416+
thd->set_secondary_engine_optimization(saved_state);
417+
410418
return err_status;
411419
}
412420

0 commit comments

Comments
 (0)