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, ...@@ -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(&param, records, double key_read_time= (get_index_only_read_time(&param, 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 @@ TABLE_READ_PLAN *get_best_disjunct_quick(PARAM *param, SEL_IMERGE *imerge, ...@@ -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 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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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,13 +3748,14 @@ tree_and(PARAM *param,SEL_TREE *tree1,SEL_TREE *tree2) ...@@ -3736,13 +3748,14 @@ 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
if (*key1)
(*key1)->test_use_count(*key1); (*key1)->test_use_count(*key1);
#endif #endif
} }
...@@ -3974,6 +3987,13 @@ key_and(SEL_ARG *key1,SEL_ARG *key2,uint clone_flag) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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() ...@@ -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() ...@@ -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() ...@@ -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?
*/ */
...@@ -883,8 +876,7 @@ JOIN::optimize() ...@@ -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() ...@@ -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)
{ {
...@@ -2572,7 +2562,7 @@ add_key_field(KEY_FIELD **key_fields,uint and_level, COND *cond, ...@@ -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, ...@@ -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 &&
(*value)->result_type() != STRING_RESULT &&
field->cmp_type() != (*value)->result_type())
return; 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 We can't use indexes if the effective collation
of the operation differ from the field 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->result_type() == STRING_RESULT && if (field->cmp_type() == STRING_RESULT &&
(*value)->result_type() == STRING_RESULT && (((Field_str*)field)->charset() != cond->compare_collation() ||
field->cmp_type() == STRING_RESULT && ((*value)->type() != Item::NULL_ITEM &&
((Field_str*)field)->charset() != cond->compare_collation()) (field->flags & BLOB_FLAG) && !field->binary())))
return; 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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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,6 +4973,28 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) ...@@ -4971,6 +4973,28 @@ 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"));
...@@ -4985,13 +5009,13 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) ...@@ -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,11 +5036,26 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) ...@@ -5012,11 +5036,26 @@ 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)
{
/*
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 Hack to handle the case where we only refer to a table
in the ON part of an OUTER JOIN. 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 tmp= new Item_int((longlong) 1,1); // Always true
}
} }
if (tmp || !cond) if (tmp || !cond)
{ {
...@@ -5217,6 +5256,7 @@ static void ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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,10 +6293,11 @@ optimize_cond(JOIN *join, COND *conds, Item::cond_result *cond_value) ...@@ -6291,10 +6293,11 @@ 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, "after negation elimination");); {
DBUG_EXECUTE("where", print_where(conds, "original"););
/* change field = field to field = const for each found field = const */ /* change field = field to field = const for each found field = const */
propagate_cond_constants((I_List<COND_CMP> *) 0,conds,conds); propagate_cond_constants((I_List<COND_CMP> *) 0,conds,conds);
/* /*
...@@ -6304,6 +6307,7 @@ optimize_cond(JOIN *join, COND *conds, Item::cond_result *cond_value) ...@@ -6304,6 +6307,7 @@ optimize_cond(JOIN *join, COND *conds, Item::cond_result *cond_value)
DBUG_EXECUTE("where",print_where(conds,"after const change");); DBUG_EXECUTE("where",print_where(conds,"after const change"););
conds= remove_eq_conds(thd, conds, cond_value) ; conds= remove_eq_conds(thd, conds, cond_value) ;
DBUG_EXECUTE("info",print_where(conds,"after remove");); DBUG_EXECUTE("info",print_where(conds,"after remove"););
}
DBUG_RETURN(conds); DBUG_RETURN(conds);
} }
...@@ -6767,7 +6771,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, ...@@ -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);
...@@ -6894,14 +6898,21 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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,7 +9417,7 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, ...@@ -9378,7 +9417,7 @@ 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.
*/ */
...@@ -10157,7 +10196,7 @@ find_order_in_list(THD *thd, Item **ref_pointer_array, ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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) else
{
const char *cmp_name; // Name to compare with alias
if (view_name.str)
{ {
append_identifier(thd, str, view_db.str, view_db.length); append_identifier(thd, str, view_db.str, view_db.length);
str->append('.'); str->append('.');
append_identifier(thd, str, view_name.str, view_name.length); append_identifier(thd, str, view_name.str, view_name.length);
if (my_strcasecmp(table_alias_charset, view_name.str, alias)) cmp_name= view_name.str;
{
str->append(' ');
append_identifier(thd, str, alias, strlen(alias));
}
} }
else if (derived) else if (derived)
{ {
str->append('('); str->append('(');
derived->print(str); derived->print(str);
str->append(") ", 2); str->append(')');
append_identifier(thd, str, alias, strlen(alias)); cmp_name= ""; // Force printing of alias
} }
else else
{ {
append_identifier(thd, str, db, db_length); append_identifier(thd, str, db, db_length);
str->append('.'); str->append('.');
append_identifier(thd, str, real_name, real_name_length); append_identifier(thd, str, real_name, real_name_length);
if (my_strcasecmp(table_alias_charset, real_name, alias)) 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) ...@@ -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) &&
......
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