summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorJan Lindström <jan.lindstrom@mariadb.com>2018-08-01 10:58:38 +0300
committerJan Lindström <jan.lindstrom@mariadb.com>2018-08-01 10:58:38 +0300
commitb286a9f8238c4b441d3e42d2b56ba3d5f563bfb1 (patch)
tree246c97d3410914ca3d7c85dc0a72a32844ee8c6c /sql
parent33e39f0682d966f67aa403a0be9bc7dbd44a69e6 (diff)
parenta49ec980422e04ce1a37344be09aa6254f16fa2a (diff)
downloadmariadb-git-b286a9f8238c4b441d3e42d2b56ba3d5f563bfb1.tar.gz
Merge tag 'mariadb-5.5.61' into 5.5-galera
Diffstat (limited to 'sql')
-rw-r--r--sql/item.cc18
-rw-r--r--sql/item.h6
-rw-r--r--sql/item_cmpfunc.cc43
-rw-r--r--sql/item_func.cc1
-rw-r--r--sql/item_func.h7
-rw-r--r--sql/item_row.cc1
-rw-r--r--sql/item_sum.cc3
-rw-r--r--sql/log.cc10
-rw-r--r--sql/opt_subselect.cc96
-rw-r--r--sql/sql_acl.cc105
-rw-r--r--sql/sql_base.cc15
-rw-r--r--sql/sql_handler.cc1
-rw-r--r--sql/sql_select.cc92
-rw-r--r--sql/table.cc27
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;