1
0
mirror of https://github.com/MariaDB/server.git synced 2025-08-01 03:47:19 +03:00

Merge 5.5->mwl248

This commit is contained in:
Igor Babaev
2012-12-04 19:04:25 -08:00
120 changed files with 4954 additions and 522 deletions

View File

@ -1233,11 +1233,9 @@ JOIN::optimize()
DBUG_RETURN(1); // error == -1
}
if (const_table_map != found_const_table_map &&
!(select_options & SELECT_DESCRIBE) &&
(!conds ||
!(conds->used_tables() & RAND_TABLE_BIT) ||
select_lex->master_unit() == &thd->lex->unit)) // upper level SELECT
!(select_options & SELECT_DESCRIBE))
{
// There is at least one empty const table
zero_result_cause= "no matching row in const table";
DBUG_PRINT("error",("Error: %s", zero_result_cause));
error= 0;
@ -5380,7 +5378,8 @@ best_access_path(JOIN *join,
!ref_or_null_part)
{ /* use eq key */
max_key_part= (uint) ~0;
if ((key_flags & (HA_NOSAME | HA_NULL_PART_KEY)) == HA_NOSAME)
if ((key_flags & (HA_NOSAME | HA_NULL_PART_KEY)) == HA_NOSAME ||
test(key_flags & HA_EXT_NOSAME))
{
tmp = prev_record_reads(join->positions, idx, found_ref);
records=1.0;
@ -7969,18 +7968,23 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j,
*ref_key=0; // end_marker
if (j->type == JT_FT)
DBUG_RETURN(0);
ulong key_flags= j->table->actual_key_flags(keyinfo);
if (j->type == JT_CONST)
j->table->const_table= 1;
else if (((j->table->actual_key_flags(keyinfo) &
(HA_NOSAME | HA_NULL_PART_KEY))
!= HA_NOSAME) ||
else if (((key_flags & (HA_NOSAME | HA_NULL_PART_KEY))!= HA_NOSAME) ||
keyparts != j->table->actual_n_key_parts(keyinfo) ||
null_ref_key)
{
/* Must read with repeat */
j->type= null_ref_key ? JT_REF_OR_NULL : JT_REF;
j->ref.null_ref_key= null_ref_key;
j->ref.null_ref_part= null_ref_part;
if (test(key_flags & HA_EXT_NOSAME) && keyparts == keyinfo->ext_key_parts &&
!null_ref_key)
j->type= JT_EQ_REF;
else
{
/* Must read with repeat */
j->type= null_ref_key ? JT_REF_OR_NULL : JT_REF;
j->ref.null_ref_key= null_ref_key;
j->ref.null_ref_part= null_ref_part;
}
}
else if (keyuse_uses_no_tables)
{
@ -9140,7 +9144,7 @@ void JOIN::drop_unused_derived_keys()
JOIN_TAB *tab;
for (tab= first_linear_tab(this, WITHOUT_CONST_TABLES);
tab;
tab= next_linear_tab(this, tab, WITHOUT_BUSH_ROOTS))
tab= next_linear_tab(this, tab, WITH_BUSH_ROOTS))
{
TABLE *table=tab->table;
@ -10606,9 +10610,22 @@ void JOIN::cleanup(bool full)
if (full)
{
JOIN_TAB *sort_tab= first_linear_tab(this, WITHOUT_CONST_TABLES);
if (pre_sort_join_tab)
{
if (sort_tab && sort_tab->select == pre_sort_join_tab->select)
{
pre_sort_join_tab->select= NULL;
}
else
clean_pre_sort_join_tab();
}
for (tab= first_linear_tab(this, WITH_CONST_TABLES); tab;
tab= next_linear_tab(this, tab, WITH_BUSH_ROOTS))
{
tab->cleanup();
}
}
else
{
@ -16488,6 +16505,17 @@ int safe_index_read(JOIN_TAB *tab)
}
/**
Reads content of constant table
@param tab table
@param pos position of table in query plan
@retval 0 ok, one row was found or one NULL-complemented row was created
@retval -1 ok, no row was found and no NULL-complemented row was created
@retval 1 error
*/
static int
join_read_const_table(JOIN_TAB *tab, POSITION *pos)
{
@ -16606,6 +16634,16 @@ join_read_const_table(JOIN_TAB *tab, POSITION *pos)
}
/**
Read a constant table when there is at most one matching row, using a table
scan.
@param tab Table to read
@retval 0 Row was found
@retval -1 Row was not found
@retval 1 Got an error (other than row not found) during read
*/
static int
join_read_system(JOIN_TAB *tab)
{
@ -16638,12 +16676,9 @@ join_read_system(JOIN_TAB *tab)
@param tab Table to read
@retval
0 Row was found
@retval
-1 Row was not found
@retval
1 Got an error (other than row not found) during read
@retval 0 Row was found
@retval -1 Row was not found
@retval 1 Got an error (other than row not found) during read
*/
static int
@ -18478,15 +18513,18 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
*/
if (quick_type == QUICK_SELECT_I::QS_TYPE_INDEX_MERGE ||
quick_type == QUICK_SELECT_I::QS_TYPE_INDEX_INTERSECT ||
quick_type == QUICK_SELECT_I::QS_TYPE_INDEX_INTERSECT ||
quick_type == QUICK_SELECT_I::QS_TYPE_ROR_UNION ||
quick_type == QUICK_SELECT_I::QS_TYPE_ROR_INTERSECT)
goto use_filesort;
ref_key= select->quick->index;
ref_key_parts= select->quick->used_key_parts;
ref_key= MAX_KEY;
else
{
ref_key= select->quick->index;
ref_key_parts= select->quick->used_key_parts;
}
}
if (ref_key >= 0)
if (ref_key >= 0 && ref_key != MAX_KEY)
{
/*
We come here when there is a REF key.
@ -18858,6 +18896,8 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order,
TABLE *table;
SQL_SELECT *select;
JOIN_TAB *tab;
int err= 0;
bool quick_created= FALSE;
DBUG_ENTER("create_sort_index");
if (join->table_count == join->const_tables)
@ -18865,18 +18905,61 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order,
tab= join->join_tab + join->const_tables;
table= tab->table;
select= tab->select;
JOIN_TAB *save_pre_sort_join_tab= NULL;
if (join->pre_sort_join_tab)
{
/*
we've already been in this function, and stashed away the original access
method in join->pre_sort_join_tab, restore it now.
*/
/* First, restore state of the handler */
if (join->pre_sort_index != MAX_KEY)
{
if (table->file->ha_index_or_rnd_end())
goto err;
if (join->pre_sort_idx_pushed_cond)
{
table->file->idx_cond_push(join->pre_sort_index,
join->pre_sort_idx_pushed_cond);
}
}
else
{
if (table->file->ha_index_or_rnd_end() ||
table->file->ha_rnd_init(TRUE))
goto err;
}
/* Second, restore access method parameters */
tab->records= join->pre_sort_join_tab->records;
tab->select= join->pre_sort_join_tab->select;
tab->select_cond= join->pre_sort_join_tab->select_cond;
tab->type= join->pre_sort_join_tab->type;
tab->read_first_record= join->pre_sort_join_tab->read_first_record;
save_pre_sort_join_tab= join->pre_sort_join_tab;
join->pre_sort_join_tab= NULL;
}
else
{
/*
Save index #, save index condition. Do it right now, because MRR may
*/
if (table->file->inited == handler::INDEX)
{
join->pre_sort_index= table->file->active_index;
join->pre_sort_idx_pushed_cond= table->file->pushed_idx_cond;
// no need to save key_read
}
else
join->pre_sort_index= MAX_KEY;
}
/* Currently ORDER BY ... LIMIT is not supported in subqueries. */
DBUG_ASSERT(join->group_list || !join->is_in_subquery());
/*
If we have a select->quick object that is created outside of
create_sort_index() and this is part of a subquery that
potentially can be executed multiple times then we should not
delete the quick object on exit from this function.
*/
bool keep_quick= select && select->quick && join->join_tab_save;
/*
When there is SQL_BIG_RESULT do not sort using index for GROUP BY,
and thus force sorting on disk unless a group min-max optimization
@ -18928,7 +19011,7 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order,
get_quick_select_for_ref(thd, table, &tab->ref,
tab->found_records))))
goto err;
DBUG_ASSERT(!keep_quick);
quick_created= TRUE;
}
}
@ -18944,7 +19027,27 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order,
table->sort.found_records=filesort(thd, table,join->sortorder, length,
select, filesort_limit, 0,
&examined_rows);
if (quick_created)
{
/* This will delete the quick select. */
select->cleanup();
}
if (!join->pre_sort_join_tab)
{
if (save_pre_sort_join_tab)
join->pre_sort_join_tab= save_pre_sort_join_tab;
else if (!(join->pre_sort_join_tab= (JOIN_TAB*)thd->alloc(sizeof(JOIN_TAB))))
goto err;
}
*(join->pre_sort_join_tab)= *tab;
/*TODO: here, close the index scan, cancel index-only read. */
tab->records= table->sort.found_records; // For SQL_CALC_ROWS
#if 0
/* MariaDB doesn't need the following: */
if (select)
{
/*
@ -18961,6 +19064,7 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order,
tablesort_result_cache= table->sort.io_cache;
table->sort.io_cache= NULL;
// select->cleanup(); // filesort did select
/*
If a quick object was created outside of create_sort_index()
that might be reused, then do not call select->cleanup() since
@ -18983,18 +19087,61 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order,
// Restore the output resultset
table->sort.io_cache= tablesort_result_cache;
}
#endif
tab->select=NULL;
tab->set_select_cond(NULL, __LINE__);
tab->last_inner= 0;
tab->first_unmatched= 0;
tab->type=JT_ALL; // Read with normal read_record
tab->read_first_record= join_init_read_record;
tab->table->file->ha_index_or_rnd_end();
if (err)
goto err;
tab->join->examined_rows+=examined_rows;
table->disable_keyread(); // Restore if we used indexes
DBUG_RETURN(table->sort.found_records == HA_POS_ERROR);
err:
DBUG_RETURN(-1);
}
void JOIN::clean_pre_sort_join_tab()
{
//TABLE *table= pre_sort_join_tab->table;
/*
Note: we can come here for fake_select_lex object. That object will have
the table already deleted by st_select_lex_unit::cleanup().
We rely on that fake_select_lex didn't have quick select.
*/
#if 0
if (pre_sort_join_tab->select && pre_sort_join_tab->select->quick)
{
/*
We need to preserve tablesort's output resultset here, because
QUICK_INDEX_MERGE_SELECT::~QUICK_INDEX_MERGE_SELECT (called by
SQL_SELECT::cleanup()) may free it assuming it's the result of the quick
select operation that we no longer need. Note that all the other parts of
this data structure are cleaned up when
QUICK_INDEX_MERGE_SELECT::get_next encounters end of data, so the next
SQL_SELECT::cleanup() call changes sort.io_cache alone.
*/
IO_CACHE *tablesort_result_cache;
tablesort_result_cache= table->sort.io_cache;
table->sort.io_cache= NULL;
pre_sort_join_tab->select->cleanup();
table->quick_keys.clear_all(); // as far as we cleanup select->quick
table->intersect_keys.clear_all();
table->sort.io_cache= tablesort_result_cache;
}
#endif
//table->disable_keyread(); // Restore if we used indexes
if (pre_sort_join_tab->select && pre_sort_join_tab->select->quick)
{
pre_sort_join_tab->select->cleanup();
}
}
/*****************************************************************************
Remove duplicates from tmp table
This should be recoded to add a unique index to the table and remove
@ -20474,40 +20621,66 @@ change_to_use_tmp_fields(THD *thd, Item **ref_pointer_array,
res_selected_fields.empty();
res_all_fields.empty();
uint i, border= all_fields.elements - elements;
for (i= 0; (item= it++); i++)
uint border= all_fields.elements - elements;
for (uint i= 0; (item= it++); i++)
{
Field *field;
if ((item->with_sum_func && item->type() != Item::SUM_FUNC_ITEM) ||
(item->type() == Item::FUNC_ITEM &&
((Item_func*)item)->functype() == Item_func::SUSERVAR_FUNC))
if (item->with_sum_func && item->type() != Item::SUM_FUNC_ITEM)
item_field= item;
else
else if (item->type() == Item::FIELD_ITEM)
item_field= item->get_tmp_table_item(thd);
else if (item->type() == Item::FUNC_ITEM &&
((Item_func*)item)->functype() == Item_func::SUSERVAR_FUNC)
{
if (item->type() == Item::FIELD_ITEM)
field= item->get_tmp_table_field();
if (field != NULL)
{
item_field= item->get_tmp_table_item(thd);
/*
Replace "@:=<expression>" with "@:=<tmp table column>". Otherwise,
we would re-evaluate <expression>, and if expression were
a subquery, this would access already-unlocked tables.
*/
Item_func_set_user_var* suv=
new Item_func_set_user_var((Item_func_set_user_var*) item);
Item_field *new_field= new Item_field(field);
if (!suv || !new_field || suv->fix_fields(thd, (Item**)&suv))
DBUG_RETURN(true); // Fatal error
((Item *)suv)->name= item->name;
/*
We are replacing the argument of Item_func_set_user_var after its
value has been read. The argument's null_value should be set by
now, so we must set it explicitly for the replacement argument
since the null_value may be read without any preceeding call to
val_*().
*/
new_field->update_null_value();
List<Item> list;
list.push_back(new_field);
suv->set_arguments(list);
item_field= suv;
}
else if ((field= item->get_tmp_table_field()))
{
if (item->type() == Item::SUM_FUNC_ITEM && field->table->group)
item_field= ((Item_sum*) item)->result_item(field);
else
item_field= (Item*) new Item_field(field);
if (!item_field)
DBUG_RETURN(TRUE); // Fatal error
else
item_field= item;
}
else if ((field= item->get_tmp_table_field()))
{
if (item->type() == Item::SUM_FUNC_ITEM && field->table->group)
item_field= ((Item_sum*) item)->result_item(field);
else
item_field= (Item*) new Item_field(field);
if (!item_field)
DBUG_RETURN(true); // Fatal error
if (item->real_item()->type() != Item::FIELD_ITEM)
field->orig_table= 0;
item_field->name= item->name;
if (item->type() == Item::REF_ITEM)
{
Item_field *ifield= (Item_field *) item_field;
Item_ref *iref= (Item_ref *) item;
ifield->table_name= iref->table_name;
ifield->db_name= iref->db_name;
}
if (item->real_item()->type() != Item::FIELD_ITEM)
field->orig_table= 0;
item_field->name= item->name;
if (item->type() == Item::REF_ITEM)
{
Item_field *ifield= (Item_field *) item_field;
Item_ref *iref= (Item_ref *) item;
ifield->table_name= iref->table_name;
ifield->db_name= iref->db_name;
}
#ifndef DBUG_OFF
if (!item_field->name)
{
@ -20519,20 +20692,20 @@ change_to_use_tmp_fields(THD *thd, Item **ref_pointer_array,
item_field->name= sql_strmake(str.ptr(),str.length());
}
#endif
}
else
item_field= item;
}
else
item_field= item;
res_all_fields.push_back(item_field);
ref_pointer_array[((i < border)? all_fields.elements-i-1 : i-border)]=
item_field;
}
List_iterator_fast<Item> itr(res_all_fields);
for (i= 0; i < border; i++)
for (uint i= 0; i < border; i++)
itr++;
itr.sublist(res_selected_fields, elements);
DBUG_RETURN(FALSE);
DBUG_RETURN(false);
}
@ -22712,6 +22885,7 @@ test_if_cheaper_ordering(const JOIN_TAB *tab, ORDER *order, TABLE *table,
ha_rows table_records= table->stat_records();
bool group= join && join->group && order == join->group_list;
ha_rows ref_key_quick_rows= HA_POS_ERROR;
const bool has_limit= (select_limit_arg != HA_POS_ERROR);
/*
If not used with LIMIT, only use keys if the whole query can be
@ -22736,7 +22910,8 @@ test_if_cheaper_ordering(const JOIN_TAB *tab, ORDER *order, TABLE *table,
else
keys= usable_keys;
if (ref_key >= 0 && table->covering_keys.is_set(ref_key))
if (ref_key >= 0 && ref_key != MAX_KEY &&
table->covering_keys.is_set(ref_key))
ref_key_quick_rows= table->quick_rows[ref_key];
if (join)
@ -22843,7 +23018,7 @@ test_if_cheaper_ordering(const JOIN_TAB *tab, ORDER *order, TABLE *table,
be included into the result set.
*/
if (select_limit > table_records/rec_per_key)
select_limit= table_records;
select_limit= table_records;
else
select_limit= (ha_rows) (select_limit*rec_per_key);
} /* group */
@ -22925,7 +23100,7 @@ test_if_cheaper_ordering(const JOIN_TAB *tab, ORDER *order, TABLE *table,
*new_key= best_key;
*new_key_direction= best_key_direction;
*new_select_limit= best_select_limit;
*new_select_limit= has_limit ? best_select_limit : table_records;
if (new_used_key_parts != NULL)
*new_used_key_parts= best_key_parts;