mirror of
https://github.com/MariaDB/server.git
synced 2026-05-15 11:27:39 +02:00
Merge branch '10.2' of github.com:MariaDB/server into bb-10.2-mariarocks
This commit is contained in:
commit
fb0b3640fe
17 changed files with 1965 additions and 151 deletions
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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); }
|
||||
|
|
|
|||
217
sql/opt_range.cc
217
sql/opt_range.cc
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue