Commit e8b74f68 authored by unknown's avatar unknown

Manual merge with implementation for WL#1724

parent 22ecf1d7
......@@ -1672,8 +1672,9 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
if (!head->used_keys.is_clear_all())
{
int key_for_use= find_shortest_key(head, &head->used_keys);
double key_read_time= get_index_only_read_time(&param, records,
key_for_use);
double key_read_time= (get_index_only_read_time(&param, records,
key_for_use) +
(double) records / TIME_FOR_COMPARE);
DBUG_PRINT("info", ("'all'+'using index' scan will be using key %d, "
"read time %g", key_for_use, key_read_time));
if (key_read_time < read_time)
......@@ -2176,6 +2177,12 @@ TABLE_READ_PLAN *get_best_disjunct_quick(PARAM *param, SEL_IMERGE *imerge,
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
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,
......@@ -2190,6 +2197,7 @@ inline double get_index_only_read_time(const PARAM* param, ha_rows records,
return read_time;
}
typedef struct st_ror_scan_info
{
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->ror_scans_map.set_bit(idx);
}
double cpu_cost= (double) found_records / TIME_FOR_COMPARE;
if (found_records != HA_POS_ERROR && found_records > 2 &&
read_index_only &&
(param->table->file->index_flags(keynr, param->max_key_part,1) &
HA_KEYREAD_ONLY) &&
!(pk_is_clustered && keynr == param->table->primary_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
/*
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.
*/
found_read_time= (param->table->file->read_time(keynr,
param->range_count,
found_records)+
(double) found_records / TIME_FOR_COMPARE);
found_read_time= param->table->file->read_time(keynr,
param->range_count,
found_records) +
cpu_cost;
DBUG_PRINT("info",("read_time: %g found_read_time: %g",
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 field_length=field->pack_length()+maybe_null;
bool optimize_range;
SEL_ARG *tree;
char *str, *str2;
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())
DBUG_RETURN(0);
optimize_range= field->optimize_range(param->real_keynr[key_part->key],
key_part->part);
if (type == Item_func::LIKE_FUNC)
{
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;
uint length,offset,min_length,max_length;
if (!field->optimize_range(param->real_keynr[key_part->key],
key_part->part))
if (!optimize_range)
DBUG_RETURN(0); // Can't optimize this
if (!(res= value->val_str(&tmp)))
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));
}
if (!field->optimize_range(param->real_keynr[key_part->key],
key_part->part) &&
if (!optimize_range &&
type != Item_func::EQ_FUNC &&
type != Item_func::EQUAL_FUNC)
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())
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 */
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())
flag|=CLONE_KEY2_MAYBE;
*key1=key_and(*key1,*key2,flag);
if ((*key1)->type == SEL_ARG::IMPOSSIBLE)
if (*key1 && (*key1)->type == SEL_ARG::IMPOSSIBLE)
{
tree1->type= SEL_TREE::IMPOSSIBLE;
DBUG_RETURN(tree1);
}
result_keys.set_bit(key1 - tree1->keys);
#ifdef EXTRA_DEBUG
(*key1)->test_use_count(*key1);
if (*key1)
(*key1)->test_use_count(*key1);
#endif
}
}
......@@ -3974,6 +3987,13 @@ key_and(SEL_ARG *key1,SEL_ARG *key2,uint clone_flag)
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--;
key2->use_count--;
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--;
key2->use_count--;
if (key1->part != key2->part)
if (key1->part != key2->part ||
(key1->min_flag | key2->min_flag) & GEOM_FLAG)
{
key1->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);
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);
return;
}
......@@ -4724,7 +4745,7 @@ void SEL_ARG::test_use_count(SEL_ARG *root)
}
}
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);
}
......
......@@ -226,27 +226,13 @@ int handle_select(THD *thd, LEX *lex, select_result *result)
thd->net.report_error));
if (thd->net.report_error)
res= 1;
if (res > 0)
if (unlikely(res))
{
if (result)
{
if (res > 0)
result->send_error(0, NullS);
result->abort();
}
else
send_error(thd, 0, NullS);
result->abort();
res= 1; // Error sent to client
}
if (res < 0)
{
if (result)
{
result->abort();
}
res= 1;
}
if (result != lex->result)
delete result;
DBUG_RETURN(res);
}
......@@ -349,9 +335,7 @@ JOIN::prepare(Item ***rref_pointer_array,
if ((subselect= select_lex->master_unit()->item))
{
Item_subselect::trans_res res;
if ((res= ((!thd->lex->view_prepare_mode) ?
subselect->select_transformer(this) :
subselect->no_select_transform())) !=
if ((res= subselect->select_transformer(this)) !=
Item_subselect::RES_OK)
{
select_lex->fix_prepare_information(thd, &conds);
......@@ -553,6 +537,7 @@ JOIN::optimize()
if (cond_value == Item::COND_FALSE ||
(!unit->select_limit_cnt && !(select_options & OPTION_FOUND_ROWS)))
{ /* Impossible cond */
DBUG_PRINT("info", ("Impossible WHERE"));
zero_result_cause= "Impossible WHERE";
error= 0;
DBUG_RETURN(0);
......@@ -570,20 +555,24 @@ JOIN::optimize()
{
if (res > 1)
{
DBUG_PRINT("error",("Error from opt_sum_query"));
DBUG_RETURN(1);
}
if (res < 0)
{
DBUG_PRINT("info",("No matching min/max row"));
zero_result_cause= "No matching min/max row";
error=0;
DBUG_RETURN(0);
}
DBUG_PRINT("info",("Select tables optimized away"));
zero_result_cause= "Select tables optimized away";
tables_list= 0; // All tables resolved
}
}
if (!tables_list)
{
DBUG_PRINT("info",("No tables"));
error= 0;
DBUG_RETURN(0);
}
......@@ -777,6 +766,10 @@ JOIN::optimize()
(select_lex->ftfunc_list->elements ?
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?
*/
......@@ -832,7 +825,7 @@ JOIN::optimize()
join_tab->info= "Using index; Using where";
else
join_tab->info= "Using index";
DBUG_RETURN(unit->item->
change_engine(new subselect_indexsubquery_engine(thd,
join_tab,
......@@ -869,7 +862,7 @@ JOIN::optimize()
as in other cases the join is done before the sort.
*/
if (const_tables != tables &&
(order || group_list) &&
(order || group_list) &&
join_tab[const_tables].type != JT_ALL &&
join_tab[const_tables].type != JT_FT &&
join_tab[const_tables].type != JT_REF_OR_NULL &&
......@@ -883,8 +876,7 @@ JOIN::optimize()
((group_list && const_tables != tables &&
(!simple_group ||
!test_if_skip_sort_order(&join_tab[const_tables], group_list,
unit->select_limit_cnt,
0))) ||
unit->select_limit_cnt, 0))) ||
select_distinct) &&
tmp_table_param.quick_group && !procedure)
{
......@@ -899,8 +891,6 @@ JOIN::optimize()
}
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 */
if (need_tmp)
{
......@@ -908,7 +898,7 @@ JOIN::optimize()
thd->proc_info="Creating tmp table";
init_items_ref_array();
tmp_table_param.hidden_field_count= (all_fields.elements -
fields_list.elements);
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 &&
old->val->eq(new_fields->val, old->field->binary()))
{
old->level= and_level;
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
eq_func True if we used =, <=> or IS NULL
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
NOTES
......@@ -2572,7 +2562,7 @@ add_key_field(KEY_FIELD **key_fields,uint and_level, COND *cond,
bool is_const=1;
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)->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.
eq_func is NEVER true when num_values > 1
*/
if (!eq_func ||
field->result_type() == STRING_RESULT &&
(*value)->result_type() != STRING_RESULT &&
field->cmp_type() != (*value)->result_type())
return;
/*
We can't use indexes if the effective collation
of the operation differ from the field collation.
*/
if (field->result_type() == STRING_RESULT &&
(*value)->result_type() == STRING_RESULT &&
field->cmp_type() == STRING_RESULT &&
((Field_str*)field)->charset() != cond->compare_collation())
return;
if (!eq_func)
return;
if (field->result_type() == STRING_RESULT)
{
if ((*value)->result_type() != STRING_RESULT)
{
if (field->cmp_type() != (*value)->result_type())
return;
}
else
{
/*
We can't use indexes if the effective collation
of the operation differ from the field collation.
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);
......@@ -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))
{
Item *tmp=new Item_null;
if (!tmp) // Should never be true
if (unlikely(!tmp)) // Should never be true
return;
add_key_field(key_fields,*and_level,cond_func,
((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;
/*
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 &
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;
byte *key_buff=j->ref.key_buff, *null_ref_key= 0;
bool keyuse_uses_no_tables= TRUE;
if (ftkey)
{
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);
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 &&
!(join->select_options & SELECT_DESCRIBE))
{ // 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->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
......@@ -4971,10 +4973,32 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
COND *const_cond=
make_cond_for_table(cond,join->const_table_map,(table_map) 0);
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())
{
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 *first_inner_tab= tab->first_inner;
table_map current_map= tab->table->map;
bool use_quick_range=0;
/*
Following force including random expression in last table condition.
It solve problem with select like SELECT * FROM t1 WHERE rand() > 0.5
*/
if (i == join->tables-1)
current_map|= OUTER_REF_TABLE_BIT | RAND_TABLE_BIT;
bool use_quick_range=0;
used_tables|=current_map;
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);
if (cond && !tmp && tab->quick)
{ // Outer join
/*
Hack to handle the case where we only refer to a table
in the ON part of an OUTER JOIN.
*/
tmp=new Item_int((longlong) 1,1); // Always true
if (tab->type != JT_ALL)
{
/*
Don't use the quick method
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)
{
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*)
join->thd->memdup((gptr) select, sizeof(SQL_SELECT));
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.
The guard will turn the predicate on only after
the first match for outer tables is encountered.
*/
*/
if (cond)
{/*
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)
{
uint i;
bool statistics= test(!(join->select_options & SELECT_DESCRIBE));
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;
tab->read_first_record= join_init_quick_read_record;
if (statistics)
statistic_increment(select_range_check_count, &LOCK_status);
statistic_increment(join->thd->status_var.select_range_check_count,
&LOCK_status);
}
else
{
......@@ -5325,13 +5366,15 @@ make_join_readinfo(JOIN *join, uint options)
if (tab->select && tab->select->quick)
{
if (statistics)
statistic_increment(select_range_count, &LOCK_status);
statistic_increment(join->thd->status_var.select_range_count,
&LOCK_status);
}
else
{
join->thd->server_status|=SERVER_QUERY_NO_INDEX_USED;
if (statistics)
statistic_increment(select_scan_count, &LOCK_status);
statistic_increment(join->thd->status_var.select_scan_count,
&LOCK_status);
}
}
else
......@@ -5339,13 +5382,15 @@ make_join_readinfo(JOIN *join, uint options)
if (tab->select && tab->select->quick)
{
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
{
join->thd->server_status|=SERVER_QUERY_NO_INDEX_USED;
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)
......@@ -5520,6 +5565,10 @@ JOIN::join_free(bool full)
if (full)
{
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.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 (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()));
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_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();
if (tmp)
......@@ -5845,7 +5897,10 @@ change_cond_ref_to_const(I_List<COND_CMP> *save_list,Item *and_father,
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();
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
......@@ -6085,9 +6084,9 @@ COND *eliminate_not_funcs(THD *thd, COND *cond)
The function removes all unnecessary braces from the expression
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:
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:
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;
TABLE_LIST *prev_table= 0;
List_iterator<TABLE_LIST> li(*join_list);
DBUG_ENTER("simplify_joins");
/*
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);
}
}
return conds;
DBUG_RETURN(conds);
}
static COND *
optimize_cond(JOIN *join, COND *conds, Item::cond_result *cond_value)
{
DBUG_ENTER("optimize_cond");
THD *thd= join->thd;
SELECT_LEX *select= thd->lex->current_select;
DBUG_ENTER("optimize_cond");
if (select->first_cond_optimization)
{
Item_arena *arena= thd->current_arena;
Item_arena backup;
if (arena)
/*
The following code will allocate the new items in a permanent
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);
if (conds)
{
DBUG_EXECUTE("where",print_where(conds,"original"););
/* eliminate NOT operators */
conds= eliminate_not_funcs(thd, conds);
}
select->first_cond_optimization= 0;
/* Convert all outer joins to inner joins if possible */
conds= simplify_joins(join, join->join_list, conds, TRUE);
select->prep_where= conds ? conds->copy_andor_structure(thd) : 0;
select->first_cond_optimization= 0;
if (arena)
thd->restore_backup_item_arena(arena, &backup);
}
......@@ -6291,19 +6293,21 @@ optimize_cond(JOIN *join, COND *conds, Item::cond_result *cond_value)
if (!conds)
{
*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);
}
......@@ -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
in this array
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
modify_item 1 if item->result_field should point to new item.
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.
If modify_item is 0 then fill_record() will update
the temporary table
RETURN
0 on error
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,
item->name, table, item_sum->decimals);
case Item_sum::VARIANCE_FUNC: /* Place for sum & count */
case Item_sum::STD_FUNC:
case Item_sum::STD_FUNC:
if (group)
return new Field_string(sizeof(double)*2+sizeof(longlong),
0, item->name,table,&my_charset_bin);
else
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:
return new Field_long(9,maybe_null,item->name,table,1);
default:
......@@ -6767,7 +6771,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
(int) distinct, (int) save_sum_fields,
(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)
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
sprintf(path,"%s%s%lx_%lx_%x",mysql_tmpdir,tmp_file_prefix,current_pid,
thd->thread_id, thd->tmp_table++);
if (lower_case_table_names)
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++;
*(reg_field++)= new_field;
reclength+=new_field->pack_length();
if (!(new_field->flags & NOT_NULL_FLAG))
null_count++;
if (new_field->flags & BLOB_FLAG)
{
*blob_field++= new_field;
blob_count++;
}
((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;
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;
DBUG_RETURN(0);
err:
......@@ -7434,6 +7446,18 @@ bool create_myisam_from_heap(THD *thd, TABLE *table, TMP_TABLE_PARAM *param,
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 */
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
join_read_const(JOIN_TAB *tab)
{
......@@ -8153,6 +8190,7 @@ join_read_const(JOIN_TAB *tab)
TABLE *table= tab->table;
if (table->status & STATUS_GARBAGE) // If first read
{
table->status= 0;
if (cp_buffer_from_ref(&tab->ref))
error=HA_ERR_KEY_NOT_FOUND;
else
......@@ -8163,6 +8201,7 @@ join_read_const(JOIN_TAB *tab)
}
if (error)
{
table->status= STATUS_NOT_FOUND;
table->null_row=1;
empty_record(table);
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);
/*
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.
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)
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;
if (itemptr->type() == Item::INT_ITEM)
{ /* Order by position */
uint count= itemptr->val_int();
uint count= (uint) itemptr->val_int();
if (!count || count > fields.elements)
{
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);
return 1;
}
order->item= ref_pointer_array + count-1;
order->item= ref_pointer_array + count - 1;
order->in_field_list= 1;
order->counter= count;
order->counter_used= 1;
return 0;
}
uint counter;
Item **item= find_item_in_list(itemptr, fields, &counter, IGNORE_ERRORS);
if (item)
Item **item= find_item_in_list(itemptr, fields, &counter,
REPORT_EXCEPT_NOT_FOUND);
if (!item)
return 1;
if (item != (Item **)not_found_item)
{
order->item= ref_pointer_array + counter;
order->in_field_list=1;
return 0;
}
order->in_field_list=0;
Item *it= *order->item;
/*
......@@ -10639,7 +10685,16 @@ setup_copy_fields(THD *thd, TMP_TABLE_PARAM *param,
{
if (!(pos= new Item_copy_string(pos)))
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;
}
else
......@@ -11676,7 +11731,7 @@ int mysql_explain_union(THD *thd, SELECT_LEX_UNIT *unit, select_result *result)
SYNOPSIS
print_join()
thd thread handler
str string where table should bbe printed
str string where table should be printed
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);
str->append(')');
}
else if (view_name.str)
else
{
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))
const char *cmp_name; // Name to compare with alias
if (view_name.str)
{
str->append(' ');
append_identifier(thd, str, alias, strlen(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(") ", 2);
append_identifier(thd, str, alias, strlen(alias));
}
else
{
append_identifier(thd, str, db, db_length);
str->append('.');
append_identifier(thd, str, real_name, real_name_length);
if (my_strcasecmp(table_alias_charset, real_name, alias))
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(' ');
append_identifier(thd, str, alias, strlen(alias));
......@@ -11771,7 +11827,7 @@ void st_select_lex::print(THD *thd, String *str)
str->append("select ", 7);
//options
/* First add options */
if (options & SELECT_STRAIGHT_JOIN)
str->append("straight_join ", 14);
if ((thd->lex->lock_option == TL_READ_HIGH_PRIORITY) &&
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment