Skip to content

Commit

Permalink
Bug #30473261: CONVERT THE INDEX SUBQUERY ENGINES INTO USING THE ITER…
Browse files Browse the repository at this point in the history
…ATOR EXECUTOR [patch 8/10, deps]

Reduce the number of dependencies on item_subselect.h.
Removes approximately 170/200 dependencies when changing the file.

Change-Id: Id961aaf6a2f58df6304e657ba117304a4ce8543a
  • Loading branch information
Steinar H. Gunderson committed Dec 20, 2019
1 parent 75bbe1b commit 31bd903
Show file tree
Hide file tree
Showing 13 changed files with 153 additions and 124 deletions.
40 changes: 40 additions & 0 deletions sql/comp_creator.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#ifndef COMP_CREATOR_INCLUDED
#define COMP_CREATOR_INCLUDED

/* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License, version 2.0,
as published by the Free Software Foundation.
This program is also distributed with certain software (including
but not limited to OpenSSL) that is licensed under separate terms,
as designated in a particular file or component or in included license
documentation. The authors of MySQL hereby grant you an additional
permission to link the program and your derivative works with the
separately licensed software that they have included with MySQL.
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, version 2.0, 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 St, Fifth Floor, Boston, MA 02110-1301 USA */

// Declaration of chooser_compare_func_creator, in a separate file
// to make sure that parser_yystype.h does not need to depend on
// item_subselect.h.

class Comp_creator;

/**
Convenience typedef for a function that returns factories for Item comparators
(ie., returns Comp_creator).
@retval nullptr In case of semantic errors.
*/
using chooser_compare_func_creator = Comp_creator *(*)(bool invert);

#endif // COMP_CREATOR_INCLUDED
44 changes: 23 additions & 21 deletions sql/item_subselect.cc
Original file line number Diff line number Diff line change
Expand Up @@ -376,7 +376,8 @@ bool Item_in_subselect::mark_as_outer(Item *left_row, size_t col) {

bool Item_in_subselect::finalize_exists_transform(THD *thd,
SELECT_LEX *select_lex) {
DBUG_ASSERT(exec_method == EXEC_EXISTS_OR_MAT || exec_method == EXEC_EXISTS);
DBUG_ASSERT(exec_method == SubqueryExecMethod::EXEC_EXISTS_OR_MAT ||
exec_method == SubqueryExecMethod::EXEC_EXISTS);
/*
Change
SELECT expr1, expr2
Expand Down Expand Up @@ -419,7 +420,7 @@ bool Item_in_subselect::finalize_exists_transform(THD *thd,
return true; /* purecov: inspected */

select_lex->join->allow_outer_refs = true; // for JOIN::set_prefix_tables()
exec_method = EXEC_EXISTS;
exec_method = SubqueryExecMethod::EXEC_EXISTS;
return false;
}

Expand Down Expand Up @@ -463,15 +464,15 @@ Item *Item_in_subselect::remove_in2exists_conds(Item *conds) {

bool Item_in_subselect::finalize_materialization_transform(THD *thd,
JOIN *join) {
DBUG_ASSERT(exec_method == EXEC_EXISTS_OR_MAT);
DBUG_ASSERT(exec_method == SubqueryExecMethod::EXEC_EXISTS_OR_MAT);

DBUG_ASSERT(join == subquery->single_select_lex()->join);
// No UNION in materialized subquery so this holds:
DBUG_ASSERT(join->select_lex == unit->first_select());
DBUG_ASSERT(join->unit == unit);
DBUG_ASSERT(unit->global_parameters()->select_limit == nullptr);

exec_method = EXEC_MATERIALIZATION;
exec_method = SubqueryExecMethod::EXEC_MATERIALIZATION;

/*
We need to undo several changes which IN->EXISTS had done. But we first
Expand Down Expand Up @@ -527,19 +528,19 @@ void Item_in_subselect::cleanup() {
need_expr_cache = true;

switch (exec_method) {
case EXEC_MATERIALIZATION:
case SubqueryExecMethod::EXEC_MATERIALIZATION:
if (in2exists_info->dependent_after) {
unit->first_select()->uncacheable |= UNCACHEABLE_DEPENDENT;
unit->uncacheable |= UNCACHEABLE_DEPENDENT;
}
// fall through
case EXEC_EXISTS:
case SubqueryExecMethod::EXEC_EXISTS:
/*
Back to EXISTS_OR_MAT, so that next execution of this statement can
choose between the two.
*/
unit->global_parameters()->select_limit = nullptr;
exec_method = EXEC_EXISTS_OR_MAT;
exec_method = SubqueryExecMethod::EXEC_EXISTS_OR_MAT;
break;
default:
break;
Expand All @@ -552,7 +553,7 @@ RowIterator *Item_in_subselect::root_iterator() const {
// Only subselect_hash_sj_engine owns its own iterator;
// for subselect_indexsubquery_engine, the unit still has it, since it's a
// normally executed query block. Thus, we should never get called otherwise.
DBUG_ASSERT(exec_method == EXEC_MATERIALIZATION &&
DBUG_ASSERT(exec_method == SubqueryExecMethod::EXEC_MATERIALIZATION &&
indexsubquery_engine->engine_type() ==
subselect_indexsubquery_engine::HASH_SJ_ENGINE);
return down_cast<subselect_hash_sj_engine *>(indexsubquery_engine)
Expand Down Expand Up @@ -723,8 +724,8 @@ bool Item_in_subselect::walk(Item_processor processor, enum_walk walk,

bool Item_in_subselect::exec(THD *thd) {
DBUG_TRACE;
DBUG_ASSERT(exec_method != EXEC_MATERIALIZATION ||
(exec_method == EXEC_MATERIALIZATION &&
DBUG_ASSERT(exec_method != SubqueryExecMethod::EXEC_MATERIALIZATION ||
(exec_method == SubqueryExecMethod::EXEC_MATERIALIZATION &&
indexsubquery_engine->engine_type() ==
subselect_indexsubquery_engine::HASH_SJ_ENGINE));
/*
Expand All @@ -741,7 +742,8 @@ bool Item_in_subselect::exec(THD *thd) {
lookup, the cache hit rate, and the savings per cache hit.
*/
if (need_expr_cache && !left_expr_cache &&
exec_method == EXEC_MATERIALIZATION && init_left_expr_cache(thd))
exec_method == SubqueryExecMethod::EXEC_MATERIALIZATION &&
init_left_expr_cache(thd))
return true;

if (left_expr_cache != nullptr) {
Expand Down Expand Up @@ -1286,11 +1288,7 @@ bool Query_result_exists_subquery::send_data(THD *, List<Item> &) {
}

Item_exists_subselect::Item_exists_subselect(SELECT_LEX *select)
: Item_subselect(),
value(false),
exec_method(EXEC_UNSPECIFIED),
sj_convert_priority(0),
embedding_join_nest(nullptr) {
: Item_subselect() {
DBUG_TRACE;
init(select, new (*THR_MALLOC) Query_result_exists_subquery(this));
max_columns = UINT_MAX;
Expand Down Expand Up @@ -1466,7 +1464,7 @@ bool Item_exists_subselect::resolve_type(THD *thd) {
set_data_type_longlong();
max_length = 1;
max_columns = unit_cols();
if (exec_method == EXEC_EXISTS) {
if (exec_method == SubqueryExecMethod::EXEC_EXISTS) {
Prepared_stmt_arena_holder ps_arena_holder(thd);
/*
We need only 1 row to determine existence.
Expand Down Expand Up @@ -2459,7 +2457,8 @@ Item_subselect::trans_res Item_in_subselect::select_in_like_transformer(
If we didn't choose an execution method up to this point, we choose
the IN=>EXISTS transformation, at least temporarily.
*/
if (exec_method == EXEC_UNSPECIFIED) exec_method = EXEC_EXISTS_OR_MAT;
if (exec_method == SubqueryExecMethod::EXEC_UNSPECIFIED)
exec_method = SubqueryExecMethod::EXEC_EXISTS_OR_MAT;

/*
Both transformers call fix_fields() only for Items created inside them,
Expand Down Expand Up @@ -2494,7 +2493,8 @@ void Item_in_subselect::print(const THD *thd, String *str,
const char *tail = Item_bool_func::bool_transform_names[value_transform];
if (implicit_is_op) tail = "";
bool paren = false;
if (exec_method == EXEC_EXISTS_OR_MAT || exec_method == EXEC_EXISTS) {
if (exec_method == SubqueryExecMethod::EXEC_EXISTS_OR_MAT ||
exec_method == SubqueryExecMethod::EXEC_EXISTS) {
if (value_transform == BOOL_NEGATED) { // NOT has low associativity, but
// we're inside Item_in_optimizer,
// so () are needed only if IS TRUE/FALSE is coming.
Expand Down Expand Up @@ -2524,7 +2524,8 @@ bool Item_in_subselect::fix_fields(THD *thd_arg, Item **ref) {
abort_on_null =
value_transform == BOOL_IS_TRUE || value_transform == BOOL_NOT_TRUE;

if (exec_method == EXEC_SEMI_JOIN) return !((*ref) = new Item_func_true());
if (exec_method == SubqueryExecMethod::EXEC_SEMI_JOIN)
return !((*ref) = new Item_func_true());

if ((thd_arg->lex->context_analysis_only & CONTEXT_ANALYSIS_ONLY_VIEW) &&
left_expr && !left_expr->fixed) {
Expand Down Expand Up @@ -2686,7 +2687,8 @@ bool Item_subselect::is_evaluated() const { return unit->is_executed(); }

void Item_allany_subselect::print(const THD *thd, String *str,
enum_query_type query_type) const {
if (exec_method == EXEC_EXISTS_OR_MAT || exec_method == EXEC_EXISTS)
if (exec_method == SubqueryExecMethod::EXEC_EXISTS_OR_MAT ||
exec_method == SubqueryExecMethod::EXEC_EXISTS)
str->append(STRING_WITH_LEN("<exists>"));
else {
left_expr->print(thd, str, query_type);
Expand Down
64 changes: 24 additions & 40 deletions sql/item_subselect.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,14 @@
#include "my_time.h"
#include "mysql/udf_registration_types.h"
#include "mysql_time.h"
#include "sql/comp_creator.h"
#include "sql/enum_query_type.h"
#include "sql/item.h" // Item_result_field
#include "sql/parse_tree_node_base.h"
#include "sql/row_iterator.h"
#include "sql/sql_const.h"
#include "template_utils.h"

class Comp_creator;
class Field;
class Item_func_not_all;
class Item_in_optimizer;
Expand All @@ -64,14 +64,6 @@ struct TABLE_LIST;
template <class T>
class List;

/**
Convenience typedef used in this file, and further used by any files
including this file.
@retval NULL In case of semantic errors.
*/
typedef Comp_creator *(*chooser_compare_func_creator)(bool invert);

/* base class for subselects */

class Item_subselect : public Item_result_field {
Expand Down Expand Up @@ -343,6 +335,22 @@ class Item_maxmin_subselect final : public Item_singlerow_subselect {

/* exists subselect */

enum class SubqueryExecMethod : int {
EXEC_UNSPECIFIED, ///< No execution method specified yet.
EXEC_SEMI_JOIN, ///< Predicate is converted to semi-join nest.
/// IN was converted to correlated EXISTS, and this is a final decision.
EXEC_EXISTS,
/**
Decision between EXISTS and MATERIALIZATION is not yet taken.
IN was temporarily converted to correlated EXISTS.
All descendants of Item_in_subselect must go through this method
before they can reach EXISTS.
*/
EXEC_EXISTS_OR_MAT,
/// Predicate executed via materialization, and this is a final decision.
EXEC_MATERIALIZATION
};

class Item_exists_subselect : public Item_subselect {
typedef Item_subselect super;

Expand All @@ -355,24 +363,9 @@ class Item_exists_subselect : public Item_subselect {
The method chosen to execute the predicate, currently used for IN, =ANY
and EXISTS predicates.
*/
enum enum_exec_method {
EXEC_UNSPECIFIED, ///< No execution method specified yet.
EXEC_SEMI_JOIN, ///< Predicate is converted to semi-join nest.
/// IN was converted to correlated EXISTS, and this is a final decision.
EXEC_EXISTS,
/**
Decision between EXEC_EXISTS and EXEC_MATERIALIZATION is not yet taken.
IN was temporarily converted to correlated EXISTS.
All descendants of Item_in_subselect must go through this method
before they can reach EXEC_EXISTS.
*/
EXEC_EXISTS_OR_MAT,
/// Predicate executed via materialization, and this is a final decision.
EXEC_MATERIALIZATION
};
enum_exec_method exec_method;
SubqueryExecMethod exec_method{SubqueryExecMethod::EXEC_UNSPECIFIED};
/// Priority of this predicate in the convert-to-semi-join-nest process.
int sj_convert_priority;
int sj_convert_priority{0};
/// Decision on whether predicate is selected for semi-join transformation
enum enum_sj_selection {
/// Not selected for semi-join, evaluate as subquery predicate, or
Expand All @@ -394,26 +387,16 @@ class Item_exists_subselect : public Item_subselect {
predicate is not a candidate for transformation.
See also THD::emb_on_expr_nest.
*/
TABLE_LIST *embedding_join_nest;
TABLE_LIST *embedding_join_nest{nullptr};

Item_exists_subselect(SELECT_LEX *select);

Item_exists_subselect()
: Item_subselect(),
value(false),
exec_method(EXEC_UNSPECIFIED),
sj_convert_priority(0),
embedding_join_nest(nullptr) {}
Item_exists_subselect() : Item_subselect() {}

explicit Item_exists_subselect(const POS &pos)
: super(pos),
value(false),
exec_method(EXEC_UNSPECIFIED),
sj_convert_priority(0),
embedding_join_nest(nullptr) {}
explicit Item_exists_subselect(const POS &pos) : super(pos) {}

trans_res select_transformer(THD *, SELECT_LEX *) override {
exec_method = EXEC_EXISTS;
exec_method = SubqueryExecMethod::EXEC_EXISTS;
return RES_OK;
}
subs_type substype() const override { return EXISTS_SUBS; }
Expand Down Expand Up @@ -852,4 +835,5 @@ class subselect_hash_sj_engine final : public subselect_indexsubquery_engine {
RowIterator *root_iterator() const { return m_iterator.get(); }
void create_iterators(THD *thd) override;
};

#endif /* ITEM_SUBSELECT_INCLUDED */
9 changes: 4 additions & 5 deletions sql/opt_hints.cc
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#include "sql/derror.h" // ER_THD
#include "sql/error_handler.h"
#include "sql/item.h"
#include "sql/item_subselect.h"
#include "sql/key.h"
#include "sql/mysqld.h" // table_alias_charset
#include "sql/nested_join.h"
Expand Down Expand Up @@ -260,13 +261,11 @@ uint Opt_hints_qb::sj_enabled_strategies(uint opt_switches) const {
return opt_switches;
}

Item_exists_subselect::enum_exec_method Opt_hints_qb::subquery_strategy()
const {
SubqueryExecMethod Opt_hints_qb::subquery_strategy() const {
if (subquery_hint)
return static_cast<Item_exists_subselect::enum_exec_method>(
subquery_hint->get_args());
return static_cast<SubqueryExecMethod>(subquery_hint->get_args());

return Item_exists_subselect::EXEC_UNSPECIFIED;
return SubqueryExecMethod::EXEC_UNSPECIFIED;
}

void Opt_hints_qb::print_irregular_hints(const THD *thd, String *str) {
Expand Down
4 changes: 2 additions & 2 deletions sql/opt_hints.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,12 @@
#include "my_dbug.h"
#include "my_inttypes.h"
#include "sql/enum_query_type.h"
#include "sql/item_subselect.h" // Item_exists_subselect
#include "sql/mem_root_array.h" // Mem_root_array
#include "sql/sql_bitmap.h" // Bitmap
#include "sql/sql_show.h" // append_identifier
#include "sql_string.h" // String

enum class SubqueryExecMethod : int;
class Item;
class JOIN;
class Opt_hints_table;
Expand Down Expand Up @@ -462,7 +462,7 @@ class Opt_hints_qb : public Opt_hints {
@retval EXEC_EXISTS In-to-exists execution should be used
@retval EXEC_UNSPECIFIED No SUBQUERY hint for this query block
*/
Item_exists_subselect::enum_exec_method subquery_strategy() const;
SubqueryExecMethod subquery_strategy() const;

void print_irregular_hints(const THD *thd, String *str) override;

Expand Down
6 changes: 3 additions & 3 deletions sql/parse_tree_hints.cc
Original file line number Diff line number Diff line change
Expand Up @@ -284,11 +284,11 @@ void PT_qb_level_hint::append_args(const THD *thd, String *str) const {
break;
}
case SUBQUERY_HINT_ENUM:
switch (args) {
case Item_exists_subselect::EXEC_MATERIALIZATION:
switch (static_cast<SubqueryExecMethod>(args)) {
case SubqueryExecMethod::EXEC_MATERIALIZATION:
str->append(STRING_WITH_LEN(" MATERIALIZATION"));
break;
case Item_exists_subselect::EXEC_EXISTS:
case SubqueryExecMethod::EXEC_EXISTS:
str->append(STRING_WITH_LEN(" INTOEXISTS"));
break;
default: // Exactly one of above strategies should always be specified
Expand Down
1 change: 1 addition & 0 deletions sql/parser_yystype.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

#include "my_base.h"
#include "my_time.h" // interval_type
#include "sql/comp_creator.h"
#include "sql/handler.h"
#include "sql/item_create.h" // Cast_target
#include "sql/key_spec.h" // keytype, fk_option
Expand Down
Loading

0 comments on commit 31bd903

Please sign in to comment.