Merge for Item_equal.
BitKeeper/etc/ignore: auto-union mysql-test/r/bdb.result: Auto merged mysql-test/r/func_group.result: Auto merged mysql-test/r/innodb.result: Auto merged mysql-test/r/heap_btree.result: Auto merged mysql-test/r/select.result: Auto merged mysql-test/r/user_var.result: Auto merged mysql-test/t/range.test: Auto merged sql/item_func.cc: Auto merged sql/item_func.h: Auto merged sql/item_row.cc: Auto merged sql/item_strfunc.h: Auto merged sql/opt_sum.cc: Auto merged sql/sql_list.h: Auto merged mysql-test/r/func_test.result: Post-automerge resolution of conflicts mysql-test/r/index_merge.result: Post-automerge resolution of conflicts mysql-test/r/join_outer.result: Post-automerge resolution of conflicts mysql-test/r/range.result: Post-automerge resolution of conflicts mysql-test/r/subselect.result: Post-automerge resolution of conflicts sql/item.cc: Post-automerge resolution of conflicts sql/item.h: Post-automerge resolution of conflicts sql/item_cmpfunc.cc: Post-automerge resolution of conflicts sql/item_cmpfunc.h: Post-automerge resolution of conflicts sql/opt_range.cc: Post-automerge resolution of conflicts sql/sql_select.cc: Post-automerge resolution of conflicts sql/sql_select.h: Post-automerge resolution of conflicts
This commit is contained in:
commit
881534fb80
@ -508,6 +508,7 @@ mysql-test/install_test_db
|
||||
mysql-test/mysql-test-run
|
||||
mysql-test/ndb/ndbcluster
|
||||
mysql-test/r/*.reject
|
||||
mysql-test/r/index_merge_load.result
|
||||
mysql-test/r/rpl000001.eval
|
||||
mysql-test/r/rpl000002.eval
|
||||
mysql-test/r/rpl000014.eval
|
||||
@ -518,6 +519,7 @@ mysql-test/r/slave-running.eval
|
||||
mysql-test/r/slave-stopped.eval
|
||||
mysql-test/share/mysql
|
||||
mysql-test/std_data/*.pem
|
||||
mysql-test/t/index_merge.load
|
||||
mysql-test/var/*
|
||||
mysql.kdevprj
|
||||
mysql.proj
|
||||
|
@ -476,7 +476,7 @@ CHI Los Angeles
|
||||
explain
|
||||
select max(a3) from t1 where a2 is null and a2 = 2;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
|
||||
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE
|
||||
select max(a3) from t1 where a2 is null and a2 = 2;
|
||||
max(a3)
|
||||
NULL
|
||||
|
@ -77,7 +77,7 @@ select * from t1 where 1 xor 1;
|
||||
a
|
||||
explain extended select * from t1 where 1 xor 1;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
|
||||
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE
|
||||
Warnings:
|
||||
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where (1 xor 1)
|
||||
select - a from t1;
|
||||
|
@ -76,13 +76,13 @@ id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t0 ALL i1,i2 NULL NULL NULL 1024 Using where
|
||||
explain select * from t0 where key2 = 45 or key1 is null;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t0 range i1,i2 i2 4 NULL 1 Using where
|
||||
1 SIMPLE t0 ref i2 i2 4 const 1
|
||||
explain select * from t0 where key2=10 or key3=3 or key4 <=> null;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t0 index_merge i2,i3,i4 i2,i3 4,4 NULL 2 Using union(i2,i3); Using where
|
||||
explain select * from t0 where key2=10 or key3=3 or key4 is null;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t0 index_merge i2,i3,i4 i2,i3 4,4 NULL 2 Using union(i2,i3); Using where
|
||||
1 SIMPLE t0 index_merge i2,i3 i2,i3 4,4 NULL 2 Using where
|
||||
explain select key1 from t0 where (key1 <=> null) or (key2 < 5) or
|
||||
(key3=10) or (key4 <=> null);
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
|
@ -12,5 +12,5 @@ select * from t1 where a is null;
|
||||
a b
|
||||
explain select * from t1 where b is null;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
|
||||
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE
|
||||
drop table t1;
|
||||
|
@ -220,24 +220,22 @@ insert into t1 (x) values (1),(2),(3),(4),(5),(6),(7),(8),(9);
|
||||
update t1 set y=x;
|
||||
explain select * from t1, t1 t2 where t1.y = 2 and t2.x between 7 and t1.y+0;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ref y y 5 const 1 Using where
|
||||
1 SIMPLE t2 range x x 5 NULL 4 Using where
|
||||
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
|
||||
explain select * from t1, t1 t2 where t1.y = 2 and t2.x >= 7 and t2.x <= t1.y+0;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ref y y 5 const 1 Using where
|
||||
1 SIMPLE t2 range x x 5 NULL 4 Using where
|
||||
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
|
||||
explain select * from t1, t1 t2 where t1.y = 2 and t2.x between t1.y-1 and t1.y+1;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ref y y 5 const 1 Using where
|
||||
1 SIMPLE t2 ALL x NULL NULL NULL 9 Range checked for each record (index map: 0x1)
|
||||
1 SIMPLE t2 range x x 5 NULL 3 Using where
|
||||
explain select * from t1, t1 t2 where t1.y = 2 and t2.x >= t1.y-1 and t2.x <= t1.y+1;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ref y y 5 const 1 Using where
|
||||
1 SIMPLE t2 ALL x NULL NULL NULL 9 Range checked for each record (index map: 0x1)
|
||||
1 SIMPLE t2 range x x 5 NULL 3 Using where
|
||||
explain select * from t1, t1 t2 where t1.y = 2 and t2.x between 0 and t1.y;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ref y y 5 const 1 Using where
|
||||
1 SIMPLE t2 ALL x NULL NULL NULL 9 Using where
|
||||
1 SIMPLE t2 range x x 5 NULL 2 Using where
|
||||
explain select * from t1, t1 t2 where t1.y = 2 and t2.x >= 0 and t2.x <= t1.y;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ref y y 5 const 1 Using where
|
||||
@ -415,14 +413,26 @@ count(*)
|
||||
select count(*) from t2;
|
||||
count(*)
|
||||
1026
|
||||
analyze table t1,t2;
|
||||
Table Op Msg_type Msg_text
|
||||
test.t1 analyze status OK
|
||||
test.t2 analyze status Table is already up to date
|
||||
explain select * from t1, t2 where t1.uid=t2.uid AND t1.uid > 0;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 range uid_index uid_index 4 NULL 128 Using where
|
||||
1 SIMPLE t2 ref uid_index uid_index 4 test.t1.uid 38
|
||||
explain select * from t1, t2 where t1.uid=t2.uid AND t2.uid > 0;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 range uid_index uid_index 4 NULL 128 Using where
|
||||
1 SIMPLE t2 ref uid_index uid_index 4 test.t1.uid 38
|
||||
explain select * from t1, t2 where t1.uid=t2.uid AND t1.uid != 0;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 range uid_index uid_index 4 NULL 129 Using where
|
||||
1 SIMPLE t2 ref uid_index uid_index 4 test.t1.uid 38
|
||||
explain select * from t1, t2 where t1.uid=t2.uid AND t2.uid != 0;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 range uid_index uid_index 4 NULL 129 Using where
|
||||
1 SIMPLE t2 ref uid_index uid_index 4 test.t1.uid 38
|
||||
select * from t1, t2 where t1.uid=t2.uid AND t1.uid > 0;
|
||||
id name uid id name uid
|
||||
1001 A 1 1001 A 1
|
||||
|
@ -1375,7 +1375,7 @@ id select_type table type possible_keys key key_len ref rows Extra
|
||||
explain select t2.companynr,companyname from t4 left join t2 using (companynr) where t2.companynr > 0 and t4.companynr > 0;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t2 ALL NULL NULL NULL NULL 1199 Using where
|
||||
1 SIMPLE t4 eq_ref PRIMARY PRIMARY 1 test.t2.companynr 1 Using where
|
||||
1 SIMPLE t4 eq_ref PRIMARY PRIMARY 1 test.t2.companynr 1
|
||||
explain select t2.companynr,companyname from t4 left join t2 using (companynr) where t2.companynr > 0 or t2.companynr is null;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t4 ALL NULL NULL NULL NULL 12
|
||||
|
@ -378,8 +378,12 @@ insert into t2(id, uid, name) select id, uid, name from t1;
|
||||
select count(*) from t1;
|
||||
select count(*) from t2;
|
||||
|
||||
analyze table t1,t2;
|
||||
|
||||
explain select * from t1, t2 where t1.uid=t2.uid AND t1.uid > 0;
|
||||
explain select * from t1, t2 where t1.uid=t2.uid AND t2.uid > 0;
|
||||
explain select * from t1, t2 where t1.uid=t2.uid AND t1.uid != 0;
|
||||
explain select * from t1, t2 where t1.uid=t2.uid AND t2.uid != 0;
|
||||
|
||||
select * from t1, t2 where t1.uid=t2.uid AND t1.uid > 0;
|
||||
select * from t1, t2 where t1.uid=t2.uid AND t1.uid != 0;
|
||||
|
27
sql/item.cc
27
sql/item.cc
@ -408,6 +408,7 @@ bool DTCollation::aggregate(DTCollation &dt, bool superset_conversion)
|
||||
|
||||
Item_field::Item_field(Field *f)
|
||||
:Item_ident(NullS, f->table_name, f->field_name),
|
||||
item_equal(0),
|
||||
have_privileges(0), any_privileges(0)
|
||||
{
|
||||
set_field(f);
|
||||
@ -418,6 +419,7 @@ Item_field::Item_field(Field *f)
|
||||
Item_field::Item_field(THD *thd, Field *f)
|
||||
:Item_ident(NullS, thd->strdup(f->table_name),
|
||||
thd->strdup(f->field_name)),
|
||||
item_equal(0),
|
||||
have_privileges(0), any_privileges(0)
|
||||
{
|
||||
set_field(f);
|
||||
@ -434,6 +436,7 @@ Item_field::Item_field(THD *thd, Item_field *item)
|
||||
any_privileges(item->any_privileges)
|
||||
{
|
||||
collation.set(DERIVATION_IMPLICIT);
|
||||
item_equal= item->item_equal;
|
||||
}
|
||||
|
||||
void Item_field::set_field(Field *field_par)
|
||||
@ -1582,7 +1585,29 @@ void Item_field::cleanup()
|
||||
I.e. we can drop 'field'.
|
||||
*/
|
||||
field= result_field= 0;
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
/*
|
||||
Find a field among specified multiple equalities
|
||||
|
||||
SYNOPSIS
|
||||
find_item_equal()
|
||||
cond_equal reference to list of multiple equalities where
|
||||
the field (this object) is to be looked for
|
||||
|
||||
DESCRIPTION
|
||||
The function first searches the field among multiple equalities
|
||||
of the current level (in the cond_equal->current_level list).
|
||||
If it fails, it continues searching in upper levels accessed
|
||||
through a pointer cond_equal->upper_levels.
|
||||
The search terminates as soon as a multiple equality containing
|
||||
the field is found.
|
||||
|
||||
RETURN VALUES
|
||||
First Item_equal containing the field, if success
|
||||
0, otherwise
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
void Item::init_make_field(Send_field *tmp_field,
|
||||
|
29
sql/item.h
29
sql/item.h
@ -90,6 +90,7 @@ public:
|
||||
};
|
||||
|
||||
typedef bool (Item::*Item_processor)(byte *arg);
|
||||
typedef Item* (Item::*Item_transformer) (byte *arg);
|
||||
|
||||
class Item {
|
||||
Item(const Item &); /* Prevent use of these */
|
||||
@ -261,8 +262,15 @@ public:
|
||||
return (this->*processor)(arg);
|
||||
}
|
||||
|
||||
virtual Item* transform(Item_transformer transformer, byte *arg)
|
||||
{
|
||||
return (this->*transformer)(arg);
|
||||
}
|
||||
|
||||
virtual bool remove_dependence_processor(byte * arg) { 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_const_item() const { return const_cast<Item*>(this); } /* For SPs mostly. */
|
||||
@ -440,6 +448,8 @@ public:
|
||||
bool any_privileges, bool allocate_view_names);
|
||||
};
|
||||
|
||||
class Item_equal;
|
||||
class COND_EQUAL;
|
||||
|
||||
class Item_field :public Item_ident
|
||||
{
|
||||
@ -458,7 +468,8 @@ public:
|
||||
Item_field(const char *db_par,const char *table_name_par,
|
||||
const char *field_name_par)
|
||||
:Item_ident(db_par,table_name_par,field_name_par),
|
||||
field(0), result_field(0), have_privileges(0), any_privileges(0)
|
||||
field(0), result_field(0), item_equal(0),}
|
||||
have_privileges(0), any_privileges(0)
|
||||
{ collation.set(DERIVATION_IMPLICIT); }
|
||||
// Constructor need to process subselect with temporary tables (see Item)
|
||||
Item_field(THD *thd, Item_field *item);
|
||||
@ -498,6 +509,9 @@ public:
|
||||
bool is_null() { return field->is_null(); }
|
||||
Item *get_tmp_table_item(THD *thd);
|
||||
void cleanup();
|
||||
Item_equal *find_item_equal(COND_EQUAL *cond_equal);
|
||||
Item *equal_fields_propagator(byte *arg);
|
||||
bool replace_equal_field_processor(byte *arg);
|
||||
inline uint32 max_disp_length() { return field->max_length(); }
|
||||
Item_field *filed_for_view_update() { return this; }
|
||||
friend class Item_default_value;
|
||||
@ -1173,6 +1187,19 @@ public:
|
||||
return arg->walk(processor, args) ||
|
||||
(this->*processor)(args);
|
||||
}
|
||||
|
||||
/*
|
||||
This method like the walk method traverses the item tree, but
|
||||
at the same time it can replace some nodes in the tree
|
||||
*/
|
||||
Item *transform(Item_transformer transformer, byte *args)
|
||||
{
|
||||
Item *new_item= arg->transform(transformer, args);
|
||||
if (!new_item)
|
||||
return 0;
|
||||
arg= new_item;
|
||||
return (this->*transformer)(args);
|
||||
}
|
||||
};
|
||||
|
||||
class Item_insert_value : public Item_field
|
||||
|
@ -256,7 +256,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;
|
||||
if (field->store_for_compare())
|
||||
@ -2008,6 +2008,44 @@ bool Item_cond::walk(Item_processor processor, byte *arg)
|
||||
return Item_func::walk(processor, arg);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Transform an Item_cond object with a transformer callback function
|
||||
|
||||
SYNOPSIS
|
||||
transform()
|
||||
transformer the transformer callback function to be applied to the nodes
|
||||
of the tree of the object
|
||||
arg parameter to be passed to the transformer
|
||||
|
||||
DESCRIPTION
|
||||
The function recursively applies the transform method with the
|
||||
same transformer to each member item of the codition list.
|
||||
If the call of the method for a member item returns a new item
|
||||
the old item is substituted for a new one.
|
||||
After this the transform method is applied to the root node
|
||||
of the Item_cond object.
|
||||
|
||||
RETURN VALUES
|
||||
Item returned as the result of transformation of the root node
|
||||
*/
|
||||
|
||||
Item *Item_cond::transform(Item_transformer transformer, byte *arg)
|
||||
{
|
||||
List_iterator<Item> li(list);
|
||||
Item *item;
|
||||
while ((item= li++))
|
||||
{
|
||||
Item *new_item= item->transform(transformer, arg);
|
||||
if (!new_item)
|
||||
return 0;
|
||||
if (new_item != item)
|
||||
li.replace(new_item);
|
||||
}
|
||||
return Item_func::transform(transformer, arg);
|
||||
}
|
||||
|
||||
|
||||
void Item_cond::split_sum_func(Item **ref_pointer_array, List<Item> &fields)
|
||||
{
|
||||
List_iterator<Item> li(list);
|
||||
@ -2854,3 +2892,289 @@ Item *Item_bool_rowready_func2::negated_item()
|
||||
DBUG_ASSERT(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
uint Item_equal::members()
|
||||
{
|
||||
uint count= 0;
|
||||
List_iterator_fast<Item_field> li(fields);
|
||||
Item_field *item;
|
||||
while ((item= li++))
|
||||
count++;
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Check whether a field is referred in the multiple equality
|
||||
|
||||
SYNOPSIS
|
||||
contains()
|
||||
field field whose occurence is to be checked
|
||||
|
||||
DESCRIPTION
|
||||
The function checks whether field is occured in the Item_equal object
|
||||
|
||||
RETURN VALUES
|
||||
1 if nultiple equality contains a reference to field
|
||||
0 otherwise
|
||||
*/
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Join members of another Item_equal object
|
||||
|
||||
SYNOPSIS
|
||||
merge()
|
||||
item multiple equality whose members are to be joined
|
||||
|
||||
DESCRIPTION
|
||||
The function actually merges two multiple equalitis.
|
||||
After this operation the Item_equal object additionally contains
|
||||
the field items of another item of the type Item_equal.
|
||||
If the optional constant items are not equal the cond_false flag is
|
||||
set to 1.
|
||||
|
||||
RETURN VALUES
|
||||
none
|
||||
*/
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Order field items in multiple equality according to a sorting criteria
|
||||
|
||||
SYNOPSIS
|
||||
sort()
|
||||
cmp function to compare field item
|
||||
arg context extra parameter for the cmp function
|
||||
|
||||
DESCRIPTION
|
||||
The function perform ordering of the field items in the Item_equal
|
||||
object according to the criteria determined by the cmp callback parameter.
|
||||
If cmp(item_field1,item_field2,arg)<0 than item_field1 must be
|
||||
placed after item_fiel2.
|
||||
|
||||
IMPLEMENTATION
|
||||
The function sorts field items by the exchange sort algorithm.
|
||||
The list of field items is looked through and whenever two neighboring
|
||||
members follow in a wrong order they are swapped. This is performed
|
||||
again and again until we get all members in a right order.
|
||||
|
||||
RETURN VALUES
|
||||
None
|
||||
*/
|
||||
|
||||
void Item_equal::sort(Item_field_cmpfunc cmp, void *arg)
|
||||
{
|
||||
bool swap;
|
||||
List_iterator<Item_field> it(fields);
|
||||
do
|
||||
{
|
||||
Item_field *item1= it++;
|
||||
Item_field **ref1= it.ref();
|
||||
Item_field *item2;
|
||||
|
||||
swap= FALSE;
|
||||
while ((item2= it++))
|
||||
{
|
||||
Item_field **ref2= it.ref();
|
||||
if (cmp(item1, item2, arg) < 0)
|
||||
{
|
||||
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;
|
||||
if ((const_item_cache= cond_false))
|
||||
return;
|
||||
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::transform(Item_transformer transformer, byte *arg)
|
||||
{
|
||||
List_iterator<Item_field> it(fields);
|
||||
Item *item;
|
||||
while ((item= it++))
|
||||
{
|
||||
Item *new_item= item->transform(transformer, arg);
|
||||
if (!new_item)
|
||||
return 0;
|
||||
if (new_item != item)
|
||||
it.replace((Item_field *) new_item);
|
||||
}
|
||||
return Item_func::transform(transformer, arg);
|
||||
}
|
||||
|
||||
void Item_equal::print(String *str)
|
||||
{
|
||||
str->append(func_name());
|
||||
str->append('(');
|
||||
List_iterator_fast<Item_field> it(fields);
|
||||
Item *item;
|
||||
if (const_item)
|
||||
const_item->print(str);
|
||||
else
|
||||
{
|
||||
item= it++;
|
||||
item->print(str);
|
||||
}
|
||||
while ((item= it++))
|
||||
{
|
||||
str->append(',');
|
||||
str->append(' ');
|
||||
item->print(str);
|
||||
}
|
||||
str->append(')');
|
||||
}
|
||||
|
||||
|
@ -20,6 +20,9 @@
|
||||
#ifdef __GNUC__
|
||||
#pragma interface /* gcc class implementation */
|
||||
#endif
|
||||
#ifdef __GNUC__
|
||||
template class List_iterator_fast<Item_field>;
|
||||
#endif
|
||||
|
||||
extern Item_result item_cmp_type(Item_result a,Item_result b);
|
||||
class Item_bool_func2;
|
||||
@ -27,6 +30,8 @@ class Arg_comparator;
|
||||
|
||||
typedef int (Arg_comparator::*arg_cmp_func)();
|
||||
|
||||
typedef int (*Item_field_cmpfunc)(Item_field *f1, Item_field *f2, void *arg);
|
||||
|
||||
class Arg_comparator: public Sql_alloc
|
||||
{
|
||||
Item **a, **b;
|
||||
@ -957,6 +962,7 @@ public:
|
||||
Item_cond(List<Item> &nlist)
|
||||
:Item_bool_func(), list(nlist), abort_on_null(0) {}
|
||||
bool add(Item *item) { return list.push_back(item); }
|
||||
void add_at_head(List<Item> *nlist) { list.prepand(nlist); }
|
||||
bool fix_fields(THD *, struct st_table_list *, Item **ref);
|
||||
|
||||
enum Type type() const { return COND_ITEM; }
|
||||
@ -969,13 +975,151 @@ public:
|
||||
void top_level_item() { abort_on_null=1; }
|
||||
void copy_andor_arguments(THD *thd, Item_cond *item);
|
||||
bool walk(Item_processor processor, byte *arg);
|
||||
Item *transform(Item_transformer transformer, byte *arg);
|
||||
void neg_arguments(THD *thd);
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
The class Item_equal is used to represent conjuctions of equality
|
||||
predicates of the form field1 = field2, and field=const in where
|
||||
conditions and on expressions.
|
||||
|
||||
All equality predicates of the form field1=field2 contained in a
|
||||
conjuction are substituted for a sequence of items of this class.
|
||||
An item of this class Item_equal(f1,f2,...fk) respresents a
|
||||
multiple equality f1=f2=...=fk.
|
||||
|
||||
If a conjuction contains predicates f1=f2 and f2=f3, a new item of
|
||||
this class is created Item_equal(f1,f2,f3) representing the multiple
|
||||
equality f1=f2=f3 that substitutes the above equality predicates in
|
||||
the conjuction.
|
||||
A conjuction of the predicates f2=f1 and f3=f1 and f3=f2 will be
|
||||
substituted for the item representing the same multiple equality
|
||||
f1=f2=f3.
|
||||
An item Item_equal(f1,f2) can appear instead of a conjuction of
|
||||
f2=f1 and f1=f2, or instead of just the predicate f1=f2.
|
||||
|
||||
An item of the class Item_equal inherites equalities from outer
|
||||
conjunctive levels.
|
||||
|
||||
Suppose we have a where condition of the following form:
|
||||
WHERE f1=f2 AND f3=f4 AND f3=f5 AND ... AND (...OR (f1=f3 AND ...)).
|
||||
In this case:
|
||||
f1=f2 will be substituted for Item_equal(f1,f2);
|
||||
f3=f4 and f3=f5 will be substituted for Item_equal(f3,f4,f5);
|
||||
f1=f3 will be substituted for Item_equal(f1,f2,f3,f4,f5);
|
||||
|
||||
An object of the class Item_equal can contain an optional constant
|
||||
item c. Thenit represents a multiple equality of the form
|
||||
c=f1=...=fk.
|
||||
|
||||
Objects of the class Item_equal are used for the following:
|
||||
|
||||
1. An object Item_equal(t1.f1,...,tk.fk) allows us to consider any
|
||||
pair of tables ti and tj as joined by an equi-condition.
|
||||
Thus it provide us with additional access paths from table to table.
|
||||
|
||||
2. An object Item_equal(t1.f1,...,tk.fk) is applied to deduce new
|
||||
SARGable predicates:
|
||||
f1=...=fk AND P(fi) => f1=...=fk AND P(fi) AND P(fj).
|
||||
It also can give us additional index scans and can allow us to
|
||||
improve selectivity estimates.
|
||||
|
||||
3. An object Item_equal(t1.f1,...,tk.fk) is used to optimize the
|
||||
selected execution plan for the query: if table ti is accessed
|
||||
before the table tj then in any predicate P in the where condition
|
||||
the occurence of tj.fj is substituted for ti.fi. This can allow
|
||||
an evaluation of the predicate at an earlier step.
|
||||
|
||||
When feature 1 is supported they say that join transitive closure
|
||||
is employed.
|
||||
When feature 2 is supported they say that search argument transitive
|
||||
closure is employed.
|
||||
Both features are usually supported by preprocessing original query and
|
||||
adding additional predicates.
|
||||
We do not just add predicates, we rather dynamically replace some
|
||||
predicates that can not be used to access tables in the investigated
|
||||
plan for those, obtained by substitution of some fields for equal fields,
|
||||
that can be used.
|
||||
*/
|
||||
|
||||
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);
|
||||
uint members();
|
||||
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(Item_field_cmpfunc cmp, void *arg);
|
||||
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 *transform(Item_transformer transformer, byte *arg);
|
||||
void print(String *str);
|
||||
CHARSET_INFO *compare_collation()
|
||||
{ return fields.head()->collation.collation; }
|
||||
};
|
||||
|
||||
class COND_EQUAL
|
||||
{
|
||||
public:
|
||||
uint max_members; /* max number of members the current level
|
||||
list and all lower level lists */
|
||||
COND_EQUAL *upper_levels; /* multiple equalities of upper and levels */
|
||||
List<Item_equal> current_level; /* list of multiple equalities of
|
||||
the current and level */
|
||||
COND_EQUAL()
|
||||
{
|
||||
max_members= 0;
|
||||
upper_levels= 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
|
||||
{
|
||||
public:
|
||||
COND_EQUAL cond_equal; /* contains list of Item_equal objects for
|
||||
the current and level and reference
|
||||
to multiple equalities of upper and levels */
|
||||
Item_cond_and() :Item_cond() {}
|
||||
Item_cond_and(Item *i1,Item *i2) :Item_cond(i1,i2) {}
|
||||
Item_cond_and(THD *thd, Item_cond_and *item) :Item_cond(thd, item) {}
|
||||
|
@ -260,6 +260,45 @@ bool Item_func::walk (Item_processor processor, byte *argument)
|
||||
return (this->*processor)(argument);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Transform an Item_func object with a transformer callback function
|
||||
|
||||
SYNOPSIS
|
||||
transform()
|
||||
transformer the transformer callback function to be applied to the nodes
|
||||
of the tree of the object
|
||||
argument parameter to be passed to the transformer
|
||||
|
||||
DESCRIPTION
|
||||
The function recursively applies the transform method with the
|
||||
same transformer to each argument the function.
|
||||
If the call of the method for a member item returns a new item
|
||||
the old item is substituted for a new one.
|
||||
After this the transform method is applied to the root node
|
||||
of the Item_func object.
|
||||
|
||||
RETURN VALUES
|
||||
Item returned as the result of transformation of the root node
|
||||
*/
|
||||
|
||||
Item *Item_func::transform(Item_transformer transformer, 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)->transform(transformer, argument);
|
||||
if (!new_item)
|
||||
return 0;
|
||||
*arg= new_item;
|
||||
}
|
||||
}
|
||||
return (this->*transformer)(argument);
|
||||
}
|
||||
|
||||
|
||||
void Item_func::split_sum_func(Item **ref_pointer_array, List<Item> &fields)
|
||||
{
|
||||
Item **arg, **arg_end;
|
||||
|
@ -40,7 +40,8 @@ public:
|
||||
enum Functype { UNKNOWN_FUNC,EQ_FUNC,EQUAL_FUNC,NE_FUNC,LT_FUNC,LE_FUNC,
|
||||
GE_FUNC,GT_FUNC,FT_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,
|
||||
SP_EQUALS_FUNC, SP_DISJOINT_FUNC,SP_INTERSECTS_FUNC,
|
||||
SP_TOUCHES_FUNC,SP_CROSSES_FUNC,SP_WITHIN_FUNC,
|
||||
@ -50,7 +51,8 @@ public:
|
||||
NOT_FUNC, NOT_ALL_FUNC,
|
||||
NOW_FUNC, TRIG_COND_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; }
|
||||
virtual enum Functype functype() const { return UNKNOWN_FUNC; }
|
||||
Item_func(void):
|
||||
@ -150,6 +152,7 @@ public:
|
||||
bool allow_superset_comversion= FALSE);
|
||||
|
||||
bool walk(Item_processor processor, byte *arg);
|
||||
Item *transform(Item_transformer transformer, byte *arg);
|
||||
};
|
||||
|
||||
|
||||
|
@ -145,6 +145,18 @@ bool Item_row::walk(Item_processor processor, byte *arg)
|
||||
return (this->*processor)(arg);
|
||||
}
|
||||
|
||||
Item *Item_row::transform(Item_transformer transformer, byte *arg)
|
||||
{
|
||||
for (uint i= 0; i < arg_count; i++)
|
||||
{
|
||||
Item *new_item= items[i]->transform(transformer, arg);
|
||||
if (!new_item)
|
||||
return 0;
|
||||
items[i]= new_item;
|
||||
}
|
||||
return (this->*transformer)(arg);
|
||||
}
|
||||
|
||||
void Item_row::bring_value()
|
||||
{
|
||||
for (uint i= 0; i < arg_count; i++)
|
||||
|
@ -65,6 +65,7 @@ public:
|
||||
void print(String *str);
|
||||
|
||||
bool walk(Item_processor processor, byte *arg);
|
||||
Item *transform(Item_transformer transformer, byte *arg);
|
||||
|
||||
uint cols() { return arg_count; }
|
||||
Item* el(uint i) { return items[i]; }
|
||||
|
@ -428,6 +428,14 @@ public:
|
||||
return item->walk(processor, arg) ||
|
||||
Item_str_func::walk(processor, arg);
|
||||
}
|
||||
Item *transform(Item_transformer transformer, byte *arg)
|
||||
{
|
||||
Item *new_item= item->transform(transformer, arg);
|
||||
if (!new_item)
|
||||
return 0;
|
||||
item= new_item;
|
||||
return Item_str_func::transform(transformer, arg);
|
||||
}
|
||||
void print(String *str);
|
||||
};
|
||||
|
||||
|
207
sql/opt_range.cc
207
sql/opt_range.cc
@ -3148,12 +3148,98 @@ QUICK_SELECT_I *TRP_ROR_UNION::make_quick(PARAM *param,
|
||||
DBUG_RETURN(quick_roru);
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
/*
|
||||
Build a SEL_TREE for a simple predicate
|
||||
|
||||
SYNOPSIS
|
||||
get_func_mm_tree()
|
||||
param PARAM from SQL_SELECT::test_quick_select
|
||||
cond_func item for the predicate
|
||||
field field in the predicate
|
||||
value constant in the predicate
|
||||
cmp_type compare type for the field
|
||||
|
||||
RETURN
|
||||
Pointer to thre built tree
|
||||
*/
|
||||
|
||||
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");
|
||||
|
||||
switch (cond_func->functype()) {
|
||||
case Item_func::NE_FUNC:
|
||||
tree= get_mm_parts(param, cond_func, field, Item_func::LT_FUNC,
|
||||
value, cmp_type);
|
||||
if (tree)
|
||||
{
|
||||
tree= tree_or(param, tree, get_mm_parts(param, cond_func, field,
|
||||
Item_func::GT_FUNC,
|
||||
value, cmp_type));
|
||||
}
|
||||
break;
|
||||
case Item_func::BETWEEN:
|
||||
tree= get_mm_parts(param, cond_func, field, Item_func::GE_FUNC,
|
||||
cond_func->arguments()[1],cmp_type);
|
||||
if (tree)
|
||||
{
|
||||
tree= tree_and(param, tree, get_mm_parts(param, cond_func, field,
|
||||
Item_func::LE_FUNC,
|
||||
cond_func->arguments()[2],
|
||||
cmp_type));
|
||||
}
|
||||
break;
|
||||
case Item_func::IN_FUNC:
|
||||
{
|
||||
Item_func_in *func=(Item_func_in*) cond_func;
|
||||
tree= get_mm_parts(param, cond_func, field, Item_func::EQ_FUNC,
|
||||
func->arguments()[1], cmp_type);
|
||||
if (tree)
|
||||
{
|
||||
Item **arg, **end;
|
||||
for (arg= func->arguments()+2, end= arg+func->argument_count()-2;
|
||||
arg < end ; arg++)
|
||||
{
|
||||
tree= tree_or(param, tree, get_mm_parts(param, cond_func, field,
|
||||
Item_func::EQ_FUNC,
|
||||
*arg,
|
||||
cmp_type));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
/*
|
||||
Here the function for the following predicates are processed:
|
||||
<, <=, =, >=, >, LIKE, IS NULL, IS NOT NULL.
|
||||
If the predicate is of the form (value op field) it is handled
|
||||
as the equivalent predicate (field rev_op value), e.g.
|
||||
2 <= a is handled as a >= 2.
|
||||
*/
|
||||
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, cond_func, field, func_type, value, cmp_type);
|
||||
}
|
||||
}
|
||||
|
||||
DBUG_RETURN(tree);
|
||||
|
||||
}
|
||||
|
||||
/* make a select tree of all keys in condition */
|
||||
|
||||
static SEL_TREE *get_mm_tree(PARAM *param,COND *cond)
|
||||
{
|
||||
SEL_TREE *tree=0;
|
||||
SEL_TREE *ftree= 0;
|
||||
Item_field *field_item= 0;
|
||||
Item *value;
|
||||
DBUG_ENTER("get_mm_tree");
|
||||
|
||||
if (cond->type() == Item::COND_ITEM)
|
||||
@ -3201,9 +3287,12 @@ static SEL_TREE *get_mm_tree(PARAM *param,COND *cond)
|
||||
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)
|
||||
{ // Should be a field
|
||||
ref_tables= cond->used_tables();
|
||||
if ((ref_tables & param->current_table) ||
|
||||
(ref_tables & ~(param->prev_tables | param->read_tables)))
|
||||
DBUG_RETURN(0);
|
||||
@ -3214,80 +3303,42 @@ static SEL_TREE *get_mm_tree(PARAM *param,COND *cond)
|
||||
if (cond_func->select_optimize() == Item_func::OPTIMIZE_NONE)
|
||||
DBUG_RETURN(0); // Can't be calculated
|
||||
|
||||
param->cond= cond;
|
||||
|
||||
if (cond_func->functype() == Item_func::BETWEEN)
|
||||
switch (cond_func->functype()) {
|
||||
case Item_func::BETWEEN:
|
||||
if (cond_func->arguments()[0]->type() != Item::FIELD_ITEM)
|
||||
DBUG_RETURN(0);
|
||||
field_item= (Item_field*) (cond_func->arguments()[0]);
|
||||
value= NULL;
|
||||
break;
|
||||
case Item_func::IN_FUNC:
|
||||
{
|
||||
if (cond_func->arguments()[0]->type() == Item::FIELD_ITEM)
|
||||
{
|
||||
Field *field=((Item_field*) (cond_func->arguments()[0]))->field;
|
||||
Item_result cmp_type=field->cmp_type();
|
||||
DBUG_RETURN(tree_and(param,
|
||||
get_mm_parts(param, cond_func, field,
|
||||
Item_func::GE_FUNC,
|
||||
cond_func->arguments()[1], cmp_type),
|
||||
get_mm_parts(param, cond_func, field,
|
||||
Item_func::LE_FUNC,
|
||||
cond_func->arguments()[2], cmp_type)));
|
||||
}
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
if (cond_func->functype() == Item_func::IN_FUNC)
|
||||
{ // COND OR
|
||||
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)
|
||||
DBUG_RETURN(0);
|
||||
field_item= (Item_field*) (func->key_item());
|
||||
value= NULL;
|
||||
break;
|
||||
}
|
||||
case Item_func::MULT_EQUAL_FUNC:
|
||||
{
|
||||
Item_equal *item_equal= (Item_equal *) cond;
|
||||
if (!(value= item_equal->get_const()))
|
||||
DBUG_RETURN(0);
|
||||
Item_equal_iterator it(*item_equal);
|
||||
ref_tables= value->used_tables();
|
||||
while ((field_item= it++))
|
||||
{
|
||||
Field *field=((Item_field*) (func->key_item()))->field;
|
||||
Item_result cmp_type=field->cmp_type();
|
||||
tree= get_mm_parts(param,cond_func,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++)
|
||||
Field *field= field_item->field;
|
||||
Item_result cmp_type= field->cmp_type();
|
||||
if (!((ref_tables | field->table->map) & param_comp))
|
||||
{
|
||||
SEL_TREE *new_tree=get_mm_parts(param,cond_func,field,
|
||||
Item_func::EQ_FUNC,
|
||||
func->arguments()[i],cmp_type);
|
||||
tree=tree_or(param,tree,new_tree);
|
||||
tree= get_mm_parts(param, cond, field, Item_func::EQ_FUNC,
|
||||
value,cmp_type);
|
||||
ftree= !ftree ? tree : tree_and(param, ftree, tree);
|
||||
}
|
||||
DBUG_RETURN(tree);
|
||||
}
|
||||
DBUG_RETURN(0); // Can't optimize this IN
|
||||
}
|
||||
|
||||
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, cond_func,
|
||||
((Item_field*) (cond_func->arguments()[0]))->field,
|
||||
cond_func->functype(),
|
||||
cond_func->arg_count > 1 ? cond_func->arguments()[1] :
|
||||
0,
|
||||
((Item_field*) (cond_func->arguments()[0]))->field->
|
||||
cmp_type());
|
||||
}
|
||||
/* check const op field */
|
||||
if (!tree &&
|
||||
cond_func->have_rev_func() &&
|
||||
cond_func->arguments()[1]->type() == Item::FIELD_ITEM)
|
||||
{
|
||||
DBUG_RETURN(get_mm_parts(param, cond_func,
|
||||
((Item_field*)
|
||||
(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);
|
||||
|
||||
DBUG_RETURN(ftree);
|
||||
}
|
||||
|
||||
|
||||
@ -3296,17 +3347,10 @@ get_mm_parts(PARAM *param, COND *cond_func, Field *field,
|
||||
Item_func::Functype type,
|
||||
Item *value, Item_result cmp_type)
|
||||
{
|
||||
bool ne_func= FALSE;
|
||||
DBUG_ENTER("get_mm_parts");
|
||||
if (field->table != param->table)
|
||||
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 *end = param->key_parts_end;
|
||||
SEL_TREE *tree=0;
|
||||
@ -3344,15 +3388,6 @@ get_mm_parts(PARAM *param, COND *cond_func, Field *field,
|
||||
}
|
||||
}
|
||||
|
||||
if (ne_func)
|
||||
{
|
||||
SEL_TREE *tree2= get_mm_parts(param, cond_func,
|
||||
field, Item_func::GT_FUNC,
|
||||
value, cmp_type);
|
||||
if (tree2)
|
||||
tree= tree_or(param,tree,tree2);
|
||||
}
|
||||
|
||||
DBUG_RETURN(tree);
|
||||
}
|
||||
|
||||
|
@ -341,6 +341,18 @@ static bool simple_pred(Item_func *func_item, Item **args, bool *inv_order)
|
||||
Item *item;
|
||||
*inv_order= 0;
|
||||
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:
|
||||
/* field IS NULL */
|
||||
item= func_item->arguments()[0];
|
||||
@ -481,6 +493,9 @@ static bool matching_cond(bool max_fl, TABLE_REF *ref, KEY *keyinfo,
|
||||
case Item_func::BETWEEN:
|
||||
between= 1;
|
||||
break;
|
||||
case Item_func::MULT_EQUAL_FUNC:
|
||||
eq_type= 1;
|
||||
break;
|
||||
default:
|
||||
return 0; // Can't optimize function
|
||||
}
|
||||
|
@ -127,10 +127,12 @@ public:
|
||||
void remove(list_node **prev)
|
||||
{
|
||||
list_node *node=(*prev)->next;
|
||||
delete *prev;
|
||||
*prev=node;
|
||||
if (!--elements)
|
||||
last= &first;
|
||||
else if (last == &(*prev)->next)
|
||||
last= prev;
|
||||
delete *prev;
|
||||
*prev=node;
|
||||
}
|
||||
inline void *pop(void)
|
||||
{
|
||||
@ -143,9 +145,36 @@ public:
|
||||
}
|
||||
inline void concat(base_list *list)
|
||||
{
|
||||
*last= list->first;
|
||||
last= list->last;
|
||||
elements+= list->elements;
|
||||
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 void prepand(base_list *list)
|
||||
{
|
||||
if (!list->is_empty())
|
||||
{
|
||||
*list->last= first;
|
||||
first= list->first;
|
||||
elements+= list->elements;
|
||||
}
|
||||
}
|
||||
inline list_node* last_node() { return *last; }
|
||||
inline list_node* first_node() { return first;}
|
||||
@ -257,6 +286,9 @@ public:
|
||||
inline T* head() {return (T*) base_list::head(); }
|
||||
inline T** head_ref() {return (T**) base_list::head_ref(); }
|
||||
inline T* pop() {return (T*) base_list::pop(); }
|
||||
inline void concat(List<T> *list) { base_list::concat(list); }
|
||||
inline void disjoin(List<T> *list) { base_list::disjoin(list); }
|
||||
inline void prepand(List<T> *list) { base_list::prepand(list); }
|
||||
void delete_elements(void)
|
||||
{
|
||||
list_node *element,*next;
|
||||
@ -267,7 +299,6 @@ public:
|
||||
}
|
||||
empty();
|
||||
}
|
||||
inline void concat(List<T> *list) { base_list::concat(list); }
|
||||
};
|
||||
|
||||
|
||||
@ -278,6 +309,8 @@ public:
|
||||
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(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 T** ref(void) { return (T**) base_list_iterator::ref(); }
|
||||
};
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -222,6 +222,7 @@ class JOIN :public Sql_alloc
|
||||
Item *conds_history; // store WHERE for explain
|
||||
TABLE_LIST *tables_list; //hold 'tables' parameter of mysql_select
|
||||
List<TABLE_LIST> *join_list; // list of joined tables in reverse order
|
||||
COND_EQUAL *cond_equal;
|
||||
SQL_SELECT *select; //created in optimisation phase
|
||||
JOIN_TAB *return_tab; //used only for outer joins
|
||||
Item **ref_pointer_array; //used pointer reference for this select
|
||||
@ -284,6 +285,7 @@ class JOIN :public Sql_alloc
|
||||
ref_pointer_array_size= 0;
|
||||
zero_result_cause= 0;
|
||||
optimized= 0;
|
||||
cond_equal= 0;
|
||||
|
||||
fields_list= fields_arg;
|
||||
bzero((char*) &keyuse,sizeof(keyuse));
|
||||
|
Loading…
x
Reference in New Issue
Block a user