diff --git a/sql/item.h b/sql/item.h index f3c16d3aa54..3c06ab88055 100644 --- a/sql/item.h +++ b/sql/item.h @@ -2753,6 +2753,13 @@ class Item : public Parse_tree_node { virtual Item *equality_substitution_transformer(uchar *) { return this; } + virtual Item *in_predicate_to_in_subs_transformer(uchar *){ return this; } + + virtual void mark_as_condition_AND_part(TABLE_LIST *) {} + + // void set_name(THD * thd, const char * str, size_t length, + // const CHARSET_INFO * cs); + /** Check if a partition function is allowed. @@ -4063,6 +4070,8 @@ class Item_ident_for_show final : public Item { class COND_EQUAL; class Item_equal; +const LEX_CSTRING empty_clex_str= {"", 0}; +const LEX_CSTRING star_clex_str= {"*", 1}; class Item_field : public Item_ident { typedef Item_ident super; @@ -4386,8 +4395,14 @@ class Item_asterisk : public Item_field { */ Item_asterisk(const POS &pos, const char *opt_schema_name, const char *opt_table_name) - : super(pos, opt_schema_name, opt_table_name, "*") {} + : super(pos, opt_schema_name, opt_table_name, "*") { + } + Item_asterisk(Name_resolution_context *context, const char *opt_schema_name, + const char *opt_table_name) + : super(context, opt_schema_name, opt_table_name, "*") { + } + bool itemize(Parse_context *pc, Item **res) override; bool fix_fields(THD *, Item **) override { assert(false); // should never happen: see setup_wild() diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 01dce166559..ff2e73de0a5 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -89,6 +89,7 @@ #include "sql/sql_time.h" // str_to_datetime #include "sql/system_variables.h" #include "sql/thd_raii.h" +#include "protocol.h" using std::max; using std::min; @@ -5411,8 +5412,341 @@ void Item_func_in::cleanup() { DBUG_VOID_RETURN; } +bool fix_fields_for_tvc(THD *thd, List_iterator_fast> &li) +{ + DBUG_ENTER("fix_fields_for_tvc"); + List *lst; + li.rewind(); + + while ((lst= li++)) + { + List_iterator it(*lst); + Item *item; + + while ((item= it++)) + { + if(item->fixed){ + continue; + } + if((item->fix_fields(thd,it.ref()) || item->check_cols(1))){ + DBUG_RETURN(true); + } + } + } + DBUG_RETURN(false); +} + +bool table_value_constr::prepare(THD *thd_arg, Query_block *qb, + Query_result*tmp_result, + Query_expression*unit_arg){ + DBUG_ENTER("table_value_constr::prepare"); + //qb->in_tvc= true; + if(!thd_arg->variables.in_subquery_conversion_threshold_enabled) + DBUG_RETURN(true); + List_iterator_fast> li(lists_of_values); + + List *first_elem = li++; + uint cnt= first_elem->elements; + Item_type_holder *holders= type_holders; + + if (cnt == 0) + { + DBUG_RETURN(true); + } + + if (fix_fields_for_tvc(thd_arg, li)) + DBUG_RETURN(true); + + if(!holders){ + List_iterator_fast it(*first_elem); + Item *item; + qb->fields.clear(); + for (uint pos= 0; (item= it++); pos++) + { + //item->item_name = NAME_STRING("_col_1"); + qb->fields.push_back(item); + } + } + + result= tmp_result; + if (result && result->prepare(thd_arg,qb->fields, unit_arg)) + DBUG_RETURN(true); + + DBUG_RETURN(false); +} + +bool table_value_constr::optimize(THD *thd_arg){ + DBUG_ENTER("table_value_constr::optimize"); + if (query_block->has_sj_candidates() && query_block->flatten_subqueries(thd_arg)) + return true; + query_block->set_sj_candidates(nullptr); + DBUG_RETURN(false); +} + + +bool table_value_constr::exec(Query_block *qb){ + DBUG_ENTER("table_value_constr::exec"); + List_iterator_fast> li(lists_of_values); + List *elem; + THD *cur_thd= qb->parent_lex->thd; + ha_rows send_records= 0; + int rc=0; + + if (result->send_result_set_metadata(current_thd,qb->fields, + Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)) + { + DBUG_RETURN(true); + } + + //fix_rownum_pointers(sl->parent_lex->thd, sl, &send_records); + mem_root_deque new_deque(current_thd->mem_root); + while ((elem = li++)) + { + cur_thd->get_stmt_da()->inc_current_row_for_condition(); + if (send_records >= qb->master_query_expression()->select_limit_cnt) + break; + new_deque.clear(); + List_iterator it(*elem); + Item *item; + while ((item = it++)) { + new_deque.push_back(item); + } + rc = result->send_data(cur_thd, new_deque); + if (!rc) + send_records++; + else if (rc > 0) + DBUG_RETURN(true); + } + + if (result->send_eof(cur_thd)) + DBUG_RETURN(true); + + DBUG_RETURN(false); + +} + +static bool cmp_row_types(Item* item1, Item* item2) +{ + return false; + uint n= item1->cols(); + if (item2->check_cols(n)) + return true; + + for (uint i=0; i < n; i++) + { + Item *inner= item1->element_index(i); + Item *outer= item2->element_index(i); + if(inner->type() != outer->type() && + inner->result_type() != outer->result_type()) + return true; + /*TODO: check inner item subquery_type whether allows materialization*/ + } + return false; +} + +static bool create_tvc_name(THD *thd, Query_block *parent_select, + const char **alias) +{ + char buff[6]; + int len = snprintf(buff, sizeof(buff), "tvc_%u", parent_select ? parent_select->curr_tvc_name : 0); + *alias = thd->strmake(buff, len); + return alias == nullptr; +} + +Item * Item_func_in::in_predicate_to_in_subs_transformer(uchar *arg){ + if (!transform_into_subq) + return this; + + List> value_list; + LEX *lex = current_thd->lex; + Query_block *parent_query_block = lex->current_query_block(); + uint8 save_derived_tables = parent_query_block->derived_table_count; + Mem_root_array sj_candidates_local(current_thd->mem_root); + Query_block *sq_select = nullptr; + Item *item; + + for (uint i=1; i < arg_count; i++) + { + if (!args[i]->const_item()) + { + return this; + } + + if (cmp_row_types(args[i], args[0])) + { + return this; + } + } + + sq_select = lex->new_query(lex->current_query_block()); + lex->set_current_query_block(sq_select); + sq_select->linkage = DERIVED_TABLE_TYPE; + sq_select->parsing_place= CTX_SELECT_LIST; + sq_select->tvc = 0; + + /* Create item list as '*' for the subquery SQ */ + item = new (current_thd->mem_root) Item_asterisk (&sq_select->context,nullptr,nullptr); + if (item == NULL || sq_select->add_item_to_list(item)) + return this; + sq_select->with_wild++; + + Query_block *tvc_select; // select for tvc + Query_expression *derived_unit; // unit for tvc_select + tvc_select = lex->new_query(lex->current_query_block()); + lex->set_current_query_block(tvc_select); + tvc_select->linkage = DERIVED_TABLE_TYPE; + derived_unit = tvc_select->master_query_expression(); + + + if (create_value_list_for_tvc(current_thd, value_list)) + return this; + if (!(tvc_select->tvc= + new (current_thd->mem_root) + table_value_constr(value_list, + tvc_select,sq_select, + tvc_select->active_options()))) + goto err; + + Table_ident *ti; + const char* alias; + TABLE_LIST *derived_tab; + if(!(ti= new (current_thd->mem_root) Table_ident(derived_unit))){ + goto err; + } + create_tvc_name(current_thd, parent_query_block, &alias); + + if (!(derived_tab= + sq_select->add_table_to_list(current_thd, + ti, alias, 0, TL_READ, MDL_SHARED_READ))) + goto err; + sq_select->add_joined_table(derived_tab); + sq_select ->select_n_where_fields += derived_unit->first_query_block()->select_n_where_fields; + sq_select->context.table_list= sq_select->table_list.first; + sq_select->context.first_name_resolution_table= sq_select->table_list.first; + sq_select->set_where_cond(nullptr); + //sq_select->parsing_place= parent_query_block->parsing_place; + sq_select->parsing_place= CTX_NONE; + Item_in_subselect *in_subs; + Item *sq; + if (!(in_subs= + new (current_thd->mem_root) Item_in_subselect(args[0], sq_select))) + goto err; + in_subs->value_transform = BOOL_IS_TRUE; + in_subs->strategy = Subquery_strategy::UNSPECIFIED; + sq = in_subs; + parent_query_block->set_sj_candidates(&sj_candidates_local); + parent_query_block->resolve_place = Query_block::RESOLVE_CONDITION; + current_thd->lex->set_current_query_block(parent_query_block); + if (sq->fix_fields(current_thd, (Item **)&sq)) + goto err; + parent_query_block->curr_tvc_name ++; + parent_query_block->set_where_cond(sq); + //if(!negated) + // in_subs->embedding_join_nest; + if (parent_query_block->has_sj_candidates() && parent_query_block->flatten_subqueries(current_thd)) + goto err; + derived_unit->derived_table->optimize_derived(current_thd); + sq = parent_query_block->where_cond(); + return sq; +err: + parent_query_block->derived_table_count= save_derived_tables; + current_thd->lex->set_current_query_block(parent_query_block); + return NULL; +} + +bool Item_func_in::create_value_list_for_tvc(THD *thd, + List> &values) +{ + bool is_list_of_rows= args[1]->type() == Item::ROW_ITEM; + + for (uint i=1; i < arg_count; i++) + { + char col_name[16] = {0}; + List *tvc_value; + if (!(tvc_value= new (thd->mem_root) List())) + return true; + + if (is_list_of_rows) + { + Item_row *row_list= (Item_row *)(args[i]); + + if (!row_list) + return true; + + for (uint j=0; j < row_list->cols(); j++) + { + if (i == 1){ + snprintf(col_name, sizeof(col_name), "_col_%d", j + 1); + row_list->element_index(j)->item_name = NAME_STRING(col_name); + } + if (tvc_value->push_back(row_list->element_index(j),thd->mem_root)) + return true; + } + } + else + { + if (i == 1){ + args[i]->item_name = NAME_STRING("_col_1"); + } + if (tvc_value->push_back(args[i])) + return true; + } + + if (values.push_back(tvc_value, thd->mem_root)) + return true; + } + return false; +} + +void Item_func_in::mark_as_condition_AND_part(TABLE_LIST *embedding){ + THD *thd= current_thd; + + if (!transform_into_subq_checked) + { + if ((transform_into_subq= to_be_transformed_into_in_subq(thd))) + thd->lex->current_query_block()->in_funcs.push_back(this, thd->mem_root); + transform_into_subq_checked= true; + } +} + +bool Item_func_in::to_be_transformed_into_in_subq(THD *thd){ + bool is_row_list= args[1]->type() == Item::ROW_ITEM; + uint values_count= arg_count-1; + + if (is_row_list) + values_count*= ((Item_row *)(args[1]))->cols(); + + if (thd->variables.in_subquery_conversion_threshold == 0 || + thd->variables.in_subquery_conversion_threshold > values_count) + return false; + + if (!(thd->lex->context_analysis_only & CONTEXT_ANALYSIS_ONLY_PREPARE)) + return true; + + /* Occurence of '?' in IN list is checked only for PREPARE commands */ + for (uint i=1; i < arg_count; i++) + { + if (!is_row_list) + { + if (args[i]->type() == Item::PARAM_ITEM) + return false; + } + else + { + Item_row *row_list= (Item_row *)(args[i]); + for (uint j=0; j < row_list->cols(); j++) + { + if (row_list->element_index(j)->type() == Item::PARAM_ITEM) + return false; + } + } + } + return true; +} + Item_func_in::~Item_func_in() { cleanup_arrays(); } + Item_cond::Item_cond(THD *thd, Item_cond *item) : Item_bool_func(thd, item), abort_on_null(item->abort_on_null) { /* diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 2f7ba2fda6f..706bc69bf4a 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -52,6 +52,7 @@ #include "sql/table.h" #include "sql_string.h" #include "template_utils.h" // down_cast +#include "query_result.h" class Arg_comparator; class Field; @@ -2015,8 +2016,45 @@ class Item_func_case final : public Item_func { enum Functype functype() const override { return CASE_FUNC; } }; -/** - in_expr [NOT] IN (in_value_list). +class table_value_constr +{ +public: + List> lists_of_values; + Query_result* result; + Query_block *query_block; + Query_block * parent_query_block; + Item_type_holder *type_holders; + + enum { QEP_NOT_PRESENT_YET, QEP_AVAILABLE} have_query_plan; + + //Explain_context *explain; + ulonglong select_options; + + table_value_constr(List> tvc_values, Query_block *qb, Query_block * parent_qb, + ulonglong select_options_arg) : + lists_of_values(tvc_values), result(0), query_block(qb), parent_query_block(parent_qb),type_holders(0), + have_query_plan(QEP_NOT_PRESENT_YET), + select_options(select_options_arg) + { } + + ha_rows get_records() { return lists_of_values.elements; } + + bool prepare(THD *thd_arg, Query_block *qb, + Query_result*tmp_result, + Query_expression*unit_arg); + + bool to_be_wrapped_as_with_tail(); + + // int save_explain_data_intern(THD *thd_arg, + // Explain_context *output); + bool optimize(THD *thd_arg); + bool exec(Query_block *qb); + + void print(THD *thd_arg, String *str, enum_query_type query_type); + bool walk_values(Item_processor processor, bool walk_subquery, void *arg); +}; + +/**g The current implementation distinguishes 2 cases: 1) all items in in_value_list are constants and have the same @@ -2039,7 +2077,13 @@ class Item_func_in final : public Item_func_opt_neg { bool have_null{false}; /// Set to true when bisection values are populated bool populated{false}; - + /** + Set to true when IN predicate is transformed into an IN subquery. + This transformation is done by the in_predicate_to_in_subs_transformer() + function. + */ + bool transform_into_subq{false}; + bool transform_into_subq_checked{false}; private: /// Set to true if the values arguments are const bool values_are_const{true}; @@ -2058,7 +2102,7 @@ class Item_func_in final : public Item_func_opt_neg { public: Item_func_in(const POS &pos, PT_item_list *list, bool is_negation) - : Item_func_opt_neg(pos, list, is_negation) { + : Item_func_opt_neg(pos, list, is_negation),transform_into_subq_checked(false) { memset(&cmp_items, 0, sizeof(cmp_items)); allowed_arg_cols = 0; // Fetch this value from first argument } @@ -2110,6 +2154,10 @@ class Item_func_in final : public Item_func_opt_neg { not_null_tables_cache |= args[0]->not_null_tables(); } + Item *in_predicate_to_in_subs_transformer(uchar *arg) override; + bool to_be_transformed_into_in_subq(THD *thd); + bool create_value_list_for_tvc(THD *thd,List> &values); + void mark_as_condition_AND_part(TABLE_LIST *embedding) override; private: /** Usable if @ is made only of constants. Returns true if one diff --git a/sql/opt_explain_json.cc b/sql/opt_explain_json.cc index f8fd3a6e968..7fa9c91ea17 100644 --- a/sql/opt_explain_json.cc +++ b/sql/opt_explain_json.cc @@ -2026,6 +2026,15 @@ bool Explain_format_JSON::begin_context(enum_parsing_context ctx_arg, current_context = ctx; break; } + case CTX_IN_WHERE:{ + assert(subquery != nullptr); + subquery_ctx *ctx = + new (*THR_MALLOC) subquery_ctx(CTX_WHERE, nullptr, current_context); + if (ctx == nullptr || current_context->add_where_subquery(ctx, subquery)) + return true; + current_context = ctx; + break; + } default: assert(!"Unknown EXPLAIN context!"); return true; diff --git a/sql/opt_sum.cc b/sql/opt_sum.cc index f018e2ac4b1..52f7039d4e6 100644 --- a/sql/opt_sum.cc +++ b/sql/opt_sum.cc @@ -89,6 +89,9 @@ static bool reckey_in_range(bool max_fl, TABLE_REF *ref, Item_field *item_field, Item *cond, uint range_fl, uint prefix_len); static bool maxmin_in_range(bool max_fl, Item_field *item_field, Item *cond); + + + /** Get exact count of rows in all tables. This is called, when at least one of the table handlers support HA_COUNT_ROWS_INSTANT, but not @@ -618,6 +621,13 @@ bool optimize_aggregated_query(THD *thd, Query_block *select, return false; } +bool group_by_placement(THD *thd, Query_block *select, + const mem_root_deque &fields, + Item *conds, aggregate_evaluated *decision){ + return true; +} + + /** Test if the predicate compares a field with constants. diff --git a/sql/parse_tree_node_base.h b/sql/parse_tree_node_base.h index 95bb2c00ed5..112e8923629 100644 --- a/sql/parse_tree_node_base.h +++ b/sql/parse_tree_node_base.h @@ -85,7 +85,9 @@ enum enum_parsing_context { CTX_UNION, CTX_UNION_RESULT, ///< Pseudo-table context for UNION result CTX_QUERY_SPEC, ///< Inner SELECTs of UNION expression - CTX_RETURNING_CLAUSE // RETURNING clause execution context + CTX_RETURNING_CLAUSE, // RETURNING clause execution context + CTX_IN_WHERE, ///< IN() subquery in WHERE clause item tree + CTX_IN_ON ///< IN() subquery in ON clause item tree }; /** diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc index 793092f010d..b3ce09593b8 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -1656,26 +1656,39 @@ bool TABLE_LIST::materialize_derived(THD *thd) { assert(table->s->primary_key == MAX_KEY); } - if (table->hash_field) { - table->file->ha_index_init(0, false); + bool tvc_exsit = false; + bool res = false; + auto query_cursor = unit->first_query_block(); + for (Query_block *qb = query_cursor; qb; qb= qb->next_query_block()){ + if(qb->tvc){ + res = qb->tvc->exec(qb); + tvc_exsit = true; + } } - // execute unit without cleaning up - if (unit->force_create_iterators(thd)) { - return true; - } - bool res = unit->execute(thd); + if(!tvc_exsit){ - if (table->hash_field) { - table->file->ha_index_or_rnd_end(); + if (table->hash_field) { + table->file->ha_index_init(0, false); + } + + // execute unit without cleaning up + if (unit->force_create_iterators(thd)) { + return true; + } + res = unit->execute(thd); + + if (table->hash_field) { + table->file->ha_index_or_rnd_end(); + } } if (!res) { - /* - Here we entirely fix both TABLE_LIST and list of SELECT's as - there were no derived tables - */ - if (derived_result->flush()) res = true; /* purecov: inspected */ + /* + Here we entirely fix both TABLE_LIST and list of SELECT's as + there were no derived tables + */ + if (derived_result->flush()) res = true; /* purecov: inspected */ } table->materialized = true; diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 4541d61c20a..f4ec87d8362 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -674,7 +674,6 @@ Query_block *LEX::new_query(Query_block *curr_query_block) { thd, curr_query_block, nullptr, nullptr, parsing_place); if (sel_query_expression == nullptr) return nullptr; Query_block *const select = sel_query_expression->first_query_block(); - if (select->set_context(nullptr)) return nullptr; /* purecov: inspected */ /* Assume that a subquery has an outer name resolution context @@ -2267,7 +2266,7 @@ Query_expression::Query_expression(enum_parsing_context parsing_context) m_with_clause(nullptr), derived_table(nullptr), first_recursive(nullptr), - m_lateral_deps(0) { + m_lateral_deps(0){ switch (parsing_context) { case CTX_ORDER_BY: explain_marker = CTX_ORDER_BY_SQ; // A subquery in ORDER BY @@ -2284,6 +2283,8 @@ Query_expression::Query_expression(enum_parsing_context parsing_context) case CTX_INSERT_VALUES: case CTX_INSERT_UPDATE: case CTX_WHERE: + case CTX_IN_WHERE: + case CTX_IN_ON: case CTX_DERIVED: case CTX_NONE: // A subquery in a non-select case CTX_RETURNING_CLAUSE: @@ -2307,9 +2308,10 @@ Query_block::Query_block(MEM_ROOT *mem_root, Item *where, Item *having) first_context(&context), top_join_list(mem_root), join_list(&top_join_list), + tvc(nullptr), m_where_cond(where), m_having_cond(having), - returning_fields(nullptr) {} + returning_fields(nullptr){} /** Set the name resolution context for the specified query block. diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 134df0922dd..751028363b2 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -2029,6 +2029,12 @@ class Query_block { Use TABLE_LIST::next_leaf to traverse the list. */ TABLE_LIST *leaf_tables{nullptr}; + /* + List of IN-predicates in this query block that + can be transformed into IN-subselect defined with TVC. + */ + List in_funcs; + table_value_constr *tvc; // Last table for LATERAL join, used by table functions TABLE_LIST *end_lateral_table{nullptr}; @@ -2070,7 +2076,13 @@ class Query_block { enum_parsing_context parsing_place{CTX_NONE}; /// Parse context: is inside a set function if this is positive uint in_sum_expr{0}; - + /* + Number of current derived table made with TVC during the + transformation of IN-predicate into IN-subquery for this + st_select_lex. + */ + uint curr_tvc_name; + //List in_funcs; /** Three fields used by semi-join transformations to know when semi-join is possible, and in which condition tree the subquery predicate is located. diff --git a/sql/sql_optimizer.cc b/sql/sql_optimizer.cc index 8cf83799a28..15edfc15397 100644 --- a/sql/sql_optimizer.cc +++ b/sql/sql_optimizer.cc @@ -244,6 +244,45 @@ static void SaveCondEqualLists(COND_EQUAL *cond_equal) { SaveCondEqualLists(cond_equal->upper_levels); } +bool JOIN::transform_in_predicates_into_in_subq(THD *thd) { + DBUG_ENTER("JOIN::transform_in_predicates_into_in_subq"); + if (!query_block->in_funcs.elements) + DBUG_RETURN(false); + + Query_block *save_current_query_block = thd->lex->current_query_block(); + enum_parsing_context save_parsing_place = query_block->parsing_place; + thd->lex->set_current_query_block(query_block); + + if(where_cond){ + query_block->parsing_place = CTX_WHERE; + where_cond = where_cond->transform(&Item::in_predicate_to_in_subs_transformer, 0); + if(!where_cond) + DBUG_RETURN(true); + query_block->set_where_cond(where_cond); + } + + auto join_list = query_block->join_list; + if(join_list){ + TABLE_LIST *table; + auto iter = join_list->begin(); + while(iter != join_list->end()){ + table = *iter; + query_block->parsing_place = CTX_ON; + if(table->join_cond()){ + table->set_join_cond(table->join_cond()->transform(&Item::in_predicate_to_in_subs_transformer, 0)); + } + if(!table->join_cond()) + DBUG_RETURN(true); + iter ++; + } + } + + query_block->in_funcs.clear(); + query_block->parsing_place = save_parsing_place; + thd->lex->set_current_query_block(save_current_query_block); + DBUG_RETURN(false); +} + /** Optimizes one query block into a query execution plan (QEP.) @@ -359,6 +398,8 @@ bool JOIN::optimize(bool finalize_access_paths) { } } } + if(thd->variables.in_subquery_conversion_threshold_enabled) + transform_in_predicates_into_in_subq(thd); if (thd->lex->using_hypergraph_optimizer) { // The hypergraph optimizer also wants all subselect items to be optimized, @@ -548,6 +589,9 @@ bool JOIN::optimize(bool finalize_access_paths) { // Ensure there are no errors prior making query plan if (thd->is_error()) return true; + //group by placement optimize + + if (thd->lex->using_hypergraph_optimizer) { Item *where_cond_no_in2exists = remove_in2exists_conds(thd, where_cond); Item *having_cond_no_in2exists = remove_in2exists_conds(thd, having_cond); diff --git a/sql/sql_optimizer.h b/sql/sql_optimizer.h index 6bc139abd0b..6a09005d02f 100644 --- a/sql/sql_optimizer.h +++ b/sql/sql_optimizer.h @@ -681,6 +681,8 @@ class JOIN { bool plan_is_single_table() { return primary_tables - const_tables == 1; } bool optimize(bool finalize_access_paths); + + bool transform_in_predicates_into_in_subq(THD *thd); #if defined(HAVE_PX) bool px_generate_plan(px_access_path::Split_Position *split_position); diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index d5b43ffa5b8..d043158f445 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -7188,7 +7188,7 @@ TABLE_LIST *Query_block::add_table_to_list( first_table = first_table ? first_table->next_local : nullptr; for (TABLE_LIST *tables = first_table; tables; tables = tables->next_local) { - if (!my_strcasecmp(table_alias_charset, alias_str, tables->alias) && + if (! my_strcasecmp(table_alias_charset, alias_str, tables->alias) && !strcmp(ptr->db, tables->db)) { my_error(ER_NONUNIQ_TABLE, MYF(0), alias_str); /* purecov: tested */ return nullptr; /* purecov: tested */ diff --git a/sql/sql_resolver.cc b/sql/sql_resolver.cc index 11f32791806..69b3feb0b0b 100644 --- a/sql/sql_resolver.cc +++ b/sql/sql_resolver.cc @@ -1685,7 +1685,7 @@ bool Query_block::setup_conds(THD *thd) { return true; assert(m_where_cond->data_type() != MYSQL_TYPE_INVALID); - + m_where_cond->mark_as_condition_AND_part((TABLE_LIST*)0x1); // Simplify the where condition if it's a const item if (m_where_cond->const_item() && !thd->lex->is_view_context_analysis() && !m_where_cond->walk(&Item::is_non_const_over_literals, @@ -1737,6 +1737,7 @@ bool Query_block::setup_join_cond(THD *thd, resolve_place = Query_block::RESOLVE_JOIN_NEST; resolve_nest = tr; thd->where = "on clause"; + join_cond->mark_as_condition_AND_part(tr); if ((!join_cond->fixed && join_cond->fix_fields(thd, ref)) || join_cond->check_cols(1)) return true; diff --git a/sql/sql_union.cc b/sql/sql_union.cc index 62887c62e27..a0db3e01086 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -478,7 +478,9 @@ bool Query_expression::prepare(THD *thd, Query_result *sel_result, // All query blocks get their options in this phase sl->set_query_result(tmp_result); sl->make_active_options(added_options | SELECT_NO_UNLOCK, removed_options); - + if(sl->tvc){ + sl->tvc->prepare(thd, sl, tmp_result, this); + } thd->lex->set_current_query_block(sl); if (sl == first_recursive) { @@ -700,7 +702,10 @@ bool Query_expression::optimize(THD *thd, TABLE *materialize_destination, // LIMIT is required for optimization if (set_limit(thd, query_block)) return true; /* purecov: inspected */ - + if(query_block->tvc){ + if (query_block->tvc->optimize(thd)) + return true; /* purecov: inspected */ + } if (query_block->optimize(thd, finalize_access_paths)) return true; /* diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index f81bc3e5339..8b10df16c3b 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -8584,6 +8584,22 @@ static Sys_var_ulonglong Sys_txsql_recycle_bin_max_size( static Sys_var_deprecated_alias Sys_recycle_bin_max_size( "recycle_bin_max_size", Sys_txsql_recycle_bin_max_size); +static Sys_var_uint Sys_in_subquery_conversion_threshold( + "in_predicate_conversion_threshold", + "The minimum number of scalar elements in the value list of " + "IN predicate that triggers its conversion to IN subquery. Set to " + "0 to disable the conversion", + SESSION_VAR(in_subquery_conversion_threshold), CMD_LINE(REQUIRED_ARG), + VALID_RANGE(0, UINT_MAX), DEFAULT(1000),BLOCK_SIZE(1)); + +static Sys_var_bool Sys_in_subquery_conversion_threshold_enabled( + "in_predicate_conversion_threshold_enabled", + "The minimum number of scalar elements in the value list of " + "IN predicate that triggers its conversion to IN subquery. Set to " + "0 to disable the conversion", + SESSION_VAR(in_subquery_conversion_threshold_enabled), CMD_LINE(OPT_ARG), + DEFAULT(false)); + #ifdef HAVE_TDSQL static Sys_var_bool Sys_threadpool_eager_mode( "thread_pool_eager_mode", diff --git a/sql/system_variables.h b/sql/system_variables.h index 3a431fb8a2e..6dfff865963 100644 --- a/sql/system_variables.h +++ b/sql/system_variables.h @@ -498,7 +498,12 @@ struct System_variables { @sa Sys_threshold_of_interesting_order_for_merge_join */ uint threshold_of_interesting_order_for_merge_join; - + + /** + @sa Sys_in_subquery_conversion_threshold + */ + uint in_subquery_conversion_threshold; + bool in_subquery_conversion_threshold_enabled; /** @sa Sys_txsql_range_estimation_by_histogram */