diff options
author | Jan Lindström <jan.lindstrom@mariadb.com> | 2018-08-01 10:58:38 +0300 |
---|---|---|
committer | Jan Lindström <jan.lindstrom@mariadb.com> | 2018-08-01 10:58:38 +0300 |
commit | b286a9f8238c4b441d3e42d2b56ba3d5f563bfb1 (patch) | |
tree | 246c97d3410914ca3d7c85dc0a72a32844ee8c6c /sql | |
parent | 33e39f0682d966f67aa403a0be9bc7dbd44a69e6 (diff) | |
parent | a49ec980422e04ce1a37344be09aa6254f16fa2a (diff) | |
download | mariadb-git-b286a9f8238c4b441d3e42d2b56ba3d5f563bfb1.tar.gz |
Merge tag 'mariadb-5.5.61' into 5.5-galera
Diffstat (limited to 'sql')
-rw-r--r-- | sql/item.cc | 18 | ||||
-rw-r--r-- | sql/item.h | 6 | ||||
-rw-r--r-- | sql/item_cmpfunc.cc | 43 | ||||
-rw-r--r-- | sql/item_func.cc | 1 | ||||
-rw-r--r-- | sql/item_func.h | 7 | ||||
-rw-r--r-- | sql/item_row.cc | 1 | ||||
-rw-r--r-- | sql/item_sum.cc | 3 | ||||
-rw-r--r-- | sql/log.cc | 10 | ||||
-rw-r--r-- | sql/opt_subselect.cc | 96 | ||||
-rw-r--r-- | sql/sql_acl.cc | 105 | ||||
-rw-r--r-- | sql/sql_base.cc | 15 | ||||
-rw-r--r-- | sql/sql_handler.cc | 1 | ||||
-rw-r--r-- | sql/sql_select.cc | 92 | ||||
-rw-r--r-- | sql/table.cc | 27 |
14 files changed, 303 insertions, 122 deletions
diff --git a/sql/item.cc b/sql/item.cc index 08a00615c0c..33c35f8c3e0 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -1,5 +1,5 @@ /* - Copyright (c) 2000, 2016, Oracle and/or its affiliates. + Copyright (c) 2000, 2018, Oracle and/or its affiliates. Copyright (c) 2010, 2018, MariaDB Corporation This program is free software; you can redistribute it and/or modify @@ -504,6 +504,7 @@ Item::Item(): in_rollup= 0; decimals= 0; max_length= 0; with_subselect= 0; + with_param= 0; cmp_context= IMPOSSIBLE_RESULT; /* Initially this item is not attached to any JOIN_TAB. */ join_tab_idx= MAX_TABLES; @@ -550,6 +551,7 @@ Item::Item(THD *thd, Item *item): null_value(item->null_value), unsigned_flag(item->unsigned_flag), with_sum_func(item->with_sum_func), + with_param(item->with_param), with_field(item->with_field), fixed(item->fixed), is_autogenerated_name(item->is_autogenerated_name), @@ -1486,6 +1488,9 @@ bool Item_sp_variable::fix_fields(THD *thd, Item **) max_length= it->max_length; decimals= it->decimals; unsigned_flag= it->unsigned_flag; + with_param= 1; + if (thd->lex->current_select->master_unit()->item) + thd->lex->current_select->master_unit()->item->with_param= 1; fixed= 1; collation.set(it->collation.collation, it->collation.derivation); @@ -7234,6 +7239,7 @@ void Item_ref::set_properties() split_sum_func() doesn't try to change the reference. */ with_sum_func= (*ref)->with_sum_func; + with_param= (*ref)->with_param; with_field= (*ref)->with_field; unsigned_flag= (*ref)->unsigned_flag; fixed= 1; @@ -7681,6 +7687,7 @@ Item_cache_wrapper::Item_cache_wrapper(Item *item_arg) decimals= orig_item->decimals; collation.set(orig_item->collation); with_sum_func= orig_item->with_sum_func; + with_param= orig_item->with_param; with_field= orig_item->with_field; unsigned_flag= orig_item->unsigned_flag; name= item_arg->name; @@ -8534,10 +8541,10 @@ bool Item_insert_value::fix_fields(THD *thd, Item **items) } else { - Field *tmp_field= field_arg->field; - /* charset doesn't matter here, it's to avoid sigsegv only */ - tmp_field= new Field_null(0, 0, Field::NONE, field_arg->field->field_name, - &my_charset_bin); + static uchar null_bit=1; + /* charset doesn't matter here */ + Field *tmp_field= new Field_string(0, 0, &null_bit, 1, Field::NONE, + field_arg->field->field_name, &my_charset_bin); if (tmp_field) { tmp_field->init(field_arg->field->table); @@ -9648,6 +9655,7 @@ bool Item_type_holder::join_types(THD *thd, Item *item) if (Field::result_merge_type(fld_type) == DECIMAL_RESULT) { + collation.set_numeric(); decimals= min(max(decimals, item->decimals), DECIMAL_MAX_SCALE); int item_int_part= item->decimal_int_part(); int item_prec = max(prev_decimal_int_part, item_int_part) + decimals; diff --git a/sql/item.h b/sql/item.h index 830f8bf14a4..1bded7377ee 100644 --- a/sql/item.h +++ b/sql/item.h @@ -644,6 +644,7 @@ public: bool null_value; /* if item is null */ bool unsigned_flag; bool with_sum_func; /* True if item contains a sum func */ + bool with_param; /* True if contains an SP parameter */ /** True if any item except Item_sum_func contains a field. Set during parsing. */ @@ -1233,6 +1234,11 @@ public: { return FALSE; } + bool cleanup_is_expensive_cache_processor(uchar *arg) + { + is_expensive_cache= (int8)(-1); + return 0; + } /* To call bool function for all arguments */ struct bool_func_call_args diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 39f497e3828..6fb650b975b 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -1546,6 +1546,7 @@ bool Item_in_optimizer::fix_left(THD *thd, Item **ref) } eval_not_null_tables(NULL); with_sum_func= args[0]->with_sum_func; + with_param= args[0]->with_param || args[1]->with_param; with_field= args[0]->with_field; if ((const_item_cache= args[0]->const_item())) { @@ -1587,6 +1588,7 @@ bool Item_in_optimizer::fix_fields(THD *thd, Item **ref) with_subselect= 1; with_sum_func= with_sum_func || args[1]->with_sum_func; with_field= with_field || args[1]->with_field; + with_param= args[0]->with_param || args[1]->with_param; used_tables_cache|= args[1]->used_tables(); const_item_cache&= args[1]->const_item(); fixed= 1; @@ -2108,6 +2110,7 @@ void Item_func_interval::fix_length_and_dec() used_tables_cache|= row->used_tables(); not_null_tables_cache= row->not_null_tables(); with_sum_func= with_sum_func || row->with_sum_func; + with_param= with_param || row->with_param; with_field= with_field || row->with_field; const_item_cache&= row->const_item(); } @@ -4335,6 +4338,7 @@ Item_cond::fix_fields(THD *thd, Item **ref) List_iterator<Item> li(list); Item *item; uchar buff[sizeof(char*)]; // Max local vars in function + bool is_and_cond= functype() == Item_func::COND_AND_FUNC; not_null_tables_cache= used_tables_cache= 0; const_item_cache= 1; @@ -4396,26 +4400,33 @@ Item_cond::fix_fields(THD *thd, Item **ref) (item= *li.ref())->check_cols(1)) return TRUE; /* purecov: inspected */ used_tables_cache|= item->used_tables(); - if (item->const_item()) + if (item->const_item() && !item->with_param && + !item->is_expensive() && !cond_has_datetime_is_null(item)) { - if (!item->is_expensive() && !cond_has_datetime_is_null(item) && - item->val_int() == 0) + if (item->val_int() == is_and_cond && top_level()) { /* - This is "... OR false_cond OR ..." + a. This is "... AND true_cond AND ..." + In this case, true_cond has no effect on cond_and->not_null_tables() + b. This is "... OR false_cond/null cond OR ..." In this case, false_cond has no effect on cond_or->not_null_tables() */ } else { /* - This is "... OR const_cond OR ..." + a. This is "... AND false_cond/null_cond AND ..." + The whole condition is FALSE/UNKNOWN. + b. This is "... OR const_cond OR ..." In this case, cond_or->not_null_tables()=0, because the condition const_cond might evaluate to true (regardless of whether some tables were NULL-complemented). */ + not_null_tables_cache= (table_map) 0; and_tables_cache= (table_map) 0; } + if (thd->is_error()) + return TRUE; } else { @@ -4427,6 +4438,7 @@ Item_cond::fix_fields(THD *thd, Item **ref) } with_sum_func= with_sum_func || item->with_sum_func; + with_param= with_param || item->with_param; with_field= with_field || item->with_field; with_subselect|= item->has_subquery(); if (item->maybe_null) @@ -4443,30 +4455,36 @@ bool Item_cond::eval_not_null_tables(uchar *opt_arg) { Item *item; + bool is_and_cond= functype() == Item_func::COND_AND_FUNC; List_iterator<Item> li(list); not_null_tables_cache= (table_map) 0; and_tables_cache= ~(table_map) 0; while ((item=li++)) { table_map tmp_table_map; - if (item->const_item()) + if (item->const_item() && !item->with_param && + !item->is_expensive() && !cond_has_datetime_is_null(item)) { - if (!item->is_expensive() && !cond_has_datetime_is_null(item) && - item->val_int() == 0) + if (item->val_int() == is_and_cond && top_level()) { /* - This is "... OR false_cond OR ..." + a. This is "... AND true_cond AND ..." + In this case, true_cond has no effect on cond_and->not_null_tables() + b. This is "... OR false_cond/null cond OR ..." In this case, false_cond has no effect on cond_or->not_null_tables() */ } else { /* - This is "... OR const_cond OR ..." + a. This is "... AND false_cond/null_cond AND ..." + The whole condition is FALSE/UNKNOWN. + b. This is "... OR const_cond OR ..." In this case, cond_or->not_null_tables()=0, because the condition - some_cond_or might be true regardless of what tables are - NULL-complemented. + const_cond might evaluate to true (regardless of whether some tables + were NULL-complemented). */ + not_null_tables_cache= (table_map) 0; and_tables_cache= (table_map) 0; } } @@ -5118,6 +5136,7 @@ Item_func_regex::fix_fields(THD *thd, Item **ref) args[1]->fix_fields(thd, args + 1)) || args[1]->check_cols(1)) return TRUE; /* purecov: inspected */ with_sum_func=args[0]->with_sum_func || args[1]->with_sum_func; + with_param=args[0]->with_param || args[1]->with_param; with_field= args[0]->with_field || args[1]->with_field; with_subselect= args[0]->has_subquery() || args[1]->has_subquery(); max_length= 1; diff --git a/sql/item_func.cc b/sql/item_func.cc index 6833e30af23..225b47ff6e8 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -222,6 +222,7 @@ Item_func::fix_fields(THD *thd, Item **ref) maybe_null=1; with_sum_func= with_sum_func || item->with_sum_func; + with_param= with_param || item->with_param; with_field= with_field || item->with_field; used_tables_cache|= item->used_tables(); const_item_cache&= item->const_item(); diff --git a/sql/item_func.h b/sql/item_func.h index 57818228b98..3a609fc0fe0 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -83,6 +83,7 @@ public: args= tmp_arg; args[0]= a; with_sum_func= a->with_sum_func; + with_param= a->with_param; with_field= a->with_field; } Item_func(Item *a,Item *b): @@ -91,6 +92,7 @@ public: args= tmp_arg; args[0]= a; args[1]= b; with_sum_func= a->with_sum_func || b->with_sum_func; + with_param= a->with_param || b->with_param; with_field= a->with_field || b->with_field; } Item_func(Item *a,Item *b,Item *c): @@ -102,6 +104,7 @@ public: arg_count= 3; args[0]= a; args[1]= b; args[2]= c; with_sum_func= a->with_sum_func || b->with_sum_func || c->with_sum_func; + with_param= a->with_param || b->with_param || c->with_param; with_field= a->with_field || b->with_field || c->with_field; } } @@ -115,6 +118,8 @@ public: args[0]= a; args[1]= b; args[2]= c; args[3]= d; with_sum_func= a->with_sum_func || b->with_sum_func || c->with_sum_func || d->with_sum_func; + with_param= a->with_param || b->with_param || + c->with_param || d->with_param; with_field= a->with_field || b->with_field || c->with_field || d->with_field; } @@ -128,6 +133,8 @@ public: args[0]= a; args[1]= b; args[2]= c; args[3]= d; args[4]= e; with_sum_func= a->with_sum_func || b->with_sum_func || c->with_sum_func || d->with_sum_func || e->with_sum_func ; + with_param= a->with_param || b->with_param || + c->with_param || d->with_param || e->with_param; with_field= a->with_field || b->with_field || c->with_field || d->with_field || e->with_field; } diff --git a/sql/item_row.cc b/sql/item_row.cc index 9e81c053b69..9fe34dd00fd 100644 --- a/sql/item_row.cc +++ b/sql/item_row.cc @@ -125,6 +125,7 @@ bool Item_row::fix_fields(THD *thd, Item **ref) with_sum_func= with_sum_func || item->with_sum_func; with_field= with_field || item->with_field; with_subselect|= item->with_subselect; + with_param|= item->with_param; } fixed= 1; return FALSE; diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 709c2b6f7b5..16334cd7b30 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -1164,6 +1164,7 @@ Item_sum_num::fix_fields(THD *thd, Item **ref) return TRUE; set_if_bigger(decimals, args[i]->decimals); with_subselect|= args[i]->with_subselect; + with_param|= args[i]->with_param; } result_field=0; max_length=float_length(decimals); @@ -1195,6 +1196,7 @@ Item_sum_hybrid::fix_fields(THD *thd, Item **ref) return TRUE; decimals=item->decimals; with_subselect= args[0]->with_subselect; + with_param= args[0]->with_param; switch (hybrid_type= item->result_type()) { case INT_RESULT: @@ -3430,6 +3432,7 @@ Item_func_group_concat::fix_fields(THD *thd, Item **ref) args[i]->check_cols(1)) return TRUE; with_subselect|= args[i]->with_subselect; + with_param|= args[i]->with_param; } /* skip charset aggregation for order columns */ diff --git a/sql/log.cc b/sql/log.cc index ca7833a0460..2ada5ecafcf 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -2601,14 +2601,14 @@ void MYSQL_LOG::close(uint exiting) if (log_type == LOG_BIN && mysql_file_sync(log_file.file, MYF(MY_WME)) && ! write_error) { write_error= 1; - sql_print_error(ER_THD_OR_DEFAULT(current_thd, ER_ERROR_ON_WRITE), name, errno); + sql_print_error(ER_DEFAULT(ER_ERROR_ON_WRITE), name, errno); } if (!(exiting & LOG_CLOSE_DELAYED_CLOSE) && mysql_file_close(log_file.file, MYF(MY_WME)) && ! write_error) { write_error= 1; - sql_print_error(ER_THD_OR_DEFAULT(current_thd, ER_ERROR_ON_WRITE), name, errno); + sql_print_error(ER_DEFAULT(ER_ERROR_ON_WRITE), name, errno); } } @@ -2792,7 +2792,7 @@ err: if (!write_error) { write_error= 1; - sql_print_error(ER(ER_ERROR_ON_WRITE), name, errno); + sql_print_error(ER_DEFAULT(ER_ERROR_ON_WRITE), name, errno); } mysql_mutex_unlock(&LOCK_log); return TRUE; @@ -2968,7 +2968,7 @@ bool MYSQL_QUERY_LOG::write(THD *thd, time_t current_time, if (! write_error) { write_error= 1; - sql_print_error(ER(ER_ERROR_ON_WRITE), name, tmp_errno); + sql_print_error(ER_DEFAULT(ER_ERROR_ON_WRITE), name, tmp_errno); } } } @@ -6529,7 +6529,7 @@ void MYSQL_BIN_LOG::close(uint exiting) if (mysql_file_close(index_file.file, MYF(0)) < 0 && ! write_error) { write_error= 1; - sql_print_error(ER(ER_ERROR_ON_WRITE), index_file_name, errno); + sql_print_error(ER_DEFAULT(ER_ERROR_ON_WRITE), index_file_name, errno); } } log_state= (exiting & LOG_CLOSE_TO_BE_OPENED) ? LOG_TO_BE_OPENED : LOG_CLOSED; diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc index 1bda84bacd7..f472cf16710 100644 --- a/sql/opt_subselect.cc +++ b/sql/opt_subselect.cc @@ -440,6 +440,7 @@ bool subquery_types_allow_materialization(Item_in_subselect *in_subs); static bool replace_where_subcondition(JOIN *, Item **, Item *, Item *, bool); static int subq_sj_candidate_cmp(Item_in_subselect* el1, Item_in_subselect* el2, void *arg); +static void reset_equality_number_for_subq_conds(Item * cond); static bool convert_subq_to_sj(JOIN *parent_join, Item_in_subselect *subq_pred); static bool convert_subq_to_jtbm(JOIN *parent_join, Item_in_subselect *subq_pred, bool *remove); @@ -815,6 +816,9 @@ int check_and_do_in_subquery_rewrites(JOIN *join) details) * require that compared columns have exactly the same type. This is a temporary measure to avoid BUG#36752-type problems. + + JOIN_TAB::keyuse_is_valid_for_access_in_chosen_plan expects that for Semi Join Materialization + Scan all the items in the select list of the IN Subquery are of the type Item::FIELD_ITEM. */ static @@ -1453,6 +1457,67 @@ static int subq_sj_candidate_cmp(Item_in_subselect* el1, Item_in_subselect* el2, } +/** + @brief + reset the value of the field in_eqaulity_no for all Item_func_eq + items in the where clause of the subquery. + + Look for in_equality_no description in Item_func_eq class + + DESCRIPTION + Lets have an example: + SELECT t1.a FROM t1 WHERE t1.a IN + (SELECT t2.a FROM t2 where t2.b IN + (select t3.b from t3 where t3.c=27 )) + + So for such a query we have the parent, child and + grandchild select. + + So for the equality t2.b = t3.b we set the value for in_equality_no to + 0 according to its description. Wewe do the same for t1.a = t2.a. + But when we look at the child select (with the grandchild select merged), + the query would be + + SELECT t1.a FROM t1 WHERE t1.a IN + (SELECT t2.a FROM t2 where t2.b = t3.b and t3.c=27) + + and then when the child select is merged into the parent select the query + would look like + + SELECT t1.a FROM t1, semi-join-nest(t2,t3) + WHERE t1.a =t2.a and t2.b = t3.b and t3.c=27 + + Still we would have in_equality_no set for t2.b = t3.b + though it does not take part in the semi-join equality for the parent select, + so we should reset its value to UINT_MAX. + + @param cond WHERE clause of the subquery +*/ + +static void reset_equality_number_for_subq_conds(Item * cond) +{ + if (!cond) + return; + if (cond->type() == Item::COND_ITEM) + { + List_iterator<Item> li(*((Item_cond*) cond)->argument_list()); + Item *item; + while ((item=li++)) + { + if (item->type() == Item::FUNC_ITEM && + ((Item_func*)item)->functype()== Item_func::EQ_FUNC) + ((Item_func_eq*)item)->in_equality_no= UINT_MAX; + } + } + else + { + if (cond->type() == Item::FUNC_ITEM && + ((Item_func*)cond)->functype()== Item_func::EQ_FUNC) + ((Item_func_eq*)cond)->in_equality_no= UINT_MAX; + } + return; +} + /* Convert a subquery predicate into a TABLE_LIST semi-join nest @@ -1710,6 +1775,7 @@ static bool convert_subq_to_sj(JOIN *parent_join, Item_in_subselect *subq_pred) */ sj_nest->sj_in_exprs= subq_pred->left_expr->cols(); sj_nest->nested_join->sj_outer_expr_list.empty(); + reset_equality_number_for_subq_conds(sj_nest->sj_on_expr); if (subq_pred->left_expr->cols() == 1) { @@ -3532,7 +3598,8 @@ void fix_semijoin_strategies_for_picked_join_order(JOIN *join) first= tablenr - sjm->tables + 1; join->best_positions[first].n_sj_tables= sjm->tables; join->best_positions[first].sj_strategy= SJ_OPT_MATERIALIZE; - join->sjm_lookup_tables|= s->table->map; + for (uint i= first; i < first+ sjm->tables; i++) + join->sjm_lookup_tables |= join->best_positions[i].table->table->map; } else if (pos->sj_strategy == SJ_OPT_MATERIALIZE_SCAN) { @@ -3725,21 +3792,29 @@ bool setup_sj_materialization_part1(JOIN_TAB *sjm_tab) SJ_MATERIALIZATION_INFO *sjm= emb_sj_nest->sj_mat_info; THD *thd= tab->join->thd; /* First the calls come to the materialization function */ - //List<Item> &item_list= emb_sj_nest->sj_subq_pred->unit->first_select()->item_list; - + DBUG_ASSERT(sjm->is_used); /* Set up the table to write to, do as select_union::create_result_table does */ sjm->sjm_table_param.init(); sjm->sjm_table_param.bit_fields_as_long= TRUE; - //List_iterator<Item> it(item_list); SELECT_LEX *subq_select= emb_sj_nest->sj_subq_pred->unit->first_select(); - Item **p_item= subq_select->ref_pointer_array; - Item **p_end= p_item + subq_select->item_list.elements; - //while((right_expr= it++)) - for(;p_item != p_end; p_item++) - sjm->sjm_table_cols.push_back(*p_item); + List_iterator<Item> it(subq_select->item_list); + Item *item; + while((item= it++)) + { + /* + This semi-join replaced the subquery (subq_select) and so on + re-executing it will not be prepared. To use the Items from its + select list we have to prepare (fix_fields) them + */ + if (!item->fixed && item->fix_fields(thd, it.ref())) + DBUG_RETURN(TRUE); + item= *(it.ref()); // it can be changed by fix_fields + DBUG_ASSERT(!item->name_length || item->name_length == strlen(item->name)); + sjm->sjm_table_cols.push_back(item, thd->mem_root); + } sjm->sjm_table_param.field_count= subq_select->item_list.elements; sjm->sjm_table_param.force_not_null_cols= TRUE; @@ -5872,6 +5947,7 @@ bool JOIN::choose_tableless_subquery_plan() functions produce empty subquery result. There is no need to further rewrite the subquery because it will not be executed at all. */ + exec_const_cond= 0; return FALSE; } @@ -5903,6 +5979,6 @@ bool JOIN::choose_tableless_subquery_plan() tmp_having= having; } } - exec_const_cond= conds; + exec_const_cond= zero_result_cause ? 0 : conds; return FALSE; } diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 15a238193dd..dd5ab783e4d 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2000, 2016, Oracle and/or its affiliates. +/* Copyright (c) 2000, 2018, Oracle and/or its affiliates. Copyright (c) 2009, 2018, MariaDB This program is free software; you can redistribute it and/or modify @@ -4487,6 +4487,7 @@ end_index_init: exists. @param thd A pointer to the thread handler object. + @param table A pointer to the table list. @see grant_reload @@ -4495,31 +4496,22 @@ end_index_init: @retval TRUE An error has occurred. */ -static my_bool grant_reload_procs_priv(THD *thd) +static my_bool grant_reload_procs_priv(THD *thd, TABLE_LIST *table) { HASH old_proc_priv_hash, old_func_priv_hash; - TABLE_LIST table; my_bool return_val= FALSE; DBUG_ENTER("grant_reload_procs_priv"); - table.init_one_table("mysql", 5, "procs_priv", - strlen("procs_priv"), "procs_priv", - TL_READ); - table.open_type= OT_BASE_ONLY; - - if (open_and_lock_tables(thd, &table, FALSE, MYSQL_LOCK_IGNORE_TIMEOUT)) - DBUG_RETURN(TRUE); - - mysql_rwlock_wrlock(&LOCK_grant); /* Save a copy of the current hash if we need to undo the grant load */ old_proc_priv_hash= proc_priv_hash; old_func_priv_hash= func_priv_hash; - if ((return_val= grant_load_procs_priv(table.table))) + if ((return_val= grant_load_procs_priv(table->table))) { /* Error; Reverting to old hash */ DBUG_PRINT("error",("Reverting to old privileges")); - grant_free(); + my_hash_free(&proc_priv_hash); + my_hash_free(&func_priv_hash); proc_priv_hash= old_proc_priv_hash; func_priv_hash= old_func_priv_hash; } @@ -4528,9 +4520,7 @@ static my_bool grant_reload_procs_priv(THD *thd) my_hash_free(&old_proc_priv_hash); my_hash_free(&old_func_priv_hash); } - mysql_rwlock_unlock(&LOCK_grant); - close_mysql_tables(thd); DBUG_RETURN(return_val); } @@ -4552,7 +4542,7 @@ static my_bool grant_reload_procs_priv(THD *thd) my_bool grant_reload(THD *thd) { - TABLE_LIST tables[2]; + TABLE_LIST tables[3]; HASH old_column_priv_hash; MEM_ROOT old_mem; my_bool return_val= 1; @@ -4568,15 +4558,57 @@ my_bool grant_reload(THD *thd) tables[1].init_one_table(C_STRING_WITH_LEN("mysql"), C_STRING_WITH_LEN("columns_priv"), "columns_priv", TL_READ); + tables[2].init_one_table(C_STRING_WITH_LEN("mysql"), + C_STRING_WITH_LEN("procs_priv"), + "procs_priv", TL_READ); + tables[0].next_local= tables[0].next_global= tables+1; - tables[0].open_type= tables[1].open_type= OT_BASE_ONLY; + tables[1].next_local= tables[1].next_global= tables+2; + tables[0].open_type= tables[1].open_type= tables[2].open_type= OT_BASE_ONLY; + + /* + Reload will work in the following manner:- + + proc_priv_hash structure + / \ + not initialized initialized + / \ | + mysql.procs_priv table Server Startup | + is missing \ | + | open_and_lock_tables() + Assume we are working on /success \failure + pre 4.1 system tables. Normal Scenario. An error is thrown. + A warning is printed Reload column privilege. Retain the old hash. + and continue with Reload function and + reloading the column procedure privileges, + privileges. if available. + */ + + if (!(my_hash_inited(&proc_priv_hash))) + tables[2].open_strategy= TABLE_LIST::OPEN_IF_EXISTS; /* To avoid deadlocks we should obtain table locks before obtaining LOCK_grant rwlock. */ if (open_and_lock_tables(thd, tables, FALSE, MYSQL_LOCK_IGNORE_TIMEOUT)) + { + if (thd->stmt_da->is_error()) + { + sql_print_error("Fatal error: Can't open and lock privilege tables: %s", + thd->stmt_da->message()); + } goto end; + } + + if (tables[2].table == NULL) + { + sql_print_warning("Table 'mysql.procs_priv' does not exist. " + "Please run mysql_upgrade."); + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_NO_SUCH_TABLE, + ER(ER_NO_SUCH_TABLE), tables[2].db, + tables[2].table_name); + } mysql_rwlock_wrlock(&LOCK_grant); old_column_priv_hash= column_priv_hash; @@ -4588,10 +4620,18 @@ my_bool grant_reload(THD *thd) old_mem= memex; init_sql_alloc(&memex, ACL_ALLOC_BLOCK_SIZE, 0); - if ((return_val= grant_load(thd, tables))) + /* + tables[2].table i.e. procs_priv can be null if we are working with + pre 4.1 privilage tables + */ + if ((return_val= (grant_load(thd, tables) || + (tables[2].table != NULL && + grant_reload_procs_priv(thd, &tables[2]))) + )) { // Error. Revert to old hash DBUG_PRINT("error",("Reverting to old privileges")); - grant_free(); /* purecov: deadcode */ + my_hash_free(&column_priv_hash); + free_root(&memex,MYF(0)); column_priv_hash= old_column_priv_hash; /* purecov: deadcode */ memex= old_mem; /* purecov: deadcode */ } @@ -4599,22 +4639,12 @@ my_bool grant_reload(THD *thd) { my_hash_free(&old_column_priv_hash); free_root(&old_mem,MYF(0)); + grant_version++; } mysql_rwlock_unlock(&LOCK_grant); - close_mysql_tables(thd); - - /* - It is OK failing to load procs_priv table because we may be - working with 4.1 privilege tables. - */ - if (grant_reload_procs_priv(thd)) - return_val= 1; - - mysql_rwlock_wrlock(&LOCK_grant); - grant_version++; - mysql_rwlock_unlock(&LOCK_grant); end: + close_mysql_tables(thd); DBUG_RETURN(return_val); } @@ -7191,17 +7221,12 @@ bool sp_grant_privileges(THD *thd, const char *sp_db, const char *sp_name, if (!(combo=(LEX_USER*) thd->alloc(sizeof(st_lex_user)))) DBUG_RETURN(TRUE); - combo->user.str= sctx->user; + combo->user.str= (char *) sctx->priv_user; mysql_mutex_lock(&acl_cache->lock); - if ((au= find_acl_user(combo->host.str=(char*)sctx->host_or_ip,combo->user.str,FALSE))) - goto found_acl; - if ((au= find_acl_user(combo->host.str=(char*)sctx->host, combo->user.str,FALSE))) - goto found_acl; - if ((au= find_acl_user(combo->host.str=(char*)sctx->ip, combo->user.str,FALSE))) - goto found_acl; - if((au= find_acl_user(combo->host.str=(char*)"%", combo->user.str, FALSE))) + if ((au= find_acl_user(combo->host.str= (char *) sctx->priv_host, + combo->user.str, FALSE))) goto found_acl; mysql_mutex_unlock(&acl_cache->lock); diff --git a/sql/sql_base.cc b/sql/sql_base.cc index b1979de36e6..2c0a5abf236 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -6448,6 +6448,9 @@ find_field_in_natural_join(THD *thd, TABLE_LIST *table_ref, const char *name, column reference. See create_view_field() for details. */ item= nj_col->create_item(thd); + if (!item) + DBUG_RETURN(NULL); + /* *ref != NULL means that *ref contains the item that we need to replace. If the item was aliased by the user, set the alias to @@ -7706,6 +7709,7 @@ store_natural_using_join_columns(THD *thd, TABLE_LIST *natural_using_join, Query_arena *arena, backup; bool result= TRUE; List<Natural_join_column> *non_join_columns; + List<Natural_join_column> *join_columns; DBUG_ENTER("store_natural_using_join_columns"); DBUG_ASSERT(!natural_using_join->join_columns); @@ -7713,7 +7717,7 @@ store_natural_using_join_columns(THD *thd, TABLE_LIST *natural_using_join, arena= thd->activate_stmt_arena_if_needed(&backup); if (!(non_join_columns= new List<Natural_join_column>) || - !(natural_using_join->join_columns= new List<Natural_join_column>)) + !(join_columns= new List<Natural_join_column>)) goto err; /* Append the columns of the first join operand. */ @@ -7722,7 +7726,7 @@ store_natural_using_join_columns(THD *thd, TABLE_LIST *natural_using_join, nj_col_1= it_1.get_natural_column_ref(); if (nj_col_1->is_common) { - natural_using_join->join_columns->push_back(nj_col_1); + join_columns->push_back(nj_col_1); /* Reset the common columns for the next call to mark_common_columns. */ nj_col_1->is_common= FALSE; } @@ -7743,7 +7747,7 @@ store_natural_using_join_columns(THD *thd, TABLE_LIST *natural_using_join, { const char *using_field_name_ptr= using_field_name->c_ptr(); List_iterator_fast<Natural_join_column> - it(*(natural_using_join->join_columns)); + it(*join_columns); Natural_join_column *common_field; for (;;) @@ -7776,7 +7780,8 @@ store_natural_using_join_columns(THD *thd, TABLE_LIST *natural_using_join, } if (non_join_columns->elements > 0) - natural_using_join->join_columns->concat(non_join_columns); + join_columns->concat(non_join_columns); + natural_using_join->join_columns= join_columns; natural_using_join->is_join_columns_complete= TRUE; result= FALSE; @@ -8008,7 +8013,6 @@ static bool setup_natural_join_row_types(THD *thd, DBUG_PRINT("info", ("using cached setup_natural_join_row_types")); DBUG_RETURN(false); } - context->select_lex->first_natural_join_processing= false; List_iterator_fast<TABLE_LIST> table_ref_it(*from_clause); TABLE_LIST *table_ref; /* Current table reference. */ @@ -8053,6 +8057,7 @@ static bool setup_natural_join_row_types(THD *thd, change on re-execution */ context->natural_join_first_table= context->first_name_resolution_table; + context->select_lex->first_natural_join_processing= false; DBUG_RETURN (false); } diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc index f5c79e59bf2..778507ebc38 100644 --- a/sql/sql_handler.cc +++ b/sql/sql_handler.cc @@ -980,6 +980,7 @@ SQL_HANDLER *mysql_ha_read_prepare(THD *thd, TABLE_LIST *tables, if (!(handler= mysql_ha_find_handler(thd, tables->alias))) DBUG_RETURN(0); tables->table= handler->table; // This is used by fix_fields + handler->table->pos_in_table_list= tables; if (mysql_ha_fix_cond_and_key(handler, mode, keyname, key_expr, cond, 1)) DBUG_RETURN(0); DBUG_RETURN(handler); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 90bb536c0e2..b2b2bcde80c 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1034,9 +1034,6 @@ JOIN::optimize() eval_select_list_used_tables(); - if (optimize_constant_subqueries()) - DBUG_RETURN(1); - table_count= select_lex->leaf_tables.elements; if (setup_ftfuncs(select_lex)) /* should be after having->fix_fields */ @@ -1098,6 +1095,16 @@ JOIN::optimize() thd->restore_active_arena(arena, &backup); } + if (optimize_constant_subqueries()) + DBUG_RETURN(1); + + if (conds && conds->has_subquery()) + (void) conds->walk(&Item::cleanup_is_expensive_cache_processor, + 0, (uchar*)0); + if (having && having->has_subquery()) + (void) having->walk(&Item::cleanup_is_expensive_cache_processor, + 0, (uchar*)0); + if (setup_jtbm_semi_joins(this, join_list, &conds)) DBUG_RETURN(1); @@ -1136,10 +1143,18 @@ JOIN::optimize() if (cond_value == Item::COND_FALSE || having_value == Item::COND_FALSE || (!unit->select_limit_cnt && !(select_options & OPTION_FOUND_ROWS))) { /* Impossible cond */ - DBUG_PRINT("info", (having_value == Item::COND_FALSE ? - "Impossible HAVING" : "Impossible WHERE")); - zero_result_cause= having_value == Item::COND_FALSE ? - "Impossible HAVING" : "Impossible WHERE"; + if (unit->select_limit_cnt) + { + DBUG_PRINT("info", (having_value == Item::COND_FALSE ? + "Impossible HAVING" : "Impossible WHERE")); + zero_result_cause= having_value == Item::COND_FALSE ? + "Impossible HAVING" : "Impossible WHERE"; + } + else + { + DBUG_PRINT("info", ("Zero limit")); + zero_result_cause= "Zero limit"; + } table_count= top_join_tab_count= 0; error= 0; goto setup_subq_exit; @@ -3448,8 +3463,8 @@ make_join_statistics(JOIN *join, List<TABLE_LIST> &tables_list, int ref_changed; do { - more_const_tables_found: ref_changed = 0; + more_const_tables_found: found_ref=0; /* @@ -3614,7 +3629,7 @@ make_join_statistics(JOIN *join, List<TABLE_LIST> &tables_list, } } } - } while (join->const_table_map & found_ref && ref_changed); + } while (ref_changed); join->sort_by_table= get_sort_by_table(join->order, join->group_list, join->select_lex->leaf_tables, @@ -7430,8 +7445,13 @@ bool JOIN_TAB::keyuse_is_valid_for_access_in_chosen_plan(JOIN *join, st_select_lex *sjm_sel= emb_sj_nest->sj_subq_pred->unit->first_select(); for (uint i= 0; i < sjm_sel->item_list.elements; i++) { - if (sjm_sel->ref_pointer_array[i] == keyuse->val) - return true; + DBUG_ASSERT(sjm_sel->ref_pointer_array[i]->real_item()->type() == Item::FIELD_ITEM); + if (keyuse->val->real_item()->type() == Item::FIELD_ITEM) + { + Field *field = ((Item_field*)sjm_sel->ref_pointer_array[i]->real_item())->field; + if (field->eq(((Item_field*)keyuse->val->real_item())->field)) + return true; + } } return false; } @@ -7986,7 +8006,6 @@ static bool create_hj_key_for_table(JOIN *join, JOIN_TAB *join_tab, if (first_keyuse) { key_parts++; - first_keyuse= FALSE; } else { @@ -7996,7 +8015,7 @@ static bool create_hj_key_for_table(JOIN *join, JOIN_TAB *join_tab, if (curr->keypart == keyuse->keypart && !(~used_tables & curr->used_tables) && join_tab->keyuse_is_valid_for_access_in_chosen_plan(join, - keyuse) && + curr) && are_tables_local(join_tab, curr->used_tables)) break; } @@ -8004,6 +8023,7 @@ static bool create_hj_key_for_table(JOIN *join, JOIN_TAB *join_tab, key_parts++; } } + first_keyuse= FALSE; keyuse++; } while (keyuse->table == table && keyuse->is_for_hash_join()); if (!key_parts) @@ -23730,21 +23750,18 @@ void JOIN::set_allowed_join_cache_types() void JOIN::save_query_plan(Join_plan_state *save_to) { - if (keyuse.elements) - { - DYNAMIC_ARRAY tmp_keyuse; - /* Swap the current and the backup keyuse internal arrays. */ - tmp_keyuse= keyuse; - keyuse= save_to->keyuse; /* keyuse is reset to an empty array. */ - save_to->keyuse= tmp_keyuse; + DYNAMIC_ARRAY tmp_keyuse; + /* Swap the current and the backup keyuse internal arrays. */ + tmp_keyuse= keyuse; + keyuse= save_to->keyuse; /* keyuse is reset to an empty array. */ + save_to->keyuse= tmp_keyuse; - for (uint i= 0; i < table_count; i++) - { - save_to->join_tab_keyuse[i]= join_tab[i].keyuse; - join_tab[i].keyuse= NULL; - save_to->join_tab_checked_keys[i]= join_tab[i].checked_keys; - join_tab[i].checked_keys.clear_all(); - } + for (uint i= 0; i < table_count; i++) + { + save_to->join_tab_keyuse[i]= join_tab[i].keyuse; + join_tab[i].keyuse= NULL; + save_to->join_tab_checked_keys[i]= join_tab[i].checked_keys; + join_tab[i].checked_keys.clear_all(); } memcpy((uchar*) save_to->best_positions, (uchar*) best_positions, sizeof(POSITION) * (table_count + 1)); @@ -23782,20 +23799,17 @@ void JOIN::reset_query_plan() void JOIN::restore_query_plan(Join_plan_state *restore_from) { - if (restore_from->keyuse.elements) - { - DYNAMIC_ARRAY tmp_keyuse; - tmp_keyuse= keyuse; - keyuse= restore_from->keyuse; - restore_from->keyuse= tmp_keyuse; - - for (uint i= 0; i < table_count; i++) - { - join_tab[i].keyuse= restore_from->join_tab_keyuse[i]; - join_tab[i].checked_keys= restore_from->join_tab_checked_keys[i]; - } + DYNAMIC_ARRAY tmp_keyuse; + tmp_keyuse= keyuse; + keyuse= restore_from->keyuse; + restore_from->keyuse= tmp_keyuse; + for (uint i= 0; i < table_count; i++) + { + join_tab[i].keyuse= restore_from->join_tab_keyuse[i]; + join_tab[i].checked_keys= restore_from->join_tab_checked_keys[i]; } + memcpy((uchar*) best_positions, (uchar*) restore_from->best_positions, sizeof(POSITION) * (table_count + 1)); /* Restore SJM nests */ diff --git a/sql/table.cc b/sql/table.cc index 2381343bc66..11da1b0bd94 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -1465,7 +1465,11 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head, if ((uchar)field_type == (uchar)MYSQL_TYPE_VIRTUAL) { - DBUG_ASSERT(interval_nr); // Expect non-null expression + if (!interval_nr) // Expect non-null expression + { + error= 4; + goto err; + } /* The interval_id byte in the .frm file stores the length of the expression statement for a virtual column. @@ -5261,6 +5265,8 @@ Item *create_view_field(THD *thd, TABLE_LIST *view, Item **field_ref, Item *item= new Item_direct_view_ref(&view->view->select_lex.context, field_ref, view->alias, name, view); + if (!item) + return NULL; /* Force creation of nullable item for the result tmp table for outer joined views/derived tables. @@ -5490,7 +5496,7 @@ Field_iterator_table_ref::get_or_create_column_ref(THD *thd, TABLE_LIST *parent_ nj_col= natural_join_it.column_ref(); DBUG_ASSERT(nj_col); } - DBUG_ASSERT(!nj_col->table_field || + DBUG_ASSERT(!nj_col->table_field || !nj_col->table_field->field || nj_col->table_ref->table == nj_col->table_field->field->table); /* @@ -5539,7 +5545,7 @@ Field_iterator_table_ref::get_or_create_column_ref(THD *thd, TABLE_LIST *parent_ RETURN # Pointer to a column of a natural join (or its operand) - NULL No memory to allocate the column + NULL We didn't originally have memory to allocate the column */ Natural_join_column * @@ -5555,7 +5561,7 @@ Field_iterator_table_ref::get_natural_column_ref() */ nj_col= natural_join_it.column_ref(); DBUG_ASSERT(nj_col && - (!nj_col->table_field || + (!nj_col->table_field || !nj_col->table_field->field || nj_col->table_ref->table == nj_col->table_field->field->table)); return nj_col; } @@ -6063,6 +6069,14 @@ void TABLE::create_key_part_by_field(KEY_PART_INFO *key_part_info, The function checks whether a possible key satisfies the constraints imposed on the keys of any temporary table. + We need to filter out BLOB columns here, because ref access optimizer creates + KEYUSE objects for equalities for non-key columns for two puproses: + 1. To discover possible keys for derived_with_keys optimization + 2. To do hash joins + For the purpose of #1, KEYUSE objects are not created for "blob_column=..." . + However, they might be created for #2. In order to catch that case, we filter + them out here. + @return TRUE if the key is valid @return FALSE otherwise */ @@ -6078,11 +6092,12 @@ bool TABLE::check_tmp_key(uint key, uint key_parts, { uint fld_idx= next_field_no(arg); reg_field= field + fld_idx; + if ((*reg_field)->type() == MYSQL_TYPE_BLOB) + return FALSE; uint fld_store_len= (uint16) (*reg_field)->key_length(); if ((*reg_field)->real_maybe_null()) fld_store_len+= HA_KEY_NULL_LENGTH; - if ((*reg_field)->type() == MYSQL_TYPE_BLOB || - (*reg_field)->real_type() == MYSQL_TYPE_VARCHAR || + if ((*reg_field)->real_type() == MYSQL_TYPE_VARCHAR || (*reg_field)->type() == MYSQL_TYPE_GEOMETRY) fld_store_len+= HA_KEY_BLOB_LENGTH; key_len+= fld_store_len; |