This ChangeSet Introdices Item_equal.
The objects of this class represent multiple conjunctive equalities in where conditions: =(f1,f2,...fn) <=> f1=f2 and f2= ... and =fn. The objects are used to generate new possibale paths to access the tables when executing a query. They are also used to optimize the execution plan chosen by the optimizer for the query. sql/item.cc: Introduced Item_equal sql/item.h: Introduced Item_equal. Added traverse method. sql/item_cmpfunc.cc: Introduced Item_equal. Added traverse mehtod. sql/item_cmpfunc.h: Itroduced Item_equal and Item_equal_iterator. sql/item_func.cc: Added traverse method. Introduced Item_equal. sql/item_func.h: Introduced Item_equal. Added traverse method. sql/item_row.cc: Added traverse method. sql/item_row.h: Added traverse method. sql/item_strfunc.h: Added traverse method. sql/opt_range.cc: Used Item_equal in range analysis. sql/opt_sum.cc: Introduced Item_equal. sql/sql_list.h: Added concat and disjoin methods to lists. Fixed remove method for lists. sql/sql_select.cc: Introdiced Item_equal: created Item_equal; used Item_equal objects to generate new paths to access tables. used Item_equal objects to optimize the execution plan chosen by optimizer. sql/sql_select.h: Introduced Item_equal.
This commit is contained in:
parent
afe2186e3b
commit
da566c16c0
47
sql/item.cc
47
sql/item.cc
@ -299,7 +299,8 @@ bool DTCollation::aggregate(DTCollation &dt)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Item_field::Item_field(Field *f) :Item_ident(NullS,f->table_name,f->field_name)
|
Item_field::Item_field(Field *f)
|
||||||
|
:Item_ident(NullS,f->table_name,f->field_name), item_equal(0)
|
||||||
{
|
{
|
||||||
set_field(f);
|
set_field(f);
|
||||||
collation.set(DERIVATION_IMPLICIT);
|
collation.set(DERIVATION_IMPLICIT);
|
||||||
@ -313,6 +314,7 @@ Item_field::Item_field(THD *thd, Item_field &item)
|
|||||||
result_field(item.result_field)
|
result_field(item.result_field)
|
||||||
{
|
{
|
||||||
collation.set(DERIVATION_IMPLICIT);
|
collation.set(DERIVATION_IMPLICIT);
|
||||||
|
item_equal= item.item_equal;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Item_field::set_field(Field *field_par)
|
void Item_field::set_field(Field *field_par)
|
||||||
@ -969,6 +971,49 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Item_equal *Item_field::find_item_equal(COND_EQUAL *cond_equal)
|
||||||
|
{
|
||||||
|
Item_equal *item= 0;
|
||||||
|
while (cond_equal)
|
||||||
|
{
|
||||||
|
List_iterator_fast<Item_equal> li(cond_equal->current_level);
|
||||||
|
while ((item= li++))
|
||||||
|
{
|
||||||
|
if (item->contains(field))
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
cond_equal= cond_equal->parent_level;
|
||||||
|
}
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
Item *Item_field::equal_fields_propagator(byte *arg)
|
||||||
|
{
|
||||||
|
COND_EQUAL *cond_equal= (COND_EQUAL *) arg;
|
||||||
|
item_equal= find_item_equal(cond_equal);
|
||||||
|
Item *item= 0;
|
||||||
|
if (item_equal)
|
||||||
|
item= item_equal->get_const();
|
||||||
|
if (item)
|
||||||
|
item->fixed= 0;
|
||||||
|
else
|
||||||
|
item= this;
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Item_field::replace_equal_field_processor(byte *arg)
|
||||||
|
{
|
||||||
|
if (item_equal)
|
||||||
|
{
|
||||||
|
Item_field *subst= item_equal->get_first();
|
||||||
|
if (subst && !field->eq(subst->field))
|
||||||
|
{
|
||||||
|
field= subst->field;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void Item::init_make_field(Send_field *tmp_field,
|
void Item::init_make_field(Send_field *tmp_field,
|
||||||
enum enum_field_types field_type)
|
enum enum_field_types field_type)
|
||||||
|
26
sql/item.h
26
sql/item.h
@ -83,6 +83,7 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
typedef bool (Item::*Item_processor)(byte *arg);
|
typedef bool (Item::*Item_processor)(byte *arg);
|
||||||
|
typedef Item* (Item::*Item_calculator) (byte *arg);
|
||||||
|
|
||||||
class Item {
|
class Item {
|
||||||
Item(const Item &); /* Prevent use of these */
|
Item(const Item &); /* Prevent use of these */
|
||||||
@ -201,8 +202,15 @@ public:
|
|||||||
return (this->*processor)(arg);
|
return (this->*processor)(arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual Item* traverse(Item_calculator calculator, byte *arg)
|
||||||
|
{
|
||||||
|
return (this->*calculator)(arg);
|
||||||
|
}
|
||||||
|
|
||||||
virtual bool remove_dependence_processor(byte * arg) { return 0; }
|
virtual bool remove_dependence_processor(byte * arg) { return 0; }
|
||||||
virtual bool remove_fixed(byte * arg) { fixed= 0; return 0; }
|
virtual bool remove_fixed(byte * arg) { fixed= 0; return 0; }
|
||||||
|
virtual Item *equal_fields_propagator(byte * arg) { return this; }
|
||||||
|
virtual bool replace_equal_field_processor(byte * arg) { return 0; }
|
||||||
|
|
||||||
virtual Item *this_item() { return this; } /* For SPs mostly. */
|
virtual Item *this_item() { return this; } /* For SPs mostly. */
|
||||||
virtual Item *this_const_item() const { return const_cast<Item*>(this); } /* For SPs mostly. */
|
virtual Item *this_const_item() const { return const_cast<Item*>(this); } /* For SPs mostly. */
|
||||||
@ -311,17 +319,21 @@ public:
|
|||||||
bool remove_dependence_processor(byte * arg);
|
bool remove_dependence_processor(byte * arg);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class Item_equal;
|
||||||
|
class COND_EQUAL;
|
||||||
|
|
||||||
class Item_field :public Item_ident
|
class Item_field :public Item_ident
|
||||||
{
|
{
|
||||||
void set_field(Field *field);
|
void set_field(Field *field);
|
||||||
public:
|
public:
|
||||||
Field *field,*result_field;
|
Field *field,*result_field;
|
||||||
|
Item_equal *item_equal;
|
||||||
// Item_field() {}
|
// Item_field() {}
|
||||||
|
|
||||||
Item_field(const char *db_par,const char *table_name_par,
|
Item_field(const char *db_par,const char *table_name_par,
|
||||||
const char *field_name_par)
|
const char *field_name_par)
|
||||||
:Item_ident(db_par,table_name_par,field_name_par),field(0),result_field(0)
|
:Item_ident(db_par,table_name_par,field_name_par),field(0),result_field(0),
|
||||||
|
item_equal(0)
|
||||||
{ collation.set(DERIVATION_IMPLICIT); }
|
{ collation.set(DERIVATION_IMPLICIT); }
|
||||||
// Constructor need to process subselect with temporary tables (see Item)
|
// Constructor need to process subselect with temporary tables (see Item)
|
||||||
Item_field(THD *thd, Item_field &item);
|
Item_field(THD *thd, Item_field &item);
|
||||||
@ -355,6 +367,9 @@ public:
|
|||||||
bool get_time(TIME *ltime);
|
bool get_time(TIME *ltime);
|
||||||
bool is_null() { return field->is_null(); }
|
bool is_null() { return field->is_null(); }
|
||||||
Item *get_tmp_table_item(THD *thd);
|
Item *get_tmp_table_item(THD *thd);
|
||||||
|
Item_equal *find_item_equal(COND_EQUAL *cond_equal);
|
||||||
|
Item *equal_fields_propagator(byte *arg);
|
||||||
|
bool replace_equal_field_processor(byte *arg);
|
||||||
friend class Item_default_value;
|
friend class Item_default_value;
|
||||||
friend class Item_insert_value;
|
friend class Item_insert_value;
|
||||||
};
|
};
|
||||||
@ -897,6 +912,15 @@ public:
|
|||||||
return arg->walk(processor, args) ||
|
return arg->walk(processor, args) ||
|
||||||
(this->*processor)(args);
|
(this->*processor)(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Item *traverse(Item_calculator calculator, byte *args)
|
||||||
|
{
|
||||||
|
Item *new_item= arg->traverse(calculator, args);
|
||||||
|
if (!new_item)
|
||||||
|
return 0;
|
||||||
|
arg= new_item;
|
||||||
|
return (this->*calculator)(args);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class Item_insert_value : public Item_field
|
class Item_insert_value : public Item_field
|
||||||
|
@ -225,7 +225,7 @@ void Item_bool_func2::fix_length_and_dec()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Make a special case of compare with fields to get nicer DATE comparisons
|
// Make a special case of compare with fields to get nicer DATE comparisons
|
||||||
if (args[0]->type() == FIELD_ITEM)
|
if (args[0]->type() == FIELD_ITEM && !args[0]->const_item())
|
||||||
{
|
{
|
||||||
Field *field=((Item_field*) args[0])->field;
|
Field *field=((Item_field*) args[0])->field;
|
||||||
if (field->store_for_compare())
|
if (field->store_for_compare())
|
||||||
@ -238,7 +238,7 @@ void Item_bool_func2::fix_length_and_dec()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (args[1]->type() == FIELD_ITEM)
|
if (args[1]->type() == FIELD_ITEM && !args[1]->const_item())
|
||||||
{
|
{
|
||||||
Field *field=((Item_field*) args[1])->field;
|
Field *field=((Item_field*) args[1])->field;
|
||||||
if (field->store_for_compare())
|
if (field->store_for_compare())
|
||||||
@ -1712,6 +1712,21 @@ bool Item_cond::walk(Item_processor processor, byte *arg)
|
|||||||
return Item_func::walk(processor, arg);
|
return Item_func::walk(processor, arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Item *Item_cond::traverse(Item_calculator calculator, byte *arg)
|
||||||
|
{
|
||||||
|
List_iterator<Item> li(list);
|
||||||
|
Item *item;
|
||||||
|
while ((item= li++))
|
||||||
|
{
|
||||||
|
Item *new_item= item->traverse(calculator, arg);
|
||||||
|
if (!new_item)
|
||||||
|
return 0;
|
||||||
|
if (new_item != item)
|
||||||
|
li.replace(new_item);
|
||||||
|
}
|
||||||
|
return Item_func::traverse(calculator, arg);
|
||||||
|
}
|
||||||
|
|
||||||
void Item_cond::split_sum_func(Item **ref_pointer_array, List<Item> &fields)
|
void Item_cond::split_sum_func(Item **ref_pointer_array, List<Item> &fields)
|
||||||
{
|
{
|
||||||
List_iterator<Item> li(list);
|
List_iterator<Item> li(list);
|
||||||
@ -2499,3 +2514,217 @@ Item *Item_cond_or::neg_transformer() /* NOT(a OR b OR ...) -> */
|
|||||||
neg_arguments();
|
neg_arguments();
|
||||||
return new Item_cond_and(list);
|
return new Item_cond_and(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Item_equal::Item_equal(Item_field *f1, Item_field *f2)
|
||||||
|
: Item_bool_func(), const_item(0), eval_item(0), cond_false(0)
|
||||||
|
{
|
||||||
|
const_item_cache= 0;
|
||||||
|
fields.push_back(f1);
|
||||||
|
fields.push_back(f2);
|
||||||
|
}
|
||||||
|
|
||||||
|
Item_equal::Item_equal(Item *c, Item_field *f)
|
||||||
|
: Item_bool_func(), eval_item(0), cond_false(0)
|
||||||
|
{
|
||||||
|
const_item_cache= 0;
|
||||||
|
fields.push_back(f);
|
||||||
|
const_item= c;
|
||||||
|
}
|
||||||
|
|
||||||
|
Item_equal::Item_equal(Item_equal *item_equal)
|
||||||
|
: Item_bool_func(), eval_item(0), cond_false(0)
|
||||||
|
{
|
||||||
|
const_item_cache= 0;
|
||||||
|
List_iterator_fast<Item_field> li(item_equal->fields);
|
||||||
|
Item_field *item;
|
||||||
|
while ((item= li++))
|
||||||
|
{
|
||||||
|
fields.push_back(item);
|
||||||
|
}
|
||||||
|
const_item= item_equal->const_item;
|
||||||
|
cond_false= item_equal->cond_false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Item_equal::add(Item *c)
|
||||||
|
{
|
||||||
|
if (cond_false)
|
||||||
|
return;
|
||||||
|
if (!const_item)
|
||||||
|
{
|
||||||
|
const_item= c;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Item_func_eq *func= new Item_func_eq(c, const_item);
|
||||||
|
func->set_cmp_func();
|
||||||
|
cond_false = !(func->val_int());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Item_equal::add(Item_field *f)
|
||||||
|
{
|
||||||
|
fields.push_back(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Item_equal::contains(Field *field)
|
||||||
|
{
|
||||||
|
List_iterator_fast<Item_field> it(fields);
|
||||||
|
Item_field *item;
|
||||||
|
while ((item= it++))
|
||||||
|
{
|
||||||
|
if (field->eq(item->field))
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Item_equal::merge(Item_equal *item)
|
||||||
|
{
|
||||||
|
fields.concat(&item->fields);
|
||||||
|
Item *c= item->const_item;
|
||||||
|
if (c)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
The flag cond_false will be set to 1 after this, if
|
||||||
|
the multiple equality already contains a constant and its
|
||||||
|
value is not equal to the value of c.
|
||||||
|
*/
|
||||||
|
add(const_item);
|
||||||
|
}
|
||||||
|
cond_false|= item->cond_false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Item_equal::sort(void *table_join_idx)
|
||||||
|
{
|
||||||
|
bool swap;
|
||||||
|
void **idx= (void **) table_join_idx;
|
||||||
|
List_iterator<Item_field> it(fields);
|
||||||
|
do
|
||||||
|
{
|
||||||
|
Item_field *item1= it++;
|
||||||
|
Item_field **ref1= it.ref();
|
||||||
|
Item_field *item2;
|
||||||
|
Item_field **ref2;
|
||||||
|
|
||||||
|
if (!item1)
|
||||||
|
break;
|
||||||
|
swap= FALSE;
|
||||||
|
while ((item2= it++))
|
||||||
|
{
|
||||||
|
ref2= it.ref();
|
||||||
|
if (idx[item1->field->table->tablenr] >
|
||||||
|
idx[item2->field->table->tablenr])
|
||||||
|
{
|
||||||
|
Item_field *item= *ref1;
|
||||||
|
*ref1= *ref2;
|
||||||
|
*ref2= item;
|
||||||
|
swap= TRUE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
item1= item2;
|
||||||
|
ref1= ref2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
it.rewind();
|
||||||
|
} while (swap);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Item_equal::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
|
||||||
|
{
|
||||||
|
List_iterator_fast<Item_field> li(fields);
|
||||||
|
Item *item;
|
||||||
|
not_null_tables_cache= used_tables_cache= 0;
|
||||||
|
const_item_cache= 0;
|
||||||
|
while ((item=li++))
|
||||||
|
{
|
||||||
|
table_map tmp_table_map;
|
||||||
|
used_tables_cache|= item->used_tables();
|
||||||
|
tmp_table_map= item->not_null_tables();
|
||||||
|
not_null_tables_cache|= tmp_table_map;
|
||||||
|
if (item->maybe_null)
|
||||||
|
maybe_null=1;
|
||||||
|
}
|
||||||
|
fix_length_and_dec();
|
||||||
|
fixed= 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Item_equal::update_used_tables()
|
||||||
|
{
|
||||||
|
List_iterator_fast<Item_field> li(fields);
|
||||||
|
Item *item;
|
||||||
|
not_null_tables_cache= used_tables_cache= 0;
|
||||||
|
while ((item=li++))
|
||||||
|
{
|
||||||
|
item->update_used_tables();
|
||||||
|
used_tables_cache|= item->used_tables();
|
||||||
|
const_item_cache&= item->const_item();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
longlong Item_equal::val_int()
|
||||||
|
{
|
||||||
|
if (cond_false)
|
||||||
|
return 0;
|
||||||
|
List_iterator_fast<Item_field> it(fields);
|
||||||
|
Item *item= const_item ? const_item : it++;
|
||||||
|
if ((null_value= item->null_value))
|
||||||
|
return 0;
|
||||||
|
eval_item->store_value(item);
|
||||||
|
while((item= it++))
|
||||||
|
{
|
||||||
|
if ((null_value= item->null_value) || eval_item->cmp(item))
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Item_equal::fix_length_and_dec()
|
||||||
|
{
|
||||||
|
Item *item= const_item ? const_item : get_first();
|
||||||
|
eval_item= cmp_item::get_comparator(item);
|
||||||
|
if (item->result_type() == STRING_RESULT)
|
||||||
|
eval_item->cmp_charset= cmp_collation.collation;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Item_equal::walk(Item_processor processor, byte *arg)
|
||||||
|
{
|
||||||
|
List_iterator_fast<Item_field> it(fields);
|
||||||
|
Item *item;
|
||||||
|
while ((item= it++))
|
||||||
|
if (item->walk(processor, arg))
|
||||||
|
return 1;
|
||||||
|
return Item_func::walk(processor, arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
Item *Item_equal::traverse(Item_calculator calculator, byte *arg)
|
||||||
|
{
|
||||||
|
List_iterator<Item_field> it(fields);
|
||||||
|
Item *item;
|
||||||
|
while ((item= it++))
|
||||||
|
{
|
||||||
|
Item *new_item= item->traverse(calculator, arg);
|
||||||
|
if (!new_item)
|
||||||
|
return 0;
|
||||||
|
if (new_item != item)
|
||||||
|
it.replace((Item_field *) new_item);
|
||||||
|
}
|
||||||
|
return Item_func::traverse(calculator, arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Item_equal::print(String *str)
|
||||||
|
{
|
||||||
|
str->append(func_name());
|
||||||
|
str->append('(');
|
||||||
|
List_iterator_fast<Item_field> it(fields);
|
||||||
|
Item *item;
|
||||||
|
if ((item= it++))
|
||||||
|
item->print(str);
|
||||||
|
while ((item= it++))
|
||||||
|
{
|
||||||
|
str->append(',');
|
||||||
|
str->append(' ');
|
||||||
|
item->print(str);
|
||||||
|
}
|
||||||
|
str->append(')');
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -908,13 +908,76 @@ public:
|
|||||||
void top_level_item() { abort_on_null=1; }
|
void top_level_item() { abort_on_null=1; }
|
||||||
void copy_andor_arguments(THD *thd, Item_cond *item);
|
void copy_andor_arguments(THD *thd, Item_cond *item);
|
||||||
bool walk(Item_processor processor, byte *arg);
|
bool walk(Item_processor processor, byte *arg);
|
||||||
|
Item *traverse(Item_calculator calculator, byte *arg);
|
||||||
void neg_arguments();
|
void neg_arguments();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class Item_equal: public Item_bool_func
|
||||||
|
{
|
||||||
|
List<Item_field> fields; /* list of equal field items */
|
||||||
|
Item *const_item; /* optional constant item equal to fields items */
|
||||||
|
cmp_item *eval_item;
|
||||||
|
bool cond_false;
|
||||||
|
DTCollation cmp_collation;
|
||||||
|
public:
|
||||||
|
inline Item_equal()
|
||||||
|
: Item_bool_func(), const_item(0), eval_item(0), cond_false(0)
|
||||||
|
{ const_item_cache=0 ;}
|
||||||
|
Item_equal(Item_field *f1, Item_field *f2);
|
||||||
|
Item_equal(Item *c, Item_field *f);
|
||||||
|
Item_equal(Item_equal *item_equal);
|
||||||
|
inline Item* get_const() { return const_item; }
|
||||||
|
void add(Item *c);
|
||||||
|
void add(Item_field *f);
|
||||||
|
bool is_false() { return cond_false; }
|
||||||
|
bool contains(Field *field);
|
||||||
|
Item_field* get_first() { return fields.head(); }
|
||||||
|
void merge(Item_equal *item);
|
||||||
|
enum Functype functype() const { return MULT_EQUAL_FUNC; }
|
||||||
|
longlong val_int();
|
||||||
|
const char *func_name() const { return "multiple equal"; }
|
||||||
|
optimize_type select_optimize() const { return OPTIMIZE_EQUAL; }
|
||||||
|
void sort(void *table_join_idx);
|
||||||
|
friend class Item_equal_iterator;
|
||||||
|
void fix_length_and_dec();
|
||||||
|
bool fix_fields(THD *thd, TABLE_LIST *tables, Item **ref);
|
||||||
|
void update_used_tables();
|
||||||
|
bool walk(Item_processor processor, byte *arg);
|
||||||
|
Item *traverse(Item_calculator calculator, byte *arg);
|
||||||
|
void print(String *str);
|
||||||
|
};
|
||||||
|
|
||||||
|
class COND_EQUAL
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
COND_EQUAL *parent_level;
|
||||||
|
List<Item_equal> current_level;
|
||||||
|
COND_EQUAL() { parent_level= 0; }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class Item_equal_iterator :List_iterator_fast<Item_field>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
inline Item_equal_iterator(Item_equal &item_equal)
|
||||||
|
:List_iterator_fast<Item_field> (item_equal.fields)
|
||||||
|
{}
|
||||||
|
inline Item_field* operator++(int)
|
||||||
|
{
|
||||||
|
Item_field *item= (*(List_iterator_fast<Item_field> *) this)++;
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
inline void rewind(void)
|
||||||
|
{
|
||||||
|
List_iterator_fast<Item_field>::rewind();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
class Item_cond_and :public Item_cond
|
class Item_cond_and :public Item_cond
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
COND_EQUAL cond_equal;
|
||||||
Item_cond_and() :Item_cond() {}
|
Item_cond_and() :Item_cond() {}
|
||||||
Item_cond_and(Item *i1,Item *i2) :Item_cond(i1,i2) {}
|
Item_cond_and(Item *i1,Item *i2) :Item_cond(i1,i2) {}
|
||||||
Item_cond_and(THD *thd, Item_cond_and &item) :Item_cond(thd, item) {}
|
Item_cond_and(THD *thd, Item_cond_and &item) :Item_cond(thd, item) {}
|
||||||
|
@ -242,6 +242,40 @@ bool Item_func::walk (Item_processor processor, byte *argument)
|
|||||||
return (this->*processor)(argument);
|
return (this->*processor)(argument);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Item *Item_func::traverse(Item_calculator calculator, byte *argument)
|
||||||
|
{
|
||||||
|
if (arg_count)
|
||||||
|
{
|
||||||
|
Item **arg,**arg_end;
|
||||||
|
for (arg= args, arg_end= args+arg_count; arg != arg_end; arg++)
|
||||||
|
{
|
||||||
|
Item *new_item= (*arg)->traverse(calculator, argument);
|
||||||
|
if (!new_item)
|
||||||
|
return 0;
|
||||||
|
*arg= new_item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (this->*calculator)(argument);
|
||||||
|
}
|
||||||
|
|
||||||
|
Item *Item_func::equal_fields_propagator(byte *argument)
|
||||||
|
{
|
||||||
|
if (arg_count)
|
||||||
|
{
|
||||||
|
Item **arg,**arg_end;
|
||||||
|
for (arg= args, arg_end= args+arg_count; arg != arg_end; arg++)
|
||||||
|
{
|
||||||
|
if (!(*arg)->fixed)
|
||||||
|
{
|
||||||
|
fix_fields(current_thd, 0, 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void Item_func::split_sum_func(Item **ref_pointer_array, List<Item> &fields)
|
void Item_func::split_sum_func(Item **ref_pointer_array, List<Item> &fields)
|
||||||
{
|
{
|
||||||
Item **arg, **arg_end;
|
Item **arg, **arg_end;
|
||||||
|
@ -40,7 +40,8 @@ public:
|
|||||||
enum Functype { UNKNOWN_FUNC,EQ_FUNC,EQUAL_FUNC,NE_FUNC,LT_FUNC,LE_FUNC,
|
enum Functype { UNKNOWN_FUNC,EQ_FUNC,EQUAL_FUNC,NE_FUNC,LT_FUNC,LE_FUNC,
|
||||||
GE_FUNC,GT_FUNC,FT_FUNC,
|
GE_FUNC,GT_FUNC,FT_FUNC,
|
||||||
LIKE_FUNC,NOTLIKE_FUNC,ISNULL_FUNC,ISNOTNULL_FUNC,
|
LIKE_FUNC,NOTLIKE_FUNC,ISNULL_FUNC,ISNOTNULL_FUNC,
|
||||||
COND_AND_FUNC, COND_OR_FUNC, COND_XOR_FUNC, BETWEEN, IN_FUNC,
|
COND_AND_FUNC, COND_OR_FUNC, COND_XOR_FUNC,
|
||||||
|
BETWEEN, IN_FUNC, MULT_EQUAL_FUNC,
|
||||||
INTERVAL_FUNC, ISNOTNULLTEST_FUNC,
|
INTERVAL_FUNC, ISNOTNULLTEST_FUNC,
|
||||||
SP_EQUALS_FUNC, SP_DISJOINT_FUNC,SP_INTERSECTS_FUNC,
|
SP_EQUALS_FUNC, SP_DISJOINT_FUNC,SP_INTERSECTS_FUNC,
|
||||||
SP_TOUCHES_FUNC,SP_CROSSES_FUNC,SP_WITHIN_FUNC,
|
SP_TOUCHES_FUNC,SP_CROSSES_FUNC,SP_WITHIN_FUNC,
|
||||||
@ -49,7 +50,8 @@ public:
|
|||||||
SP_POINTN,SP_GEOMETRYN,SP_INTERIORRINGN,
|
SP_POINTN,SP_GEOMETRYN,SP_INTERIORRINGN,
|
||||||
NOT_FUNC, NOT_ALL_FUNC,
|
NOT_FUNC, NOT_ALL_FUNC,
|
||||||
GUSERVAR_FUNC};
|
GUSERVAR_FUNC};
|
||||||
enum optimize_type { OPTIMIZE_NONE,OPTIMIZE_KEY,OPTIMIZE_OP, OPTIMIZE_NULL };
|
enum optimize_type { OPTIMIZE_NONE,OPTIMIZE_KEY,OPTIMIZE_OP, OPTIMIZE_NULL,
|
||||||
|
OPTIMIZE_EQUAL };
|
||||||
enum Type type() const { return FUNC_ITEM; }
|
enum Type type() const { return FUNC_ITEM; }
|
||||||
virtual enum Functype functype() const { return UNKNOWN_FUNC; }
|
virtual enum Functype functype() const { return UNKNOWN_FUNC; }
|
||||||
Item_func(void):
|
Item_func(void):
|
||||||
@ -146,6 +148,8 @@ public:
|
|||||||
bool agg_arg_collations_for_comparison(DTCollation &c, Item **items, uint nitems);
|
bool agg_arg_collations_for_comparison(DTCollation &c, Item **items, uint nitems);
|
||||||
|
|
||||||
bool walk(Item_processor processor, byte *arg);
|
bool walk(Item_processor processor, byte *arg);
|
||||||
|
Item *traverse(Item_calculator calculator, byte *arg);
|
||||||
|
Item *equal_fields_propagator(byte *arg);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -140,6 +140,18 @@ bool Item_row::walk(Item_processor processor, byte *arg)
|
|||||||
return (this->*processor)(arg);
|
return (this->*processor)(arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Item *Item_row::traverse(Item_calculator calculator, byte *arg)
|
||||||
|
{
|
||||||
|
for (uint i= 0; i < arg_count; i++)
|
||||||
|
{
|
||||||
|
Item *new_item= items[i]->traverse(calculator, arg);
|
||||||
|
if (!new_item)
|
||||||
|
return 0;
|
||||||
|
items[i]= new_item;
|
||||||
|
}
|
||||||
|
return (this->*calculator)(arg);
|
||||||
|
}
|
||||||
|
|
||||||
void Item_row::bring_value()
|
void Item_row::bring_value()
|
||||||
{
|
{
|
||||||
for (uint i= 0; i < arg_count; i++)
|
for (uint i= 0; i < arg_count; i++)
|
||||||
|
@ -71,6 +71,7 @@ public:
|
|||||||
void print(String *str);
|
void print(String *str);
|
||||||
|
|
||||||
bool walk(Item_processor processor, byte *arg);
|
bool walk(Item_processor processor, byte *arg);
|
||||||
|
Item *traverse(Item_calculator calculator, byte *arg);
|
||||||
|
|
||||||
uint cols() { return arg_count; }
|
uint cols() { return arg_count; }
|
||||||
Item* el(uint i) { return items[i]; }
|
Item* el(uint i) { return items[i]; }
|
||||||
|
@ -427,6 +427,14 @@ public:
|
|||||||
return item->walk(processor, arg) ||
|
return item->walk(processor, arg) ||
|
||||||
Item_str_func::walk(processor, arg);
|
Item_str_func::walk(processor, arg);
|
||||||
}
|
}
|
||||||
|
Item *traverse(Item_calculator calculator, byte *arg)
|
||||||
|
{
|
||||||
|
Item *new_item= item->traverse(calculator, arg);
|
||||||
|
if (!new_item)
|
||||||
|
return 0;
|
||||||
|
item= new_item;
|
||||||
|
return Item_str_func::traverse(calculator, arg);
|
||||||
|
}
|
||||||
void print(String *str);
|
void print(String *str);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
216
sql/opt_range.cc
216
sql/opt_range.cc
@ -762,11 +762,72 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
|
|||||||
DBUG_RETURN(records ? test(quick) : -1);
|
DBUG_RETURN(records ? test(quick) : -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static SEL_TREE *get_func_mm_tree(PARAM *param, Item_func *cond_func,
|
||||||
|
Field *field, Item *value,
|
||||||
|
Item_result cmp_type)
|
||||||
|
{
|
||||||
|
SEL_TREE *tree= 0;
|
||||||
|
DBUG_ENTER("get_func_mm_tree");
|
||||||
|
|
||||||
|
if (cond_func->functype() == Item_func::NE_FUNC)
|
||||||
|
{
|
||||||
|
|
||||||
|
tree= get_mm_parts(param, field, Item_func::LT_FUNC,
|
||||||
|
value, cmp_type);
|
||||||
|
if (tree)
|
||||||
|
{
|
||||||
|
tree= tree_or(param, tree, get_mm_parts(param, field,
|
||||||
|
Item_func::GT_FUNC,
|
||||||
|
value, cmp_type));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (cond_func->functype() == Item_func::BETWEEN)
|
||||||
|
{
|
||||||
|
|
||||||
|
tree= get_mm_parts(param, field, Item_func::GE_FUNC,
|
||||||
|
cond_func->arguments()[1],cmp_type);
|
||||||
|
if (tree)
|
||||||
|
{
|
||||||
|
tree= tree_and(param, tree, get_mm_parts(param, field,
|
||||||
|
Item_func::LE_FUNC,
|
||||||
|
cond_func->arguments()[2],
|
||||||
|
cmp_type));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (cond_func->functype() == Item_func::IN_FUNC)
|
||||||
|
{
|
||||||
|
Item_func_in *func=(Item_func_in*) cond_func;
|
||||||
|
tree= get_mm_parts(param, field, Item_func::EQ_FUNC,
|
||||||
|
func->arguments()[1], cmp_type);
|
||||||
|
if (tree)
|
||||||
|
{
|
||||||
|
for (uint i =2 ; i < func->argument_count() ; i++)
|
||||||
|
{
|
||||||
|
tree= tree_or(param, tree, get_mm_parts(param, field,
|
||||||
|
Item_func::EQ_FUNC,
|
||||||
|
func->arguments()[i],
|
||||||
|
cmp_type));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Item_func::Functype func_type=
|
||||||
|
(value != cond_func->arguments()[0]) ? cond_func->functype() :
|
||||||
|
((Item_bool_func2*) cond_func)->rev_functype();
|
||||||
|
tree= get_mm_parts(param, field, func_type, value, cmp_type);
|
||||||
|
}
|
||||||
|
DBUG_RETURN(tree);
|
||||||
|
}
|
||||||
|
|
||||||
/* make a select tree of all keys in condition */
|
/* make a select tree of all keys in condition */
|
||||||
|
|
||||||
static SEL_TREE *get_mm_tree(PARAM *param,COND *cond)
|
static SEL_TREE *get_mm_tree(PARAM *param,COND *cond)
|
||||||
{
|
{
|
||||||
SEL_TREE *tree=0;
|
SEL_TREE *tree=0;
|
||||||
|
SEL_TREE *ftree= 0;
|
||||||
|
Item_field *field_item= 0;
|
||||||
|
Item *value;
|
||||||
DBUG_ENTER("get_mm_tree");
|
DBUG_ENTER("get_mm_tree");
|
||||||
|
|
||||||
if (cond->type() == Item::COND_ITEM)
|
if (cond->type() == Item::COND_ITEM)
|
||||||
@ -814,9 +875,12 @@ static SEL_TREE *get_mm_tree(PARAM *param,COND *cond)
|
|||||||
DBUG_RETURN(new SEL_TREE(SEL_TREE::IMPOSSIBLE));
|
DBUG_RETURN(new SEL_TREE(SEL_TREE::IMPOSSIBLE));
|
||||||
}
|
}
|
||||||
|
|
||||||
table_map ref_tables=cond->used_tables();
|
table_map ref_tables= 0;
|
||||||
|
table_map param_comp= ~(param->prev_tables | param->read_tables |
|
||||||
|
param->current_table);
|
||||||
if (cond->type() != Item::FUNC_ITEM)
|
if (cond->type() != Item::FUNC_ITEM)
|
||||||
{ // Should be a field
|
{ // Should be a field
|
||||||
|
ref_tables= cond->used_tables();
|
||||||
if ((ref_tables & param->current_table) ||
|
if ((ref_tables & param->current_table) ||
|
||||||
(ref_tables & ~(param->prev_tables | param->read_tables)))
|
(ref_tables & ~(param->prev_tables | param->read_tables)))
|
||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
@ -828,76 +892,98 @@ static SEL_TREE *get_mm_tree(PARAM *param,COND *cond)
|
|||||||
DBUG_RETURN(0); // Can't be calculated
|
DBUG_RETURN(0); // Can't be calculated
|
||||||
|
|
||||||
if (cond_func->functype() == Item_func::BETWEEN)
|
if (cond_func->functype() == Item_func::BETWEEN)
|
||||||
{
|
{
|
||||||
if (cond_func->arguments()[0]->type() == Item::FIELD_ITEM)
|
if (cond_func->arguments()[0]->type() == Item::FIELD_ITEM)
|
||||||
{
|
{
|
||||||
Field *field=((Item_field*) (cond_func->arguments()[0]))->field;
|
field_item= (Item_field*) (cond_func->arguments()[0]);
|
||||||
Item_result cmp_type=field->cmp_type();
|
value= NULL;
|
||||||
DBUG_RETURN(tree_and(param,
|
|
||||||
get_mm_parts(param, field,
|
|
||||||
Item_func::GE_FUNC,
|
|
||||||
cond_func->arguments()[1], cmp_type),
|
|
||||||
get_mm_parts(param, field,
|
|
||||||
Item_func::LE_FUNC,
|
|
||||||
cond_func->arguments()[2], cmp_type)));
|
|
||||||
}
|
}
|
||||||
DBUG_RETURN(0);
|
else
|
||||||
|
DBUG_RETURN(0);
|
||||||
}
|
}
|
||||||
if (cond_func->functype() == Item_func::IN_FUNC)
|
else if (cond_func->functype() == Item_func::IN_FUNC)
|
||||||
{ // COND OR
|
{
|
||||||
Item_func_in *func=(Item_func_in*) cond_func;
|
Item_func_in *func=(Item_func_in*) cond_func;
|
||||||
if (func->key_item()->type() == Item::FIELD_ITEM)
|
if (func->key_item()->type() == Item::FIELD_ITEM)
|
||||||
{
|
{
|
||||||
Field *field=((Item_field*) (func->key_item()))->field;
|
field_item= (Item_field*) (func->key_item());
|
||||||
Item_result cmp_type=field->cmp_type();
|
value= NULL;
|
||||||
tree= get_mm_parts(param,field,Item_func::EQ_FUNC,
|
|
||||||
func->arguments()[1],cmp_type);
|
|
||||||
if (!tree)
|
|
||||||
DBUG_RETURN(tree); // Not key field
|
|
||||||
for (uint i=2 ; i < func->argument_count(); i++)
|
|
||||||
{
|
|
||||||
SEL_TREE *new_tree=get_mm_parts(param,field,Item_func::EQ_FUNC,
|
|
||||||
func->arguments()[i],cmp_type);
|
|
||||||
tree=tree_or(param,tree,new_tree);
|
|
||||||
}
|
|
||||||
DBUG_RETURN(tree);
|
|
||||||
}
|
}
|
||||||
DBUG_RETURN(0); // Can't optimize this IN
|
else
|
||||||
|
DBUG_RETURN(0);
|
||||||
}
|
}
|
||||||
|
else if (cond_func->functype() == Item_func::MULT_EQUAL_FUNC)
|
||||||
if (ref_tables & ~(param->prev_tables | param->read_tables |
|
|
||||||
param->current_table))
|
|
||||||
DBUG_RETURN(0); // Can't be calculated yet
|
|
||||||
if (!(ref_tables & param->current_table))
|
|
||||||
DBUG_RETURN(new SEL_TREE(SEL_TREE::MAYBE)); // This may be false or true
|
|
||||||
|
|
||||||
/* check field op const */
|
|
||||||
/* btw, ft_func's arguments()[0] isn't FIELD_ITEM. SerG*/
|
|
||||||
if (cond_func->arguments()[0]->type() == Item::FIELD_ITEM)
|
|
||||||
{
|
{
|
||||||
tree= get_mm_parts(param,
|
Item_equal *item_equal= (Item_equal *) cond;
|
||||||
((Item_field*) (cond_func->arguments()[0]))->field,
|
Item_equal_iterator it(*item_equal);
|
||||||
cond_func->functype(),
|
if (!(value= item_equal->get_const()))
|
||||||
cond_func->arg_count > 1 ? cond_func->arguments()[1] :
|
value= it++;
|
||||||
0,
|
while (value)
|
||||||
((Item_field*) (cond_func->arguments()[0]))->field->
|
{
|
||||||
cmp_type());
|
ref_tables= value->used_tables();
|
||||||
|
Item_equal_iterator li(*item_equal);
|
||||||
|
while ((field_item= li++))
|
||||||
|
{
|
||||||
|
if (field_item != value)
|
||||||
|
{
|
||||||
|
Field *field= field_item->field;
|
||||||
|
Item_result cmp_type= field->cmp_type();
|
||||||
|
if (!((ref_tables | field->table->map) & param_comp))
|
||||||
|
{
|
||||||
|
tree= get_mm_parts(param, field, Item_func::EQ_FUNC,
|
||||||
|
value,cmp_type);
|
||||||
|
ftree= !ftree ? tree : tree_and(param, ftree, tree);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (item_equal->get_const())
|
||||||
|
break;
|
||||||
|
value= it++;
|
||||||
|
}
|
||||||
|
DBUG_RETURN(ftree);
|
||||||
}
|
}
|
||||||
/* check const op field */
|
else if (cond_func->arguments()[0]->type() == Item::FIELD_ITEM)
|
||||||
if (!tree &&
|
|
||||||
cond_func->have_rev_func() &&
|
|
||||||
cond_func->arguments()[1]->type() == Item::FIELD_ITEM)
|
|
||||||
{
|
{
|
||||||
DBUG_RETURN(get_mm_parts(param,
|
field_item= (Item_field*) (cond_func->arguments()[0]);
|
||||||
((Item_field*)
|
value= cond_func->arg_count > 1 ? cond_func->arguments()[1] : 0;
|
||||||
(cond_func->arguments()[1]))->field,
|
|
||||||
((Item_bool_func2*) cond_func)->rev_functype(),
|
|
||||||
cond_func->arguments()[0],
|
|
||||||
((Item_field*)
|
|
||||||
(cond_func->arguments()[1]))->field->cmp_type()
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
DBUG_RETURN(tree);
|
else if (cond_func->have_rev_func() &&
|
||||||
|
cond_func->arguments()[1]->type() == Item::FIELD_ITEM)
|
||||||
|
{
|
||||||
|
field_item= (Item_field*) (cond_func->arguments()[1]);
|
||||||
|
value= cond_func->arguments()[0];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
DBUG_RETURN(0);
|
||||||
|
|
||||||
|
for (uint i= 0; i < cond_func->arg_count; i++)
|
||||||
|
{
|
||||||
|
Item *arg= cond_func->arguments()[i];
|
||||||
|
if (arg != field_item)
|
||||||
|
ref_tables|= arg->used_tables();
|
||||||
|
}
|
||||||
|
Field *field= field_item->field;
|
||||||
|
Item_result cmp_type= field->cmp_type();
|
||||||
|
if (!((ref_tables | field->table->map) & param_comp))
|
||||||
|
ftree= get_func_mm_tree(param, cond_func, field, value, cmp_type);
|
||||||
|
Item_equal *item_equal= field_item->item_equal;
|
||||||
|
if (item_equal)
|
||||||
|
{
|
||||||
|
Item_equal_iterator it(*item_equal);
|
||||||
|
Item_field *item;
|
||||||
|
while ((item= it++))
|
||||||
|
{
|
||||||
|
Field *f= item->field;
|
||||||
|
if (field->eq(f))
|
||||||
|
continue;
|
||||||
|
if (!((ref_tables | f->table->map) & param_comp))
|
||||||
|
{
|
||||||
|
tree= get_func_mm_tree(param, cond_func, f, value, cmp_type);
|
||||||
|
ftree= !ftree ? tree : tree_and(param, ftree, tree);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DBUG_RETURN(ftree);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -905,17 +991,10 @@ static SEL_TREE *
|
|||||||
get_mm_parts(PARAM *param, Field *field, Item_func::Functype type,
|
get_mm_parts(PARAM *param, Field *field, Item_func::Functype type,
|
||||||
Item *value, Item_result cmp_type)
|
Item *value, Item_result cmp_type)
|
||||||
{
|
{
|
||||||
bool ne_func= FALSE;
|
|
||||||
DBUG_ENTER("get_mm_parts");
|
DBUG_ENTER("get_mm_parts");
|
||||||
if (field->table != param->table)
|
if (field->table != param->table)
|
||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
|
|
||||||
if (type == Item_func::NE_FUNC)
|
|
||||||
{
|
|
||||||
ne_func= TRUE;
|
|
||||||
type= Item_func::LT_FUNC;
|
|
||||||
}
|
|
||||||
|
|
||||||
KEY_PART *key_part = param->key_parts;
|
KEY_PART *key_part = param->key_parts;
|
||||||
KEY_PART *end = param->key_parts_end;
|
KEY_PART *end = param->key_parts_end;
|
||||||
SEL_TREE *tree=0;
|
SEL_TREE *tree=0;
|
||||||
@ -951,13 +1030,6 @@ get_mm_parts(PARAM *param, Field *field, Item_func::Functype type,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ne_func)
|
|
||||||
{
|
|
||||||
SEL_TREE *tree2= get_mm_parts(param, field, Item_func::GT_FUNC,
|
|
||||||
value, cmp_type);
|
|
||||||
if (tree2)
|
|
||||||
tree= tree_or(param,tree,tree2);
|
|
||||||
}
|
|
||||||
DBUG_RETURN(tree);
|
DBUG_RETURN(tree);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -352,6 +352,18 @@ static bool simple_pred(Item_func *func_item, Item **args, bool *inv_order)
|
|||||||
Item *item;
|
Item *item;
|
||||||
*inv_order= 0;
|
*inv_order= 0;
|
||||||
switch (func_item->argument_count()) {
|
switch (func_item->argument_count()) {
|
||||||
|
case 0:
|
||||||
|
/* MULT_EQUAL_FUNC */
|
||||||
|
{
|
||||||
|
Item_equal *item_equal= (Item_equal *) func_item;
|
||||||
|
Item_equal_iterator it(*item_equal);
|
||||||
|
args[0]= it++;
|
||||||
|
if (it++)
|
||||||
|
return 0;
|
||||||
|
if (!(args[1]= item_equal->get_const()))
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
/* field IS NULL */
|
/* field IS NULL */
|
||||||
item= func_item->arguments()[0];
|
item= func_item->arguments()[0];
|
||||||
@ -492,6 +504,9 @@ static bool matching_cond(bool max_fl, TABLE_REF *ref, KEY *keyinfo,
|
|||||||
case Item_func::BETWEEN:
|
case Item_func::BETWEEN:
|
||||||
between= 1;
|
between= 1;
|
||||||
break;
|
break;
|
||||||
|
case Item_func::MULT_EQUAL_FUNC:
|
||||||
|
eq_type= 1;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return 0; // Can't optimize function
|
return 0; // Can't optimize function
|
||||||
}
|
}
|
||||||
|
@ -121,10 +121,12 @@ public:
|
|||||||
void remove(list_node **prev)
|
void remove(list_node **prev)
|
||||||
{
|
{
|
||||||
list_node *node=(*prev)->next;
|
list_node *node=(*prev)->next;
|
||||||
delete *prev;
|
|
||||||
*prev=node;
|
|
||||||
if (!--elements)
|
if (!--elements)
|
||||||
last= &first;
|
last= &first;
|
||||||
|
else if (last == &(*prev)->next)
|
||||||
|
last= prev;
|
||||||
|
delete *prev;
|
||||||
|
*prev=node;
|
||||||
}
|
}
|
||||||
inline void *pop(void)
|
inline void *pop(void)
|
||||||
{
|
{
|
||||||
@ -135,6 +137,30 @@ public:
|
|||||||
last= &first;
|
last= &first;
|
||||||
return tmp->info;
|
return tmp->info;
|
||||||
}
|
}
|
||||||
|
inline void concat(base_list *list)
|
||||||
|
{
|
||||||
|
if (!list->is_empty())
|
||||||
|
{
|
||||||
|
*last= list->first;
|
||||||
|
last= list->last;
|
||||||
|
elements+= list->elements;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
inline void disjoin(base_list *list)
|
||||||
|
{
|
||||||
|
list_node **prev= &first;
|
||||||
|
list_node *node= first;
|
||||||
|
list_node *list_first= list->first;
|
||||||
|
elements=0;
|
||||||
|
while (node && node != list_first)
|
||||||
|
{
|
||||||
|
prev= &node->next;
|
||||||
|
node= node->next;
|
||||||
|
elements++;
|
||||||
|
}
|
||||||
|
*prev= *last;
|
||||||
|
last= prev;
|
||||||
|
}
|
||||||
inline list_node* last_node() { return *last; }
|
inline list_node* last_node() { return *last; }
|
||||||
inline list_node* first_node() { return first;}
|
inline list_node* first_node() { return first;}
|
||||||
inline void *head() { return first->info; }
|
inline void *head() { return first->info; }
|
||||||
@ -245,6 +271,8 @@ public:
|
|||||||
inline T* head() {return (T*) base_list::head(); }
|
inline T* head() {return (T*) base_list::head(); }
|
||||||
inline T** head_ref() {return (T**) base_list::head_ref(); }
|
inline T** head_ref() {return (T**) base_list::head_ref(); }
|
||||||
inline T* pop() {return (T*) base_list::pop(); }
|
inline T* pop() {return (T*) base_list::pop(); }
|
||||||
|
inline void concat(List<T> *list) { return base_list::concat(list); }
|
||||||
|
inline void disjoin(List<T> *list) { return base_list::disjoin(list); }
|
||||||
void delete_elements(void)
|
void delete_elements(void)
|
||||||
{
|
{
|
||||||
list_node *element,*next;
|
list_node *element,*next;
|
||||||
@ -265,6 +293,8 @@ public:
|
|||||||
inline T* operator++(int) { return (T*) base_list_iterator::next(); }
|
inline T* operator++(int) { return (T*) base_list_iterator::next(); }
|
||||||
inline T *replace(T *a) { return (T*) base_list_iterator::replace(a); }
|
inline T *replace(T *a) { return (T*) base_list_iterator::replace(a); }
|
||||||
inline T *replace(List<T> &a) { return (T*) base_list_iterator::replace(a); }
|
inline T *replace(List<T> &a) { return (T*) base_list_iterator::replace(a); }
|
||||||
|
inline void rewind(void) { base_list_iterator::rewind(); }
|
||||||
|
inline void remove() { base_list_iterator::remove(); }
|
||||||
inline void after(T *a) { base_list_iterator::after(a); }
|
inline void after(T *a) { base_list_iterator::after(a); }
|
||||||
inline T** ref(void) { return (T**) base_list_iterator::ref(); }
|
inline T** ref(void) { return (T**) base_list_iterator::ref(); }
|
||||||
};
|
};
|
||||||
|
@ -72,6 +72,11 @@ static int return_zero_rows(JOIN *join, select_result *res,TABLE_LIST *tables,
|
|||||||
uint select_options, const char *info,
|
uint select_options, const char *info,
|
||||||
Item *having, Procedure *proc,
|
Item *having, Procedure *proc,
|
||||||
SELECT_LEX_UNIT *unit);
|
SELECT_LEX_UNIT *unit);
|
||||||
|
static Item *flatten_condition(COND *cond);
|
||||||
|
static COND *build_all_equal_items(COND *cond,
|
||||||
|
COND_EQUAL *inherited);
|
||||||
|
static COND* substitute_for_best_equal_field(COND *cond,
|
||||||
|
void *table_join_idx);
|
||||||
static COND *optimize_cond(COND *conds,Item::cond_result *cond_value);
|
static COND *optimize_cond(COND *conds,Item::cond_result *cond_value);
|
||||||
static COND *remove_eq_conds(COND *cond,Item::cond_result *cond_value);
|
static COND *remove_eq_conds(COND *cond,Item::cond_result *cond_value);
|
||||||
static bool const_expression_in_where(COND *conds,Item *item, Item **comp_item);
|
static bool const_expression_in_where(COND *conds,Item *item, Item **comp_item);
|
||||||
@ -526,6 +531,56 @@ JOIN::optimize()
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* eliminate NOT operators */
|
||||||
|
conds= eliminate_not_funcs(conds);
|
||||||
|
DBUG_EXECUTE("where", print_where(conds, "after negation elimination"););
|
||||||
|
|
||||||
|
/* Eliminate nested AND/OR in conditions */
|
||||||
|
if (conds)
|
||||||
|
conds= flatten_condition(conds);
|
||||||
|
{
|
||||||
|
TABLE_LIST *tables;
|
||||||
|
for (tables= tables_list; tables; tables= tables->next)
|
||||||
|
{
|
||||||
|
if (tables->on_expr)
|
||||||
|
tables->on_expr= flatten_condition(tables->on_expr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Build all multiple equality predicates and eliminate equality
|
||||||
|
predicates that can be inferred from these multiple equalities.
|
||||||
|
For each reference of a field included into a multiple equality
|
||||||
|
that occurs in a function set a pointer to the multiple equality
|
||||||
|
predicate. Substitute a constant instead of this field if the
|
||||||
|
multiple equality contains a constant.
|
||||||
|
*/
|
||||||
|
if (conds)
|
||||||
|
{
|
||||||
|
conds= build_all_equal_items(conds, NULL);
|
||||||
|
conds->update_used_tables();
|
||||||
|
if (conds->type() == Item::COND_ITEM &&
|
||||||
|
((Item_cond*) conds)->functype() == Item_func::COND_AND_FUNC)
|
||||||
|
cond_equal= &((Item_cond_and*) conds)->cond_equal;
|
||||||
|
else if (conds->type() == Item::FUNC_ITEM &&
|
||||||
|
((Item_cond*) conds)->functype() == Item_func::MULT_EQUAL_FUNC)
|
||||||
|
{
|
||||||
|
cond_equal= new COND_EQUAL;
|
||||||
|
cond_equal->current_level.push_back((Item_equal *) conds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
TABLE_LIST *tables;
|
||||||
|
for (tables= tables_list; tables; tables= tables->next)
|
||||||
|
{
|
||||||
|
if (tables->on_expr)
|
||||||
|
{
|
||||||
|
tables->on_expr= build_all_equal_items(tables->on_expr, cond_equal);
|
||||||
|
tables->on_expr->update_used_tables();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
conds= optimize_cond(conds,&cond_value);
|
conds= optimize_cond(conds,&cond_value);
|
||||||
if (thd->net.report_error)
|
if (thd->net.report_error)
|
||||||
{
|
{
|
||||||
@ -626,6 +681,30 @@ JOIN::optimize()
|
|||||||
}
|
}
|
||||||
mysql_unlock_some_tables(thd, this->table, const_tables);
|
mysql_unlock_some_tables(thd, this->table, const_tables);
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
Among the equal fields belonging to the same multiple equality
|
||||||
|
choose the one that is to be retrieved first and substitute
|
||||||
|
all references to these in where condition for a reference for
|
||||||
|
the selected field.
|
||||||
|
*/
|
||||||
|
if (conds)
|
||||||
|
{
|
||||||
|
conds= substitute_for_best_equal_field(conds, map2table);
|
||||||
|
conds->update_used_tables();
|
||||||
|
}
|
||||||
|
{
|
||||||
|
TABLE_LIST *tables;
|
||||||
|
for (tables= tables_list; tables; tables= tables->next)
|
||||||
|
{
|
||||||
|
if (tables->on_expr)
|
||||||
|
{
|
||||||
|
tables->on_expr= substitute_for_best_equal_field(tables->on_expr,
|
||||||
|
map2table);
|
||||||
|
tables->on_expr->update_used_tables();
|
||||||
|
map2table[tables->table->tablenr]->on_expr= tables->on_expr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if (!conds && outer_join)
|
if (!conds && outer_join)
|
||||||
{
|
{
|
||||||
/* Handle the case where we have an OUTER JOIN without a WHERE */
|
/* Handle the case where we have an OUTER JOIN without a WHERE */
|
||||||
@ -2202,6 +2281,35 @@ add_key_field(KEY_FIELD **key_fields,uint and_level,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
add_key_equal_fields(KEY_FIELD **key_fields, uint and_level,
|
||||||
|
Item_field *field_item,
|
||||||
|
bool eq_func, Item **val,
|
||||||
|
uint num_values, table_map usable_tables)
|
||||||
|
{
|
||||||
|
Field *field= field_item->field;
|
||||||
|
add_key_field(key_fields, and_level, field,
|
||||||
|
eq_func, val, num_values, usable_tables);
|
||||||
|
Item_equal *item_equal= field_item->item_equal;
|
||||||
|
if (item_equal)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Add to the set of possible key values every substitution of
|
||||||
|
the field for an equal field included into item_equal
|
||||||
|
*/
|
||||||
|
Item_equal_iterator it(*item_equal);
|
||||||
|
Item_field *item;
|
||||||
|
while ((item= it++))
|
||||||
|
{
|
||||||
|
if (!field->eq(item->field))
|
||||||
|
{
|
||||||
|
add_key_field(key_fields, and_level, item->field,
|
||||||
|
eq_func, val, num_values, usable_tables);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
add_key_fields(JOIN_TAB *stat,KEY_FIELD **key_fields,uint *and_level,
|
add_key_fields(JOIN_TAB *stat,KEY_FIELD **key_fields,uint *and_level,
|
||||||
COND *cond, table_map usable_tables)
|
COND *cond, table_map usable_tables)
|
||||||
@ -2247,11 +2355,11 @@ add_key_fields(JOIN_TAB *stat,KEY_FIELD **key_fields,uint *and_level,
|
|||||||
// BETWEEN or IN
|
// BETWEEN or IN
|
||||||
if (cond_func->key_item()->real_item()->type() == Item::FIELD_ITEM &&
|
if (cond_func->key_item()->real_item()->type() == Item::FIELD_ITEM &&
|
||||||
!(cond_func->used_tables() & OUTER_REF_TABLE_BIT))
|
!(cond_func->used_tables() & OUTER_REF_TABLE_BIT))
|
||||||
add_key_field(key_fields,*and_level,
|
add_key_equal_fields(key_fields,*and_level,
|
||||||
((Item_field*) (cond_func->key_item()->real_item()))->
|
(Item_field*) (cond_func->key_item()->real_item()),
|
||||||
field, 0,
|
0, cond_func->arguments()+1,
|
||||||
cond_func->arguments()+1, cond_func->argument_count()-1,
|
cond_func->argument_count()-1,
|
||||||
usable_tables);
|
usable_tables);
|
||||||
break;
|
break;
|
||||||
case Item_func::OPTIMIZE_OP:
|
case Item_func::OPTIMIZE_OP:
|
||||||
{
|
{
|
||||||
@ -2261,21 +2369,19 @@ add_key_fields(JOIN_TAB *stat,KEY_FIELD **key_fields,uint *and_level,
|
|||||||
if (cond_func->arguments()[0]->real_item()->type() == Item::FIELD_ITEM &&
|
if (cond_func->arguments()[0]->real_item()->type() == Item::FIELD_ITEM &&
|
||||||
!(cond_func->arguments()[0]->used_tables() & OUTER_REF_TABLE_BIT))
|
!(cond_func->arguments()[0]->used_tables() & OUTER_REF_TABLE_BIT))
|
||||||
{
|
{
|
||||||
add_key_field(key_fields,*and_level,
|
add_key_equal_fields(key_fields, *and_level,
|
||||||
((Item_field*) (cond_func->arguments()[0])->real_item())
|
(Item_field*) (cond_func->arguments()[0])->real_item(),
|
||||||
->field,
|
equal_func,
|
||||||
equal_func,
|
cond_func->arguments()+1, 1, usable_tables);
|
||||||
cond_func->arguments()+1, 1, usable_tables);
|
|
||||||
}
|
}
|
||||||
if (cond_func->arguments()[1]->real_item()->type() == Item::FIELD_ITEM &&
|
if (cond_func->arguments()[1]->real_item()->type() == Item::FIELD_ITEM &&
|
||||||
cond_func->functype() != Item_func::LIKE_FUNC &&
|
cond_func->functype() != Item_func::LIKE_FUNC &&
|
||||||
!(cond_func->arguments()[1]->used_tables() & OUTER_REF_TABLE_BIT))
|
!(cond_func->arguments()[1]->used_tables() & OUTER_REF_TABLE_BIT))
|
||||||
{
|
{
|
||||||
add_key_field(key_fields,*and_level,
|
add_key_equal_fields(key_fields,*and_level,
|
||||||
((Item_field*) (cond_func->arguments()[1])->real_item())
|
(Item_field*) (cond_func->arguments()[1])->real_item(),
|
||||||
->field,
|
equal_func,
|
||||||
equal_func,
|
cond_func->arguments(),1,usable_tables);
|
||||||
cond_func->arguments(),1,usable_tables);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -2287,15 +2393,55 @@ add_key_fields(JOIN_TAB *stat,KEY_FIELD **key_fields,uint *and_level,
|
|||||||
Item *tmp=new Item_null;
|
Item *tmp=new Item_null;
|
||||||
if (!tmp) // Should never be true
|
if (!tmp) // Should never be true
|
||||||
return;
|
return;
|
||||||
add_key_field(key_fields,*and_level,
|
add_key_equal_fields(key_fields,*and_level,
|
||||||
((Item_field*) (cond_func->arguments()[0])->real_item())
|
(Item_field*) (cond_func->arguments()[0])->real_item(),
|
||||||
->field,
|
|
||||||
cond_func->functype() == Item_func::ISNULL_FUNC,
|
cond_func->functype() == Item_func::ISNULL_FUNC,
|
||||||
&tmp, 1, usable_tables);
|
&tmp, 1, usable_tables);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case Item_func::OPTIMIZE_EQUAL:
|
||||||
|
Item_equal *item_equal= (Item_equal *) cond;
|
||||||
|
Item *const_item= item_equal->get_const();
|
||||||
|
Item_equal_iterator it(*item_equal);
|
||||||
|
Item_field *item;
|
||||||
|
if (const_item)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
For each field field1 from item_equal consider the equality
|
||||||
|
field1=const_item as a condition allowing an index access of the table
|
||||||
|
with field1 by the keys value of field1.
|
||||||
|
*/
|
||||||
|
while ((item= it++))
|
||||||
|
{
|
||||||
|
add_key_field(key_fields, *and_level, item->field,
|
||||||
|
TRUE, &const_item, 1, usable_tables);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Consider all pairs of different fields included into item_equal.
|
||||||
|
For each of them (field1, field1) consider the equality
|
||||||
|
field1=field2 as a condition allowing an index access of the table
|
||||||
|
with field1 by the keys value of field2.
|
||||||
|
*/
|
||||||
|
Item_equal_iterator fi(*item_equal);
|
||||||
|
while ((item= fi++))
|
||||||
|
{
|
||||||
|
Field *field= item->field;
|
||||||
|
while ((item= it++))
|
||||||
|
{
|
||||||
|
if (!field->eq(item->field))
|
||||||
|
{
|
||||||
|
add_key_field(key_fields, *and_level, field,
|
||||||
|
TRUE, (Item **) &item, 1, usable_tables);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
it.rewind();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -2669,21 +2815,33 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
|
|||||||
{
|
{
|
||||||
uint keypart=keyuse->keypart;
|
uint keypart=keyuse->keypart;
|
||||||
uint found_part_ref_or_null= KEY_OPTIMIZE_REF_OR_NULL;
|
uint found_part_ref_or_null= KEY_OPTIMIZE_REF_OR_NULL;
|
||||||
|
bool usable= 0;
|
||||||
|
table_map best_part_found_ref= 0;
|
||||||
|
double best_prev_record_reads= DBL_MAX;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
if (!(rest_tables & keyuse->used_tables) &&
|
if (!(rest_tables & keyuse->used_tables) &&
|
||||||
!(found_ref_or_null & keyuse->optimize))
|
!(found_ref_or_null & keyuse->optimize))
|
||||||
{
|
{
|
||||||
found_part|=keyuse->keypart_map;
|
found_part|=keyuse->keypart_map;
|
||||||
found_ref|= keyuse->used_tables;
|
double tmp= prev_record_reads(join,
|
||||||
|
(table_map) (found_ref | keyuse->used_tables));
|
||||||
|
if (tmp < best_prev_record_reads)
|
||||||
|
{
|
||||||
|
best_part_found_ref= keyuse->used_tables;
|
||||||
|
best_prev_record_reads= tmp;
|
||||||
|
}
|
||||||
if (rec > keyuse->ref_table_rows)
|
if (rec > keyuse->ref_table_rows)
|
||||||
rec= keyuse->ref_table_rows;
|
rec= keyuse->ref_table_rows;
|
||||||
found_part_ref_or_null&= keyuse->optimize;
|
found_part_ref_or_null&= keyuse->optimize;
|
||||||
|
usable= 1;
|
||||||
}
|
}
|
||||||
keyuse++;
|
keyuse++;
|
||||||
found_ref_or_null|= found_part_ref_or_null;
|
found_ref|= best_part_found_ref;
|
||||||
} while (keyuse->table == table && keyuse->key == key &&
|
} while (keyuse->table == table && keyuse->key == key &&
|
||||||
keyuse->keypart == keypart);
|
keyuse->keypart == keypart);
|
||||||
|
if (usable)
|
||||||
|
found_ref_or_null|= found_part_ref_or_null;
|
||||||
} while (keyuse->table == table && keyuse->key == key);
|
} while (keyuse->table == table && keyuse->key == key);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -3394,7 +3552,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
|
|||||||
}
|
}
|
||||||
|
|
||||||
COND *tmp=make_cond_for_table(cond,used_tables,current_map);
|
COND *tmp=make_cond_for_table(cond,used_tables,current_map);
|
||||||
if (!tmp && tab->quick)
|
if (!tmp && tab->quick && tab->type == JT_ALL)
|
||||||
{ // Outer join
|
{ // Outer join
|
||||||
/*
|
/*
|
||||||
Hack to handle the case where we only refer to a table
|
Hack to handle the case where we only refer to a table
|
||||||
@ -4089,6 +4247,583 @@ template class List<Item_func_match>;
|
|||||||
template class List_iterator<Item_func_match>;
|
template class List_iterator<Item_func_match>;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
Eliminate nesting in AND/OR subexpressions od a condition
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
flatten_condition()
|
||||||
|
cond condition where to eliminate nesting
|
||||||
|
|
||||||
|
DESCRIPTION
|
||||||
|
The function traverse the condition and recursively eliminates
|
||||||
|
nesting for AND/OR subexpressions:
|
||||||
|
... AND (p AND ... r) AND ... => ... AND p AND ... r AND ...
|
||||||
|
... OR (p OR ... r) OR ... => ... OR p OR ... r OR ...
|
||||||
|
|
||||||
|
NOTES
|
||||||
|
Nesting in AND/OR subexpresions inside of NOT/XOR formulas is not
|
||||||
|
eliminated.
|
||||||
|
|
||||||
|
RETURN
|
||||||
|
The transformed condition
|
||||||
|
*/
|
||||||
|
static Item *flatten_condition(COND *cond)
|
||||||
|
{
|
||||||
|
if (cond->type() == Item::COND_ITEM)
|
||||||
|
{
|
||||||
|
Item_func::Functype functype= ((Item_cond*) cond)->functype();
|
||||||
|
if (functype == Item_func::COND_AND_FUNC ||
|
||||||
|
functype == Item_func::COND_OR_FUNC)
|
||||||
|
{
|
||||||
|
|
||||||
|
List<Item> *args= ((Item_cond*) cond)->argument_list();
|
||||||
|
List_iterator<Item> li(*args);
|
||||||
|
Item *item;
|
||||||
|
List<Item> list;
|
||||||
|
while ((item= li++))
|
||||||
|
{
|
||||||
|
item= flatten_condition(item);
|
||||||
|
if (item->type() == Item::COND_ITEM &&
|
||||||
|
((Item_func*) item)->functype() == functype)
|
||||||
|
{
|
||||||
|
list.concat(((Item_cond*) item)->argument_list());
|
||||||
|
li.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
args->concat(&list);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cond;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Find the multiple equality predicate containing a field
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
find_item_equal()
|
||||||
|
cond_equal multiple equalities to search in
|
||||||
|
field field to look for
|
||||||
|
inherited_fl :out set up to TRUE iff multiple equality is found
|
||||||
|
on upper levels (not on current level of cond_equal)
|
||||||
|
|
||||||
|
DESCRIPTION
|
||||||
|
The function retrieves the multiple equalities accessed through
|
||||||
|
the con_equal structure from current level and up looking for
|
||||||
|
an equality containing field. It stops retrieval as soon as the equality
|
||||||
|
is found and set up inherited_fl to TRUE if it's found on upper levels.
|
||||||
|
|
||||||
|
RETURN
|
||||||
|
Item_equal for the found multiple equality predicate if a success;
|
||||||
|
NULL - otherwise.
|
||||||
|
*/
|
||||||
|
|
||||||
|
Item_equal *find_item_equal(COND_EQUAL *cond_equal, Field *field,
|
||||||
|
bool *inherited_fl)
|
||||||
|
{
|
||||||
|
Item_equal *item= 0;
|
||||||
|
bool in_upper_level= FALSE;
|
||||||
|
while (cond_equal)
|
||||||
|
{
|
||||||
|
List_iterator_fast<Item_equal> li(cond_equal->current_level);
|
||||||
|
while ((item= li++))
|
||||||
|
{
|
||||||
|
if (item->contains(field))
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
in_upper_level= TRUE;
|
||||||
|
cond_equal= cond_equal->parent_level;
|
||||||
|
}
|
||||||
|
in_upper_level= FALSE;
|
||||||
|
finish:
|
||||||
|
if (inherited_fl)
|
||||||
|
*inherited_fl= in_upper_level;
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Check whether an item is a simple equality predicate and if so
|
||||||
|
create/find a multiple equality for this predicate
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
check_equality()
|
||||||
|
item item to check
|
||||||
|
cond_equal multiple equalities that must hold together with the predicate
|
||||||
|
|
||||||
|
DESCRIPTION
|
||||||
|
This function first checks whether an item is a simple equality i.e.
|
||||||
|
the one that equates a field with another field or a constant.
|
||||||
|
If this is the case the function looks a for a multiple equality
|
||||||
|
in the lists referenced directly or indirectly by cond_equal. If it
|
||||||
|
doesn't find any it builds a multiple equality that covers
|
||||||
|
the predicate, i.e. the predicate can be inferred from it. The built
|
||||||
|
multiple equality could be obtained in such a way: create a binary
|
||||||
|
multiple equality equivalent to the predicate, than merge it, if
|
||||||
|
possible, with one of old multiple equalities. This guarantees that
|
||||||
|
the set of multiple equalities covering equality predicates will
|
||||||
|
be minimal.
|
||||||
|
|
||||||
|
NOTES
|
||||||
|
Now only fields that have the same type defintions (verified by
|
||||||
|
the Field::eq_def method) are placed to the same multiple equalities.
|
||||||
|
Because of this some equality predicates are not eliminated and
|
||||||
|
can be used in constant propagation procedure.
|
||||||
|
We could weeken the equlity test as soon as at least one of the
|
||||||
|
equal fields is to be equal to a constant. It would require a
|
||||||
|
more complicated implementation: we would have to store, in
|
||||||
|
general case, its own constant for each fields from the multiple
|
||||||
|
equality. But at the same time it would allow us to get rid
|
||||||
|
of constant propagation completely: it would be done by the call
|
||||||
|
to build_all_equal_items.
|
||||||
|
|
||||||
|
IMPLEMENTATION
|
||||||
|
The implementation does not follow exactly the above rules to
|
||||||
|
build a new multiple equality for the equality predicate.
|
||||||
|
If it processes the equality of the form field1=field2, it
|
||||||
|
looks for multiple equalities me1 containig field1 and me2 containing
|
||||||
|
field2. If only one of them is found the fuction expand it by
|
||||||
|
the lacking field. If multiple equalities for both fields are
|
||||||
|
found they are merged. If both searches fail a new multiple equality
|
||||||
|
containing just field1 and field2 is added to the existing
|
||||||
|
multiple equalities.
|
||||||
|
If the function processes the predicate of the form field1=const,
|
||||||
|
it looks for a multiple equality containing field1. If found, the
|
||||||
|
function checks the constant of the multiple equality. If the value
|
||||||
|
is unknown, it is setup to const. Otherwise the value is compared with
|
||||||
|
const and the evaluation of the equality predicate is performed.
|
||||||
|
When expanding/merging equality predicates from the upper levels
|
||||||
|
the function first copies them for the current level. It looks
|
||||||
|
acceptable, as this happens rarely. The implementation without
|
||||||
|
copying would be much more complicated.
|
||||||
|
|
||||||
|
RETURN
|
||||||
|
TRUE - if the predicate is a simple equality predicate
|
||||||
|
FALSE - otherwise
|
||||||
|
*/
|
||||||
|
|
||||||
|
static bool check_equality(Item *item, COND_EQUAL *cond_equal)
|
||||||
|
{
|
||||||
|
if (item->type() == Item::FUNC_ITEM &&
|
||||||
|
((Item_func*) item)->functype() == Item_func::EQ_FUNC)
|
||||||
|
{
|
||||||
|
Item *left_item= ((Item_func*) item)->arguments()[0];
|
||||||
|
Item *right_item= ((Item_func*) item)->arguments()[1];
|
||||||
|
if (left_item->type() == Item::FIELD_ITEM &&
|
||||||
|
right_item->type() == Item::FIELD_ITEM)
|
||||||
|
{
|
||||||
|
/* The predicate the form field1=field2 is processed */
|
||||||
|
|
||||||
|
Field *left_field= ((Item_field*) left_item)->field;
|
||||||
|
Field *right_field= ((Item_field*) right_item)->field;
|
||||||
|
|
||||||
|
if (!left_field->eq_def(right_field))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if (left_field->eq(right_field))
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
/* Search for multiple equalities containing field1 and/or field2 */
|
||||||
|
bool left_copyfl, right_copyfl;
|
||||||
|
Item_equal *left_item_equal=
|
||||||
|
find_item_equal(cond_equal, left_field, &left_copyfl);
|
||||||
|
Item_equal *right_item_equal=
|
||||||
|
find_item_equal(cond_equal, right_field, &right_copyfl);
|
||||||
|
|
||||||
|
if (left_item_equal && left_item_equal == right_item_equal)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
The equality predicate is inference of one of the existing
|
||||||
|
multiple equalities
|
||||||
|
*/
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy the found multiple equalities at the current level if needed */
|
||||||
|
if (left_copyfl)
|
||||||
|
{
|
||||||
|
left_item_equal= new Item_equal(left_item_equal);
|
||||||
|
cond_equal->current_level.push_back(left_item_equal);
|
||||||
|
}
|
||||||
|
if (right_copyfl)
|
||||||
|
{
|
||||||
|
right_item_equal= new Item_equal(right_item_equal);
|
||||||
|
cond_equal->current_level.push_back(right_item_equal);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (left_item_equal)
|
||||||
|
{
|
||||||
|
if (! right_item_equal)
|
||||||
|
left_item_equal->add((Item_field *) right_item);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Merge two multiple equalities forming a new one */
|
||||||
|
left_item_equal->merge(right_item_equal);
|
||||||
|
/* Remove the merged multiple equality from the list */
|
||||||
|
List_iterator<Item_equal> li(cond_equal->current_level);
|
||||||
|
while ((li++) != right_item_equal);
|
||||||
|
li.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (right_item_equal)
|
||||||
|
right_item_equal->add((Item_field *) left_item);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Multiple equalities for neither of the fields has been found */
|
||||||
|
Item_equal *item= new Item_equal((Item_field *) left_item,
|
||||||
|
(Item_field *) right_item);
|
||||||
|
cond_equal->current_level.push_back(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* The predicate of the form field=const/const=field is processed */
|
||||||
|
Item *const_item= 0;
|
||||||
|
Item_field *field_item= 0;
|
||||||
|
if (left_item->type() == Item::FIELD_ITEM &&
|
||||||
|
right_item->const_item())
|
||||||
|
{
|
||||||
|
field_item= (Item_field*) left_item;
|
||||||
|
const_item= right_item;
|
||||||
|
}
|
||||||
|
else if (right_item->type() == Item::FIELD_ITEM &&
|
||||||
|
left_item->const_item())
|
||||||
|
{
|
||||||
|
field_item= (Item_field*) right_item;
|
||||||
|
const_item= left_item;
|
||||||
|
}
|
||||||
|
if (const_item &&
|
||||||
|
field_item->result_type() == const_item->result_type())
|
||||||
|
{
|
||||||
|
bool copyfl;
|
||||||
|
Item_equal *item_equal = find_item_equal(cond_equal,
|
||||||
|
field_item->field, ©fl);
|
||||||
|
if (copyfl)
|
||||||
|
{
|
||||||
|
item_equal= new Item_equal(item_equal);
|
||||||
|
cond_equal->current_level.push_back(item_equal);
|
||||||
|
}
|
||||||
|
if (item_equal)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
The flag cond_false will be set to 1 after this, if item_equal
|
||||||
|
already contains a constant and its value is not equal to
|
||||||
|
the value of const_item.
|
||||||
|
*/
|
||||||
|
item_equal->add(const_item);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
item_equal= new Item_equal(const_item, field_item);
|
||||||
|
cond_equal->current_level.push_back(item_equal);
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Replace all equality predicates in a condition by multiple equality items
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
build_all_equal_items()
|
||||||
|
cond condition(expression) where to make replacement
|
||||||
|
inherited path to all inherited multiple equality items
|
||||||
|
|
||||||
|
DESCRIPTION
|
||||||
|
At each 'and' level the function detects items for equality predicates
|
||||||
|
and replaced them by a set of multiple equality items of class Item_equal,
|
||||||
|
taking into account inherited equalities from upper levels.
|
||||||
|
If an equality predicate is used not in a conjunction it's just
|
||||||
|
replaced by a multiple equality predicate.
|
||||||
|
The functuion also traverse the cond tree and and for each field reference
|
||||||
|
sets a ponter to the multiple equality item containing the field, if there
|
||||||
|
is any. If this multiple equality equates fields to a constant the
|
||||||
|
function replace the field reference by the constant.
|
||||||
|
|
||||||
|
NOTES
|
||||||
|
Multiple equality predicate =(f1,..fn) is equivalent to the conjuction of
|
||||||
|
f1=f2, .., fn-1=fn. It substitutes any inference from these
|
||||||
|
equality predicates that is equivalent to the conjunction.
|
||||||
|
Thus, =(a1,a2,a3) can substitute for ((a1=a3) AND (a2=a3) AND (a2=a1)) as
|
||||||
|
it is equivalent to ((a1=a2) AND (a2=a3)).
|
||||||
|
The function always makes a subsitution of all equality predicates occured
|
||||||
|
in a conjuction for a minimal set of multiple equality predicates.
|
||||||
|
This set can be considered as a canonical representation of the
|
||||||
|
sub-conjunction of the equality predicates.
|
||||||
|
E.g. (t1.a=t2.b AND t2.b>5 AND t1.a=t3.c) is replaced by
|
||||||
|
(=(t1.a,t2.b,t3.c) AND t2.b>5), not by
|
||||||
|
(=(t1.a,t2.b) AND =(t1.a,t3.c) AND t2.b>5);
|
||||||
|
while (t1.a=t2.b AND t2.b>5 AND t3.c,t4.d) is replaced by
|
||||||
|
(=(t1.a,t2.b) AND =(t3.c=t4.d) AND t2.b>5),
|
||||||
|
but if additionally =(t4.d,t2.b) is inherited, it
|
||||||
|
will be replaced by (=(t1.a,t2.b,t3.c,t4.d) AND t2.b>5)
|
||||||
|
|
||||||
|
IMPLEMENTATION
|
||||||
|
The function performs the substitution in a recursive descent by
|
||||||
|
the condtion tree, passing to the next AND level a chain of multiple
|
||||||
|
equality predicates which have been built at the upper levels.
|
||||||
|
The Item_equal items built at the level are attached to other
|
||||||
|
non-equality conjucts as a sublist. The pointer to the inherited
|
||||||
|
multiple equalities is saved in the and condition object (Item_cond_and).
|
||||||
|
This chain allows us for any field reference occurence easyly to find a
|
||||||
|
multiple equality that must be held for this occurence.
|
||||||
|
|
||||||
|
RETURN
|
||||||
|
pointer to the transformed condition
|
||||||
|
*/
|
||||||
|
|
||||||
|
static COND *build_all_equal_items(COND *cond,
|
||||||
|
COND_EQUAL *inherited)
|
||||||
|
{
|
||||||
|
COND_EQUAL cond_equal;
|
||||||
|
cond_equal.parent_level= inherited;
|
||||||
|
|
||||||
|
if (cond->type() == Item::COND_ITEM)
|
||||||
|
{
|
||||||
|
bool and_level= ((Item_cond*) cond)->functype() ==
|
||||||
|
Item_func::COND_AND_FUNC;
|
||||||
|
List<Item> *args= ((Item_cond*) cond)->argument_list();
|
||||||
|
|
||||||
|
List_iterator<Item> li(*args);
|
||||||
|
Item *item;
|
||||||
|
|
||||||
|
if (and_level)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Retrieve all conjucts of this level detecting the equality
|
||||||
|
that are subject to substitution by multiple equality items and
|
||||||
|
removing each such predicate from the conjunction after after having
|
||||||
|
found/created a multiple equality whose inference the predicate is.
|
||||||
|
*/
|
||||||
|
while ((item= li++))
|
||||||
|
{
|
||||||
|
if (check_equality(item, &cond_equal))
|
||||||
|
li.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
List_iterator_fast<Item_equal> it(cond_equal.current_level);
|
||||||
|
while ((item= it++))
|
||||||
|
{
|
||||||
|
item->fix_fields(current_thd, 0, 0);
|
||||||
|
}
|
||||||
|
((Item_cond_and*)cond)->cond_equal= cond_equal;
|
||||||
|
inherited= &(((Item_cond_and*)cond)->cond_equal);
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
Make replacement of equality predicates for lower levels
|
||||||
|
of the condition expression.
|
||||||
|
*/
|
||||||
|
List_iterator<Item> it(*args);
|
||||||
|
while((item= it++))
|
||||||
|
{
|
||||||
|
Item *new_item;
|
||||||
|
if ((new_item = build_all_equal_items(item, inherited))!= item)
|
||||||
|
{
|
||||||
|
/* This replacement happens only for standalone equalities */
|
||||||
|
it.replace(new_item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (and_level)
|
||||||
|
args->concat((List<Item> *)&cond_equal.current_level);
|
||||||
|
}
|
||||||
|
else if (cond->type() == Item::FUNC_ITEM)
|
||||||
|
{
|
||||||
|
/* Standalone equalities are handled here */
|
||||||
|
Item_equal *item_equal;
|
||||||
|
if (check_equality(cond, &cond_equal) &&
|
||||||
|
(item_equal= cond_equal.current_level.pop()))
|
||||||
|
{
|
||||||
|
item_equal->fix_fields(current_thd, 0, 0);
|
||||||
|
return item_equal;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cond= cond->traverse(&Item::equal_fields_propagator,
|
||||||
|
(byte *) inherited);
|
||||||
|
cond->update_used_tables();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cond;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Generate minimal set of simple equalities equivalent to a multiple equality
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
eliminate_item_equal()
|
||||||
|
cond condition to add the generated equality to
|
||||||
|
cond_equal structure to access multiple equality of upper levels
|
||||||
|
item_equal multiple equality to generate simple equality from
|
||||||
|
|
||||||
|
DESCRIPTION
|
||||||
|
The function retrieves the fields of the multiple equality item
|
||||||
|
item_equal and for each field f:
|
||||||
|
- if item_equal contains const it generates the equality f=const_item;
|
||||||
|
- otherwise, if f is not the first field, generates the equality
|
||||||
|
f=item_equal->get_first().
|
||||||
|
All generated equality are added to the cond conjunction.
|
||||||
|
|
||||||
|
NOTES
|
||||||
|
Before generating an equality function checks that it has not
|
||||||
|
been generated for multiple equalies of the upper levels.
|
||||||
|
If cond is equal to 0, then not more then one equality is generated
|
||||||
|
and a pointer to it is returned as the result of the function.
|
||||||
|
|
||||||
|
RETURN
|
||||||
|
The condition with generated simple equalities or
|
||||||
|
a pointer to the simple generated equality.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static Item *eliminate_item_equal(COND *cond, COND_EQUAL *cond_equal,
|
||||||
|
Item_equal *item_equal)
|
||||||
|
{
|
||||||
|
Item *item_const= item_equal->get_const();
|
||||||
|
Item_equal_iterator it(*item_equal);
|
||||||
|
Item *head;
|
||||||
|
if (item_const)
|
||||||
|
head= item_const;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
head= item_equal->get_first();
|
||||||
|
it++;
|
||||||
|
}
|
||||||
|
Item_field *item_field;
|
||||||
|
Item *new_item= 0;
|
||||||
|
while ((item_field= it++))
|
||||||
|
{
|
||||||
|
Item_equal *upper= item_field->find_item_equal(cond_equal);
|
||||||
|
Item_field *item= item_field;
|
||||||
|
if (upper)
|
||||||
|
{
|
||||||
|
if (item_const)
|
||||||
|
{
|
||||||
|
if (upper->get_const())
|
||||||
|
item= 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Item_equal_iterator li(*item_equal);
|
||||||
|
while ((item= li++) != item_field)
|
||||||
|
{
|
||||||
|
if (item->find_item_equal(cond_equal) == upper)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (item == item_field)
|
||||||
|
{
|
||||||
|
if (!cond && new_item)
|
||||||
|
{
|
||||||
|
cond= new Item_cond_and();
|
||||||
|
((Item_cond *) cond)->add(new_item);
|
||||||
|
}
|
||||||
|
item_field->item_equal= item_equal;
|
||||||
|
new_item= new Item_func_eq(item_field, head);
|
||||||
|
((Item_func_eq *) new_item)->fix_length_and_dec();
|
||||||
|
if (cond)
|
||||||
|
((Item_cond *) cond)->add(new_item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!cond)
|
||||||
|
cond= (COND *) new_item;
|
||||||
|
return cond;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Substitute every field reference in a condition by the best equal field
|
||||||
|
and eliminate all multiplle equality predicates
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
substitute_for_best_equal_field()
|
||||||
|
cond condition to process
|
||||||
|
table_join_idx index to tables determining field preference
|
||||||
|
|
||||||
|
DESCRIPTION
|
||||||
|
The function retrieves the cond condition and for each encountered
|
||||||
|
multiple equality predicate it sorts the field references in it
|
||||||
|
according to the order of tables specified by the table_join_idx
|
||||||
|
parameter. Then it eliminates the multiple equality predicate it
|
||||||
|
replacing it by the conjunction of simple equality predicates
|
||||||
|
equating every field from the multiple equality to the first
|
||||||
|
field in it, or to the constant, if there is any.
|
||||||
|
After this the function retrieves all other conjuncted
|
||||||
|
predicates substitute every field reference by the field reference
|
||||||
|
to the first equal field or equal constant if there are any.
|
||||||
|
|
||||||
|
NOTES
|
||||||
|
At the first glance full sort of fields in multiple equality
|
||||||
|
seems to be an overkill. Yet it's not the case due to possible
|
||||||
|
new fields in multiple equality item of lower levels. We want
|
||||||
|
the order in them to comply with the order of upper levels.
|
||||||
|
|
||||||
|
RETURN
|
||||||
|
The transformed condition
|
||||||
|
*/
|
||||||
|
|
||||||
|
static COND* substitute_for_best_equal_field(COND *cond,
|
||||||
|
void *table_join_idx)
|
||||||
|
{
|
||||||
|
Item_equal *item_equal;
|
||||||
|
|
||||||
|
if (cond->type() == Item::COND_ITEM)
|
||||||
|
{
|
||||||
|
List<Item> *cond_list= ((Item_cond*) cond)->argument_list();
|
||||||
|
COND_EQUAL *cond_equal= 0;
|
||||||
|
|
||||||
|
bool and_level= ((Item_cond*) cond)->functype() ==
|
||||||
|
Item_func::COND_AND_FUNC;
|
||||||
|
if (and_level)
|
||||||
|
{
|
||||||
|
cond_equal= &((Item_cond_and *) cond)->cond_equal;
|
||||||
|
cond_list->disjoin((List<Item> *) &cond_equal->current_level);
|
||||||
|
|
||||||
|
List_iterator_fast<Item_equal> it(cond_equal->current_level);
|
||||||
|
while((item_equal= it++))
|
||||||
|
{
|
||||||
|
item_equal->sort(table_join_idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List_iterator<Item> li(*cond_list);
|
||||||
|
Item *item;
|
||||||
|
while ((item= li++))
|
||||||
|
{
|
||||||
|
Item *new_item =substitute_for_best_equal_field(item,
|
||||||
|
table_join_idx);
|
||||||
|
if (new_item != item)
|
||||||
|
li.replace(new_item);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (and_level)
|
||||||
|
{
|
||||||
|
List_iterator_fast<Item_equal> it(cond_equal->current_level);
|
||||||
|
while((item_equal= it++))
|
||||||
|
{
|
||||||
|
eliminate_item_equal(cond, cond_equal->parent_level, item_equal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (cond->type() == Item::FUNC_ITEM &&
|
||||||
|
((Item_cond*) cond)->functype() == Item_func::MULT_EQUAL_FUNC)
|
||||||
|
{
|
||||||
|
item_equal= (Item_equal *) cond;
|
||||||
|
item_equal->sort(table_join_idx);
|
||||||
|
return eliminate_item_equal(0, 0, item_equal);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
cond->walk(&Item::replace_equal_field_processor, 0);
|
||||||
|
return cond;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
change field = field to field = const for each found field = const in the
|
change field = field to field = const for each found field = const in the
|
||||||
and_level
|
and_level
|
||||||
@ -4318,9 +5053,6 @@ optimize_cond(COND *conds,Item::cond_result *cond_value)
|
|||||||
return conds;
|
return conds;
|
||||||
}
|
}
|
||||||
DBUG_EXECUTE("where",print_where(conds,"original"););
|
DBUG_EXECUTE("where",print_where(conds,"original"););
|
||||||
/* eliminate NOT operators */
|
|
||||||
conds= eliminate_not_funcs(conds);
|
|
||||||
DBUG_EXECUTE("where", print_where(conds, "after negation elimination"););
|
|
||||||
/* 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);
|
||||||
/*
|
/*
|
||||||
@ -4412,7 +5144,8 @@ remove_eq_conds(COND *cond,Item::cond_result *cond_value)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (cond->type() == Item::FUNC_ITEM &&
|
else if (cond->type() == Item::FUNC_ITEM &&
|
||||||
((Item_func*) cond)->functype() == Item_func::ISNULL_FUNC)
|
((Item_func*) cond)->functype() == Item_func::ISNULL_FUNC &&
|
||||||
|
!cond->const_item())
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
Handles this special case for some ODBC applications:
|
Handles this special case for some ODBC applications:
|
||||||
@ -4463,6 +5196,22 @@ remove_eq_conds(COND *cond,Item::cond_result *cond_value)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (cond->type() == Item::FUNC_ITEM &&
|
||||||
|
((Item_func*) cond)->functype() == Item_func::MULT_EQUAL_FUNC)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
The is_false method for an multiple equality item returns 1
|
||||||
|
when the conjunction with this item originally contained an
|
||||||
|
equality that was inconsistent with the multiple equality
|
||||||
|
predicate or has been inherited from other multiple equality
|
||||||
|
for which is_false returns 1.
|
||||||
|
*/
|
||||||
|
if (((Item_equal *) cond)->is_false())
|
||||||
|
{
|
||||||
|
*cond_value= Item::COND_FALSE;
|
||||||
|
return (COND*) 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
else if (cond->const_item())
|
else if (cond->const_item())
|
||||||
{
|
{
|
||||||
*cond_value= eval_const_cond(cond) ? Item::COND_TRUE : Item::COND_FALSE;
|
*cond_value= eval_const_cond(cond) ? Item::COND_TRUE : Item::COND_FALSE;
|
||||||
|
@ -184,6 +184,7 @@ class JOIN :public Sql_alloc
|
|||||||
ORDER *order, *group_list, *proc_param; //hold parameters of mysql_select
|
ORDER *order, *group_list, *proc_param; //hold parameters of mysql_select
|
||||||
COND *conds; // ---"---
|
COND *conds; // ---"---
|
||||||
Item *conds_history; // store WHERE for explain
|
Item *conds_history; // store WHERE for explain
|
||||||
|
COND_EQUAL *cond_equal;
|
||||||
TABLE_LIST *tables_list; //hold 'tables' parameter of mysql_selec
|
TABLE_LIST *tables_list; //hold 'tables' parameter of mysql_selec
|
||||||
SQL_SELECT *select; //created in optimisation phase
|
SQL_SELECT *select; //created in optimisation phase
|
||||||
Item **ref_pointer_array; //used pointer reference for this select
|
Item **ref_pointer_array; //used pointer reference for this select
|
||||||
@ -243,6 +244,7 @@ class JOIN :public Sql_alloc
|
|||||||
ref_pointer_array_size= 0;
|
ref_pointer_array_size= 0;
|
||||||
zero_result_cause= 0;
|
zero_result_cause= 0;
|
||||||
optimized= 0;
|
optimized= 0;
|
||||||
|
cond_equal= 0;
|
||||||
|
|
||||||
fields_list= fields;
|
fields_list= fields;
|
||||||
bzero((char*) &keyuse,sizeof(keyuse));
|
bzero((char*) &keyuse,sizeof(keyuse));
|
||||||
|
Loading…
x
Reference in New Issue
Block a user