mirror of
https://github.com/MariaDB/server.git
synced 2025-01-17 20:42:30 +01:00
Fixed bug #21698: erroneously a field could be replaced by an
equal constant under any circumstances. In fact this substitution can be allowed if the field is not of a type string or if the field reference serves as an argument of a comparison predicate.
This commit is contained in:
parent
ca3229dc1b
commit
34206c6f80
10 changed files with 247 additions and 24 deletions
|
@ -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
|
||||||
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));
|
||||||
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
|
||||||
|
|
41
sql/item.cc
41
sql/item.cc
|
@ -3745,14 +3745,49 @@ 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)
|
||||||
|
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
equal_fields_propagator()
|
equal_fields_propagator()
|
||||||
arg - reference to list of multiple equalities where
|
arg - reference to list of multiple equalities where
|
||||||
the field (this object) is to be looked for
|
the field (this object) is to be looked for
|
||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
The function looks for a multiple equality containing the field item
|
The function looks for a multiple equality containing the field item
|
||||||
|
@ -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
|
||||||
|
|
18
sql/item.h
18
sql/item.h
|
@ -410,7 +410,8 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
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 @@ public:
|
||||||
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 @@ public:
|
||||||
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 @@ public:
|
||||||
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);
|
||||||
|
|
|
@ -2747,16 +2747,16 @@ bool Item_cond::walk(Item_processor processor, byte *arg)
|
||||||
|
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
transform()
|
transform()
|
||||||
transformer the transformer callback function to be applied to the nodes
|
transformer the transformer callback function to be applied to the nodes
|
||||||
of the tree of the object
|
of the tree of the object
|
||||||
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)
|
||||||
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 @@ public:
|
||||||
}
|
}
|
||||||
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 @@ public:
|
||||||
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,22 +234,21 @@ 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
|
||||||
|
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
transform()
|
transform()
|
||||||
transformer the transformer callback function to be applied to the nodes
|
transformer the transformer callback function to be applied to the nodes
|
||||||
of the tree of the object
|
of the tree of the object
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
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 @@ public:
|
||||||
}
|
}
|
||||||
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);
|
||||||
|
|
|
@ -6593,8 +6593,8 @@ static bool check_equality(Item *item, COND_EQUAL *cond_equal)
|
||||||
|
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
build_equal_items_for_cond()
|
build_equal_items_for_cond()
|
||||||
cond condition(expression) where to make replacement
|
cond condition(expression) where to make replacement
|
||||||
inherited path to all inherited multiple equality items
|
inherited path to all inherited multiple equality items
|
||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
At each 'and' level the function detects items for equality predicates
|
At each 'and' level the function detects items for equality predicates
|
||||||
|
@ -6608,7 +6608,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
|
||||||
|
@ -6756,9 +6758,14 @@ 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;
|
||||||
(byte *) inherited);
|
cond= cond->compile(&Item::subst_argument_checker,
|
||||||
|
&dummy,
|
||||||
|
&Item::equal_fields_propagator,
|
||||||
|
(byte *) inherited);
|
||||||
cond->update_used_tables();
|
cond->update_used_tables();
|
||||||
}
|
}
|
||||||
return cond;
|
return cond;
|
||||||
|
|
Loading…
Reference in a new issue