/* Copyright (C) 2019-20 MariaDB Corporation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include "ha_mcs_opt_rewrites.h" /*@brief in_subselect_rewrite_walk - Rewrites Item_in_subselect*/ /************************************************************ * DESCRIPTION: * It traverses filter predicates searching for * Item_in_subselect and rewrites it adding equi-join predicate * to finalise IN_2_EXISTS rewrite. * PARAMETERS: * item_arg - Item to check. * arg - bool to early return if predicate injection fails. * RETURN: ***********************************************************/ void in_subselect_rewrite_walk(const Item* item_arg, void* arg) { bool* result = reinterpret_cast(arg); if (*result) return; Item* item = const_cast(item_arg); JOIN* join = nullptr; if (typeid(*item) == typeid(Item_in_subselect)) { Item_in_subselect* sub = reinterpret_cast(item); // MCS 1.4.3 doesn't support IN + subquery with UNION so // we safe to take this JOIN. join = sub->unit->first_select()->join; // Inject equi-JOIN predicates if needed. *result = sub->create_in_to_exists_cond(join); *result = (*result) ? *result : sub->inject_in_to_exists_cond(join); sub->unit->first_select()->prep_where = join->conds ? join->conds->copy_andor_structure(current_thd) : 0; } else if (typeid(*item) == typeid(Item_singlerow_subselect)) { Item_singlerow_subselect* sub = reinterpret_cast(item); // MCS 1.4.3 doesn't support IN + subquery with UNION so // we safe to take this JOIN. join = sub->unit->first_select()->join; } else { // Exit for any but dedicated Items. return; } // Walk recursively to process nested IN ops. if (join->conds) { join->conds->traverse_cond(in_subselect_rewrite_walk, arg, Item::POSTFIX); } } // Sets SELECT_LEX::first_cond_optimization void first_cond_optimization_flag_set(SELECT_LEX* select_lex) { select_lex->first_cond_optimization = true; } // Unsets SELECT_LEX::first_cond_optimization void first_cond_optimization_flag_unset(SELECT_LEX* select_lex) { select_lex->first_cond_optimization = false; } /* @brief first_cond_optimization_flag_toggle() - Sets/Unsets first_cond_optimization */ /************************************************************ * DESCRIPTION: * This function traverses SELECT_LEX::table_list recursively * to set/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* that describes the query. * func - Pointer to a function which either sets/unsets * SELECT_LEX::first_cond_optimization ***********************************************************/ void first_cond_optimization_flag_toggle(SELECT_LEX* select_lex, void (*func)(SELECT_LEX*)) { for (TABLE_LIST* tl = select_lex->get_table_list(); tl; tl = tl->next_local) { if (tl->is_view_or_derived()) { SELECT_LEX_UNIT* unit = tl->get_unit(); if (unit) { for (SELECT_LEX* sl = unit->first_select(); sl; sl = sl->next_select()) { first_cond_optimization_flag_toggle(sl, func); } } } } (*func)(select_lex); } /* @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 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++)) { 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()) result = in_subselect_rewrite(sl); } } if (select_lex->join && select_lex->join->conds) { select_lex->join->conds->traverse_cond(in_subselect_rewrite_walk, &result, Item::POSTFIX); } return result; }