Commit 1a18998c authored by Igor Babaev's avatar Igor Babaev

Fixed LP bugs #717577, #724942.

Both these two bugs happened due to the following problem.
When a view column is referenced in the query an Item_direct_view_ref
object is created that is refers to the Item_field for the column.
All references to the same view column refer to the same Item_field.
Different references can belong to different AND/OR levels and,
as a result, can be included in different Item_equal object.
These Item_equal objects may include different constant objects.
If these constant objects are substituted for the Item_field created
for a view column we have a conflict situation when the second
substitution annuls the first substitution. This leads to
wrong result sets returned by the query. Bug #724942 demonstrates
such an erroneous behaviour.
Test case of the bug #717577 produces wrong result sets because best
equal fields of the multiple equalities built for different OR levels
of the WHERE condition differs. The subsitution for the best equal field
in the second OR branch overwrites the the substitution made for the
first branch.

To avoid such conflicts we have to substitute for the references
to the view columns rather than for the underlying field items.
To make such substitutions possible we have to include into
multiple equalities references to view columns rather than 
field items created for such columns.

This patch modifies the Item_equal class to include references
to view columns into multiple equality objects. It also performs
a clean up of the class methods and adds more comments. The methods
of the Item_direct_view_ref class that assist substitutions for
references to view columns has been also added by this patch.
parent c6327abb
...@@ -3959,3 +3959,158 @@ WHERE t3.pk = v1.a AND t2.b = 1 AND t2.b = t3.pk AND v1.a BETWEEN 2 AND 5; ...@@ -3959,3 +3959,158 @@ WHERE t3.pk = v1.a AND t2.b = 1 AND t2.b = t3.pk AND v1.a BETWEEN 2 AND 5;
a pk b pk b a pk b pk b
DROP VIEW v1; DROP VIEW v1;
DROP TABLE t1, t2, t3; DROP TABLE t1, t2, t3;
#
# Bug#717577: substitution for best field in a query over a view and
# with OR in the WHERE condition
#
create table t1 (a int, b int);
insert into t1 values (2,4), (1,3);
create table t2 (c int);
insert into t2 values (6), (4), (1), (3), (8), (3), (4), (2);
select * from t1,t2 where t2.c=t1.a and t2.c < 3 or t2.c=t1.b and t2.c >=4;
a b c
2 4 4
1 3 1
2 4 4
2 4 2
explain extended
select * from t1,t2 where t2.c=t1.a and t2.c < 3 or t2.c=t1.b and t2.c >=4;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where
1 SIMPLE t2 ALL NULL NULL NULL NULL 8 100.00 Using where; Using join buffer (flat, BNL join)
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t2`.`c` AS `c` from `test`.`t1` join `test`.`t2` where (((`test`.`t2`.`c` = `test`.`t1`.`a`) and (`test`.`t1`.`a` < 3)) or ((`test`.`t2`.`c` = `test`.`t1`.`b`) and (`test`.`t1`.`b` >= 4)))
create view v1 as select * from t2;
select * from t1,v1 where v1.c=t1.a and v1.c < 3 or v1.c=t1.b and v1.c >=4;
a b c
2 4 4
1 3 1
2 4 4
2 4 2
explain extended
select * from t1,v1 where v1.c=t1.a and v1.c < 3 or v1.c=t1.b and v1.c >=4;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where
1 SIMPLE t2 ALL NULL NULL NULL NULL 8 100.00 Using where; Using join buffer (flat, BNL join)
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t2`.`c` AS `c` from `test`.`t1` join `test`.`t2` where (((`test`.`t2`.`c` = `test`.`t1`.`a`) and (`test`.`t1`.`a` < 3)) or ((`test`.`t2`.`c` = `test`.`t1`.`b`) and (`test`.`t1`.`b` >= 4)))
create view v2 as select * from v1;
select * from t1,v2 where v2.c=t1.a and v2.c < 3 or v2.c=t1.b and v2.c >=4;
a b c
2 4 4
1 3 1
2 4 4
2 4 2
explain extended
select * from t1,v2 where v2.c=t1.a and v2.c < 3 or v2.c=t1.b and v2.c >=4;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where
1 SIMPLE t2 ALL NULL NULL NULL NULL 8 100.00 Using where; Using join buffer (flat, BNL join)
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t2`.`c` AS `c` from `test`.`t1` join `test`.`t2` where (((`test`.`t2`.`c` = `test`.`t1`.`a`) and (`test`.`t1`.`a` < 3)) or ((`test`.`t2`.`c` = `test`.`t1`.`b`) and (`test`.`t1`.`b` >= 4)))
create view v3 as select * from t1;
select * from v3,v2 where v2.c=v3.a and v2.c < 3 or v2.c=v3.b and v2.c >=4;
a b c
2 4 4
1 3 1
2 4 4
2 4 2
explain extended
select * from v3,v2 where v2.c=v3.a and v2.c < 3 or v2.c=v3.b and v2.c >=4;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where
1 SIMPLE t2 ALL NULL NULL NULL NULL 8 100.00 Using where; Using join buffer (flat, BNL join)
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t2`.`c` AS `c` from `test`.`t1` join `test`.`t2` where (((`test`.`t2`.`c` = `test`.`t1`.`a`) and (`test`.`t1`.`a` < 3)) or ((`test`.`t2`.`c` = `test`.`t1`.`b`) and (`test`.`t1`.`b` >= 4)))
drop view v1,v2,v3;
drop table t1,t2;
#
# Bug#724942: substitution of the constant into a view field
#
CREATE TABLE t1 (a int);
INSERT INTO t1 VALUES (2), (9), (9), (6), (5), (4), (7);
CREATE VIEW v1 AS SELECT * FROM t1;
SELECT * FROM v1 WHERE a > -1 OR a > 6 AND a = 3;
a
2
9
9
6
5
4
7
EXPLAIN EXTENDED
SELECT * FROM v1 WHERE a > -1 OR a > 6 AND a = 3;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 7 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where (`test`.`t1`.`a` > -(1))
SELECT * FROM v1 WHERE a > -1 OR a AND a = 0;
a
2
9
9
6
5
4
7
EXPLAIN EXTENDED
SELECT * FROM v1 WHERE a > -1 OR a AND a = 0;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 7 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where (`test`.`t1`.`a` > -(1))
CREATE VIEW v2 AS SELECT * FROM v1;
SELECT * FROM v2 WHERE a > -1 OR a AND a = 0;
a
2
9
9
6
5
4
7
EXPLAIN EXTENDED
SELECT * FROM v2 WHERE a > -1 OR a AND a = 0;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 7 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where (`test`.`t1`.`a` > -(1))
DROP VIEW v1,v2;
DROP TABLE t1;
CREATE TABLE t1 (a varchar(10), KEY (a)) ;
INSERT INTO t1 VALUES
('DD'), ('ZZ'), ('ZZ'), ('KK'), ('FF'), ('HH'),('MM');
CREATE VIEW v1 AS SELECT * FROM t1;
SELECT * FROM v1 WHERE a > 'JJ' OR a <> 0 AND a = 'VV';
a
KK
MM
ZZ
ZZ
Warnings:
Warning 1292 Truncated incorrect DOUBLE value: 'VV'
EXPLAIN EXTENDED
SELECT * FROM v1 WHERE a > 'JJ' OR a <> 0 AND a = 'VV';
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 range a a 13 NULL 4 100.00 Using where; Using index
Warnings:
Warning 1292 Truncated incorrect DOUBLE value: 'VV'
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where (`test`.`t1`.`a` > 'JJ')
SELECT * FROM v1 WHERE a > 'JJ' OR a AND a = 'VV';
a
KK
MM
ZZ
ZZ
Warnings:
Warning 1292 Truncated incorrect INTEGER value: 'VV'
EXPLAIN EXTENDED
SELECT * FROM v1 WHERE a > 'JJ' OR a AND a = 'VV';
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 range a a 13 NULL 4 100.00 Using where; Using index
Warnings:
Warning 1292 Truncated incorrect INTEGER value: 'VV'
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where (`test`.`t1`.`a` > 'JJ')
DROP VIEW v1;
DROP TABLE t1;
...@@ -3983,3 +3983,77 @@ SELECT * FROM v1, t2, t3 ...@@ -3983,3 +3983,77 @@ SELECT * FROM v1, t2, t3
DROP VIEW v1; DROP VIEW v1;
DROP TABLE t1, t2, t3; DROP TABLE t1, t2, t3;
--echo #
--echo # Bug#717577: substitution for best field in a query over a view and
--echo # with OR in the WHERE condition
--echo #
create table t1 (a int, b int);
insert into t1 values (2,4), (1,3);
create table t2 (c int);
insert into t2 values (6), (4), (1), (3), (8), (3), (4), (2);
select * from t1,t2 where t2.c=t1.a and t2.c < 3 or t2.c=t1.b and t2.c >=4;
explain extended
select * from t1,t2 where t2.c=t1.a and t2.c < 3 or t2.c=t1.b and t2.c >=4;
create view v1 as select * from t2;
select * from t1,v1 where v1.c=t1.a and v1.c < 3 or v1.c=t1.b and v1.c >=4;
explain extended
select * from t1,v1 where v1.c=t1.a and v1.c < 3 or v1.c=t1.b and v1.c >=4;
create view v2 as select * from v1;
select * from t1,v2 where v2.c=t1.a and v2.c < 3 or v2.c=t1.b and v2.c >=4;
explain extended
select * from t1,v2 where v2.c=t1.a and v2.c < 3 or v2.c=t1.b and v2.c >=4;
create view v3 as select * from t1;
select * from v3,v2 where v2.c=v3.a and v2.c < 3 or v2.c=v3.b and v2.c >=4;
explain extended
select * from v3,v2 where v2.c=v3.a and v2.c < 3 or v2.c=v3.b and v2.c >=4;
drop view v1,v2,v3;
drop table t1,t2;
--echo #
--echo # Bug#724942: substitution of the constant into a view field
--echo #
CREATE TABLE t1 (a int);
INSERT INTO t1 VALUES (2), (9), (9), (6), (5), (4), (7);
CREATE VIEW v1 AS SELECT * FROM t1;
SELECT * FROM v1 WHERE a > -1 OR a > 6 AND a = 3;
EXPLAIN EXTENDED
SELECT * FROM v1 WHERE a > -1 OR a > 6 AND a = 3;
SELECT * FROM v1 WHERE a > -1 OR a AND a = 0;
EXPLAIN EXTENDED
SELECT * FROM v1 WHERE a > -1 OR a AND a = 0;
CREATE VIEW v2 AS SELECT * FROM v1;
SELECT * FROM v2 WHERE a > -1 OR a AND a = 0;
EXPLAIN EXTENDED
SELECT * FROM v2 WHERE a > -1 OR a AND a = 0;
DROP VIEW v1,v2;
DROP TABLE t1;
CREATE TABLE t1 (a varchar(10), KEY (a)) ;
INSERT INTO t1 VALUES
('DD'), ('ZZ'), ('ZZ'), ('KK'), ('FF'), ('HH'),('MM');
CREATE VIEW v1 AS SELECT * FROM t1;
SELECT * FROM v1 WHERE a > 'JJ' OR a <> 0 AND a = 'VV';
EXPLAIN EXTENDED
SELECT * FROM v1 WHERE a > 'JJ' OR a <> 0 AND a = 'VV';
SELECT * FROM v1 WHERE a > 'JJ' OR a AND a = 'VV';
EXPLAIN EXTENDED
SELECT * FROM v1 WHERE a > 'JJ' OR a AND a = 'VV';
DROP VIEW v1;
DROP TABLE t1;
...@@ -4670,13 +4670,14 @@ Item_equal *Item_field::find_item_equal(COND_EQUAL *cond_equal) ...@@ -4670,13 +4670,14 @@ Item_equal *Item_field::find_item_equal(COND_EQUAL *cond_equal)
/** /**
Check whether a field can be substituted by an equal item. Check whether a field item can be substituted for an equal item
The function checks whether a substitution of the field @details
occurrence for an equal item is valid. The function checks whether a substitution of a field item for
an equal item is valid.
@param arg *arg != NULL <-> the field is in the context where @param arg *arg != NULL && **arg <-> the field is in the context
substitution for an equal item is valid where substitution for an equal item is valid
@note @note
The following statement is not always true: The following statement is not always true:
...@@ -4701,7 +4702,8 @@ Item_equal *Item_field::find_item_equal(COND_EQUAL *cond_equal) ...@@ -4701,7 +4702,8 @@ Item_equal *Item_field::find_item_equal(COND_EQUAL *cond_equal)
bool Item_field::subst_argument_checker(uchar **arg) bool Item_field::subst_argument_checker(uchar **arg)
{ {
return (result_type() != STRING_RESULT) || (*arg); return (!(*arg) && (result_type() != STRING_RESULT)) ||
((*arg) && (**arg));
} }
...@@ -4738,6 +4740,7 @@ static void convert_zerofill_number_to_string(Item **item, Field_num *field) ...@@ -4738,6 +4740,7 @@ static void convert_zerofill_number_to_string(Item **item, Field_num *field)
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).
@details
The function looks for a multiple equality containing the field item The function looks for a multiple equality containing the field item
among those referenced by arg. among those referenced by arg.
In the case such equality exists the function does the following. In the case such equality exists the function does the following.
...@@ -4814,6 +4817,7 @@ bool Item_field::set_no_const_sub(uchar *arg) ...@@ -4814,6 +4817,7 @@ bool Item_field::set_no_const_sub(uchar *arg)
Replace an Item_field for an equal Item_field that evaluated earlier Replace an Item_field for an equal Item_field that evaluated earlier
(if any). (if any).
@details
If this->item_equal points to some item and coincides with arg then If this->item_equal points to some item and coincides with arg then
the function returns a pointer to an item that is taken from the function returns a pointer to an item that is taken from
the very beginning of the item_equal list which the Item_field the very beginning of the item_equal list which the Item_field
...@@ -4828,7 +4832,7 @@ bool Item_field::set_no_const_sub(uchar *arg) ...@@ -4828,7 +4832,7 @@ bool Item_field::set_no_const_sub(uchar *arg)
@note @note
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 thransformer method. of the transformer method.
@return @return
- pointer to a replacement Item_field if there is a better equal item or - pointer to a replacement Item_field if there is a better equal item or
...@@ -4848,7 +4852,9 @@ Item *Item_field::replace_equal_field(uchar *arg) ...@@ -4848,7 +4852,9 @@ Item *Item_field::replace_equal_field(uchar *arg)
return this; return this;
return const_item; return const_item;
} }
Item_field *subst= item_equal->get_first(this); Item_field *subst= (Item_field *)(item_equal->get_first(this));
if (subst)
subst= (Item_field *) (subst->real_item());
if (subst && !field->eq(subst->field)) if (subst && !field->eq(subst->field))
return subst; return subst;
} }
...@@ -6377,7 +6383,8 @@ Item* Item_ref::compile(Item_analyzer analyzer, uchar **arg_p, ...@@ -6377,7 +6383,8 @@ Item* Item_ref::compile(Item_analyzer analyzer, uchar **arg_p,
/* Compile the Item we are referencing. */ /* Compile the Item we are referencing. */
DBUG_ASSERT((*ref) != NULL); DBUG_ASSERT((*ref) != NULL);
Item *new_item= (*ref)->compile(analyzer, arg_p, transformer, arg_t); uchar *arg_v= *arg_p;
Item *new_item= (*ref)->compile(analyzer, &arg_v, transformer, arg_t);
if (new_item && *ref != new_item) if (new_item && *ref != new_item)
current_thd->change_item_tree(ref, new_item); current_thd->change_item_tree(ref, new_item);
...@@ -7226,6 +7233,130 @@ bool Item_direct_view_ref::eq(const Item *item, bool binary_cmp) const ...@@ -7226,6 +7233,130 @@ bool Item_direct_view_ref::eq(const Item *item, bool binary_cmp) const
return FALSE; return FALSE;
} }
Item_equal *Item_direct_view_ref::find_item_equal(COND_EQUAL *cond_equal)
{
Item* field_item= real_item();
if (field_item->type() != FIELD_ITEM)
return NULL;
return ((Item_field *) field_item)->find_item_equal(cond_equal);
}
/**
Check whether a reference to field item can be substituted for an equal item
@details
The function checks whether a substitution of a reference to field item for
an equal item is valid.
@param arg *arg != NULL && **arg <-> the reference is in the context
where substitution for an equal item is valid
@note
See also the note for Item_field::subst_argument_checker
@retval
TRUE substitution is valid
@retval
FALSE otherwise
*/
bool Item_direct_view_ref::subst_argument_checker(uchar **arg)
{
bool res= (!(*arg) && (result_type() != STRING_RESULT)) ||
((*arg) && (**arg));
/* Block any substitution into the wrapped object */
if (*arg)
**arg= (uchar) 0;
return res;
}
/**
Set a pointer to the multiple equality the view field reference belongs to
(if any).
@details
The function looks for a multiple equality containing this item of the type
Item_direct_view_ref among those referenced by arg.
In the case such equality exists the function does the following.
If the found multiple equality contains a constant, then the item
is substituted for this constant, otherwise the function sets a pointer
to the multiple equality in the item.
@param arg reference to list of multiple equalities where
the item (this object) is to be looked for
@note
This function is supposed to be called as a callback parameter in calls
of the compile method.
@note
The function calls Item_field::equal_fields_propagator for the field item
this->real_item() to do the job. Then it takes the pointer to equal_item
from this field item and assigns it to this->item_equal.
@return
- pointer to the replacing constant item, if the field item was substituted
- pointer to the field item, otherwise.
*/
Item *Item_direct_view_ref::equal_fields_propagator(uchar *arg)
{
Item *field_item= real_item();
if (field_item->type() != FIELD_ITEM)
return this;
Item *item= field_item->equal_fields_propagator(arg);
set_item_equal(field_item->get_item_equal());
field_item->set_item_equal(NULL);
if (item != field_item)
return item;
return this;
}
/**
Replace an Item_direct_view_ref for an equal Item_field evaluated earlier
(if any).
@details
If this->item_equal points to some item and coincides with arg then
the function returns a pointer to a field item that is referred to by the
first element of the item_equal list which the Item_direct_view_ref
object belongs to unless item_equal contains a constant item. In this
case the function returns this constant item (if the substitution does
not require conversion).
If the Item_direct_view_item object does not refer any Item_equal object
'this' is returned .
@param arg NULL or points to so some item of the Item_equal type
@note
This function is supposed to be called as a callback parameter in calls
of the transformer method.
@note
The function calls Item_field::replace_equal_field for the field item
this->real_item() to do the job.
@return
- pointer to a replacement Item_field if there is a better equal item or
a pointer to a constant equal item;
- this - otherwise.
*/
Item *Item_direct_view_ref::replace_equal_field(uchar *arg)
{
Item *field_item= real_item();
if (field_item->type() != FIELD_ITEM)
return this;
field_item->set_item_equal(item_equal);
Item *item= field_item->replace_equal_field(arg);
field_item->set_item_equal(0);
return item;
}
bool Item_default_value::eq(const Item *item, bool binary_cmp) const bool Item_default_value::eq(const Item *item, bool binary_cmp) const
{ {
return item->type() == DEFAULT_VALUE_ITEM && return item->type() == DEFAULT_VALUE_ITEM &&
......
...@@ -487,6 +487,9 @@ typedef bool (Item::*Item_analyzer) (uchar **argp); ...@@ -487,6 +487,9 @@ typedef bool (Item::*Item_analyzer) (uchar **argp);
typedef Item* (Item::*Item_transformer) (uchar *arg); typedef Item* (Item::*Item_transformer) (uchar *arg);
typedef void (*Cond_traverser) (const Item *item, void *arg); typedef void (*Cond_traverser) (const Item *item, void *arg);
class Item_equal;
class COND_EQUAL;
class Item { class Item {
Item(const Item &); /* Prevent use of these */ Item(const Item &); /* Prevent use of these */
...@@ -1179,6 +1182,9 @@ class Item { ...@@ -1179,6 +1182,9 @@ class Item {
Item* set_expr_cache(THD *thd, List<Item*> &depends_on); Item* set_expr_cache(THD *thd, List<Item*> &depends_on);
virtual Item *get_cached_item() { return NULL; } virtual Item *get_cached_item() { return NULL; }
virtual Item_equal *get_item_equal() { return NULL; }
virtual void set_item_equal(Item_equal *item_eq) {};
virtual Item_equal *find_item_equal(COND_EQUAL *cond_equal) { return NULL; }
}; };
...@@ -1610,9 +1616,6 @@ class Item_ident_for_show :public Item ...@@ -1610,9 +1616,6 @@ class Item_ident_for_show :public Item
}; };
class Item_equal;
class COND_EQUAL;
class Item_field :public Item_ident class Item_field :public Item_ident
{ {
protected: protected:
...@@ -1707,6 +1710,8 @@ class Item_field :public Item_ident ...@@ -1707,6 +1710,8 @@ class Item_field :public Item_ident
{ {
return field->can_be_compared_as_longlong(); return field->can_be_compared_as_longlong();
} }
Item_equal *get_item_equal() { return item_equal; }
void set_item_equal(Item_equal *item_eq) { item_equal= item_eq; }
Item_equal *find_item_equal(COND_EQUAL *cond_equal); Item_equal *find_item_equal(COND_EQUAL *cond_equal);
bool subst_argument_checker(uchar **arg); bool subst_argument_checker(uchar **arg);
Item *equal_fields_propagator(uchar *arg); Item *equal_fields_propagator(uchar *arg);
...@@ -2720,17 +2725,19 @@ class Item_cache_wrapper :public Item_result_field ...@@ -2720,17 +2725,19 @@ class Item_cache_wrapper :public Item_result_field
*/ */
class Item_direct_view_ref :public Item_direct_ref class Item_direct_view_ref :public Item_direct_ref
{ {
Item_equal *item_equal;
public: public:
Item_direct_view_ref(Name_resolution_context *context_arg, Item **item, Item_direct_view_ref(Name_resolution_context *context_arg, Item **item,
const char *table_name_arg, const char *table_name_arg,
const char *field_name_arg) const char *field_name_arg)
:Item_direct_ref(context_arg, item, table_name_arg, field_name_arg) {} :Item_direct_ref(context_arg, item, table_name_arg, field_name_arg),
item_equal(0) {}
/* Constructor need to process subselect with temporary tables (see Item) */ /* Constructor need to process subselect with temporary tables (see Item) */
Item_direct_view_ref(THD *thd, Item_direct_ref *item) Item_direct_view_ref(THD *thd, Item_direct_ref *item)
:Item_direct_ref(thd, item) {} :Item_direct_ref(thd, item), item_equal(0) {}
Item_direct_view_ref(TABLE_LIST *view_arg, Item **item, Item_direct_view_ref(TABLE_LIST *view_arg, Item **item,
const char *field_name_arg) const char *field_name_arg)
:Item_direct_ref(view_arg, item, field_name_arg) :Item_direct_ref(view_arg, item, field_name_arg), item_equal(0)
{} {}
bool fix_fields(THD *, Item **); bool fix_fields(THD *, Item **);
...@@ -2742,6 +2749,12 @@ class Item_direct_view_ref :public Item_direct_ref ...@@ -2742,6 +2749,12 @@ class Item_direct_view_ref :public Item_direct_ref
return item; return item;
} }
virtual Ref_Type ref_type() { return VIEW_REF; } virtual Ref_Type ref_type() { return VIEW_REF; }
Item_equal *get_item_equal() { return item_equal; }
void set_item_equal(Item_equal *item_eq) { item_equal= item_eq; }
Item_equal *find_item_equal(COND_EQUAL *cond_equal);
bool subst_argument_checker(uchar **arg);
Item *equal_fields_propagator(uchar *arg);
Item *replace_equal_field(uchar *arg);
}; };
......
This diff is collapsed.
...@@ -26,7 +26,7 @@ class Arg_comparator; ...@@ -26,7 +26,7 @@ class Arg_comparator;
typedef int (Arg_comparator::*arg_cmp_func)(); typedef int (Arg_comparator::*arg_cmp_func)();
typedef int (*Item_field_cmpfunc)(Item_field *f1, Item_field *f2, void *arg); typedef int (*Item_field_cmpfunc)(Item *f1, Item *f2, void *arg);
class Arg_comparator: public Sql_alloc class Arg_comparator: public Sql_alloc
{ {
...@@ -1614,28 +1614,64 @@ class Item_cond :public Item_bool_func ...@@ -1614,28 +1614,64 @@ class Item_cond :public Item_bool_func
class Item_equal: public Item_bool_func 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 */ The list of equal items. Currently the list can contain:
- Item_fields items for references to table columns
- Item_direct_view_ref items for references to view columns
- one const item
If the list contains a constant item this item is always first in the list.
The list contains at least two elements.
Currently all Item_fields/Item_direct_view_ref items in the list should
refer to table columns with equavalent type definitions. In particular
if these are string columns they should have the same charset/collation.
Use objects of the companion class Item_equal_fields_iterator to iterate
over all items from the list of the Item_field/Item_direct_view_ref classes.
*/
List<Item> equal_items;
/*
TRUE <-> one of the items is a const item.
Such item is always first in in the equal_items list
*/
bool with_const;
/*
The field eval_item is used when this item is evaluated
with the method val_int()
*/
cmp_item *eval_item; cmp_item *eval_item;
Arg_comparator cmp; /*
This initially is set to FALSE. It becomes TRUE when this item is evaluated
as being always false. If the flag is TRUE the contents of the list
the equal_items should be ignored.
*/
bool cond_false; bool cond_false;
/*
compare_as_dates=TRUE <-> constants equal to fields from equal_items
must be compared as datetimes and not as strings.
compare_as_dates can be TRUE only if with_const=TRUE
*/
bool compare_as_dates; bool compare_as_dates;
/*
The comparator used to compare constants equal to fields from equal_items
as datetimes. The comparator is used only if compare_as_dates=TRUE
*/
Arg_comparator cmp;
public: public:
inline Item_equal() inline Item_equal()
: Item_bool_func(), const_item(0), eval_item(0), cond_false(0) : Item_bool_func(), with_const(FALSE), eval_item(0), cond_false(0)
{ const_item_cache=0 ;} { const_item_cache=0 ;}
Item_equal(Item_field *f1, Item_field *f2); Item_equal(Item *f1, Item *f2, bool with_const_item);
Item_equal(Item *c, Item_field *f);
Item_equal(Item_equal *item_equal); Item_equal(Item_equal *item_equal);
inline Item* get_const() { return const_item; } /* Currently the const item is always the first in the list of equal items */
void compare_const(Item *c); inline Item* get_const() { return with_const ? equal_items.head() : NULL; }
void add(Item *c, Item_field *f); void add_const(Item *c, Item *f = NULL);
void add(Item *c); /** Add a non-constant item to the multiple equality */
void add(Item_field *f); void add(Item *f) { equal_items.push_back(f); }
uint members();
bool contains(Field *field); bool contains(Field *field);
Item_field* get_first(Item_field *field); Item* get_first(Item *field);
uint n_fields() { return fields.elements; } /** Get number of field items / references to field items in this object */
uint n_field_items() { return equal_items.elements-test(with_const); }
void merge(Item_equal *item); void merge(Item_equal *item);
void update_const(); void update_const();
enum Functype functype() const { return MULT_EQUAL_FUNC; } enum Functype functype() const { return MULT_EQUAL_FUNC; }
...@@ -1643,15 +1679,14 @@ class Item_equal: public Item_bool_func ...@@ -1643,15 +1679,14 @@ class Item_equal: public Item_bool_func
const char *func_name() const { return "multiple equal"; } const char *func_name() const { return "multiple equal"; }
optimize_type select_optimize() const { return OPTIMIZE_EQUAL; } optimize_type select_optimize() const { return OPTIMIZE_EQUAL; }
void sort(Item_field_cmpfunc compare, void *arg); void sort(Item_field_cmpfunc compare, void *arg);
friend class Item_equal_iterator;
void fix_length_and_dec(); void fix_length_and_dec();
bool fix_fields(THD *thd, Item **ref); bool fix_fields(THD *thd, Item **ref);
void update_used_tables(); void update_used_tables();
bool walk(Item_processor processor, bool walk_subquery, uchar *arg); bool walk(Item_processor processor, bool walk_subquery, uchar *arg);
Item *transform(Item_transformer transformer, uchar *arg); Item *transform(Item_transformer transformer, uchar *arg);
virtual void print(String *str, enum_query_type query_type); virtual void print(String *str, enum_query_type query_type);
CHARSET_INFO *compare_collation() CHARSET_INFO *compare_collation();
{ return fields.head()->collation.collation; } friend class Item_equal_fields_iterator;
friend Item *eliminate_item_equal(COND *cond, COND_EQUAL *upper_levels, friend Item *eliminate_item_equal(COND *cond, COND_EQUAL *upper_levels,
Item_equal *item_equal); Item_equal *item_equal);
friend bool setup_sj_materialization(struct st_join_table *tab); friend bool setup_sj_materialization(struct st_join_table *tab);
...@@ -1672,23 +1707,52 @@ class COND_EQUAL: public Sql_alloc ...@@ -1672,23 +1707,52 @@ class COND_EQUAL: public Sql_alloc
}; };
class Item_equal_iterator : public List_iterator_fast<Item_field> /*
The class Item_equal_fields_iterator is used to iterate over references
to table/view columns from a list of equal items.
*/
class Item_equal_fields_iterator : public List_iterator_fast<Item>
{ {
Item_equal *item_equal;
Item *curr_item;
public: public:
inline Item_equal_iterator(Item_equal &item_equal) Item_equal_fields_iterator(Item_equal &item_eq)
:List_iterator_fast<Item_field> (item_equal.fields) :List_iterator_fast<Item> (item_eq.equal_items)
{}
inline Item_field* operator++(int)
{ {
Item_field *item= (*(List_iterator_fast<Item_field> *) this)++; curr_item= NULL;
return item; item_equal= &item_eq;
if (item_eq.with_const)
{
List_iterator_fast<Item> *list_it= this;
curr_item= (*list_it)++;
}
} }
inline void rewind(void) Item* operator++(int)
{ {
List_iterator_fast<Item_field>::rewind(); List_iterator_fast<Item> *list_it= this;
curr_item= (*list_it)++;
return curr_item;
}
Item ** ref()
{
return List_iterator_fast<Item>::ref();
}
void rewind(void)
{
List_iterator_fast<Item> *list_it= this;
list_it->rewind();
if (item_equal->with_const)
curr_item= (*list_it)++;
}
Field *get_curr_field()
{
Item_field *item= (Item_field *) (curr_item->real_item());
return item->field;
} }
}; };
class Item_cond_and :public Item_cond class Item_cond_and :public Item_cond
{ {
public: public:
......
...@@ -7104,11 +7104,10 @@ static SEL_TREE *get_full_func_mm_tree(RANGE_OPT_PARAM *param, ...@@ -7104,11 +7104,10 @@ static SEL_TREE *get_full_func_mm_tree(RANGE_OPT_PARAM *param,
Item_equal *item_equal= field_item->item_equal; Item_equal *item_equal= field_item->item_equal;
if (item_equal) if (item_equal)
{ {
Item_equal_iterator it(*item_equal); Item_equal_fields_iterator it(*item_equal);
Item_field *item; while (it++)
while ((item= it++))
{ {
Field *f= item->field; Field *f= it.get_curr_field();
if (field->eq(f)) if (field->eq(f))
continue; continue;
if (!((ref_tables | f->table->map) & param_comp)) if (!((ref_tables | f->table->map) & param_comp))
...@@ -7259,11 +7258,11 @@ static SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param,COND *cond) ...@@ -7259,11 +7258,11 @@ static SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param,COND *cond)
Item_equal *item_equal= (Item_equal *) cond; Item_equal *item_equal= (Item_equal *) cond;
if (!(value= item_equal->get_const())) if (!(value= item_equal->get_const()))
DBUG_RETURN(0); DBUG_RETURN(0);
Item_equal_iterator it(*item_equal); Item_equal_fields_iterator it(*item_equal);
ref_tables= value->used_tables(); ref_tables= value->used_tables();
while ((field_item= it++)) while (it++)
{ {
Field *field= field_item->field; Field *field= it.get_curr_field();
Item_result cmp_type= field->cmp_type(); Item_result cmp_type= field->cmp_type();
if (!((ref_tables | field->table->map) & param_comp)) if (!((ref_tables | field->table->map) & param_comp))
{ {
......
...@@ -2383,13 +2383,13 @@ bool setup_sj_materialization(JOIN_TAB *tab) ...@@ -2383,13 +2383,13 @@ bool setup_sj_materialization(JOIN_TAB *tab)
if (item_eq) if (item_eq)
{ {
List_iterator<Item_field> it(item_eq->fields); List_iterator<Item> it(item_eq->equal_items);
Item_field *item; Item *item;
while ((item= it++)) while ((item= it++))
{ {
if (!(item->used_tables() & ~emb_sj_nest->sj_inner_tables)) if (!(item->used_tables() & ~emb_sj_nest->sj_inner_tables))
{ {
copy_to= item->field; copy_to= ((Item_field *) (item->real_item()))->field;
break; break;
} }
} }
......
...@@ -473,7 +473,7 @@ bool simple_pred(Item_func *func_item, Item **args, bool *inv_order) ...@@ -473,7 +473,7 @@ bool simple_pred(Item_func *func_item, Item **args, bool *inv_order)
/* MULT_EQUAL_FUNC */ /* MULT_EQUAL_FUNC */
{ {
Item_equal *item_equal= (Item_equal *) func_item; Item_equal *item_equal= (Item_equal *) func_item;
Item_equal_iterator it(*item_equal); Item_equal_fields_iterator it(*item_equal);
args[0]= it++; args[0]= it++;
if (it++) if (it++)
return 0; return 0;
......
...@@ -1208,15 +1208,16 @@ void build_eq_mods_for_cond(Dep_analysis_context *ctx, ...@@ -1208,15 +1208,16 @@ void build_eq_mods_for_cond(Dep_analysis_context *ctx,
if (!(fvl= new List<Dep_value_field>)) if (!(fvl= new List<Dep_value_field>))
break; /* purecov: inspected */ break; /* purecov: inspected */
Item_equal_iterator it(*item_equal); Item_equal_fields_iterator it(*item_equal);
Item_field *item; Item *item;
Item *bound_item= item_equal->get_const(); Item *bound_item= item_equal->get_const();
while ((item= it++)) while ((item= it++))
{ {
Field *equal_field= it.get_curr_field();
if ((item->used_tables() & ctx->usable_tables)) if ((item->used_tables() & ctx->usable_tables))
{ {
Dep_value_field *field_val; Dep_value_field *field_val;
if ((field_val= ctx->get_field_value(item->field))) if ((field_val= ctx->get_field_value(equal_field)))
fvl->push_back(field_val); fvl->push_back(field_val);
} }
else else
......
This diff is collapsed.
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