diff options
Diffstat (limited to 'sql')
-rw-r--r-- | sql/item_subselect.cc | 26 | ||||
-rw-r--r-- | sql/item_subselect.h | 8 | ||||
-rw-r--r-- | sql/item_sum.h | 1 | ||||
-rw-r--r-- | sql/mysqld.h | 2 | ||||
-rw-r--r-- | sql/opt_subselect.cc | 80 | ||||
-rw-r--r-- | sql/opt_sum.cc | 9 | ||||
-rw-r--r-- | sql/rpl_mi.cc | 6 | ||||
-rw-r--r-- | sql/sql_lex.cc | 1 | ||||
-rw-r--r-- | sql/sql_lex.h | 5 | ||||
-rw-r--r-- | sql/sql_select.cc | 18 |
10 files changed, 140 insertions, 16 deletions
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 6330165702e..3ca7d3afa6c 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -1430,8 +1430,9 @@ Item_in_subselect::Item_in_subselect(THD *thd, Item * left_exp, st_select_lex *select_lex): Item_exists_subselect(thd), left_expr_cache(0), first_execution(TRUE), in_strategy(SUBS_NOT_TRANSFORMED), - pushed_cond_guards(NULL), is_jtbm_merged(FALSE), is_jtbm_const_tab(FALSE), - is_flattenable_semijoin(FALSE), is_registered_semijoin(FALSE), + pushed_cond_guards(NULL), do_not_convert_to_sj(FALSE), is_jtbm_merged(FALSE), + is_jtbm_const_tab(FALSE), is_flattenable_semijoin(FALSE), + is_registered_semijoin(FALSE), upper_item(0) { DBUG_ENTER("Item_in_subselect::Item_in_subselect"); @@ -2584,6 +2585,27 @@ bool Item_in_subselect::inject_in_to_exists_cond(JOIN *join_arg) DBUG_ENTER("Item_in_subselect::inject_in_to_exists_cond"); DBUG_ASSERT(thd == join_arg->thd); + if (select_lex->min_max_opt_list.elements) + { + /* + MIN/MAX optimizations have been applied to Item_sum objects + of the subquery this subquery predicate in opt_sum_query(). + Injection of new condition invalidates this optimizations. + Thus those optimizations must be rolled back. + */ + List_iterator_fast<Item_sum> it(select_lex->min_max_opt_list); + Item_sum *item; + while ((item= it++)) + { + item->clear(); + item->reset_forced_const(); + } + if (where_item) + where_item->update_used_tables(); + if (having_item) + having_item->update_used_tables(); + } + if (where_item) { List<Item> *and_args= NULL; diff --git a/sql/item_subselect.h b/sql/item_subselect.h index 60449e06323..009aff5ed80 100644 --- a/sql/item_subselect.h +++ b/sql/item_subselect.h @@ -489,6 +489,8 @@ public: Item *left_expr_orig; /* Priority of this predicate in the convert-to-semi-join-nest process. */ int sj_convert_priority; + /* May be TRUE only for the candidates to semi-join conversion */ + bool do_not_convert_to_sj; /* Types of left_expr and subquery's select list allow to perform subquery materialization. Currently, we set this to FALSE when it as well could @@ -579,8 +581,8 @@ public: Item_in_subselect(THD *thd_arg): Item_exists_subselect(thd_arg), left_expr_cache(0), first_execution(TRUE), in_strategy(SUBS_NOT_TRANSFORMED), - pushed_cond_guards(NULL), func(NULL), is_jtbm_merged(FALSE), - is_jtbm_const_tab(FALSE), upper_item(0) {} + pushed_cond_guards(NULL), func(NULL), do_not_convert_to_sj(FALSE), + is_jtbm_merged(FALSE), is_jtbm_const_tab(FALSE), upper_item(0) {} void cleanup(); subs_type substype() { return IN_SUBS; } void reset() @@ -634,6 +636,8 @@ public: */ int get_identifier(); + void block_conversion_to_sj () { do_not_convert_to_sj= TRUE; } + bool test_strategy(uchar strategy) { return MY_TEST(in_strategy & strategy); } diff --git a/sql/item_sum.h b/sql/item_sum.h index 7ad037c046b..d6ccfeb8529 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -458,6 +458,7 @@ public: used_tables_cache= 0; const_item_cache= true; } + void reset_forced_const() { const_item_cache= false; } virtual bool const_during_execution() const { return false; } virtual void print(String *str, enum_query_type query_type); void fix_num_length_and_dec(); diff --git a/sql/mysqld.h b/sql/mysqld.h index 106db8176b6..419dbac1613 100644 --- a/sql/mysqld.h +++ b/sql/mysqld.h @@ -126,7 +126,7 @@ extern ulong slave_retried_transactions; extern ulong slave_run_triggers_for_rbr; extern ulonglong slave_type_conversions_options; extern my_bool read_only, opt_readonly; -extern my_bool lower_case_file_system; +extern MYSQL_PLUGIN_IMPORT my_bool lower_case_file_system; extern my_bool opt_enable_named_pipe, opt_sync_frm, opt_allow_suspicious_udfs; extern my_bool opt_secure_auth; extern const char *current_dbug_option; diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc index 042f8d4eac1..0335a663ec3 100644 --- a/sql/opt_subselect.cc +++ b/sql/opt_subselect.cc @@ -1003,6 +1003,25 @@ bool check_for_outer_joins(List<TABLE_LIST> *join_list) } +void find_and_block_conversion_to_sj(Item *to_find, + List_iterator_fast<Item_in_subselect> &li) +{ + if (to_find->type() != Item::SUBSELECT_ITEM || + ((Item_subselect *) to_find)->substype() != Item_subselect::IN_SUBS) + return; + Item_in_subselect *in_subq; + li.rewind(); + while ((in_subq= li++)) + { + if (in_subq == to_find) + { + in_subq->block_conversion_to_sj(); + return; + } + } +} + + /* Convert semi-join subquery predicates into semi-join join nests @@ -1055,7 +1074,6 @@ bool convert_join_subqueries_to_semijoins(JOIN *join) Query_arena *arena, backup; Item_in_subselect *in_subq; THD *thd= join->thd; - List_iterator<TABLE_LIST> ti(join->select_lex->leaf_tables); DBUG_ENTER("convert_join_subqueries_to_semijoins"); if (join->select_lex->sj_subselects.is_empty()) @@ -1073,6 +1091,60 @@ bool convert_join_subqueries_to_semijoins(JOIN *join) subq_sel->update_used_tables(); } + /* + Check all candidates to semi-join conversion that occur + in ON expressions of outer join. Set the flag blocking + this conversion for them. + */ + TABLE_LIST *tbl; + List_iterator<TABLE_LIST> ti(join->select_lex->leaf_tables); + while ((tbl= ti++)) + { + TABLE_LIST *embedded; + TABLE_LIST *embedding= tbl; + do + { + embedded= embedding; + if (MY_TEST(embedded->outer_join)) + { + Item *cond= embedded->on_expr; + if (!cond) + ; + else if (cond->type() != Item::COND_ITEM) + find_and_block_conversion_to_sj(cond, li); + else if (((Item_cond*) cond)->functype() == + Item_func::COND_AND_FUNC) + { + Item *item; + List_iterator<Item> it(*(((Item_cond*) cond)->argument_list())); + while ((item= it++)) + { + find_and_block_conversion_to_sj(item, li); + } + } + } + embedding= embedded->embedding; + } + while (embedding && + embedding->nested_join->join_list.head() == embedded); + } + + /* + Block conversion to semi-joins for those candidates that + are encountered in the WHERE condition of the multi-table view + with CHECK OPTION if this view is used in UPDATE/DELETE. + (This limitation can be, probably, easily lifted.) + */ + li.rewind(); + while ((in_subq= li++)) + { + if (in_subq->emb_on_expr_nest != NO_JOIN_NEST && + in_subq->emb_on_expr_nest->effective_with_check) + { + in_subq->block_conversion_to_sj(); + } + } + li.rewind(); /* First, convert child join's subqueries. We proceed bottom-up here */ while ((in_subq= li++)) @@ -1091,8 +1163,10 @@ bool convert_join_subqueries_to_semijoins(JOIN *join) if (convert_join_subqueries_to_semijoins(child_join)) DBUG_RETURN(TRUE); + + in_subq->sj_convert_priority= - MY_TEST(in_subq->emb_on_expr_nest != NO_JOIN_NEST) * MAX_TABLES * 2 + + MY_TEST(in_subq->do_not_convert_to_sj) * MAX_TABLES * 2 + in_subq->is_correlated * MAX_TABLES + child_join->outer_tables; } @@ -1125,7 +1199,7 @@ bool convert_join_subqueries_to_semijoins(JOIN *join) bool remove_item= TRUE; /* Stop processing if we've reached a subquery that's attached to the ON clause */ - if (in_subq->emb_on_expr_nest != NO_JOIN_NEST) + if (in_subq->do_not_convert_to_sj) break; if (in_subq->is_flattenable_semijoin) diff --git a/sql/opt_sum.cc b/sql/opt_sum.cc index e7d7c81b638..5d5132e7fee 100644 --- a/sql/opt_sum.cc +++ b/sql/opt_sum.cc @@ -254,6 +254,8 @@ int opt_sum_query(THD *thd, int error= 0; DBUG_ENTER("opt_sum_query"); + thd->lex->current_select->min_max_opt_list.empty(); + if (conds) where_tables= conds->used_tables(); @@ -447,7 +449,14 @@ int opt_sum_query(THD *thd, item_sum->aggregator_clear(); } else + { item_sum->reset_and_add(); + /* + Save a reference to the item for possible rollback + of the min/max optimizations for this select + */ + thd->lex->current_select->min_max_opt_list.push_back(item_sum); + } item_sum->make_const(); recalc_const_item= 1; break; diff --git a/sql/rpl_mi.cc b/sql/rpl_mi.cc index b03db07e443..c9dcf7b8fd7 100644 --- a/sql/rpl_mi.cc +++ b/sql/rpl_mi.cc @@ -664,7 +664,7 @@ file '%s')", fname); mi->connect_retry= (uint) connect_retry; mi->ssl= (my_bool) ssl; mi->ssl_verify_server_cert= ssl_verify_server_cert; - mi->heartbeat_period= master_heartbeat_period; + mi->heartbeat_period= MY_MIN(SLAVE_MAX_HEARTBEAT_PERIOD, master_heartbeat_period); } DBUG_PRINT("master_info",("log_file_name: %s position: %ld", mi->master_log_name, @@ -799,8 +799,8 @@ int flush_master_info(Master_info* mi, contents of file). But because of number of lines in the first line of file we don't care about this garbage. */ - char heartbeat_buf[sizeof(mi->heartbeat_period) * 4]; // buffer to suffice always - sprintf(heartbeat_buf, "%.3f", mi->heartbeat_period); + char heartbeat_buf[FLOATING_POINT_BUFFER]; + my_fcvt(mi->heartbeat_period, 3, heartbeat_buf, NULL); my_b_seek(file, 0L); my_b_printf(file, "%u\n%s\n%s\n%s\n%s\n%s\n%d\n%d\n%d\n%s\n%s\n%s\n%s\n%s\n%d\n%s\n%s\n%s\n%s\n%d\n%s\n%s\n" diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 691adb4896c..b3a30c69a03 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -2095,6 +2095,7 @@ void st_select_lex::init_query() leaf_tables_prep.empty(); leaf_tables.empty(); item_list.empty(); + min_max_opt_list.empty(); join= 0; having= prep_having= where= prep_where= 0; olap= UNSPECIFIED_OLAP_TYPE; diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 6f49ef145a2..240eb2373eb 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -751,6 +751,11 @@ public: */ List<Item_func_match> *ftfunc_list; List<Item_func_match> ftfunc_list_alloc; + /* + The list of items to which MIN/MAX optimizations of opt_sum_query() + have been applied. Used to rollback those optimizations if it's needed. + */ + List<Item_sum> min_max_opt_list; JOIN *join; /* after JOIN::prepare it is pointer to corresponding JOIN */ List<TABLE_LIST> top_join_list; /* join list of the top level */ List<TABLE_LIST> *join_list; /* list for the currently parsed join */ diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 0a282705e53..559473b8c19 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -9674,12 +9674,20 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) /* Step #2: Extract WHERE/ON parts */ + uint i; + for (i= join->top_join_tab_count - 1; i >= join->const_tables; i--) + { + if (!join->join_tab[i].bush_children) + break; + } + uint last_top_base_tab_idx= i; + table_map save_used_tables= 0; used_tables=((select->const_tables=join->const_table_map) | OUTER_REF_TABLE_BIT | RAND_TABLE_BIT); JOIN_TAB *tab; table_map current_map; - uint i= join->const_tables; + i= join->const_tables; for (tab= first_depth_first_tab(join); tab; tab= next_depth_first_tab(join, tab), i++) { @@ -9717,7 +9725,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) Following force including random expression in last table condition. It solve problem with select like SELECT * FROM t1 WHERE rand() > 0.5 */ - if (tab == join->join_tab + join->top_join_tab_count - 1) + if (tab == join->join_tab + last_top_base_tab_idx) current_map|= RAND_TABLE_BIT; used_tables|=current_map; @@ -9757,10 +9765,10 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) save_used_tables= 0; } else - { - tmp= make_cond_for_table(thd, cond, used_tables, current_map, i, + { + tmp= make_cond_for_table(thd, cond, used_tables, current_map, i, FALSE, FALSE); - } + } /* Add conditions added by add_not_null_conds(). */ if (tab->select_cond) add_cond_and_fix(thd, &tmp, tab->select_cond); |