mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +03:00
Manual merge with implementation for WL#1724
This commit is contained in:
@ -1672,8 +1672,9 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
|
|||||||
if (!head->used_keys.is_clear_all())
|
if (!head->used_keys.is_clear_all())
|
||||||
{
|
{
|
||||||
int key_for_use= find_shortest_key(head, &head->used_keys);
|
int key_for_use= find_shortest_key(head, &head->used_keys);
|
||||||
double key_read_time= get_index_only_read_time(¶m, records,
|
double key_read_time= (get_index_only_read_time(¶m, records,
|
||||||
key_for_use);
|
key_for_use) +
|
||||||
|
(double) records / TIME_FOR_COMPARE);
|
||||||
DBUG_PRINT("info", ("'all'+'using index' scan will be using key %d, "
|
DBUG_PRINT("info", ("'all'+'using index' scan will be using key %d, "
|
||||||
"read time %g", key_for_use, key_read_time));
|
"read time %g", key_for_use, key_read_time));
|
||||||
if (key_read_time < read_time)
|
if (key_read_time < read_time)
|
||||||
@ -2176,6 +2177,12 @@ skip_to_ror_scan:
|
|||||||
assumed that each time we read the next key from the index, the handler
|
assumed that each time we read the next key from the index, the handler
|
||||||
performs a random seek, thus the cost is proportional to the number of
|
performs a random seek, thus the cost is proportional to the number of
|
||||||
blocks read.
|
blocks read.
|
||||||
|
|
||||||
|
TODO:
|
||||||
|
Move this to handler->read_time() by adding a flag 'index-only-read' to
|
||||||
|
this call. The reason for doing this is that the current function doesn't
|
||||||
|
handle the case when the row is stored in the b-tree (like in innodb
|
||||||
|
clustered index)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
inline double get_index_only_read_time(const PARAM* param, ha_rows records,
|
inline double get_index_only_read_time(const PARAM* param, ha_rows records,
|
||||||
@ -2190,6 +2197,7 @@ inline double get_index_only_read_time(const PARAM* param, ha_rows records,
|
|||||||
return read_time;
|
return read_time;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
typedef struct st_ror_scan_info
|
typedef struct st_ror_scan_info
|
||||||
{
|
{
|
||||||
uint idx; /* # of used key in param->keys */
|
uint idx; /* # of used key in param->keys */
|
||||||
@ -3056,22 +3064,24 @@ static TRP_RANGE *get_key_scans_params(PARAM *param, SEL_TREE *tree,
|
|||||||
tree->n_ror_scans++;
|
tree->n_ror_scans++;
|
||||||
tree->ror_scans_map.set_bit(idx);
|
tree->ror_scans_map.set_bit(idx);
|
||||||
}
|
}
|
||||||
|
double cpu_cost= (double) found_records / TIME_FOR_COMPARE;
|
||||||
if (found_records != HA_POS_ERROR && found_records > 2 &&
|
if (found_records != HA_POS_ERROR && found_records > 2 &&
|
||||||
read_index_only &&
|
read_index_only &&
|
||||||
(param->table->file->index_flags(keynr, param->max_key_part,1) &
|
(param->table->file->index_flags(keynr, param->max_key_part,1) &
|
||||||
HA_KEYREAD_ONLY) &&
|
HA_KEYREAD_ONLY) &&
|
||||||
!(pk_is_clustered && keynr == param->table->primary_key))
|
!(pk_is_clustered && keynr == param->table->primary_key))
|
||||||
/* We can resolve this by only reading through this key. */
|
/* We can resolve this by only reading through this key. */
|
||||||
found_read_time= get_index_only_read_time(param,found_records,keynr);
|
found_read_time= get_index_only_read_time(param,found_records,keynr) +
|
||||||
|
cpu_cost;
|
||||||
else
|
else
|
||||||
/*
|
/*
|
||||||
cost(read_through_index) = cost(disk_io) + cost(row_in_range_checks)
|
cost(read_through_index) = cost(disk_io) + cost(row_in_range_checks)
|
||||||
The row_in_range check is in QUICK_RANGE_SELECT::cmp_next function.
|
The row_in_range check is in QUICK_RANGE_SELECT::cmp_next function.
|
||||||
*/
|
*/
|
||||||
found_read_time= (param->table->file->read_time(keynr,
|
found_read_time= param->table->file->read_time(keynr,
|
||||||
param->range_count,
|
param->range_count,
|
||||||
found_records)+
|
found_records) +
|
||||||
(double) found_records / TIME_FOR_COMPARE);
|
cpu_cost;
|
||||||
|
|
||||||
DBUG_PRINT("info",("read_time: %g found_read_time: %g",
|
DBUG_PRINT("info",("read_time: %g found_read_time: %g",
|
||||||
read_time, found_read_time));
|
read_time, found_read_time));
|
||||||
@ -3424,6 +3434,7 @@ get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part,
|
|||||||
{
|
{
|
||||||
uint maybe_null=(uint) field->real_maybe_null(), copies;
|
uint maybe_null=(uint) field->real_maybe_null(), copies;
|
||||||
uint field_length=field->pack_length()+maybe_null;
|
uint field_length=field->pack_length()+maybe_null;
|
||||||
|
bool optimize_range;
|
||||||
SEL_ARG *tree;
|
SEL_ARG *tree;
|
||||||
char *str, *str2;
|
char *str, *str2;
|
||||||
DBUG_ENTER("get_mm_leaf");
|
DBUG_ENTER("get_mm_leaf");
|
||||||
@ -3454,6 +3465,9 @@ get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part,
|
|||||||
((Field_str*)field)->charset() != conf_func->compare_collation())
|
((Field_str*)field)->charset() != conf_func->compare_collation())
|
||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
|
|
||||||
|
optimize_range= field->optimize_range(param->real_keynr[key_part->key],
|
||||||
|
key_part->part);
|
||||||
|
|
||||||
if (type == Item_func::LIKE_FUNC)
|
if (type == Item_func::LIKE_FUNC)
|
||||||
{
|
{
|
||||||
bool like_error;
|
bool like_error;
|
||||||
@ -3461,8 +3475,7 @@ get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part,
|
|||||||
String tmp(buff1,sizeof(buff1),value->collation.collation),*res;
|
String tmp(buff1,sizeof(buff1),value->collation.collation),*res;
|
||||||
uint length,offset,min_length,max_length;
|
uint length,offset,min_length,max_length;
|
||||||
|
|
||||||
if (!field->optimize_range(param->real_keynr[key_part->key],
|
if (!optimize_range)
|
||||||
key_part->part))
|
|
||||||
DBUG_RETURN(0); // Can't optimize this
|
DBUG_RETURN(0); // Can't optimize this
|
||||||
if (!(res= value->val_str(&tmp)))
|
if (!(res= value->val_str(&tmp)))
|
||||||
DBUG_RETURN(&null_element);
|
DBUG_RETURN(&null_element);
|
||||||
@ -3527,8 +3540,7 @@ get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part,
|
|||||||
DBUG_RETURN(new SEL_ARG(field,min_str,max_str));
|
DBUG_RETURN(new SEL_ARG(field,min_str,max_str));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!field->optimize_range(param->real_keynr[key_part->key],
|
if (!optimize_range &&
|
||||||
key_part->part) &&
|
|
||||||
type != Item_func::EQ_FUNC &&
|
type != Item_func::EQ_FUNC &&
|
||||||
type != Item_func::EQUAL_FUNC)
|
type != Item_func::EQUAL_FUNC)
|
||||||
DBUG_RETURN(0); // Can't optimize this
|
DBUG_RETURN(0); // Can't optimize this
|
||||||
@ -3542,7 +3554,7 @@ get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part,
|
|||||||
field->cmp_type() != value->result_type())
|
field->cmp_type() != value->result_type())
|
||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
|
|
||||||
if (value->save_in_field(field, 1) < 0)
|
if (value->save_in_field_no_warnings(field, 1) < 0)
|
||||||
{
|
{
|
||||||
/* This happens when we try to insert a NULL field in a not null column */
|
/* This happens when we try to insert a NULL field in a not null column */
|
||||||
DBUG_RETURN(&null_element); // cmp with NULL is never TRUE
|
DBUG_RETURN(&null_element); // cmp with NULL is never TRUE
|
||||||
@ -3736,14 +3748,15 @@ tree_and(PARAM *param,SEL_TREE *tree1,SEL_TREE *tree2)
|
|||||||
if (*key2 && !(*key2)->simple_key())
|
if (*key2 && !(*key2)->simple_key())
|
||||||
flag|=CLONE_KEY2_MAYBE;
|
flag|=CLONE_KEY2_MAYBE;
|
||||||
*key1=key_and(*key1,*key2,flag);
|
*key1=key_and(*key1,*key2,flag);
|
||||||
if ((*key1)->type == SEL_ARG::IMPOSSIBLE)
|
if (*key1 && (*key1)->type == SEL_ARG::IMPOSSIBLE)
|
||||||
{
|
{
|
||||||
tree1->type= SEL_TREE::IMPOSSIBLE;
|
tree1->type= SEL_TREE::IMPOSSIBLE;
|
||||||
DBUG_RETURN(tree1);
|
DBUG_RETURN(tree1);
|
||||||
}
|
}
|
||||||
result_keys.set_bit(key1 - tree1->keys);
|
result_keys.set_bit(key1 - tree1->keys);
|
||||||
#ifdef EXTRA_DEBUG
|
#ifdef EXTRA_DEBUG
|
||||||
(*key1)->test_use_count(*key1);
|
if (*key1)
|
||||||
|
(*key1)->test_use_count(*key1);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3974,6 +3987,13 @@ key_and(SEL_ARG *key1,SEL_ARG *key2,uint clone_flag)
|
|||||||
return key1;
|
return key1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((key1->min_flag | key2->min_flag) & GEOM_FLAG)
|
||||||
|
{
|
||||||
|
key1->free_tree();
|
||||||
|
key2->free_tree();
|
||||||
|
return 0; // Can't optimize this
|
||||||
|
}
|
||||||
|
|
||||||
key1->use_count--;
|
key1->use_count--;
|
||||||
key2->use_count--;
|
key2->use_count--;
|
||||||
SEL_ARG *e1=key1->first(), *e2=key2->first(), *new_tree=0;
|
SEL_ARG *e1=key1->first(), *e2=key2->first(), *new_tree=0;
|
||||||
@ -4056,7 +4076,8 @@ key_or(SEL_ARG *key1,SEL_ARG *key2)
|
|||||||
key1->use_count--;
|
key1->use_count--;
|
||||||
key2->use_count--;
|
key2->use_count--;
|
||||||
|
|
||||||
if (key1->part != key2->part)
|
if (key1->part != key2->part ||
|
||||||
|
(key1->min_flag | key2->min_flag) & GEOM_FLAG)
|
||||||
{
|
{
|
||||||
key1->free_tree();
|
key1->free_tree();
|
||||||
key2->free_tree();
|
key2->free_tree();
|
||||||
@ -4716,7 +4737,7 @@ void SEL_ARG::test_use_count(SEL_ARG *root)
|
|||||||
ulong count=count_key_part_usage(root,pos->next_key_part);
|
ulong count=count_key_part_usage(root,pos->next_key_part);
|
||||||
if (count > pos->next_key_part->use_count)
|
if (count > pos->next_key_part->use_count)
|
||||||
{
|
{
|
||||||
sql_print_error("Note: Use_count: Wrong count for key at %lx, %lu should be %lu",
|
sql_print_error("Note: Use_count: Wrong count for key at 0x%lx, %lu should be %lu",
|
||||||
pos,pos->next_key_part->use_count,count);
|
pos,pos->next_key_part->use_count,count);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -4724,7 +4745,7 @@ void SEL_ARG::test_use_count(SEL_ARG *root)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (e_count != elements)
|
if (e_count != elements)
|
||||||
sql_print_error("Warning: Wrong use count: %u (should be %u) for tree at %lx",
|
sql_print_error("Warning: Wrong use count: %u (should be %u) for tree at 0x%lx",
|
||||||
e_count, elements, (gptr) this);
|
e_count, elements, (gptr) this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -226,27 +226,13 @@ int handle_select(THD *thd, LEX *lex, select_result *result)
|
|||||||
thd->net.report_error));
|
thd->net.report_error));
|
||||||
if (thd->net.report_error)
|
if (thd->net.report_error)
|
||||||
res= 1;
|
res= 1;
|
||||||
if (res > 0)
|
if (unlikely(res))
|
||||||
{
|
{
|
||||||
if (result)
|
if (res > 0)
|
||||||
{
|
|
||||||
result->send_error(0, NullS);
|
result->send_error(0, NullS);
|
||||||
result->abort();
|
result->abort();
|
||||||
}
|
|
||||||
else
|
|
||||||
send_error(thd, 0, NullS);
|
|
||||||
res= 1; // Error sent to client
|
res= 1; // Error sent to client
|
||||||
}
|
}
|
||||||
if (res < 0)
|
|
||||||
{
|
|
||||||
if (result)
|
|
||||||
{
|
|
||||||
result->abort();
|
|
||||||
}
|
|
||||||
res= 1;
|
|
||||||
}
|
|
||||||
if (result != lex->result)
|
|
||||||
delete result;
|
|
||||||
DBUG_RETURN(res);
|
DBUG_RETURN(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -349,9 +335,7 @@ JOIN::prepare(Item ***rref_pointer_array,
|
|||||||
if ((subselect= select_lex->master_unit()->item))
|
if ((subselect= select_lex->master_unit()->item))
|
||||||
{
|
{
|
||||||
Item_subselect::trans_res res;
|
Item_subselect::trans_res res;
|
||||||
if ((res= ((!thd->lex->view_prepare_mode) ?
|
if ((res= subselect->select_transformer(this)) !=
|
||||||
subselect->select_transformer(this) :
|
|
||||||
subselect->no_select_transform())) !=
|
|
||||||
Item_subselect::RES_OK)
|
Item_subselect::RES_OK)
|
||||||
{
|
{
|
||||||
select_lex->fix_prepare_information(thd, &conds);
|
select_lex->fix_prepare_information(thd, &conds);
|
||||||
@ -553,6 +537,7 @@ JOIN::optimize()
|
|||||||
if (cond_value == Item::COND_FALSE ||
|
if (cond_value == Item::COND_FALSE ||
|
||||||
(!unit->select_limit_cnt && !(select_options & OPTION_FOUND_ROWS)))
|
(!unit->select_limit_cnt && !(select_options & OPTION_FOUND_ROWS)))
|
||||||
{ /* Impossible cond */
|
{ /* Impossible cond */
|
||||||
|
DBUG_PRINT("info", ("Impossible WHERE"));
|
||||||
zero_result_cause= "Impossible WHERE";
|
zero_result_cause= "Impossible WHERE";
|
||||||
error= 0;
|
error= 0;
|
||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
@ -570,20 +555,24 @@ JOIN::optimize()
|
|||||||
{
|
{
|
||||||
if (res > 1)
|
if (res > 1)
|
||||||
{
|
{
|
||||||
|
DBUG_PRINT("error",("Error from opt_sum_query"));
|
||||||
DBUG_RETURN(1);
|
DBUG_RETURN(1);
|
||||||
}
|
}
|
||||||
if (res < 0)
|
if (res < 0)
|
||||||
{
|
{
|
||||||
|
DBUG_PRINT("info",("No matching min/max row"));
|
||||||
zero_result_cause= "No matching min/max row";
|
zero_result_cause= "No matching min/max row";
|
||||||
error=0;
|
error=0;
|
||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
}
|
}
|
||||||
|
DBUG_PRINT("info",("Select tables optimized away"));
|
||||||
zero_result_cause= "Select tables optimized away";
|
zero_result_cause= "Select tables optimized away";
|
||||||
tables_list= 0; // All tables resolved
|
tables_list= 0; // All tables resolved
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!tables_list)
|
if (!tables_list)
|
||||||
{
|
{
|
||||||
|
DBUG_PRINT("info",("No tables"));
|
||||||
error= 0;
|
error= 0;
|
||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
}
|
}
|
||||||
@ -777,6 +766,10 @@ JOIN::optimize()
|
|||||||
(select_lex->ftfunc_list->elements ?
|
(select_lex->ftfunc_list->elements ?
|
||||||
SELECT_NO_JOIN_CACHE : 0));
|
SELECT_NO_JOIN_CACHE : 0));
|
||||||
|
|
||||||
|
/* Perform FULLTEXT search before all regular searches */
|
||||||
|
if (!(select_options & SELECT_DESCRIBE))
|
||||||
|
init_ftfuncs(thd, select_lex, test(order));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
is this simple IN subquery?
|
is this simple IN subquery?
|
||||||
*/
|
*/
|
||||||
@ -832,7 +825,7 @@ JOIN::optimize()
|
|||||||
join_tab->info= "Using index; Using where";
|
join_tab->info= "Using index; Using where";
|
||||||
else
|
else
|
||||||
join_tab->info= "Using index";
|
join_tab->info= "Using index";
|
||||||
|
|
||||||
DBUG_RETURN(unit->item->
|
DBUG_RETURN(unit->item->
|
||||||
change_engine(new subselect_indexsubquery_engine(thd,
|
change_engine(new subselect_indexsubquery_engine(thd,
|
||||||
join_tab,
|
join_tab,
|
||||||
@ -869,7 +862,7 @@ JOIN::optimize()
|
|||||||
as in other cases the join is done before the sort.
|
as in other cases the join is done before the sort.
|
||||||
*/
|
*/
|
||||||
if (const_tables != tables &&
|
if (const_tables != tables &&
|
||||||
(order || group_list) &&
|
(order || group_list) &&
|
||||||
join_tab[const_tables].type != JT_ALL &&
|
join_tab[const_tables].type != JT_ALL &&
|
||||||
join_tab[const_tables].type != JT_FT &&
|
join_tab[const_tables].type != JT_FT &&
|
||||||
join_tab[const_tables].type != JT_REF_OR_NULL &&
|
join_tab[const_tables].type != JT_REF_OR_NULL &&
|
||||||
@ -883,8 +876,7 @@ JOIN::optimize()
|
|||||||
((group_list && const_tables != tables &&
|
((group_list && const_tables != tables &&
|
||||||
(!simple_group ||
|
(!simple_group ||
|
||||||
!test_if_skip_sort_order(&join_tab[const_tables], group_list,
|
!test_if_skip_sort_order(&join_tab[const_tables], group_list,
|
||||||
unit->select_limit_cnt,
|
unit->select_limit_cnt, 0))) ||
|
||||||
0))) ||
|
|
||||||
select_distinct) &&
|
select_distinct) &&
|
||||||
tmp_table_param.quick_group && !procedure)
|
tmp_table_param.quick_group && !procedure)
|
||||||
{
|
{
|
||||||
@ -899,8 +891,6 @@ JOIN::optimize()
|
|||||||
}
|
}
|
||||||
having= 0;
|
having= 0;
|
||||||
|
|
||||||
/* Perform FULLTEXT search before all regular searches */
|
|
||||||
init_ftfuncs(thd, select_lex, test(order));
|
|
||||||
/* Create a tmp table if distinct or if the sort is too complicated */
|
/* Create a tmp table if distinct or if the sort is too complicated */
|
||||||
if (need_tmp)
|
if (need_tmp)
|
||||||
{
|
{
|
||||||
@ -908,7 +898,7 @@ JOIN::optimize()
|
|||||||
thd->proc_info="Creating tmp table";
|
thd->proc_info="Creating tmp table";
|
||||||
|
|
||||||
init_items_ref_array();
|
init_items_ref_array();
|
||||||
|
|
||||||
tmp_table_param.hidden_field_count= (all_fields.elements -
|
tmp_table_param.hidden_field_count= (all_fields.elements -
|
||||||
fields_list.elements);
|
fields_list.elements);
|
||||||
if (!(exec_tmp_table1 =
|
if (!(exec_tmp_table1 =
|
||||||
@ -2446,7 +2436,7 @@ merge_key_fields(KEY_FIELD *start,KEY_FIELD *new_fields,KEY_FIELD *end,
|
|||||||
}
|
}
|
||||||
else if (old->eq_func && new_fields->eq_func &&
|
else if (old->eq_func && new_fields->eq_func &&
|
||||||
old->val->eq(new_fields->val, old->field->binary()))
|
old->val->eq(new_fields->val, old->field->binary()))
|
||||||
|
|
||||||
{
|
{
|
||||||
old->level= and_level;
|
old->level= and_level;
|
||||||
old->optimize= ((old->optimize & new_fields->optimize &
|
old->optimize= ((old->optimize & new_fields->optimize &
|
||||||
@ -2505,7 +2495,7 @@ merge_key_fields(KEY_FIELD *start,KEY_FIELD *new_fields,KEY_FIELD *end,
|
|||||||
field Field used in comparision
|
field Field used in comparision
|
||||||
eq_func True if we used =, <=> or IS NULL
|
eq_func True if we used =, <=> or IS NULL
|
||||||
value Value used for comparison with field
|
value Value used for comparison with field
|
||||||
Is NULL for BETWEEN and IN
|
Is NULL for BETWEEN and IN
|
||||||
usable_tables Tables which can be used for key optimization
|
usable_tables Tables which can be used for key optimization
|
||||||
|
|
||||||
NOTES
|
NOTES
|
||||||
@ -2572,7 +2562,7 @@ add_key_field(KEY_FIELD **key_fields,uint and_level, COND *cond,
|
|||||||
bool is_const=1;
|
bool is_const=1;
|
||||||
for (uint i=0; i<num_values; i++)
|
for (uint i=0; i<num_values; i++)
|
||||||
/*
|
/*
|
||||||
TODO: this looks like a bug, should be
|
TODO: This looks like a bug. It should be
|
||||||
is_const&= (value[i])->const_item();
|
is_const&= (value[i])->const_item();
|
||||||
*/
|
*/
|
||||||
is_const&= (*value)->const_item();
|
is_const&= (*value)->const_item();
|
||||||
@ -2583,22 +2573,32 @@ add_key_field(KEY_FIELD **key_fields,uint and_level, COND *cond,
|
|||||||
number. cmp_type() is checked to allow compare of dates to numbers.
|
number. cmp_type() is checked to allow compare of dates to numbers.
|
||||||
eq_func is NEVER true when num_values > 1
|
eq_func is NEVER true when num_values > 1
|
||||||
*/
|
*/
|
||||||
if (!eq_func ||
|
if (!eq_func)
|
||||||
field->result_type() == STRING_RESULT &&
|
return;
|
||||||
(*value)->result_type() != STRING_RESULT &&
|
if (field->result_type() == STRING_RESULT)
|
||||||
field->cmp_type() != (*value)->result_type())
|
{
|
||||||
return;
|
if ((*value)->result_type() != STRING_RESULT)
|
||||||
|
{
|
||||||
/*
|
if (field->cmp_type() != (*value)->result_type())
|
||||||
We can't use indexes if the effective collation
|
return;
|
||||||
of the operation differ from the field collation.
|
}
|
||||||
*/
|
else
|
||||||
if (field->result_type() == STRING_RESULT &&
|
{
|
||||||
(*value)->result_type() == STRING_RESULT &&
|
/*
|
||||||
field->cmp_type() == STRING_RESULT &&
|
We can't use indexes if the effective collation
|
||||||
((Field_str*)field)->charset() != cond->compare_collation())
|
of the operation differ from the field collation.
|
||||||
return;
|
|
||||||
|
|
||||||
|
We also cannot use index on a text column, as the column may
|
||||||
|
contain 'x' 'x\t' 'x ' and 'read_next_same' will stop after
|
||||||
|
'x' when searching for WHERE col='x '
|
||||||
|
*/
|
||||||
|
if (field->cmp_type() == STRING_RESULT &&
|
||||||
|
(((Field_str*)field)->charset() != cond->compare_collation() ||
|
||||||
|
((*value)->type() != Item::NULL_ITEM &&
|
||||||
|
(field->flags & BLOB_FLAG) && !field->binary())))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DBUG_ASSERT(num_values == 1);
|
DBUG_ASSERT(num_values == 1);
|
||||||
@ -2701,7 +2701,7 @@ add_key_fields(JOIN_TAB *stat,KEY_FIELD **key_fields,uint *and_level,
|
|||||||
!(cond_func->used_tables() & OUTER_REF_TABLE_BIT))
|
!(cond_func->used_tables() & OUTER_REF_TABLE_BIT))
|
||||||
{
|
{
|
||||||
Item *tmp=new Item_null;
|
Item *tmp=new Item_null;
|
||||||
if (!tmp) // Should never be true
|
if (unlikely(!tmp)) // Should never be true
|
||||||
return;
|
return;
|
||||||
add_key_field(key_fields,*and_level,cond_func,
|
add_key_field(key_fields,*and_level,cond_func,
|
||||||
((Item_field*) (cond_func->arguments()[0])->real_item())
|
((Item_field*) (cond_func->arguments()[0])->real_item())
|
||||||
@ -4135,7 +4135,7 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
|
|||||||
rec= keyuse->ref_table_rows;
|
rec= keyuse->ref_table_rows;
|
||||||
/*
|
/*
|
||||||
If there is one 'key_column IS NULL' expression, we can
|
If there is one 'key_column IS NULL' expression, we can
|
||||||
use this ref_or_null optimsation of this field
|
use this ref_or_null optimisation of this field
|
||||||
*/
|
*/
|
||||||
found_ref_or_null|= (keyuse->optimize &
|
found_ref_or_null|= (keyuse->optimize &
|
||||||
KEY_OPTIMIZE_REF_OR_NULL);
|
KEY_OPTIMIZE_REF_OR_NULL);
|
||||||
@ -4652,6 +4652,7 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, KEYUSE *org_keyuse,
|
|||||||
|
|
||||||
store_key **ref_key= j->ref.key_copy;
|
store_key **ref_key= j->ref.key_copy;
|
||||||
byte *key_buff=j->ref.key_buff, *null_ref_key= 0;
|
byte *key_buff=j->ref.key_buff, *null_ref_key= 0;
|
||||||
|
bool keyuse_uses_no_tables= TRUE;
|
||||||
if (ftkey)
|
if (ftkey)
|
||||||
{
|
{
|
||||||
j->ref.items[0]=((Item_func*)(keyuse->val))->key_item();
|
j->ref.items[0]=((Item_func*)(keyuse->val))->key_item();
|
||||||
@ -4671,6 +4672,7 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, KEYUSE *org_keyuse,
|
|||||||
|
|
||||||
uint maybe_null= test(keyinfo->key_part[i].null_bit);
|
uint maybe_null= test(keyinfo->key_part[i].null_bit);
|
||||||
j->ref.items[i]=keyuse->val; // Save for cond removal
|
j->ref.items[i]=keyuse->val; // Save for cond removal
|
||||||
|
keyuse_uses_no_tables= keyuse_uses_no_tables && !keyuse->used_tables;
|
||||||
if (!keyuse->used_tables &&
|
if (!keyuse->used_tables &&
|
||||||
!(join->select_options & SELECT_DESCRIBE))
|
!(join->select_options & SELECT_DESCRIBE))
|
||||||
{ // Compare against constant
|
{ // Compare against constant
|
||||||
@ -4710,7 +4712,7 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, KEYUSE *org_keyuse,
|
|||||||
j->type= null_ref_key ? JT_REF_OR_NULL : JT_REF;
|
j->type= null_ref_key ? JT_REF_OR_NULL : JT_REF;
|
||||||
j->ref.null_ref_key= null_ref_key;
|
j->ref.null_ref_key= null_ref_key;
|
||||||
}
|
}
|
||||||
else if (ref_key == j->ref.key_copy)
|
else if (keyuse_uses_no_tables)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
This happen if we are using a constant expression in the ON part
|
This happen if we are using a constant expression in the ON part
|
||||||
@ -4971,10 +4973,32 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
|
|||||||
COND *const_cond=
|
COND *const_cond=
|
||||||
make_cond_for_table(cond,join->const_table_map,(table_map) 0);
|
make_cond_for_table(cond,join->const_table_map,(table_map) 0);
|
||||||
DBUG_EXECUTE("where",print_where(const_cond,"constants"););
|
DBUG_EXECUTE("where",print_where(const_cond,"constants"););
|
||||||
|
for (JOIN_TAB *tab= join->join_tab+join->const_tables;
|
||||||
|
tab < join->join_tab+join->tables ; tab++)
|
||||||
|
{
|
||||||
|
if (tab->on_expr)
|
||||||
|
{
|
||||||
|
JOIN_TAB *cond_tab= tab->first_inner;
|
||||||
|
COND *tmp= make_cond_for_table(tab->on_expr,
|
||||||
|
join->const_table_map,
|
||||||
|
(table_map) 0);
|
||||||
|
if (!tmp)
|
||||||
|
continue;
|
||||||
|
tmp= new Item_func_trig_cond(tmp, &cond_tab->not_null_compl);
|
||||||
|
if (!tmp)
|
||||||
|
DBUG_RETURN(1);
|
||||||
|
tmp->quick_fix_field();
|
||||||
|
cond_tab->select_cond= !cond_tab->select_cond ? tmp :
|
||||||
|
new Item_cond_and(cond_tab->select_cond,tmp);
|
||||||
|
if (!cond_tab->select_cond)
|
||||||
|
DBUG_RETURN(1);
|
||||||
|
cond_tab->select_cond->quick_fix_field();
|
||||||
|
}
|
||||||
|
}
|
||||||
if (const_cond && !const_cond->val_int())
|
if (const_cond && !const_cond->val_int())
|
||||||
{
|
{
|
||||||
DBUG_PRINT("info",("Found impossible WHERE condition"));
|
DBUG_PRINT("info",("Found impossible WHERE condition"));
|
||||||
DBUG_RETURN(1); // Impossible const condition
|
DBUG_RETURN(1); // Impossible const condition
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4985,13 +5009,13 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
|
|||||||
JOIN_TAB *tab=join->join_tab+i;
|
JOIN_TAB *tab=join->join_tab+i;
|
||||||
JOIN_TAB *first_inner_tab= tab->first_inner;
|
JOIN_TAB *first_inner_tab= tab->first_inner;
|
||||||
table_map current_map= tab->table->map;
|
table_map current_map= tab->table->map;
|
||||||
|
bool use_quick_range=0;
|
||||||
/*
|
/*
|
||||||
Following force including random expression in last table condition.
|
Following force including random expression in last table condition.
|
||||||
It solve problem with select like SELECT * FROM t1 WHERE rand() > 0.5
|
It solve problem with select like SELECT * FROM t1 WHERE rand() > 0.5
|
||||||
*/
|
*/
|
||||||
if (i == join->tables-1)
|
if (i == join->tables-1)
|
||||||
current_map|= OUTER_REF_TABLE_BIT | RAND_TABLE_BIT;
|
current_map|= OUTER_REF_TABLE_BIT | RAND_TABLE_BIT;
|
||||||
bool use_quick_range=0;
|
|
||||||
used_tables|=current_map;
|
used_tables|=current_map;
|
||||||
|
|
||||||
if (tab->type == JT_REF && tab->quick &&
|
if (tab->type == JT_REF && tab->quick &&
|
||||||
@ -5012,15 +5036,30 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
|
|||||||
tmp= make_cond_for_table(cond,used_tables,current_map);
|
tmp= make_cond_for_table(cond,used_tables,current_map);
|
||||||
if (cond && !tmp && tab->quick)
|
if (cond && !tmp && tab->quick)
|
||||||
{ // Outer join
|
{ // Outer join
|
||||||
/*
|
if (tab->type != JT_ALL)
|
||||||
Hack to handle the case where we only refer to a table
|
{
|
||||||
in the ON part of an OUTER JOIN.
|
/*
|
||||||
*/
|
Don't use the quick method
|
||||||
tmp=new Item_int((longlong) 1,1); // Always true
|
We come here in the case where we have 'key=constant' and
|
||||||
|
the test is removed by make_cond_for_table()
|
||||||
|
*/
|
||||||
|
delete tab->quick;
|
||||||
|
tab->quick= 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Hack to handle the case where we only refer to a table
|
||||||
|
in the ON part of an OUTER JOIN. In this case we want the code
|
||||||
|
below to check if we should use 'quick' instead.
|
||||||
|
*/
|
||||||
|
tmp= new Item_int((longlong) 1,1); // Always true
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
if (tmp || !cond)
|
if (tmp || !cond)
|
||||||
{
|
{
|
||||||
DBUG_EXECUTE("where",print_where(tmp,tab->table->table_name););
|
DBUG_EXECUTE("where",print_where(tmp,tab->table->table_name););
|
||||||
SQL_SELECT *sel=tab->select=(SQL_SELECT*)
|
SQL_SELECT *sel=tab->select=(SQL_SELECT*)
|
||||||
join->thd->memdup((gptr) select, sizeof(SQL_SELECT));
|
join->thd->memdup((gptr) select, sizeof(SQL_SELECT));
|
||||||
if (!sel)
|
if (!sel)
|
||||||
@ -5030,7 +5069,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
|
|||||||
add a match guard to the pushed down predicate.
|
add a match guard to the pushed down predicate.
|
||||||
The guard will turn the predicate on only after
|
The guard will turn the predicate on only after
|
||||||
the first match for outer tables is encountered.
|
the first match for outer tables is encountered.
|
||||||
*/
|
*/
|
||||||
if (cond)
|
if (cond)
|
||||||
{/*
|
{/*
|
||||||
Because of QUICK_GROUP_MIN_MAX_SELECT there may be a select without
|
Because of QUICK_GROUP_MIN_MAX_SELECT there may be a select without
|
||||||
@ -5217,6 +5256,7 @@ static void
|
|||||||
make_join_readinfo(JOIN *join, uint options)
|
make_join_readinfo(JOIN *join, uint options)
|
||||||
{
|
{
|
||||||
uint i;
|
uint i;
|
||||||
|
|
||||||
bool statistics= test(!(join->select_options & SELECT_DESCRIBE));
|
bool statistics= test(!(join->select_options & SELECT_DESCRIBE));
|
||||||
DBUG_ENTER("make_join_readinfo");
|
DBUG_ENTER("make_join_readinfo");
|
||||||
|
|
||||||
@ -5315,7 +5355,8 @@ make_join_readinfo(JOIN *join, uint options)
|
|||||||
join->thd->server_status|=SERVER_QUERY_NO_GOOD_INDEX_USED;
|
join->thd->server_status|=SERVER_QUERY_NO_GOOD_INDEX_USED;
|
||||||
tab->read_first_record= join_init_quick_read_record;
|
tab->read_first_record= join_init_quick_read_record;
|
||||||
if (statistics)
|
if (statistics)
|
||||||
statistic_increment(select_range_check_count, &LOCK_status);
|
statistic_increment(join->thd->status_var.select_range_check_count,
|
||||||
|
&LOCK_status);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -5325,13 +5366,15 @@ make_join_readinfo(JOIN *join, uint options)
|
|||||||
if (tab->select && tab->select->quick)
|
if (tab->select && tab->select->quick)
|
||||||
{
|
{
|
||||||
if (statistics)
|
if (statistics)
|
||||||
statistic_increment(select_range_count, &LOCK_status);
|
statistic_increment(join->thd->status_var.select_range_count,
|
||||||
|
&LOCK_status);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
join->thd->server_status|=SERVER_QUERY_NO_INDEX_USED;
|
join->thd->server_status|=SERVER_QUERY_NO_INDEX_USED;
|
||||||
if (statistics)
|
if (statistics)
|
||||||
statistic_increment(select_scan_count, &LOCK_status);
|
statistic_increment(join->thd->status_var.select_scan_count,
|
||||||
|
&LOCK_status);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -5339,13 +5382,15 @@ make_join_readinfo(JOIN *join, uint options)
|
|||||||
if (tab->select && tab->select->quick)
|
if (tab->select && tab->select->quick)
|
||||||
{
|
{
|
||||||
if (statistics)
|
if (statistics)
|
||||||
statistic_increment(select_full_range_join_count, &LOCK_status);
|
statistic_increment(join->thd->status_var.select_full_range_join_count,
|
||||||
|
&LOCK_status);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
join->thd->server_status|=SERVER_QUERY_NO_INDEX_USED;
|
join->thd->server_status|=SERVER_QUERY_NO_INDEX_USED;
|
||||||
if (statistics)
|
if (statistics)
|
||||||
statistic_increment(select_full_join_count, &LOCK_status);
|
statistic_increment(join->thd->status_var.select_full_join_count,
|
||||||
|
&LOCK_status);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!table->no_keyread)
|
if (!table->no_keyread)
|
||||||
@ -5520,6 +5565,10 @@ JOIN::join_free(bool full)
|
|||||||
if (full)
|
if (full)
|
||||||
{
|
{
|
||||||
group_fields.delete_elements();
|
group_fields.delete_elements();
|
||||||
|
/*
|
||||||
|
We can't call delete_elements() on copy_funcs as this will cause
|
||||||
|
problems in free_elements() as some of the elements are then deleted.
|
||||||
|
*/
|
||||||
tmp_table_param.copy_funcs.empty();
|
tmp_table_param.copy_funcs.empty();
|
||||||
tmp_table_param.cleanup();
|
tmp_table_param.cleanup();
|
||||||
}
|
}
|
||||||
@ -5704,7 +5753,7 @@ remove_const(JOIN *join,ORDER *first_order, COND *cond, bool *simple_order)
|
|||||||
}
|
}
|
||||||
if ((ref=order_tables & (not_const_tables ^ first_table)))
|
if ((ref=order_tables & (not_const_tables ^ first_table)))
|
||||||
{
|
{
|
||||||
if (only_eq_ref_tables(join,first_order,ref))
|
if (!(order_tables & first_table) && only_eq_ref_tables(join,first_order,ref))
|
||||||
{
|
{
|
||||||
DBUG_PRINT("info",("removing: %s", order->item[0]->full_name()));
|
DBUG_PRINT("info",("removing: %s", order->item[0]->full_name()));
|
||||||
continue;
|
continue;
|
||||||
@ -5827,7 +5876,10 @@ change_cond_ref_to_const(I_List<COND_CMP> *save_list,Item *and_father,
|
|||||||
Item *right_item= func->arguments()[1];
|
Item *right_item= func->arguments()[1];
|
||||||
Item_func::Functype functype= func->functype();
|
Item_func::Functype functype= func->functype();
|
||||||
|
|
||||||
if (right_item->eq(field,0) && left_item != value)
|
if (right_item->eq(field,0) && left_item != value &&
|
||||||
|
(left_item->result_type() != STRING_RESULT ||
|
||||||
|
value->result_type() != STRING_RESULT ||
|
||||||
|
left_item->collation.collation == value->collation.collation))
|
||||||
{
|
{
|
||||||
Item *tmp=value->new_item();
|
Item *tmp=value->new_item();
|
||||||
if (tmp)
|
if (tmp)
|
||||||
@ -5845,7 +5897,10 @@ change_cond_ref_to_const(I_List<COND_CMP> *save_list,Item *and_father,
|
|||||||
func->set_cmp_func();
|
func->set_cmp_func();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (left_item->eq(field,0) && right_item != value)
|
else if (left_item->eq(field,0) && right_item != value &&
|
||||||
|
(right_item->result_type() != STRING_RESULT ||
|
||||||
|
value->result_type() != STRING_RESULT ||
|
||||||
|
right_item->collation.collation == value->collation.collation))
|
||||||
{
|
{
|
||||||
Item *tmp=value->new_item();
|
Item *tmp=value->new_item();
|
||||||
if (tmp)
|
if (tmp)
|
||||||
@ -5965,62 +6020,6 @@ propagate_cond_constants(I_List<COND_CMP> *save_list,COND *and_father,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
Eliminate NOT functions from the condition tree.
|
|
||||||
|
|
||||||
SYNPOSIS
|
|
||||||
eliminate_not_funcs()
|
|
||||||
thd thread handler
|
|
||||||
cond condition tree
|
|
||||||
|
|
||||||
DESCRIPTION
|
|
||||||
Eliminate NOT functions from the condition tree where it's possible.
|
|
||||||
Recursively traverse condition tree to find all NOT functions.
|
|
||||||
Call neg_transformer() method for negated arguments.
|
|
||||||
|
|
||||||
NOTE
|
|
||||||
If neg_transformer() returned a new condition we call fix_fields().
|
|
||||||
We don't delete any items as it's not needed. They will be deleted
|
|
||||||
later at once.
|
|
||||||
|
|
||||||
RETURN
|
|
||||||
New condition tree
|
|
||||||
*/
|
|
||||||
|
|
||||||
COND *eliminate_not_funcs(THD *thd, COND *cond)
|
|
||||||
{
|
|
||||||
DBUG_ENTER("eliminate_not_funcs");
|
|
||||||
|
|
||||||
if (!cond)
|
|
||||||
DBUG_RETURN(cond);
|
|
||||||
if (cond->type() == Item::COND_ITEM) /* OR or AND */
|
|
||||||
{
|
|
||||||
List_iterator<Item> li(*((Item_cond*) cond)->argument_list());
|
|
||||||
Item *item;
|
|
||||||
while ((item= li++))
|
|
||||||
{
|
|
||||||
Item *new_item= eliminate_not_funcs(thd, item);
|
|
||||||
if (item != new_item)
|
|
||||||
VOID(li.replace(new_item)); /* replace item with a new condition */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (cond->type() == Item::FUNC_ITEM && /* 'NOT' operation? */
|
|
||||||
((Item_func*) cond)->functype() == Item_func::NOT_FUNC)
|
|
||||||
{
|
|
||||||
COND *new_cond= ((Item_func*) cond)->arguments()[0]->neg_transformer(thd);
|
|
||||||
if (new_cond)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
Here we can delete the NOT function. Something like: delete cond;
|
|
||||||
But we don't need to do it. All items will be deleted later at once.
|
|
||||||
*/
|
|
||||||
cond= new_cond;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
DBUG_RETURN(cond);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Simplify joins replacing outer joins by inner joins whenever it's possible
|
Simplify joins replacing outer joins by inner joins whenever it's possible
|
||||||
|
|
||||||
@ -6085,9 +6084,9 @@ COND *eliminate_not_funcs(THD *thd, COND *cond)
|
|||||||
|
|
||||||
The function removes all unnecessary braces from the expression
|
The function removes all unnecessary braces from the expression
|
||||||
produced by the conversions.
|
produced by the conversions.
|
||||||
E.g. SELECT * FROM t1, (t2, t3) WHERE t2.c < 5 AND t2.a=t1.a t3.b=t1.b
|
E.g. SELECT * FROM t1, (t2, t3) WHERE t2.c < 5 AND t2.a=t1.a AND t3.b=t1.b
|
||||||
finally is converted to:
|
finally is converted to:
|
||||||
SELECT * FROM t1, t2, t3 WHERE t2.c < 5 AND t2.a=t1.a t3.b=t1.b
|
SELECT * FROM t1, t2, t3 WHERE t2.c < 5 AND t2.a=t1.a AND t3.b=t1.b
|
||||||
|
|
||||||
It also will remove braces from the following queries:
|
It also will remove braces from the following queries:
|
||||||
SELECT * from (t1 LEFT JOIN t2 ON t2.a=t1.a) LEFT JOIN t3 ON t3.b=t2.b
|
SELECT * from (t1 LEFT JOIN t2 ON t2.a=t1.a) LEFT JOIN t3 ON t3.b=t2.b
|
||||||
@ -6122,6 +6121,7 @@ simplify_joins(JOIN *join, List<TABLE_LIST> *join_list, COND *conds, bool top)
|
|||||||
NESTED_JOIN *nested_join;
|
NESTED_JOIN *nested_join;
|
||||||
TABLE_LIST *prev_table= 0;
|
TABLE_LIST *prev_table= 0;
|
||||||
List_iterator<TABLE_LIST> li(*join_list);
|
List_iterator<TABLE_LIST> li(*join_list);
|
||||||
|
DBUG_ENTER("simplify_joins");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Try to simplify join operations from join_list.
|
Try to simplify join operations from join_list.
|
||||||
@ -6255,35 +6255,37 @@ simplify_joins(JOIN *join, List<TABLE_LIST> *join_list, COND *conds, bool top)
|
|||||||
li.replace(nested_join->join_list);
|
li.replace(nested_join->join_list);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return conds;
|
DBUG_RETURN(conds);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static COND *
|
static COND *
|
||||||
optimize_cond(JOIN *join, COND *conds, Item::cond_result *cond_value)
|
optimize_cond(JOIN *join, COND *conds, Item::cond_result *cond_value)
|
||||||
{
|
{
|
||||||
DBUG_ENTER("optimize_cond");
|
|
||||||
|
|
||||||
THD *thd= join->thd;
|
THD *thd= join->thd;
|
||||||
SELECT_LEX *select= thd->lex->current_select;
|
SELECT_LEX *select= thd->lex->current_select;
|
||||||
|
DBUG_ENTER("optimize_cond");
|
||||||
|
|
||||||
if (select->first_cond_optimization)
|
if (select->first_cond_optimization)
|
||||||
{
|
{
|
||||||
Item_arena *arena= thd->current_arena;
|
/*
|
||||||
Item_arena backup;
|
The following code will allocate the new items in a permanent
|
||||||
if (arena)
|
MEMROOT for prepared statements and stored procedures.
|
||||||
|
*/
|
||||||
|
|
||||||
|
Item_arena *arena= thd->current_arena, backup;
|
||||||
|
if (arena->is_conventional())
|
||||||
|
arena= 0; // For easier test
|
||||||
|
else
|
||||||
thd->set_n_backup_item_arena(arena, &backup);
|
thd->set_n_backup_item_arena(arena, &backup);
|
||||||
|
|
||||||
if (conds)
|
select->first_cond_optimization= 0;
|
||||||
{
|
|
||||||
DBUG_EXECUTE("where",print_where(conds,"original"););
|
|
||||||
/* eliminate NOT operators */
|
|
||||||
conds= eliminate_not_funcs(thd, conds);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Convert all outer joins to inner joins if possible */
|
/* Convert all outer joins to inner joins if possible */
|
||||||
conds= simplify_joins(join, join->join_list, conds, TRUE);
|
conds= simplify_joins(join, join->join_list, conds, TRUE);
|
||||||
|
|
||||||
select->prep_where= conds ? conds->copy_andor_structure(thd) : 0;
|
select->prep_where= conds ? conds->copy_andor_structure(thd) : 0;
|
||||||
select->first_cond_optimization= 0;
|
|
||||||
if (arena)
|
if (arena)
|
||||||
thd->restore_backup_item_arena(arena, &backup);
|
thd->restore_backup_item_arena(arena, &backup);
|
||||||
}
|
}
|
||||||
@ -6291,19 +6293,21 @@ optimize_cond(JOIN *join, COND *conds, Item::cond_result *cond_value)
|
|||||||
if (!conds)
|
if (!conds)
|
||||||
{
|
{
|
||||||
*cond_value= Item::COND_TRUE;
|
*cond_value= Item::COND_TRUE;
|
||||||
DBUG_RETURN(conds);
|
select->prep_where= 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DBUG_EXECUTE("where", print_where(conds, "original"););
|
||||||
|
/* change field = field to field = const for each found field = const */
|
||||||
|
propagate_cond_constants((I_List<COND_CMP> *) 0,conds,conds);
|
||||||
|
/*
|
||||||
|
Remove all instances of item == item
|
||||||
|
Remove all and-levels where CONST item != CONST item
|
||||||
|
*/
|
||||||
|
DBUG_EXECUTE("where",print_where(conds,"after const change"););
|
||||||
|
conds= remove_eq_conds(thd, conds, cond_value) ;
|
||||||
|
DBUG_EXECUTE("info",print_where(conds,"after remove"););
|
||||||
}
|
}
|
||||||
|
|
||||||
DBUG_EXECUTE("where", print_where(conds, "after negation elimination"););
|
|
||||||
/* change field = field to field = const for each found field = const */
|
|
||||||
propagate_cond_constants((I_List<COND_CMP> *) 0,conds,conds);
|
|
||||||
/*
|
|
||||||
Remove all instances of item == item
|
|
||||||
Remove all and-levels where CONST item != CONST item
|
|
||||||
*/
|
|
||||||
DBUG_EXECUTE("where",print_where(conds,"after const change"););
|
|
||||||
conds= remove_eq_conds(thd, conds, cond_value) ;
|
|
||||||
DBUG_EXECUTE("info",print_where(conds,"after remove"););
|
|
||||||
DBUG_RETURN(conds);
|
DBUG_RETURN(conds);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -6631,7 +6635,7 @@ static Field* create_tmp_field_from_item(THD *thd,
|
|||||||
copy_func If set and item is a function, store copy of item
|
copy_func If set and item is a function, store copy of item
|
||||||
in this array
|
in this array
|
||||||
from_field if field will be created using other field as example,
|
from_field if field will be created using other field as example,
|
||||||
pointer example field will be written here
|
pointer example field will be written here
|
||||||
group 1 if we are going to do a relative group by on result
|
group 1 if we are going to do a relative group by on result
|
||||||
modify_item 1 if item->result_field should point to new item.
|
modify_item 1 if item->result_field should point to new item.
|
||||||
This is relevent for how fill_record() is going to
|
This is relevent for how fill_record() is going to
|
||||||
@ -6640,7 +6644,7 @@ static Field* create_tmp_field_from_item(THD *thd,
|
|||||||
the record in the original table.
|
the record in the original table.
|
||||||
If modify_item is 0 then fill_record() will update
|
If modify_item is 0 then fill_record() will update
|
||||||
the temporary table
|
the temporary table
|
||||||
|
|
||||||
RETURN
|
RETURN
|
||||||
0 on error
|
0 on error
|
||||||
new_created field
|
new_created field
|
||||||
@ -6664,13 +6668,13 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
|
|||||||
return new Field_double(item_sum->max_length,maybe_null,
|
return new Field_double(item_sum->max_length,maybe_null,
|
||||||
item->name, table, item_sum->decimals);
|
item->name, table, item_sum->decimals);
|
||||||
case Item_sum::VARIANCE_FUNC: /* Place for sum & count */
|
case Item_sum::VARIANCE_FUNC: /* Place for sum & count */
|
||||||
case Item_sum::STD_FUNC:
|
case Item_sum::STD_FUNC:
|
||||||
if (group)
|
if (group)
|
||||||
return new Field_string(sizeof(double)*2+sizeof(longlong),
|
return new Field_string(sizeof(double)*2+sizeof(longlong),
|
||||||
0, item->name,table,&my_charset_bin);
|
0, item->name,table,&my_charset_bin);
|
||||||
else
|
else
|
||||||
return new Field_double(item_sum->max_length, maybe_null,
|
return new Field_double(item_sum->max_length, maybe_null,
|
||||||
item->name,table,item_sum->decimals);
|
item->name,table,item_sum->decimals);
|
||||||
case Item_sum::UNIQUE_USERS_FUNC:
|
case Item_sum::UNIQUE_USERS_FUNC:
|
||||||
return new Field_long(9,maybe_null,item->name,table,1);
|
return new Field_long(9,maybe_null,item->name,table,1);
|
||||||
default:
|
default:
|
||||||
@ -6767,7 +6771,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
|
|||||||
(int) distinct, (int) save_sum_fields,
|
(int) distinct, (int) save_sum_fields,
|
||||||
(ulong) rows_limit,test(group)));
|
(ulong) rows_limit,test(group)));
|
||||||
|
|
||||||
statistic_increment(created_tmp_tables, &LOCK_status);
|
statistic_increment(thd->status_var.created_tmp_tables, &LOCK_status);
|
||||||
|
|
||||||
if (use_temp_pool)
|
if (use_temp_pool)
|
||||||
temp_pool_slot = bitmap_set_next(&temp_pool);
|
temp_pool_slot = bitmap_set_next(&temp_pool);
|
||||||
@ -6778,7 +6782,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
|
|||||||
else // if we run out of slots or we are not using tempool
|
else // if we run out of slots or we are not using tempool
|
||||||
sprintf(path,"%s%s%lx_%lx_%x",mysql_tmpdir,tmp_file_prefix,current_pid,
|
sprintf(path,"%s%s%lx_%lx_%x",mysql_tmpdir,tmp_file_prefix,current_pid,
|
||||||
thd->thread_id, thd->tmp_table++);
|
thd->thread_id, thd->tmp_table++);
|
||||||
|
|
||||||
if (lower_case_table_names)
|
if (lower_case_table_names)
|
||||||
my_casedn_str(files_charset_info, path);
|
my_casedn_str(files_charset_info, path);
|
||||||
|
|
||||||
@ -6894,14 +6898,21 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
|
|||||||
tmp_from_field++;
|
tmp_from_field++;
|
||||||
*(reg_field++)= new_field;
|
*(reg_field++)= new_field;
|
||||||
reclength+=new_field->pack_length();
|
reclength+=new_field->pack_length();
|
||||||
if (!(new_field->flags & NOT_NULL_FLAG))
|
|
||||||
null_count++;
|
|
||||||
if (new_field->flags & BLOB_FLAG)
|
if (new_field->flags & BLOB_FLAG)
|
||||||
{
|
{
|
||||||
*blob_field++= new_field;
|
*blob_field++= new_field;
|
||||||
blob_count++;
|
blob_count++;
|
||||||
}
|
}
|
||||||
((Item_sum*) item)->args[i]= new Item_field(new_field);
|
((Item_sum*) item)->args[i]= new Item_field(new_field);
|
||||||
|
if (!(new_field->flags & NOT_NULL_FLAG))
|
||||||
|
{
|
||||||
|
null_count++;
|
||||||
|
/*
|
||||||
|
new_field->maybe_null() is still false, it will be
|
||||||
|
changed below. But we have to setup Item_field correctly
|
||||||
|
*/
|
||||||
|
((Item_sum*) item)->args[i]->maybe_null=1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -7346,7 +7357,8 @@ static bool create_myisam_tmp_table(TABLE *table,TMP_TABLE_PARAM *param,
|
|||||||
table->db_stat=0;
|
table->db_stat=0;
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
statistic_increment(created_tmp_disk_tables, &LOCK_status);
|
statistic_increment(table->in_use->status_var.created_tmp_disk_tables,
|
||||||
|
&LOCK_status);
|
||||||
table->db_record_offset=1;
|
table->db_record_offset=1;
|
||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
err:
|
err:
|
||||||
@ -7434,6 +7446,18 @@ bool create_myisam_from_heap(THD *thd, TABLE *table, TMP_TABLE_PARAM *param,
|
|||||||
new_table.no_rows=1;
|
new_table.no_rows=1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef TO_BE_DONE_LATER_IN_4_1
|
||||||
|
/*
|
||||||
|
To use start_bulk_insert() (which is new in 4.1) we need to find
|
||||||
|
all places where a corresponding end_bulk_insert() should be put.
|
||||||
|
*/
|
||||||
|
table->file->info(HA_STATUS_VARIABLE); /* update table->file->records */
|
||||||
|
new_table.file->start_bulk_insert(table->file->records);
|
||||||
|
#else
|
||||||
|
/* HA_EXTRA_WRITE_CACHE can stay until close, no need to disable it */
|
||||||
|
new_table.file->extra(HA_EXTRA_WRITE_CACHE);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* copy all old rows */
|
/* copy all old rows */
|
||||||
while (!table->file->rnd_next(new_table.record[1]))
|
while (!table->file->rnd_next(new_table.record[1]))
|
||||||
{
|
{
|
||||||
@ -8146,6 +8170,19 @@ join_read_system(JOIN_TAB *tab)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Read a table when there is at most one matching row
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
join_read_const()
|
||||||
|
tab Table to read
|
||||||
|
|
||||||
|
RETURN
|
||||||
|
0 Row was found
|
||||||
|
-1 Row was not found
|
||||||
|
1 Got an error (other than row not found) during read
|
||||||
|
*/
|
||||||
|
|
||||||
static int
|
static int
|
||||||
join_read_const(JOIN_TAB *tab)
|
join_read_const(JOIN_TAB *tab)
|
||||||
{
|
{
|
||||||
@ -8153,6 +8190,7 @@ join_read_const(JOIN_TAB *tab)
|
|||||||
TABLE *table= tab->table;
|
TABLE *table= tab->table;
|
||||||
if (table->status & STATUS_GARBAGE) // If first read
|
if (table->status & STATUS_GARBAGE) // If first read
|
||||||
{
|
{
|
||||||
|
table->status= 0;
|
||||||
if (cp_buffer_from_ref(&tab->ref))
|
if (cp_buffer_from_ref(&tab->ref))
|
||||||
error=HA_ERR_KEY_NOT_FOUND;
|
error=HA_ERR_KEY_NOT_FOUND;
|
||||||
else
|
else
|
||||||
@ -8163,6 +8201,7 @@ join_read_const(JOIN_TAB *tab)
|
|||||||
}
|
}
|
||||||
if (error)
|
if (error)
|
||||||
{
|
{
|
||||||
|
table->status= STATUS_NOT_FOUND;
|
||||||
table->null_row=1;
|
table->null_row=1;
|
||||||
empty_record(table);
|
empty_record(table);
|
||||||
if (error != HA_ERR_KEY_NOT_FOUND)
|
if (error != HA_ERR_KEY_NOT_FOUND)
|
||||||
@ -9378,9 +9417,9 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
|
|||||||
keys.merge(table->used_keys);
|
keys.merge(table->used_keys);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
We are adding here also the index speified in FORCE INDEX clause,
|
We are adding here also the index specified in FORCE INDEX clause,
|
||||||
if any.
|
if any.
|
||||||
This is to allow users to use index in ORDER BY.
|
This is to allow users to use index in ORDER BY.
|
||||||
*/
|
*/
|
||||||
if (table->force_index)
|
if (table->force_index)
|
||||||
keys.merge(table->keys_in_use_for_query);
|
keys.merge(table->keys_in_use_for_query);
|
||||||
@ -10157,7 +10196,7 @@ find_order_in_list(THD *thd, Item **ref_pointer_array,
|
|||||||
Item *itemptr=*order->item;
|
Item *itemptr=*order->item;
|
||||||
if (itemptr->type() == Item::INT_ITEM)
|
if (itemptr->type() == Item::INT_ITEM)
|
||||||
{ /* Order by position */
|
{ /* Order by position */
|
||||||
uint count= itemptr->val_int();
|
uint count= (uint) itemptr->val_int();
|
||||||
if (!count || count > fields.elements)
|
if (!count || count > fields.elements)
|
||||||
{
|
{
|
||||||
my_printf_error(ER_BAD_FIELD_ERROR,ER(ER_BAD_FIELD_ERROR),
|
my_printf_error(ER_BAD_FIELD_ERROR,ER(ER_BAD_FIELD_ERROR),
|
||||||
@ -10165,18 +10204,25 @@ find_order_in_list(THD *thd, Item **ref_pointer_array,
|
|||||||
thd->where);
|
thd->where);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
order->item= ref_pointer_array + count-1;
|
order->item= ref_pointer_array + count - 1;
|
||||||
order->in_field_list= 1;
|
order->in_field_list= 1;
|
||||||
|
order->counter= count;
|
||||||
|
order->counter_used= 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
uint counter;
|
uint counter;
|
||||||
Item **item= find_item_in_list(itemptr, fields, &counter, IGNORE_ERRORS);
|
Item **item= find_item_in_list(itemptr, fields, &counter,
|
||||||
if (item)
|
REPORT_EXCEPT_NOT_FOUND);
|
||||||
|
if (!item)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (item != (Item **)not_found_item)
|
||||||
{
|
{
|
||||||
order->item= ref_pointer_array + counter;
|
order->item= ref_pointer_array + counter;
|
||||||
order->in_field_list=1;
|
order->in_field_list=1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
order->in_field_list=0;
|
order->in_field_list=0;
|
||||||
Item *it= *order->item;
|
Item *it= *order->item;
|
||||||
/*
|
/*
|
||||||
@ -10639,7 +10685,16 @@ setup_copy_fields(THD *thd, TMP_TABLE_PARAM *param,
|
|||||||
{
|
{
|
||||||
if (!(pos= new Item_copy_string(pos)))
|
if (!(pos= new Item_copy_string(pos)))
|
||||||
goto err;
|
goto err;
|
||||||
if (param->copy_funcs.push_back(pos))
|
/*
|
||||||
|
Item_copy_string::copy for function can call
|
||||||
|
Item_copy_string::val_int for blob via Item_ref.
|
||||||
|
But if Item_copy_string::copy for blob isn't called before,
|
||||||
|
it's value will be wrong
|
||||||
|
so let's insert Item_copy_string for blobs in the beginning of
|
||||||
|
copy_funcs
|
||||||
|
(to see full test case look at having.test, BUG #4358)
|
||||||
|
*/
|
||||||
|
if (param->copy_funcs.push_front(pos))
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -11676,7 +11731,7 @@ int mysql_explain_union(THD *thd, SELECT_LEX_UNIT *unit, select_result *result)
|
|||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
print_join()
|
print_join()
|
||||||
thd thread handler
|
thd thread handler
|
||||||
str string where table should bbe printed
|
str string where table should be printed
|
||||||
tables list of tables in join
|
tables list of tables in join
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -11732,30 +11787,31 @@ void st_table_list::print(THD *thd, String *str)
|
|||||||
print_join(thd, str, &nested_join->join_list);
|
print_join(thd, str, &nested_join->join_list);
|
||||||
str->append(')');
|
str->append(')');
|
||||||
}
|
}
|
||||||
else if (view_name.str)
|
|
||||||
{
|
|
||||||
append_identifier(thd, str, view_db.str, view_db.length);
|
|
||||||
str->append('.');
|
|
||||||
append_identifier(thd, str, view_name.str, view_name.length);
|
|
||||||
if (my_strcasecmp(table_alias_charset, view_name.str, alias))
|
|
||||||
{
|
|
||||||
str->append(' ');
|
|
||||||
append_identifier(thd, str, alias, strlen(alias));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (derived)
|
|
||||||
{
|
|
||||||
str->append('(');
|
|
||||||
derived->print(str);
|
|
||||||
str->append(") ", 2);
|
|
||||||
append_identifier(thd, str, alias, strlen(alias));
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
append_identifier(thd, str, db, db_length);
|
const char *cmp_name; // Name to compare with alias
|
||||||
str->append('.');
|
if (view_name.str)
|
||||||
append_identifier(thd, str, real_name, real_name_length);
|
{
|
||||||
if (my_strcasecmp(table_alias_charset, real_name, alias))
|
append_identifier(thd, str, view_db.str, view_db.length);
|
||||||
|
str->append('.');
|
||||||
|
append_identifier(thd, str, view_name.str, view_name.length);
|
||||||
|
cmp_name= view_name.str;
|
||||||
|
}
|
||||||
|
else if (derived)
|
||||||
|
{
|
||||||
|
str->append('(');
|
||||||
|
derived->print(str);
|
||||||
|
str->append(')');
|
||||||
|
cmp_name= ""; // Force printing of alias
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
append_identifier(thd, str, db, db_length);
|
||||||
|
str->append('.');
|
||||||
|
append_identifier(thd, str, real_name, real_name_length);
|
||||||
|
cmp_name= real_name;
|
||||||
|
}
|
||||||
|
if (my_strcasecmp(table_alias_charset, cmp_name, alias))
|
||||||
{
|
{
|
||||||
str->append(' ');
|
str->append(' ');
|
||||||
append_identifier(thd, str, alias, strlen(alias));
|
append_identifier(thd, str, alias, strlen(alias));
|
||||||
@ -11771,7 +11827,7 @@ void st_select_lex::print(THD *thd, String *str)
|
|||||||
|
|
||||||
str->append("select ", 7);
|
str->append("select ", 7);
|
||||||
|
|
||||||
//options
|
/* First add options */
|
||||||
if (options & SELECT_STRAIGHT_JOIN)
|
if (options & SELECT_STRAIGHT_JOIN)
|
||||||
str->append("straight_join ", 14);
|
str->append("straight_join ", 14);
|
||||||
if ((thd->lex->lock_option == TL_READ_HIGH_PRIORITY) &&
|
if ((thd->lex->lock_option == TL_READ_HIGH_PRIORITY) &&
|
||||||
|
Reference in New Issue
Block a user