Browse Source

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.
pull/374/head
Igor Babaev 15 years ago
parent
commit
8d9dd21d85
  1. 155
      mysql-test/r/view.result
  2. 74
      mysql-test/t/view.test
  3. 149
      sql/item.cc
  4. 25
      sql/item.h
  5. 363
      sql/item_cmpfunc.cc
  6. 118
      sql/item_cmpfunc.h
  7. 13
      sql/opt_range.cc
  8. 6
      sql/opt_subselect.cc
  9. 2
      sql/opt_sum.cc
  10. 7
      sql/opt_table_elimination.cc
  11. 147
      sql/sql_select.cc

155
mysql-test/r/view.result

@ -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
DROP VIEW v1;
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;

74
mysql-test/t/view.test

@ -3983,3 +3983,77 @@ SELECT * FROM v1, t2, t3
DROP VIEW v1;
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;

149
sql/item.cc

@ -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
occurrence for an equal item is valid.
@details
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
substitution for an equal item is valid
@param arg *arg != NULL && **arg <-> the field is in the context
where substitution for an equal item is valid
@note
The following statement is not always true:
@ -4701,7 +4702,8 @@ Item_equal *Item_field::find_item_equal(COND_EQUAL *cond_equal)
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)
Set a pointer to the multiple equality the field reference belongs to
(if any).
@details
The function looks for a multiple equality containing the field item
among those referenced by arg.
In the case such equality exists the function does the following.
@ -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
(if any).
@details
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 very beginning of the item_equal list which the Item_field
@ -4828,7 +4832,7 @@ bool Item_field::set_no_const_sub(uchar *arg)
@note
This function is supposed to be called as a callback parameter in calls
of the thransformer method.
of the transformer method.
@return
- 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)
return this;
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))
return subst;
}
@ -6377,7 +6383,8 @@ Item* Item_ref::compile(Item_analyzer analyzer, uchar **arg_p,
/* Compile the Item we are referencing. */
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)
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
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
{
return item->type() == DEFAULT_VALUE_ITEM &&

25
sql/item.h

@ -487,6 +487,9 @@ typedef bool (Item::*Item_analyzer) (uchar **argp);
typedef Item* (Item::*Item_transformer) (uchar *arg);
typedef void (*Cond_traverser) (const Item *item, void *arg);
class Item_equal;
class COND_EQUAL;
class Item {
Item(const Item &); /* Prevent use of these */
@ -1179,6 +1182,9 @@ public:
Item* set_expr_cache(THD *thd, List<Item*> &depends_on);
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 @@ public:
};
class Item_equal;
class COND_EQUAL;
class Item_field :public Item_ident
{
protected:
@ -1707,6 +1710,8 @@ public:
{
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);
bool subst_argument_checker(uchar **arg);
Item *equal_fields_propagator(uchar *arg);
@ -2720,17 +2725,19 @@ public:
*/
class Item_direct_view_ref :public Item_direct_ref
{
Item_equal *item_equal;
public:
Item_direct_view_ref(Name_resolution_context *context_arg, Item **item,
const char *table_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) */
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,
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 **);
@ -2742,6 +2749,12 @@ public:
return item;
}
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);
};

363
sql/item_cmpfunc.cc

@ -5516,43 +5516,92 @@ Item *Item_bool_rowready_func2::negated_item()
return 0;
}
Item_equal::Item_equal(Item_field *f1, Item_field *f2)
: Item_bool_func(), const_item(0), eval_item(0), cond_false(0),
compare_as_dates(FALSE)
{
const_item_cache= 0;
fields.push_back(f1);
fields.push_back(f2);
}
Item_equal::Item_equal(Item *c, Item_field *f)
/**
Construct a minimal multiple equality item
@param f1 the first equal item
@param f2 the second equal item
@param with_const_item TRUE if the first item is constant
@details
The constructor builds a new item equal object for the equality f1=f2.
One of the equal items can be constant. If this is the case it is passed
always as the first parameter and the parameter with_const_item serves
as an indicator of this case.
Currently any non-constant parameter items must point to an item of the
of the type Item_field or Item_direct_view_ref(Item_field).
*/
Item_equal::Item_equal(Item *f1, Item *f2, bool with_const_item)
: Item_bool_func(), eval_item(0), cond_false(0)
{
const_item_cache= 0;
fields.push_back(f);
const_item= c;
compare_as_dates= f->is_datetime();
with_const= with_const_item;
compare_as_dates= with_const_item && f2->is_datetime();
equal_items.push_back(f1);
equal_items.push_back(f2);
}
/**
Copy constructor for a multiple equality
@param item_equal source item for the constructor
@details
The function creates a copy of an Item_equal object.
This constructor is used when an item belongs to a multiple equality
of an upper level (an upper AND/OR level or an upper level of a nested
outer join).
*/
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;
List_iterator_fast<Item> li(item_equal->equal_items);
Item *item;
while ((item= li++))
{
fields.push_back(item);
equal_items.push_back(item);
}
const_item= item_equal->const_item;
with_const= item_equal->with_const;
compare_as_dates= item_equal->compare_as_dates;
cond_false= item_equal->cond_false;
}
void Item_equal::compare_const(Item *c)
/*
@brief
Add a constant item to the Item_equal object
@param[in] c the constant to add
@param[in] f item from the list equal_items the item c is equal to
(this parameter is optional)
@details
The method adds the constant item c to the equal_items list. If the list
doesn't have any constant item yet the item c is just put in the front
the list. Otherwise the value of c is compared with the value of the
constant item from equal_items. If they are not equal cond_false is set
to TRUE. This serves as an indicator that this Item_equal is always FALSE.
The optional parameter f is used to adjust the flag compare_as_dates.
*/
void Item_equal::add_const(Item *c, Item *f)
{
if (cond_false)
return;
if (!with_const)
{
with_const= TRUE;
if (f)
compare_as_dates= f->is_datetime();
equal_items.push_front(c);
return;
}
Item *const_item= get_const();
if (compare_as_dates)
{
cmp.set_datetime_cmp_func(this, &c, &const_item);
@ -5570,64 +5619,28 @@ void Item_equal::compare_const(Item *c)
}
void Item_equal::add(Item *c, Item_field *f)
{
if (cond_false)
return;
if (!const_item)
{
DBUG_ASSERT(f);
const_item= c;
compare_as_dates= f->is_datetime();
return;
}
compare_const(c);
}
void Item_equal::add(Item *c)
{
if (cond_false)
return;
if (!const_item)
{
const_item= c;
return;
}
compare_const(c);
}
void Item_equal::add(Item_field *f)
{
fields.push_back(f);
}
uint Item_equal::members()
{
return fields.elements;
}
/**
Check whether a field is referred in the multiple equality.
The function checks whether field is occurred in the Item_equal object .
@brief
Check whether a field is referred to in the multiple equality
@param field field whose occurrence is to be checked
@details
The function checks whether field is referred to by one of the
items from the equal_items list.
@retval
1 if nultiple equality contains a reference to field
1 if multiple equality contains a reference to field
@retval
0 otherwise
*/
bool Item_equal::contains(Field *field)
{
List_iterator_fast<Item_field> it(fields);
Item_field *item;
while ((item= it++))
Item_equal_fields_iterator it(*this);
while (it++)
{
if (field->eq(item->field))
if (field->eq(it.get_curr_field()))
return 1;
}
return 0;
@ -5635,110 +5648,168 @@ bool Item_equal::contains(Field *field)
/**
Join members of another Item_equal object.
@brief
Join members of another Item_equal object
The function actually merges two multiple equalities.
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.
@param item multiple equality whose members are to be joined
@details
The function actually merges two multiple equalities. 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 TRUE.
@notes
The function is called for any equality f1=f2 such that f1 and f2 are items
of the type Item_field or Item_direct_view_ref(Item_field), and, f1->field is
referred to in the list this->equal_items, while the list item->equal_items
contains a reference to f2->field.
*/
void Item_equal::merge(Item_equal *item)
{
fields.concat(&item->fields);
Item *c= item->const_item;
Item *c= item->get_const();
if (c)
item->equal_items.pop();
equal_items.concat(&item->equal_items);
if (c)
{
/*
The flag cond_false will be set to 1 after this, if
The flag cond_false will be set to TRUE after this if
the multiple equality already contains a constant and its
value is not equal to the value of c.
*/
add(c);
add_const(c);
}
cond_false|= item->cond_false;
}
/**
Order field items in multiple equality according to a sorting criteria.
@brief
Order equal items of the multiple equality according to a sorting criteria
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.
@param compare function to compare items from the equal_items list
@param arg context extra parameter for the cmp function
@details
The function performs ordering of the items from the equal_items list
according to the criteria determined by the cmp callback parameter.
If cmp(item1,item2,arg)<0 than item1 must be placed after item2.
The function sorts field items by the bubble sort algorithm.
@notes
The function sorts equal items by the bubble 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.
@param compare function to compare field item
@param arg context extra parameter for the cmp function
*/
void Item_equal::sort(Item_field_cmpfunc compare, void *arg)
{
bubble_sort<Item_field>(&fields, compare, arg);
bubble_sort<Item>(&equal_items, compare, arg);
}
/**
Check appearance of new constant items in the multiple equality object.
@brief
Check appearance of new constant items in the multiple equality object
The function checks appearance of new constant items among
the members of multiple equalities. Each new constant item is
compared with the designated constant item if there is any in the
multiple equality. If there is none the first new constant item
becomes designated.
@details
The function checks appearance of new constant items among the members
of the equal_items list. Each new constant item is compared with
the constant item from the list if there is any. If there is none the first
new constant item is placed at the very beginning of the list and
with_const is set to TRUE. If it happens that the compared constant items
are unequal then the flag cond_false is set to TRUE.
@notes
Currently this function is called only after substitution of constant tables.
*/
void Item_equal::update_const()
{
List_iterator<Item_field> it(fields);
Item *item;
while ((item= it++))
List_iterator<Item> it(equal_items);
if (with_const)
it++;
Item *item= it++;
while (item)
{
if (item->const_item())
{
it.remove();
add(item);
Item *next_item= it++;
add_const(item);
item= next_item;
}
else
item= it++;
}
}
/**
@brief
Fix fields in a completely built multiple equality
@param thd currently not used thread handle
@param ref not used
@details
This function is called once the multiple equality has been built out of
the WHERE/ON condition and no new members are expected to be added to the
equal_items list anymore.
As any implementation of the virtual fix_fields method the function
calculates the cached values of not_null_tables_cache, used_tables_cache,
const_item_cache and calls fix_length_and_dec().
Additionally the function sets a reference to the Item_equal object in
the non-constant items of the equal_items list unless such a reference has
been already set.
@notes
Currently this function is called only in the function
build_equal_items_for_cond.
@retval
FALSE always
*/
bool Item_equal::fix_fields(THD *thd, Item **ref)
{
List_iterator_fast<Item_field> li(fields);
Item_field *item;
DBUG_ASSERT(fixed == 0);
Item_equal_fields_iterator it(*this);
Item *item;
not_null_tables_cache= used_tables_cache= 0;
const_item_cache= 0;
while ((item= li++))
while ((item= it++))
{
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;
item->item_equal= this;
maybe_null= 1;
if (!item->get_item_equal())
item->set_item_equal(this);
}
fix_length_and_dec();
fixed= 1;
return 0;
return FALSE;
}
/**
Update the value of the used table attribute and other attributes
*/
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;
Item_equal_fields_iterator it(*this);
Item *item;
const_item_cache= 1;
while ((item=li++))
while ((item= it++))
{
item->update_used_tables();
used_tables_cache|= item->used_tables();
@ -5746,28 +5817,54 @@ void Item_equal::update_used_tables()
}
}
/**
@brief
Evaluate multiple equality
@details
The function evaluate multiple equality to a boolean value.
The function ignores non-constant items from the equal_items list.
The function returns 1 if all constant items from the list are equal.
It returns 0 if there are unequal constant items in the list or
one of the constant items is evaluated to NULL.
@notes
Currently this function can be called only at the optimization
stage after the constant table substitution, since all Item_equals
are eliminated before the execution stage.
@retval
0 multiple equality is always FALSE or NULL
1 otherwise
*/
longlong Item_equal::val_int()
{
Item_field *item_field;
if (cond_false)
return 0;
List_iterator_fast<Item_field> it(fields);
Item *item= const_item ? const_item : it++;
if ((null_value= item->is_null()))
return 0;
Item *item= get_const();
Item_equal_fields_iterator it(*this);
if (!item)
item= it++;
eval_item->store_value(item);
while ((item_field= it++))
if ((null_value= item->null_value))
return 0;
while ((item= it++))
{
Field *field= it.get_curr_field();
/* Skip fields of non-const tables. They haven't been read yet */
if (item_field->field->table->const_table)
if (field->table->const_table)
{
if ((null_value= item_field->is_null()) || eval_item->cmp(item_field))
if (eval_item->cmp(item) || (null_value= item->null_value))
return 0;
}
}
return 1;
}
void Item_equal::fix_length_and_dec()
{
Item *item= get_first(NULL);
@ -5775,10 +5872,11 @@ void Item_equal::fix_length_and_dec()
item->collation.collation);
}
bool Item_equal::walk(Item_processor processor, bool walk_subquery, uchar *arg)
{
List_iterator_fast<Item_field> it(fields);
Item *item;
Item_equal_fields_iterator it(*this);
while ((item= it++))
{
if (item->walk(processor, walk_subquery, arg))
@ -5787,12 +5885,13 @@ bool Item_equal::walk(Item_processor processor, bool walk_subquery, uchar *arg)
return Item_func::walk(processor, walk_subquery, arg);
}
Item *Item_equal::transform(Item_transformer transformer, uchar *arg)
{
DBUG_ASSERT(!current_thd->is_stmt_prepare());
List_iterator<Item_field> it(fields);
Item *item;
Item_equal_fields_iterator it(*this);
while ((item= it++))
{
Item *new_item= item->transform(transformer, arg);
@ -5811,19 +5910,15 @@ Item *Item_equal::transform(Item_transformer transformer, uchar *arg)
return Item_func::transform(transformer, arg);
}
void Item_equal::print(String *str, enum_query_type query_type)
{
str->append(func_name());
str->append('(');
List_iterator_fast<Item_field> it(fields);
List_iterator_fast<Item> it(equal_items);
Item *item;
if (const_item)
const_item->print(str, query_type);
else
{
item= it++;
item->print(str, query_type);
}
while ((item= it++))
{
str->append(',');
@ -5834,6 +5929,14 @@ void Item_equal::print(String *str, enum_query_type query_type)
}
CHARSET_INFO *Item_equal::compare_collation()
{
Item_equal_fields_iterator it(*this);
Item *item= it++;
return item->collation.collation;
}
/*
@brief Get the first equal field of multiple equality.
@param[in] field the field to get equal field to
@ -5859,13 +5962,14 @@ void Item_equal::print(String *str, enum_query_type query_type)
@retval 0 if no field found.
*/
Item_field* Item_equal::get_first(Item_field *field)
Item* Item_equal::get_first(Item *field_item)
{
List_iterator<Item_field> it(fields);
Item_field *item;
Item_equal_fields_iterator it(*this);
Item *item;
JOIN_TAB *field_tab;
if (!field)
return fields.head();
if (!field_item)
return (it++);
Field *field= ((Item_field *) (field_item->real_item()))->field;
/*
Of all equal fields, return the first one we can use. Normally, this is the
@ -5887,9 +5991,9 @@ Item_field* Item_equal::get_first(Item_field *field)
in presense of SJM nests.
*/
field_tab= field->field->table->reginfo.join_tab;
field_tab= field->table->reginfo.join_tab;
TABLE_LIST *emb_nest= field->field->table->pos_in_table_list->embedding;
TABLE_LIST *emb_nest= field->table->pos_in_table_list->embedding;
if (emb_nest && emb_nest->sj_mat_info && emb_nest->sj_mat_info->is_used)
{
@ -5916,13 +6020,13 @@ Item_field* Item_equal::get_first(Item_field *field)
/* Find an item to substitute for. */
while ((item= it++))
{
if (item->field->table->reginfo.join_tab >= first)
if (it.get_curr_field()->table->reginfo.join_tab >= first)
{
/*
If we found given field then return NULL to avoid unnecessary
substitution.
*/
return (item != field) ? item : NULL;
return (item != field_item) ? item : NULL;
}
}
}
@ -5946,7 +6050,8 @@ Item_field* Item_equal::get_first(Item_field *field)
*/
while ((item= it++))
{
TABLE_LIST *emb_nest= item->field->table->pos_in_table_list->embedding;
Item_field *fld_item= (Item_field *) (item->real_item());
TABLE_LIST *emb_nest= fld_item->field->table->pos_in_table_list->embedding;
if (!emb_nest || !emb_nest->sj_mat_info ||
!emb_nest->sj_mat_info->is_used)
{
@ -5954,7 +6059,7 @@ Item_field* Item_equal::get_first(Item_field *field)
}
}
#endif
return fields.head();
return equal_items.head();
}
// Shouldn't get here.
DBUG_ASSERT(0);

118
sql/item_cmpfunc.h

@ -26,7 +26,7 @@ class Arg_comparator;
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
{
@ -1614,28 +1614,64 @@ public:
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;
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;
/*
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;
/*
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:
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 ;}
Item_equal(Item_field *f1, Item_field *f2);
Item_equal(Item *c, Item_field *f);
Item_equal(Item *f1, Item *f2, bool with_const_item);
Item_equal(Item_equal *item_equal);
inline Item* get_const() { return const_item; }
void compare_const(Item *c);
void add(Item *c, Item_field *f);
void add(Item *c);
void add(Item_field *f);
uint members();
/* Currently the const item is always the first in the list of equal items */
inline Item* get_const() { return with_const ? equal_items.head() : NULL; }
void add_const(Item *c, Item *f = NULL);
/** Add a non-constant item to the multiple equality */
void add(Item *f) { equal_items.push_back(f); }
bool contains(Field *field);
Item_field* get_first(Item_field *field);
uint n_fields() { return fields.elements; }
Item* get_first(Item *field);
/** 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 update_const();
enum Functype functype() const { return MULT_EQUAL_FUNC; }
@ -1643,15 +1679,14 @@ public:
const char *func_name() const { return "multiple equal"; }
optimize_type select_optimize() const { return OPTIMIZE_EQUAL; }
void sort(Item_field_cmpfunc compare, void *arg);
friend class Item_equal_iterator;
void fix_length_and_dec();
bool fix_fields(THD *thd, Item **ref);
void update_used_tables();
bool walk(Item_processor processor, bool walk_subquery, uchar *arg);
Item *transform(Item_transformer transformer, uchar *arg);
virtual void print(String *str, enum_query_type query_type);
CHARSET_INFO *compare_collation()
{ return fields.head()->collation.collation; }
CHARSET_INFO *compare_collation();
friend class Item_equal_fields_iterator;
friend Item *eliminate_item_equal(COND *cond, COND_EQUAL *upper_levels,
Item_equal *item_equal);
friend bool setup_sj_materialization(struct st_join_table *tab);
@ -1672,23 +1707,52 @@ public:
};
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:
inline Item_equal_iterator(Item_equal &item_equal)
:List_iterator_fast<Item_field> (item_equal.fields)
{}
inline Item_field* operator++(int)
Item_equal_fields_iterator(Item_equal &item_eq)
:List_iterator_fast<Item> (item_eq.equal_items)
{
Item_field *item= (*(List_iterator_fast<Item_field> *) this)++;
return item;
curr_item= NULL;
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
{
public:

13
sql/opt_range.cc

@ -7104,11 +7104,10 @@ static SEL_TREE *get_full_func_mm_tree(RANGE_OPT_PARAM *param,
Item_equal *item_equal= field_item->item_equal;
if (item_equal)
{
Item_equal_iterator it(*item_equal);
Item_field *item;
while ((item= it++))
Item_equal_fields_iterator it(*item_equal);
while (it++)
{
Field *f= item->field;
Field *f= it.get_curr_field();
if (field->eq(f))
continue;
if (!((ref_tables | f->table->map) & param_comp))
@ -7259,11 +7258,11 @@ static SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param,COND *cond)
Item_equal *item_equal= (Item_equal *) cond;
if (!(value= item_equal->get_const()))
DBUG_RETURN(0);
Item_equal_iterator it(*item_equal);
Item_equal_fields_iterator it(*item_equal);
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();
if (!((ref_tables | field->table->map) & param_comp))
{

6
sql/opt_subselect.cc

@ -2383,13 +2383,13 @@ bool setup_sj_materialization(JOIN_TAB *tab)
if (item_eq)
{
List_iterator<Item_field> it(item_eq->fields);
Item_field *item;
List_iterator<Item> it(item_eq->equal_items);
Item *item;
while ((item= it++))
{
if (!(item->used_tables() & ~emb_sj_nest->sj_inner_tables))
{
copy_to= item->field;
copy_to= ((Item_field *) (item->real_item()))->field;
break;
}
}

2
sql/opt_sum.cc

@ -473,7 +473,7 @@ bool simple_pred(Item_func *func_item, Item **args, bool *inv_order)
/* MULT_EQUAL_FUNC */
{
Item_equal *item_equal= (Item_equal *) func_item;
Item_equal_iterator it(*item_equal);
Item_equal_fields_iterator it(*item_equal);
args[0]= it++;
if (it++)
return 0;

7
sql/opt_table_elimination.cc

@ -1208,15 +1208,16 @@ void build_eq_mods_for_cond(Dep_analysis_context *ctx,
if (!(fvl= new List<Dep_value_field>))
break; /* purecov: inspected */
Item_equal_iterator it(*item_equal);
Item_field *item;
Item_equal_fields_iterator it(*item_equal);
Item *item;
Item *bound_item= item_equal->get_const();
while ((item= it++))
{
Field *equal_field= it.get_curr_field();
if ((item->used_tables() & ctx->usable_tables))
{
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);
}
else

147
sql/sql_select.cc

@ -3715,28 +3715,28 @@ add_key_field(JOIN *join,
static void
add_key_equal_fields(JOIN *join, KEY_FIELD **key_fields, uint and_level,
Item_func *cond, Item_field *field_item,
Item_func *cond, Item *field_item,
bool eq_func, Item **val,
uint num_values, table_map usable_tables,
SARGABLE_PARAM **sargables)
{
Field *field= field_item->field;
Field *field= ((Item_field *) (field_item->real_item()))->field;
add_key_field(join, key_fields, and_level, cond, field,
eq_func, val, num_values, usable_tables, sargables);
Item_equal *item_equal= field_item->item_equal;
Item_equal *item_equal= field_item->get_item_equal();
if (item_equal)
{
/*
Add to the set of possible key values every substitution of
the field for an equal field included into item_equal
*/
Item_equal_iterator it(*item_equal);
Item_field *item;
while ((item= it++))
Item_equal_fields_iterator it(*item_equal);
while (it++)
{
if (!field->eq(item->field))
Field *equal_field= it.get_curr_field();
if (!field->eq(equal_field))
{
add_key_field(join, key_fields, and_level, cond, item->field,
add_key_field(join, key_fields, and_level, cond, equal_field,
eq_func, val, num_values, usable_tables,
sargables);
}
@ -3933,8 +3933,7 @@ add_key_fields(JOIN *join, KEY_FIELD **key_fields, uint *and_level,
case Item_func::OPTIMIZE_EQUAL:
Item_equal *item_equal= (Item_equal *) cond;
Item *const_item= item_equal->get_const();
Item_equal_iterator it(*item_equal);
Item_field *item;
Item_equal_fields_iterator it(*item_equal);
if (const_item)
{
/*
@ -3942,9 +3941,10 @@ add_key_fields(JOIN *join, KEY_FIELD **key_fields, uint *and_level,
field1=const_item as a condition allowing an index access of the table
with field1 by the keys value of field1.
*/
while ((item= it++))
while (it++)
{
add_key_field(join, key_fields, *and_level, cond_func, item->field,
Field *equal_field= it.get_curr_field();
add_key_field(join, key_fields, *and_level, cond_func, equal_field,
TRUE, &const_item, 1, usable_tables, sargables);
}
}
@ -3956,17 +3956,18 @@ add_key_fields(JOIN *join, KEY_FIELD **key_fields, uint *and_level,
field1=field2 as a condition allowing an index access of the table
with field1 by the keys value of field2.
*/
Item_equal_iterator fi(*item_equal);
while ((item= fi++))
Item_equal_fields_iterator fi(*item_equal);
while (fi++)
{
Field *field= item->field;
Field *field= fi.get_curr_field();
Item *item;
while ((item= it++))
{
if (!field->eq(item->field))
Field *equal_field= it.get_curr_field();
if (!field->eq(equal_field))
{
Item *tmp_item= item;
add_key_field(join, key_fields, *and_level, cond_func, field,
TRUE, &tmp_item, 1, usable_tables,
TRUE, &item, 1, usable_tables,
sargables);
}
}
@ -9195,6 +9196,8 @@ finish:
static bool check_simple_equality(Item *left_item, Item *right_item,
Item *item, COND_EQUAL *cond_equal)
{
Item *orig_left_item= left_item;
Item *orig_right_item= right_item;
if (left_item->type() == Item::REF_ITEM &&
((Item_ref*)left_item)->ref_type() == Item_ref::VIEW_REF)
{
@ -9261,7 +9264,7 @@ static bool check_simple_equality(Item *left_item, Item *right_item,
{
/* left item was found in the current or one of the upper levels */
if (! right_item_equal)
left_item_equal->add((Item_field *) right_item);
left_item_equal->add(orig_right_item);
else
{
/* Merge two multiple equalities forming a new one */
@ -9276,12 +9279,13 @@ static bool check_simple_equality(Item *left_item, Item *right_item,
{
/* left item was not found neither the current nor in upper levels */
if (right_item_equal)
right_item_equal->add((Item_field *) left_item);
right_item_equal->add(orig_left_item);
else
{
/* None of the fields was found in multiple equalities */
Item_equal *item_equal= new Item_equal((Item_field *) left_item,
(Item_field *) right_item);
Item_equal *item_equal= new Item_equal(orig_left_item,
orig_right_item,
FALSE);
cond_equal->current_level.push_back(item_equal);
}
}
@ -9292,18 +9296,21 @@ static bool check_simple_equality(Item *left_item, Item *right_item,
/* The predicate of the form field=const/const=field is processed */
Item *const_item= 0;
Item_field *field_item= 0;
Item *orig_field_item= 0;
if (left_item->type() == Item::FIELD_ITEM &&
!((Item_field*)left_item)->depended_from &&
right_item->const_item())
{
field_item= (Item_field*) left_item;
orig_field_item= left_item;
field_item= (Item_field *) left_item;
const_item= right_item;
}
else if (right_item->type() == Item::FIELD_ITEM &&
!((Item_field*)right_item)->depended_from &&
left_item->const_item())
{
field_item= (Item_field*) right_item;
orig_field_item= right_item;
field_item= (Item_field *) right_item;
const_item= left_item;
}
@ -9318,7 +9325,7 @@ static bool check_simple_equality(Item *left_item, Item *right_item,
if (!item)
{
Item_func_eq *eq_item;
if ((eq_item= new Item_func_eq(left_item, right_item)))
if ((eq_item= new Item_func_eq(orig_left_item, orig_right_item)))
return FALSE;
eq_item->set_cmp_func();
eq_item->quick_fix_field();
@ -9343,11 +9350,11 @@ static bool check_simple_equality(Item *left_item, Item *right_item,
already contains a constant and its value is not equal to
the value of const_item.
*/
item_equal->add(const_item, field_item);
item_equal->add_const(const_item, orig_field_item);
}
else
{
item_equal= new Item_equal(const_item, field_item);
item_equal= new Item_equal(const_item, orig_field_item, TRUE);
cond_equal->current_level.push_back(item_equal);
}
return TRUE;
@ -9592,7 +9599,7 @@ static COND *build_equal_items_for_cond(THD *thd, COND *cond,
item_equal->fix_fields(thd, NULL);
item_equal->update_used_tables();
set_if_bigger(thd->lex->current_select->max_equal_elems,
item_equal->members());
item_equal->n_field_items());
}
((Item_cond_and*)cond)->cond_equal= cond_equal;
@ -9623,7 +9630,8 @@ static COND *build_equal_items_for_cond(THD *thd, COND *cond,
args->concat((List<Item> *)&cond_equal.current_level);
}
}
else if (cond->type() == Item::FUNC_ITEM)
else if (cond->type() == Item::FUNC_ITEM ||
cond->real_item()->type() == Item::FIELD_ITEM)
{
List<Item> eq_list;
/*
@ -9645,10 +9653,10 @@ static COND *build_equal_items_for_cond(THD *thd, COND *cond,
{
if ((item_equal= cond_equal.current_level.pop()))
{
item_equal->fix_length_and_dec();
item_equal->fix_fields(thd, NULL);
item_equal->update_used_tables();
set_if_bigger(thd->lex->current_select->max_equal_elems,
item_equal->members());
item_equal->n_field_items());
return item_equal;
}
@ -9669,7 +9677,7 @@ static COND *build_equal_items_for_cond(THD *thd, COND *cond,
item_equal->fix_length_and_dec();
item_equal->update_used_tables();
set_if_bigger(thd->lex->current_select->max_equal_elems,
item_equal->members());
item_equal->n_field_items());
}
and_cond->cond_equal= cond_equal;
args->concat((List<Item> *)&cond_equal.current_level);
@ -9683,9 +9691,10 @@ static COND *build_equal_items_for_cond(THD *thd, COND *cond,
as soon the field is not of a string type or the field reference is
an argument of a comparison predicate.
*/
uchar *is_subst_valid= (uchar *) 1;
uchar is_subst_valid= (uchar) 1;
uchar *is_subst_valid_ptr= &is_subst_valid;
cond= cond->compile(&Item::subst_argument_checker,
&is_subst_valid,
&is_subst_valid_ptr,
&Item::equal_fields_propagator,
(uchar *) inherited);
cond->update_used_tables();
@ -9839,18 +9848,24 @@ static COND *build_equal_items(THD *thd, COND *cond,
0 otherwise
*/
static int compare_fields_by_table_order(Item_field *field1,
Item_field *field2,
static int compare_fields_by_table_order(Item *field1,
Item *field2,
void *table_join_idx)
{
int cmp= 0;
bool outer_ref= 0;
if (field2->used_tables() & OUTER_REF_TABLE_BIT)
Item_field *f1= (Item_field *) (field1->real_item());
Item_field *f2= (Item_field *) (field2->real_item());
if (f1->const_item())
return 1;
if (f2->const_item())
return -1;
if (f2->used_tables() & OUTER_REF_TABLE_BIT)
{
outer_ref= 1;
cmp= -1;
}
if (field1->used_tables() & OUTER_REF_TABLE_BIT)
if (f1->used_tables() & OUTER_REF_TABLE_BIT)
{
outer_ref= 1;
cmp++;
@ -9858,10 +9873,10 @@ static int compare_fields_by_table_order(Item_field *field1,
if (outer_ref)
return cmp;
JOIN_TAB **idx= (JOIN_TAB **) table_join_idx;
cmp= idx[field2->field->table->tablenr]-idx[field1->field->table->tablenr];
cmp= idx[f2->field->table->tablenr]-idx[f1->field->table->tablenr];
if (!cmp)
{
JOIN_TAB *tab= idx[field1->field->table->tablenr];
JOIN_TAB *tab= idx[f1->field->table->tablenr];
uint keyno= MAX_KEY;
if (tab->ref.key_parts)
keyno= tab->ref.key;
@ -9869,9 +9884,9 @@ static int compare_fields_by_table_order(Item_field *field1,
keyno = tab->select->quick->index;
if (keyno != MAX_KEY)
{
if (field2->field->part_of_key.is_set(keyno))
if (f2->field->part_of_key.is_set(keyno))
cmp= -1;
if (field1->field->part_of_key.is_set(keyno))
if (f1->field->part_of_key.is_set(keyno))
cmp++;
if (!cmp)
{
@ -9879,12 +9894,12 @@ static int compare_fields_by_table_order(Item_field *field1,
for (uint i= 0; i < key_info->key_parts; i++)
{
Field *fld= key_info->key_part[i].field;
if (fld->eq(field2->field))
if (fld->eq(f2->field))
{
cmp= -1;
break;
}
if (fld->eq(field1->field))
if (fld->eq(f1->field))
{
cmp= 1;
break;
@ -9893,14 +9908,15 @@ static int compare_fields_by_table_order(Item_field *field1,
}
}
else
cmp= field2->field->field_index-field1->field->field_index;
cmp= f2->field->field_index-f1->field->field_index;
}
return cmp < 0 ? -1 : (cmp ? 1 : 0);
}
static TABLE_LIST* embedding_sjm(Item_field *item_field)
static TABLE_LIST* embedding_sjm(Item *item)
{
Item_field *item_field= (Item_field *) (item->real_item());
TABLE_LIST *nest= item_field->field->table->pos_in_table_list->embedding;
if (nest && nest->sj_mat_info && nest->sj_mat_info->is_used)
return nest;
@ -9973,7 +9989,7 @@ Item *eliminate_item_equal(COND *cond, COND_EQUAL *upper_levels,
if (((Item *) item_equal)->const_item() && !item_equal->val_int())
return new Item_int((longlong) 0,1);
Item *item_const= item_equal->get_const();
Item_equal_iterator it(*item_equal);
Item_equal_fields_iterator it(*item_equal);
Item *head;
DBUG_ASSERT(!cond || cond->type() == Item::COND_ITEM);
@ -9989,27 +10005,26 @@ Item *eliminate_item_equal(COND *cond, COND_EQUAL *upper_levels,
else
{
TABLE_LIST *emb_nest;
Item_field *item_field;
head= item_field= item_equal->get_first(NULL);
head= item_equal->get_first(NULL);
it++;
if ((emb_nest= embedding_sjm(item_field)))
if ((emb_nest= embedding_sjm(head)))
{
current_sjm= emb_nest;
current_sjm_head= head;
}
}
Item_field *item_field;
Item *field_item;
/*
For each other item, generate "item=head" equality (except the tables that
are within SJ-Materialization nests, for those "head" is defined
differently)
*/
while ((item_field= it++))
while ((field_item= it++))
{
Item_equal *upper= item_field->find_item_equal(upper_levels);
Item_field *item= item_field;
TABLE_LIST *field_sjm= embedding_sjm(item_field);
Item_equal *upper= field_item->find_item_equal(upper_levels);
Item *item= field_item;
TABLE_LIST *field_sjm= embedding_sjm(field_item);
if (!field_sjm)
{
current_sjm= NULL;
@ -10026,8 +10041,8 @@ Item *eliminate_item_equal(COND *cond, COND_EQUAL *upper_levels,
item= 0;
else
{
Item_equal_iterator li(*item_equal);
while ((item= li++) != item_field)
Item_equal_fields_iterator li(*item_equal);
while ((item= li++) != field_item)
{
if (item->find_item_equal(upper_levels) == upper)
break;
@ -10035,11 +10050,11 @@ Item *eliminate_item_equal(COND *cond, COND_EQUAL *upper_levels,
}
}
bool produce_equality= test(item == item_field);
bool produce_equality= test(item == field_item);
if (!item_const && field_sjm && field_sjm != current_sjm)
{
/* Entering an SJM nest */
current_sjm_head= item_field;
current_sjm_head= field_item;
if (!field_sjm->sj_mat_info->is_sj_scan)
produce_equality= FALSE;
}
@ -10049,7 +10064,12 @@ Item *eliminate_item_equal(COND *cond, COND_EQUAL *upper_levels,
if (eq_item)
eq_list.push_back(eq_item);
eq_item= new Item_func_eq(item_field, current_sjm? current_sjm_head: head);
Item *head_item= current_sjm? current_sjm_head: head;
Item *head_real_item= head_item->real_item();
if (head_real_item->type() == Item::FIELD_ITEM)
head_item= head_real_item;
eq_item= new Item_func_eq(field_item->real_item(), head_item);
if (!eq_item)
return 0;
@ -10234,11 +10254,10 @@ static void update_const_equal_items(COND *cond, JOIN_TAB *tab)
if (!contained_const && item_equal->get_const())
{
/* Update keys for range analysis */
Item_equal_iterator it(*item_equal);
Item_field *item_field;
while ((item_field= it++))
Item_equal_fields_iterator it(*item_equal);
while (it++)
{
Field *field= item_field->field;
Field *field= it.get_curr_field();
JOIN_TAB *stat= field->table->reginfo.join_tab;
key_map possible_keys= field->key_start;
possible_keys.intersect(field->table->keys_in_use_for_query);

Loading…
Cancel
Save