Commit 21be389b authored by unknown's avatar unknown

Merge rurik.mysql.com:/home/igor/mysql-5.0-opt

into  rurik.mysql.com:/home/igor/dev-opt/mysql-5.0-opt-bug21698


sql/sql_select.cc:
  Auto merged
parents 3a8cdfc3 87166702
...@@ -1113,4 +1113,39 @@ conv("18383815659218730760",10,10) + 0 ...@@ -1113,4 +1113,39 @@ conv("18383815659218730760",10,10) + 0
select "18383815659218730760" + 0; select "18383815659218730760" + 0;
"18383815659218730760" + 0 "18383815659218730760" + 0
1.8383815659219e+19 1.8383815659219e+19
CREATE TABLE t1 (code varchar(10));
INSERT INTO t1 VALUES ('a12'), ('A12'), ('a13');
SELECT ASCII(code), code FROM t1 WHERE code='A12';
ASCII(code) code
97 a12
65 A12
SELECT ASCII(code), code FROM t1 WHERE code='A12' AND ASCII(code)=65;
ASCII(code) code
65 A12
INSERT INTO t1 VALUES ('a12 '), ('A12 ');
SELECT LENGTH(code), code FROM t1 WHERE code='A12';
LENGTH(code) code
3 a12
3 A12
4 a12
5 A12
SELECT LENGTH(code), code FROM t1 WHERE code='A12' AND LENGTH(code)=5;
LENGTH(code) code
5 A12
ALTER TABLE t1 ADD INDEX (code);
CREATE TABLE t2 (id varchar(10) PRIMARY KEY);
INSERT INTO t2 VALUES ('a11'), ('a12'), ('a13'), ('a14');
SELECT * FROM t1 INNER JOIN t2 ON t1.code=t2.id
WHERE t2.id='a12' AND (code < 'a00' OR LENGTH(code)=5);
code id
A12 a12
EXPLAIN EXTENDED
SELECT * FROM t1 INNER JOIN t2 ON code=id
WHERE id='a12' AND (code < 'a00' OR LENGTH(code)=5);
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref code code 13 const 3 Using where; Using index
1 SIMPLE t2 ref PRIMARY PRIMARY 12 const 1 Using where; Using index
Warnings:
Note 1003 select `test`.`t1`.`code` AS `code`,`test`.`t2`.`id` AS `id` from `test`.`t1` join `test`.`t2` where ((`test`.`t1`.`code` = _latin1'a12') and (`test`.`t2`.`id` = _latin1'a12') and (length(`test`.`t1`.`code`) = 5))
DROP TABLE t1,t2;
End of 5.0 tests End of 5.0 tests
...@@ -354,7 +354,7 @@ t3 1 a 2 b NULL 13 NULL NULL HASH ...@@ -354,7 +354,7 @@ t3 1 a 2 b NULL 13 NULL NULL HASH
explain select * from t1 ignore key(btree_idx), t3 where t1.name='matt' and t3.a = concat('',t1.name) and t3.b=t1.name; explain select * from t1 ignore key(btree_idx), t3 where t1.name='matt' and t3.a = concat('',t1.name) and t3.b=t1.name;
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref heap_idx heap_idx 22 const 7 Using where 1 SIMPLE t1 ref heap_idx heap_idx 22 const 7 Using where
1 SIMPLE t3 ref a a 44 const,const 7 Using where 1 SIMPLE t3 ref a a 44 func,const 7 Using where
drop table t1, t2, t3; drop table t1, t2, t3;
create temporary table t1 ( a int, index (a) ) engine=memory; create temporary table t1 ( a int, index (a) ) engine=memory;
insert into t1 values (1),(2),(3),(4),(5); insert into t1 values (1),(2),(3),(4),(5);
......
...@@ -753,4 +753,31 @@ select cast(rtrim(ltrim(' 20.06 ')) as decimal(19,2)); ...@@ -753,4 +753,31 @@ select cast(rtrim(ltrim(' 20.06 ')) as decimal(19,2));
select conv("18383815659218730760",10,10) + 0; select conv("18383815659218730760",10,10) + 0;
select "18383815659218730760" + 0; select "18383815659218730760" + 0;
#
# Bug #21698: substitution of a string field for a constant under a function
#
CREATE TABLE t1 (code varchar(10));
INSERT INTO t1 VALUES ('a12'), ('A12'), ('a13');
SELECT ASCII(code), code FROM t1 WHERE code='A12';
SELECT ASCII(code), code FROM t1 WHERE code='A12' AND ASCII(code)=65;
INSERT INTO t1 VALUES ('a12 '), ('A12 ');
SELECT LENGTH(code), code FROM t1 WHERE code='A12';
SELECT LENGTH(code), code FROM t1 WHERE code='A12' AND LENGTH(code)=5;
ALTER TABLE t1 ADD INDEX (code);
CREATE TABLE t2 (id varchar(10) PRIMARY KEY);
INSERT INTO t2 VALUES ('a11'), ('a12'), ('a13'), ('a14');
SELECT * FROM t1 INNER JOIN t2 ON t1.code=t2.id
WHERE t2.id='a12' AND (code < 'a00' OR LENGTH(code)=5);
EXPLAIN EXTENDED
SELECT * FROM t1 INNER JOIN t2 ON code=id
WHERE id='a12' AND (code < 'a00' OR LENGTH(code)=5);
DROP TABLE t1,t2;
--echo End of 5.0 tests --echo End of 5.0 tests
...@@ -3745,6 +3745,41 @@ Item_equal *Item_field::find_item_equal(COND_EQUAL *cond_equal) ...@@ -3745,6 +3745,41 @@ Item_equal *Item_field::find_item_equal(COND_EQUAL *cond_equal)
} }
/*
Check whether a field can be substituted by an equal item
SYNOPSIS
equal_fields_propagator()
arg - *arg != NULL <-> the field is in the context where
substitution for an equal item is valid
DESCRIPTION
The function checks whether a substitution of the field
occurrence for an equal item is valid.
NOTES
The following statement is not always true:
x=y => F(x)=F(x/y).
This means substitution of an item for an equal item not always
yields an equavalent condition.
Here's an example:
'a'='a '
(LENGTH('a')=1) != (LENGTH('a ')=2)
Such a substitution is surely valid if either the substituted
field is not of a STRING type or if it is an argument of
a comparison predicate.
RETURN
TRUE substitution is valid
FALSE otherwise
*/
bool Item_field::subst_argument_checker(byte **arg)
{
return (result_type() != STRING_RESULT) || (*arg);
}
/* /*
Set a pointer to the multiple equality the field reference belongs to Set a pointer to the multiple equality the field reference belongs to
(if any) (if any)
...@@ -3764,7 +3799,7 @@ Item_equal *Item_field::find_item_equal(COND_EQUAL *cond_equal) ...@@ -3764,7 +3799,7 @@ Item_equal *Item_field::find_item_equal(COND_EQUAL *cond_equal)
NOTES NOTES
This function is supposed to be called as a callback parameter in calls This function is supposed to be called as a callback parameter in calls
of the transform method. of the compile method.
RETURN VALUES RETURN VALUES
pointer to the replacing constant item, if the field item was substituted pointer to the replacing constant item, if the field item was substituted
......
...@@ -410,7 +410,8 @@ class Settable_routine_parameter ...@@ -410,7 +410,8 @@ class Settable_routine_parameter
}; };
typedef bool (Item::*Item_processor)(byte *arg); typedef bool (Item::*Item_processor) (byte *arg);
typedef bool (Item::*Item_analyzer) (byte **argp);
typedef Item* (Item::*Item_transformer) (byte *arg); typedef Item* (Item::*Item_transformer) (byte *arg);
typedef void (*Cond_traverser) (const Item *item, void *arg); typedef void (*Cond_traverser) (const Item *item, void *arg);
...@@ -739,6 +740,14 @@ class Item { ...@@ -739,6 +740,14 @@ class Item {
return (this->*transformer)(arg); return (this->*transformer)(arg);
} }
virtual Item* compile(Item_analyzer analyzer, byte **arg_p,
Item_transformer transformer, byte *arg_t)
{
if ((this->*analyzer) (arg_p))
return ((this->*transformer) (arg_t));
return 0;
}
virtual void traverse_cond(Cond_traverser traverser, virtual void traverse_cond(Cond_traverser traverser,
void *arg, traverse_order order) void *arg, traverse_order order)
{ {
...@@ -753,6 +762,12 @@ class Item { ...@@ -753,6 +762,12 @@ class Item {
virtual bool change_context_processor(byte *context) { return 0; } virtual bool change_context_processor(byte *context) { return 0; }
virtual bool reset_query_id_processor(byte *query_id) { return 0; } virtual bool reset_query_id_processor(byte *query_id) { return 0; }
virtual bool is_expensive_processor(byte *arg) { return 0; } virtual bool is_expensive_processor(byte *arg) { return 0; }
virtual bool subst_argument_checker(byte **arg)
{
if (*arg)
*arg= NULL;
return TRUE;
}
virtual Item *equal_fields_propagator(byte * arg) { return this; } virtual Item *equal_fields_propagator(byte * arg) { return this; }
virtual Item *set_no_const_sub(byte *arg) { return this; } virtual Item *set_no_const_sub(byte *arg) { return this; }
...@@ -1254,6 +1269,7 @@ class Item_field :public Item_ident ...@@ -1254,6 +1269,7 @@ class Item_field :public Item_ident
return field->can_be_compared_as_longlong(); return field->can_be_compared_as_longlong();
} }
Item_equal *find_item_equal(COND_EQUAL *cond_equal); Item_equal *find_item_equal(COND_EQUAL *cond_equal);
bool subst_argument_checker(byte **arg);
Item *equal_fields_propagator(byte *arg); Item *equal_fields_propagator(byte *arg);
Item *set_no_const_sub(byte *arg); Item *set_no_const_sub(byte *arg);
Item *replace_equal_field(byte *arg); Item *replace_equal_field(byte *arg);
......
...@@ -2752,11 +2752,11 @@ bool Item_cond::walk(Item_processor processor, byte *arg) ...@@ -2752,11 +2752,11 @@ bool Item_cond::walk(Item_processor processor, byte *arg)
arg parameter to be passed to the transformer arg parameter to be passed to the transformer
DESCRIPTION DESCRIPTION
The function recursively applies the transform method with the The function recursively applies the transform method to each
same transformer to each member item of the condition list. member item of the condition list.
If the call of the method for a member item returns a new item If the call of the method for a member item returns a new item
the old item is substituted for a new one. the old item is substituted for a new one.
After this the transform method is applied to the root node After this the transformer is applied to the root node
of the Item_cond object. of the Item_cond object.
RETURN VALUES RETURN VALUES
...@@ -2778,6 +2778,55 @@ Item *Item_cond::transform(Item_transformer transformer, byte *arg) ...@@ -2778,6 +2778,55 @@ Item *Item_cond::transform(Item_transformer transformer, byte *arg)
return Item_func::transform(transformer, arg); return Item_func::transform(transformer, arg);
} }
/*
Compile Item_cond object with a processor and a transformer callback functions
SYNOPSIS
compile()
analyzer the analyzer callback function to be applied to the nodes
of the tree of the object
arg_p in/out parameter to be passed to the analyzer
transformer the transformer callback function to be applied to the nodes
of the tree of the object
arg_t parameter to be passed to the transformer
DESCRIPTION
First the function applies the analyzer to the root node of
the Item_func object. Then if the analyzer succeeeds (returns TRUE)
the function recursively applies the compile method to member
item of the condition 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 transformer 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::compile(Item_analyzer analyzer, byte **arg_p,
Item_transformer transformer, byte *arg_t)
{
if (!(this->*analyzer)(arg_p))
return 0;
byte *arg_v= *arg_p;
List_iterator<Item> li(list);
Item *item;
while ((item= li++))
{
/*
The same parameter value of arg_p must be passed
to analyze any argument of the condition formula.
*/
Item *new_item= item->compile(analyzer, &arg_v, transformer, arg_t);
if (new_item && new_item != item)
li.replace(new_item);
}
return Item_func::transform(transformer, arg_t);
}
void Item_cond::traverse_cond(Cond_traverser traverser, void Item_cond::traverse_cond(Cond_traverser traverser,
void *arg, traverse_order order) void *arg, traverse_order order)
{ {
......
...@@ -240,6 +240,7 @@ class Item_bool_rowready_func2 :public Item_bool_func2 ...@@ -240,6 +240,7 @@ class Item_bool_rowready_func2 :public Item_bool_func2
} }
Item *neg_transformer(THD *thd); Item *neg_transformer(THD *thd);
virtual Item *negated_item(); virtual Item *negated_item();
bool subst_argument_checker(byte **arg) { return TRUE; }
}; };
class Item_func_not :public Item_bool_func class Item_func_not :public Item_bool_func
...@@ -1171,6 +1172,9 @@ class Item_cond :public Item_bool_func ...@@ -1171,6 +1172,9 @@ class Item_cond :public Item_bool_func
Item *transform(Item_transformer transformer, byte *arg); Item *transform(Item_transformer transformer, byte *arg);
void traverse_cond(Cond_traverser, void *arg, traverse_order order); void traverse_cond(Cond_traverser, void *arg, traverse_order order);
void neg_arguments(THD *thd); void neg_arguments(THD *thd);
bool subst_argument_checker(byte **arg) { return TRUE; }
Item *compile(Item_analyzer analyzer, byte **arg_p,
Item_transformer transformer, byte *arg_t);
}; };
......
...@@ -234,7 +234,6 @@ void Item_func::traverse_cond(Cond_traverser traverser, ...@@ -234,7 +234,6 @@ void Item_func::traverse_cond(Cond_traverser traverser,
} }
/* /*
Transform an Item_func object with a transformer callback function Transform an Item_func object with a transformer callback function
...@@ -245,11 +244,11 @@ void Item_func::traverse_cond(Cond_traverser traverser, ...@@ -245,11 +244,11 @@ void Item_func::traverse_cond(Cond_traverser traverser,
argument parameter to be passed to the transformer argument parameter to be passed to the transformer
DESCRIPTION DESCRIPTION
The function recursively applies the transform method with the The function recursively applies the transform method to each
same transformer to each argument the function. argument of the Item_func node.
If the call of the method for a member item returns a new item If the call of the method for an argument item returns a new item
the old item is substituted for a new one. the old item is substituted for a new one.
After this the transform method is applied to the root node After this the transformer is applied to the root node
of the Item_func object. of the Item_func object.
RETURN VALUES RETURN VALUES
...@@ -274,6 +273,55 @@ Item *Item_func::transform(Item_transformer transformer, byte *argument) ...@@ -274,6 +273,55 @@ Item *Item_func::transform(Item_transformer transformer, byte *argument)
} }
/*
Compile Item_func object with a processor and a transformer callback functions
SYNOPSIS
compile()
analyzer the analyzer callback function to be applied to the nodes
of the tree of the object
arg_p in/out parameter to be passed to the processor
transformer the transformer callback function to be applied to the nodes
of the tree of the object
arg_t parameter to be passed to the transformer
DESCRIPTION
First the function applies the analyzer to the root node of
the Item_func object. Then if the analizer succeeeds (returns TRUE)
the function recursively applies the compile method to each argument
of the Item_func node.
If the call of the method for an argument item returns a new item
the old item is substituted for a new one.
After this the transformer 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::compile(Item_analyzer analyzer, byte **arg_p,
Item_transformer transformer, byte *arg_t)
{
if (!(this->*analyzer)(arg_p))
return 0;
byte *arg_v= *arg_p;
if (arg_count)
{
Item **arg,**arg_end;
for (arg= args, arg_end= args+arg_count; arg != arg_end; arg++)
{
/*
The same parameter value of arg_p must be passed
to analyze any argument of the condition formula.
*/
Item *new_item= (*arg)->compile(analyzer, &arg_v, transformer, arg_t);
if (new_item && *arg != new_item)
current_thd->change_item_tree(arg, new_item);
}
}
return (this->*transformer)(arg_t);
}
/* See comments in Item_cmp_func::split_sum_func() */ /* See comments in Item_cmp_func::split_sum_func() */
void Item_func::split_sum_func(THD *thd, Item **ref_pointer_array, void Item_func::split_sum_func(THD *thd, Item **ref_pointer_array,
......
...@@ -187,6 +187,8 @@ class Item_func :public Item_result_field ...@@ -187,6 +187,8 @@ class Item_func :public Item_result_field
} }
bool walk(Item_processor processor, byte *arg); bool walk(Item_processor processor, byte *arg);
Item *transform(Item_transformer transformer, byte *arg); Item *transform(Item_transformer transformer, byte *arg);
Item* compile(Item_analyzer analyzer, byte **arg_p,
Item_transformer transformer, byte *arg_t);
void traverse_cond(Cond_traverser traverser, void traverse_cond(Cond_traverser traverser,
void * arg, traverse_order order); void * arg, traverse_order order);
bool is_expensive_processor(byte *arg); bool is_expensive_processor(byte *arg);
......
...@@ -6727,7 +6727,9 @@ static bool check_equality(Item *item, COND_EQUAL *cond_equal, ...@@ -6727,7 +6727,9 @@ static bool check_equality(Item *item, COND_EQUAL *cond_equal,
The function also traverses the cond tree and and for each field reference The function also traverses the cond tree and and for each field reference
sets a pointer to the multiple equality item containing the field, if there sets a pointer to the multiple equality item containing the field, if there
is any. If this multiple equality equates fields to a constant the is any. If this multiple equality equates fields to a constant the
function replace the field reference by the constant. function replaces the field reference by the constant in the cases
when the field is not of a string type or when the field reference is
just an argument of a comparison predicate.
The function also determines the maximum number of members in The function also determines the maximum number of members in
equality lists of each Item_cond_and object assigning it to equality lists of each Item_cond_and object assigning it to
cond_equal->max_members of this object and updating accordingly cond_equal->max_members of this object and updating accordingly
...@@ -6914,8 +6916,13 @@ static COND *build_equal_items_for_cond(COND *cond, ...@@ -6914,8 +6916,13 @@ static COND *build_equal_items_for_cond(COND *cond,
/* /*
For each field reference in cond, not from equal item predicates, For each field reference in cond, not from equal item predicates,
set a pointer to the multiple equality it belongs to (if there is any) set a pointer to the multiple equality it belongs to (if there is any)
as soon the field is not of a string type or the field reference is
an argument of a comparison predicate.
*/ */
cond= cond->transform(&Item::equal_fields_propagator, byte *dummy;
cond= cond->compile(&Item::subst_argument_checker,
&dummy,
&Item::equal_fields_propagator,
(byte *) inherited); (byte *) inherited);
cond->update_used_tables(); cond->update_used_tables();
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment