Merge branch '10.2' of github.com:MariaDB/server into bb-10.2-mariarocks

This commit is contained in:
Sergei Petrunia 2017-04-04 17:12:06 +03:00
commit fb0b3640fe
17 changed files with 1965 additions and 151 deletions

View file

@ -1662,6 +1662,7 @@ public:
void add_key_fields(JOIN *join, KEY_FIELD **key_fields, uint *and_level,
table_map usable_tables, SARGABLE_PARAM **sargables);
SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr);
SEL_TREE *get_func_row_mm_tree(RANGE_OPT_PARAM *param, Item_row *key_row);
Item* propagate_equal_fields(THD *thd, const Context &ctx, COND_EQUAL *cond)
{
/*
@ -1714,6 +1715,7 @@ public:
cmp_item *make_same();
void store_value_by_template(THD *thd, cmp_item *tmpl, Item *);
friend void Item_func_in::fix_length_and_dec();
cmp_item *get_comparator(uint i) { return comparators[i]; }
};
@ -1727,6 +1729,7 @@ public:
uchar *get_value(Item *item);
friend void Item_func_in::fix_length_and_dec();
Item_result result_type() { return ROW_RESULT; }
cmp_item *get_cmp_item() { return &tmp; }
};
/* Functions used by where clause */

View file

@ -119,6 +119,13 @@ public:
bool check_cols(uint c);
bool null_inside() { return with_null; };
void bring_value();
Item* propagate_equal_fields(THD *thd, const Context &ctx, COND_EQUAL *cond)
{
Item_args::propagate_equal_fields(thd, Context_identity(), cond);
return this;
}
bool check_vcol_func_processor(void *arg) {return FALSE; }
Item *get_copy(THD *thd, MEM_ROOT *mem_root)
{ return get_item_copy<Item_row>(thd, mem_root, this); }

View file

@ -7210,6 +7210,205 @@ SEL_TREE *Item_func_in::get_func_mm_tree(RANGE_OPT_PARAM *param,
}
/*
The structure Key_col_info is purely auxiliary and is used
only in the method Item_func_in::get_func_row_mm_tree
*/
struct Key_col_info {
Field *field; /* If != NULL the column can be used for keys */
cmp_item *comparator; /* If != 0 the column can be evaluated */
};
/**
Build SEL_TREE for the IN predicate whose arguments are rows
@param param PARAM from SQL_SELECT::test_quick_select
@param key_row First operand of the IN predicate
@note
The function builds a SEL_TREE for in IN predicate in the case
when the predicate uses row arguments. First the function
detects among the components of the key_row (c[1],...,c[n]) taken
from in the left part the predicate those that can be usable
for building SEL_TREE (c[i1],...,c[ik]). They have to contain
items whose real items are field items referring to the current
table or equal to the items referring to the current table.
For the remaining components of the row it checks whether they
can be evaluated. The result of the analysis is put into the
array of structures of the type Key_row_col_info.
After this the function builds the SEL_TREE for the following
formula that can be inferred from the given IN predicate:
c[i11]=a[1][i11] AND ... AND c[i1k1]=a[1][i1k1]
OR
...
OR
c[im1]=a[m][im1] AND ... AND c[imkm]=a[m][imkm].
Here a[1],...,a[m] are all arguments of the IN predicate from
the right part and for each j ij1,...,ijkj is a subset of
i1,...,ik such that a[j][ij1],...,a[j][ijkj] can be evaluated.
If for some j there no a[j][i1],...,a[j][ik] can be evaluated
then no SEL_TREE can be built for this predicate and the
function immediately returns 0.
If for some j by using evaluated values of key_row it can be
proven that c[ij1]=a[j][ij1] AND ... AND c[ijkj]=a[j][ijkj]
is always FALSE then this disjunct is omitted.
@returns
the built SEL_TREE if it can be constructed
0 - otherwise.
*/
SEL_TREE *Item_func_in::get_func_row_mm_tree(RANGE_OPT_PARAM *param,
Item_row *key_row)
{
DBUG_ENTER("Item_func_in::get_func_row_mm_tree");
if (negated)
DBUG_RETURN(0);
SEL_TREE *res_tree= 0;
uint used_key_cols= 0;
uint col_comparators= 0;
table_map param_comp= ~(param->prev_tables | param->read_tables |
param->current_table);
uint row_cols= key_row->cols();
Dynamic_array <Key_col_info> key_cols_info(row_cols);
cmp_item_row *row_cmp_item= (cmp_item_row *)
(array ? ((in_row *) array)->get_cmp_item() :
cmp_items[(uint) ROW_RESULT]);
Item **key_col_ptr= key_row->addr(0);
for(uint i= 0; i < row_cols; i++, key_col_ptr++)
{
Key_col_info key_col_info= {0, NULL};
Item *key_col= *key_col_ptr;
if (key_col->real_item()->type() == Item::FIELD_ITEM)
{
/*
The i-th component of key_row can be used for key access if
key_col->real_item() points to a field of the current table or
if it is equal to a field item pointing to such a field.
*/
Item_field *col_field_item= (Item_field *) (key_col->real_item());
Field *key_col_field= col_field_item->field;
if (key_col_field->table->map != param->current_table)
{
Item_equal *item_equal= col_field_item->item_equal;
if (item_equal)
{
Item_equal_fields_iterator it(*item_equal);
while (it++)
{
key_col_field= it.get_curr_field();
if (key_col_field->table->map == param->current_table)
break;
}
}
}
if (key_col_field->table->map == param->current_table)
{
key_col_info.field= key_col_field;
used_key_cols++;
}
}
else if (!(key_col->used_tables() & (param_comp | param->current_table))
&& !key_col->is_expensive())
{
/* The i-th component of key_row can be evaluated */
/* See the comment in Item::get_mm_tree_for_const */
MEM_ROOT *tmp_root= param->mem_root;
param->thd->mem_root= param->old_root;
key_col->bring_value();
key_col_info.comparator= row_cmp_item->get_comparator(i);
key_col_info.comparator->store_value(key_col);
col_comparators++;
param->thd->mem_root= tmp_root;
}
key_cols_info.push(key_col_info);
}
if (!used_key_cols)
DBUG_RETURN(0);
uint omitted_tuples= 0;
Item **arg_start= arguments() + 1;
Item **arg_end= arg_start + argument_count() - 1;
for (Item **arg= arg_start ; arg < arg_end; arg++)
{
uint i;
/*
First check whether the disjunct constructed for *arg
is really needed
*/
Item_row *arg_tuple= (Item_row *) (*arg);
if (col_comparators)
{
MEM_ROOT *tmp_root= param->mem_root;
param->thd->mem_root= param->old_root;
for (i= 0; i < row_cols; i++)
{
Key_col_info *key_col_info= &key_cols_info.at(i);
if (key_col_info->comparator)
{
Item *arg_col= arg_tuple->element_index(i);
if (!(arg_col->used_tables() & (param_comp | param->current_table)) &&
!arg_col->is_expensive() &&
key_col_info->comparator->cmp(arg_col))
{
omitted_tuples++;
break;
}
}
}
param->thd->mem_root= tmp_root;
if (i < row_cols)
continue;
}
/* The disjunct for *arg is needed: build it. */
SEL_TREE *and_tree= 0;
Item **arg_col_ptr= arg_tuple->addr(0);
for (uint i= 0; i < row_cols; i++, arg_col_ptr++)
{
Key_col_info *key_col_info= &key_cols_info.at(i);
if (!key_col_info->field)
continue;
Item *arg_col= *arg_col_ptr;
if (!(arg_col->used_tables() & (param_comp | param->current_table)) &&
!arg_col->is_expensive())
{
and_tree= tree_and(param, and_tree,
get_mm_parts(param,
key_col_info->field,
Item_func::EQ_FUNC,
arg_col->real_item()));
}
}
if (!and_tree)
{
res_tree= 0;
break;
}
/* Join the disjunct the the OR tree that is being constructed */
res_tree= !res_tree ? and_tree : tree_or(param, res_tree, and_tree);
}
if (omitted_tuples == argument_count() - 1)
{
/* It's turned out that all disjuncts are always FALSE */
res_tree= new (param->mem_root) SEL_TREE(SEL_TREE::IMPOSSIBLE,
param->mem_root, param->keys);
}
DBUG_RETURN(res_tree);
}
/*
Build conjunction of all SEL_TREEs for a simple predicate applying equalities
@ -7544,12 +7743,22 @@ SEL_TREE *Item_func_in::get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr)
if (const_item())
DBUG_RETURN(get_mm_tree_for_const(param));
if (key_item()->real_item()->type() != Item::FIELD_ITEM)
SEL_TREE *tree= 0;
switch (key_item()->real_item()->type()) {
case Item::FIELD_ITEM:
tree= get_full_func_mm_tree(param,
(Item_field*) (key_item()->real_item()),
NULL);
break;
case Item::ROW_ITEM:
tree= get_func_row_mm_tree(param,
(Item_row *) (key_item()->real_item()));
break;
default:
DBUG_RETURN(0);
Item_field *field= (Item_field*) (key_item()->real_item());
SEL_TREE *tree= get_full_func_mm_tree(param, field, NULL);
}
DBUG_RETURN(tree);
}
}
SEL_TREE *Item_equal::get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr)

View file

@ -4709,6 +4709,8 @@ static uint get_semi_join_select_list_index(Field *field)
@param num_values Number of values[] that we are comparing against
@param usable_tables Tables which can be used for key optimization
@param sargables IN/OUT Array of found sargable candidates
@param row_col_no if = n that > 0 then field is compared only
against the n-th component of row values
@note
If we are doing a NOT NULL comparison on a NOT NULL field in a outer join
@ -4722,7 +4724,8 @@ static void
add_key_field(JOIN *join,
KEY_FIELD **key_fields,uint and_level, Item_bool_func *cond,
Field *field, bool eq_func, Item **value, uint num_values,
table_map usable_tables, SARGABLE_PARAM **sargables)
table_map usable_tables, SARGABLE_PARAM **sargables,
uint row_col_no= 0)
{
uint optimize= 0;
if (eq_func &&
@ -4751,7 +4754,15 @@ add_key_field(JOIN *join,
bool optimizable=0;
for (uint i=0; i<num_values; i++)
{
table_map value_used_tables= (value[i])->used_tables();
Item *curr_val;
if (row_col_no && value[i]->real_item()->type() == Item::ROW_ITEM)
{
Item_row *value_tuple= (Item_row *) (value[i]->real_item());
curr_val= value_tuple->element_index(row_col_no - 1);
}
else
curr_val= value[i];
table_map value_used_tables= curr_val->used_tables();
used_tables|= value_used_tables;
if (!(value_used_tables & (field->table->map | RAND_TABLE_BIT)))
optimizable=1;
@ -4789,7 +4800,15 @@ add_key_field(JOIN *join,
bool is_const=1;
for (uint i=0; i<num_values; i++)
{
if (!(is_const&= value[i]->const_item()))
Item *curr_val;
if (row_col_no && value[i]->real_item()->type() == Item::ROW_ITEM)
{
Item_row *value_tuple= (Item_row *) (value[i]->real_item());
curr_val= value_tuple->element_index(row_col_no - 1);
}
else
curr_val= value[i];
if (!(is_const&= curr_val->const_item()))
break;
}
if (is_const)
@ -4856,12 +4875,14 @@ add_key_field(JOIN *join,
@param key_fields Pointer to add key, if usable
@param and_level And level, to be stored in KEY_FIELD
@param cond Condition predicate
@param field Field used in comparision
@param field_item Field item used for comparison
@param eq_func True if we used =, <=> or IS NULL
@param value Value used for comparison with field
Is NULL for BETWEEN and IN
@param value Value used for comparison with field_item
@param num_values Number of values[] that we are comparing against
@param usable_tables Tables which can be used for key optimization
@param sargables IN/OUT Array of found sargable candidates
@param row_col_no if = n that > 0 then field is compared only
against the n-th component of row values
@note
If field items f1 and f2 belong to the same multiple equality and
@ -4876,11 +4897,12 @@ add_key_equal_fields(JOIN *join, KEY_FIELD **key_fields, uint and_level,
Item_bool_func *cond, Item *field_item,
bool eq_func, Item **val,
uint num_values, table_map usable_tables,
SARGABLE_PARAM **sargables)
SARGABLE_PARAM **sargables, uint row_col_no= 0)
{
Field *field= ((Item_field *) (field_item->real_item()))->field;
add_key_field(join, key_fields, and_level, cond, field,
eq_func, val, num_values, usable_tables, sargables);
eq_func, val, num_values, usable_tables, sargables,
row_col_no);
Item_equal *item_equal= field_item->get_item_equal();
if (item_equal)
{
@ -4896,7 +4918,7 @@ add_key_equal_fields(JOIN *join, KEY_FIELD **key_fields, uint and_level,
{
add_key_field(join, key_fields, and_level, cond, equal_field,
eq_func, val, num_values, usable_tables,
sargables);
sargables, row_col_no);
}
}
}
@ -5078,6 +5100,24 @@ Item_func_in::add_key_fields(JOIN *join, KEY_FIELD **key_fields,
(Item_field*) (args[0]->real_item()), false,
args + 1, arg_count - 1, usable_tables, sargables);
}
else if (key_item()->type() == Item::ROW_ITEM &&
!(used_tables() & OUTER_REF_TABLE_BIT))
{
Item_row *key_row= (Item_row *) key_item();
Item **key_col= key_row->addr(0);
uint row_cols= key_row->cols();
for (uint i= 0; i < row_cols; i++, key_col++)
{
if (is_local_field(*key_col))
{
Item_field *field_item= (Item_field *)((*key_col)->real_item());
add_key_equal_fields(join, key_fields, *and_level, this,
field_item, false, args + 1, arg_count - 1,
usable_tables, sargables, i + 1);
}
}
}
}