From a117786027a352040975097de042bf06ae3a8193 Mon Sep 17 00:00:00 2001 From: Gagan Goel Date: Fri, 11 Sep 2020 16:35:51 -0400 Subject: [PATCH] MCOL-4282 Enable Select Handler for Prepared Statements This patch enables select handler for executing prepared statements. Most importantly, we are now activating a persistent arena which will allocate any new items in a permanent MEMROOT for prepared statements and stored procedures. Refer to JOIN::optimize_inner() for details. In processWhere(), we now use SELECT_LEX::prep_where in case we are executing a prepared statement, as this is where the saved WHERE clause is stored for prepared statement processing. In addition, we also disable derived handler for prepared statements. --- dbcon/mysql/ha_mcs_execplan.cpp | 7 ++- dbcon/mysql/ha_mcs_opt_rewrites.cpp | 73 ++++++++++++++++++++++++++--- dbcon/mysql/ha_mcs_opt_rewrites.h | 7 ++- dbcon/mysql/ha_mcs_pushdown.cpp | 41 ++++++++++++++-- 4 files changed, 114 insertions(+), 14 deletions(-) diff --git a/dbcon/mysql/ha_mcs_execplan.cpp b/dbcon/mysql/ha_mcs_execplan.cpp index 9e4fb0223..93b763ddf 100755 --- a/dbcon/mysql/ha_mcs_execplan.cpp +++ b/dbcon/mysql/ha_mcs_execplan.cpp @@ -6369,8 +6369,13 @@ int processWhere(SELECT_LEX &select_lex, Item_cond* icp = 0; bool isUpdateDelete = false; - if (join != 0) + // Flag to indicate if this is a prepared statement + bool isPS = gwi.thd->stmt_arena && gwi.thd->stmt_arena->is_stmt_execute(); + + if (join != 0 && !isPS) icp = reinterpret_cast(join->conds); + else if (isPS && select_lex.prep_where) + icp = (Item_cond*)(select_lex.prep_where); // if icp is null, try to find the where clause other where if (!join && gwi.thd->lex->derived_tables) diff --git a/dbcon/mysql/ha_mcs_opt_rewrites.cpp b/dbcon/mysql/ha_mcs_opt_rewrites.cpp index a29366fed..f3260995e 100644 --- a/dbcon/mysql/ha_mcs_opt_rewrites.cpp +++ b/dbcon/mysql/ha_mcs_opt_rewrites.cpp @@ -299,26 +299,61 @@ void in_subselect_rewrite_walk(const Item* item_arg, void* arg) } } -/*@brief in_subselect_rewrite - Rewrites Item_in_subselect*/ +/* @brief opt_flag_unset_PS() - Unsets first_cond_optimization */ /************************************************************ * DESCRIPTION: -* It traverses TABLE_LISTs running in_subselect_rewrite_walk +* This function traverses derived tables to unset +* SELECT_LEX::first_cond_optimization: a marker to control +* optimizations executing PS. If set it allows to apply +* optimizations. If unset, it disables optimizations. * PARAMETERS: -* select_lex +* select_lex - SELECT_LEX* that describes the query. +***********************************************************/ +void opt_flag_unset_PS(SELECT_LEX *select_lex) +{ + TABLE_LIST *tbl; + List_iterator_fast li(select_lex->leaf_tables); + + while ((tbl= li++)) + { + if (tbl->is_view_or_derived()) + { + SELECT_LEX_UNIT *unit= tbl->get_unit(); + + for (SELECT_LEX *sl= unit->first_select(); sl; sl= sl->next_select()) + opt_flag_unset_PS(sl); + } + } + + if (select_lex->first_cond_optimization) + { + select_lex->first_cond_optimization= false; + } +} + +/* @brief in_subselect_rewrite - Rewrites Item_in_subselect */ +/************************************************************ +* DESCRIPTION: +* This function traverses TABLE_LISTs running in_subselect_rewrite_walk +* PARAMETERS: +* select_lex - SELECT_LEX* that describes the query. * RETURN: -* bool to to indicate predicate injection failures. +* bool to indicate predicate injection failures. ***********************************************************/ bool in_subselect_rewrite(SELECT_LEX *select_lex) { bool result = false; TABLE_LIST *tbl; List_iterator_fast li(select_lex->leaf_tables); - while (!result && (tbl= li++)) + + while (!result && (tbl = li++)) { if (tbl->is_view_or_derived()) { - SELECT_LEX *dsl = tbl->derived->first_select(); - result = in_subselect_rewrite(dsl); + SELECT_LEX_UNIT *unit= tbl->get_unit(); + + for (SELECT_LEX *sl= unit->first_select(); sl; sl= sl->next_select()) + result = in_subselect_rewrite(sl); } } @@ -330,3 +365,27 @@ bool in_subselect_rewrite(SELECT_LEX *select_lex) return result; } + +uint build_bitmap_for_nested_joins_mcs(List *join_list, + uint first_unused) +{ + List_iterator li(*join_list); + TABLE_LIST *table; + DBUG_ENTER("build_bitmap_for_nested_joins_mcs"); + while ((table= li++)) + { + NESTED_JOIN *nested_join; + if ((nested_join= table->nested_join)) + { + if (nested_join->n_tables != 1) + { + /* Don't assign bits to sj-nests */ + if (table->on_expr) + nested_join->nj_map= (nested_join_map) 1 << first_unused++; + first_unused= build_bitmap_for_nested_joins_mcs(&nested_join->join_list, + first_unused); + } + } + } + DBUG_RETURN(first_unused); +} diff --git a/dbcon/mysql/ha_mcs_opt_rewrites.h b/dbcon/mysql/ha_mcs_opt_rewrites.h index 3cf985b23..2ddba9781 100644 --- a/dbcon/mysql/ha_mcs_opt_rewrites.h +++ b/dbcon/mysql/ha_mcs_opt_rewrites.h @@ -20,8 +20,11 @@ #include "idb_mysql.h" -COND *simplify_joins_mcs(JOIN *join, List *join_list, COND *conds, bool top, bool in_sj); bool in_subselect_rewrite(SELECT_LEX *select_lex); +void opt_flag_unset_PS(SELECT_LEX *select_lex); +COND *simplify_joins_mcs(JOIN *join, List *join_list, + COND *conds, bool top, bool in_sj); +uint build_bitmap_for_nested_joins_mcs(List *join_list, + uint first_unused); #endif - diff --git a/dbcon/mysql/ha_mcs_pushdown.cpp b/dbcon/mysql/ha_mcs_pushdown.cpp index 80884e6bd..8278fcf38 100644 --- a/dbcon/mysql/ha_mcs_pushdown.cpp +++ b/dbcon/mysql/ha_mcs_pushdown.cpp @@ -476,6 +476,10 @@ create_columnstore_derived_handler(THD* thd, TABLE_LIST *derived) return handler; } + // Disable derived handler for prepared statements + if (thd->stmt_arena && thd->stmt_arena->is_stmt_execute()) + return handler; + SELECT_LEX_UNIT *unit= derived->derived; SELECT_LEX *sl= unit->first_select(); @@ -748,11 +752,15 @@ create_columnstore_select_handler(THD* thd, SELECT_LEX* select_lex) return handler; } + // Flag to indicate if this is a prepared statement + bool isPS = thd->stmt_arena && thd->stmt_arena->is_stmt_execute(); + // Disable processing of select_result_interceptor classes // which intercept and transform result set rows. E.g.: // select a,b into @a1, @a2 from t1; if (((thd->lex)->result && - !((select_dumpvar *)(thd->lex)->result)->var_list.is_empty())) + !((select_dumpvar *)(thd->lex)->result)->var_list.is_empty()) && + (!isPS)) { return handler; } @@ -800,8 +808,34 @@ create_columnstore_select_handler(THD* thd, SELECT_LEX* select_lex) COND *conds = nullptr; if (!unsupported_feature) { - conds= simplify_joins_mcs(join, select_lex->join_list, - join->conds, TRUE, FALSE); + SELECT_LEX *sel= select_lex; + // Rewrite once for PS + // Refer to JOIN::optimize_inner() in sql/sql_select.cc + // for details on the optimizations performed in this block. + if (sel->first_cond_optimization) + { + create_explain_query_if_not_exists(thd->lex, thd->mem_root); + Query_arena *arena, backup; + arena= thd->activate_stmt_arena_if_needed(&backup); + sel->first_cond_optimization= false; + + conds= simplify_joins_mcs(join, select_lex->join_list, + join->conds, TRUE, FALSE); + + build_bitmap_for_nested_joins_mcs(select_lex->join_list, 0); + sel->where= conds; + + if (isPS) + sel->prep_where= conds; + + select_lex->update_used_tables(); + + if (arena) + thd->restore_active_arena(arena, &backup); + + // Unset SL::first_cond_optimization + opt_flag_unset_PS(sel); + } } if (!unsupported_feature && conds) @@ -825,7 +859,6 @@ create_columnstore_select_handler(THD* thd, SELECT_LEX* select_lex) // We shouldn't raise error now so set an error to raise it later in init_SH. handler->rewrite_error= unsupported_feature; - // Return SH even if init fails b/c CS changed SELECT_LEX structures // with simplify_joins_mcs() return handler;