Commit f5b51bc1 authored by Ramil Kalimullin's avatar Ramil Kalimullin

Fix for bug#49199: Optimizer handles incorrectly:

field='const1' AND field='const2' in some cases

Building multiple equality predicates containing
a constant which is compared as a datetime (with a field)
we should take this fact into account and compare the 
constant with another possible constatns as datetimes 
as well.

E.g. for the
SELECT ... WHERE a='2001-01-01' AND a='2001-01-01 00:00:00'
we should compare '2001-01-01' with '2001-01-01 00:00:00' as
datetimes but not as strings.


mysql-test/r/select.result:
  Fix for bug#49199: Optimizer handles incorrectly: 
  field='const1' AND field='const2' in some cases
    - test result.
mysql-test/t/select.test:
  Fix for bug#49199: Optimizer handles incorrectly: 
  field='const1' AND field='const2' in some cases
    - test case.
sql/item_cmpfunc.cc:
  Fix for bug#49199: Optimizer handles incorrectly: 
  field='const1' AND field='const2' in some cases
    - adding a constant to Item_equal compare it as
  a datetime value with stored one if there's a 
  date[time] field in a equality predicate.
sql/item_cmpfunc.h:
  Fix for bug#49199: Optimizer handles incorrectly: 
  field='const1' AND field='const2' in some cases
    - adding a constant to Item_equal compare it as
  a datetime value with stored one if there's a 
  date[time] field in a equality predicate.
sql/sql_select.cc:
  Fix for bug#49199: Optimizer handles incorrectly: 
  field='const1' AND field='const2' in some cases
    - adding a constant to Item_equal compare it as
  a datetime value with stored one if there's a 
  date[time] field in a equality predicate.
parent 026541c6
...@@ -4456,4 +4456,88 @@ SELECT 1 FROM t2 JOIN t1 ON 1=1 ...@@ -4456,4 +4456,88 @@ SELECT 1 FROM t2 JOIN t1 ON 1=1
WHERE a != '1' AND NOT a >= b OR NOT ROW(b,a )<> ROW(a,a); WHERE a != '1' AND NOT a >= b OR NOT ROW(b,a )<> ROW(a,a);
1 1
DROP TABLE t1,t2; DROP TABLE t1,t2;
#
# Bug #49199: Optimizer handles incorrectly:
# field='const1' AND field='const2' in some cases
CREATE TABLE t1(a DATETIME NOT NULL);
INSERT INTO t1 VALUES('2001-01-01');
SELECT * FROM t1 WHERE a='2001-01-01' AND a='2001-01-01 00:00:00';
a
2001-01-01 00:00:00
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a='2001-01-01' AND a='2001-01-01 00:00:00';
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 system NULL NULL NULL NULL 1
Warnings:
Note 1003 select '2001-01-01 00:00:00' AS `a` from `test`.`t1` where 1
DROP TABLE t1;
CREATE TABLE t1(a DATE NOT NULL);
INSERT INTO t1 VALUES('2001-01-01');
SELECT * FROM t1 WHERE a='2001-01-01' AND a='2001-01-01 00:00:00';
a
2001-01-01
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a='2001-01-01' AND a='2001-01-01 00:00:00';
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 system NULL NULL NULL NULL 1
Warnings:
Note 1003 select '2001-01-01' AS `a` from `test`.`t1` where 1
DROP TABLE t1;
CREATE TABLE t1(a TIMESTAMP NOT NULL);
INSERT INTO t1 VALUES('2001-01-01');
SELECT * FROM t1 WHERE a='2001-01-01' AND a='2001-01-01 00:00:00';
a
2001-01-01 00:00:00
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a='2001-01-01' AND a='2001-01-01 00:00:00';
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 system NULL NULL NULL NULL 1
Warnings:
Note 1003 select '2001-01-01 00:00:00' AS `a` from `test`.`t1` where 1
DROP TABLE t1;
CREATE TABLE t1(a DATETIME NOT NULL, b DATE NOT NULL);
INSERT INTO t1 VALUES('2001-01-01', '2001-01-01');
SELECT * FROM t1 WHERE a='2001-01-01' AND a=b AND b='2001-01-01 00:00:00';
a b
2001-01-01 00:00:00 2001-01-01
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a='2001-01-01' AND a=b AND b='2001-01-01 00:00:00';
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 system NULL NULL NULL NULL 1
Warnings:
Note 1003 select '2001-01-01 00:00:00' AS `a`,'2001-01-01' AS `b` from `test`.`t1` where 1
DROP TABLE t1;
CREATE TABLE t1(a DATETIME NOT NULL, b VARCHAR(20) NOT NULL);
INSERT INTO t1 VALUES('2001-01-01', '2001-01-01');
SELECT * FROM t1 WHERE a='2001-01-01' AND a=b AND b='2001-01-01 00:00:00';
a b
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a='2001-01-01' AND a=b AND b='2001-01-01 00:00:00';
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
Warnings:
Note 1003 select '2001-01-01 00:00:00' AS `a`,'2001-01-01' AS `b` from `test`.`t1` where 0
SELECT * FROM t1 WHERE a='2001-01-01 00:00:00' AND a=b AND b='2001-01-01';
a b
2001-01-01 00:00:00 2001-01-01
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a='2001-01-01 00:00:00' AND a=b AND b='2001-01-01';
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 system NULL NULL NULL NULL 1
Warnings:
Note 1003 select '2001-01-01 00:00:00' AS `a`,'2001-01-01' AS `b` from `test`.`t1` where 1
DROP TABLE t1;
CREATE TABLE t1(a DATETIME NOT NULL, b DATE NOT NULL);
INSERT INTO t1 VALUES('2001-01-01', '2001-01-01');
SELECT x.a, y.a, z.a FROM t1 x
JOIN t1 y ON x.a=y.a
JOIN t1 z ON y.a=z.a
WHERE x.a='2001-01-01' AND z.a='2001-01-01 00:00:00';
a a a
2001-01-01 00:00:00 2001-01-01 00:00:00 2001-01-01 00:00:00
EXPLAIN EXTENDED SELECT x.a, y.a, z.a FROM t1 x
JOIN t1 y ON x.a=y.a
JOIN t1 z ON y.a=z.a
WHERE x.a='2001-01-01' AND z.a='2001-01-01 00:00:00';
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE x system NULL NULL NULL NULL 1
1 SIMPLE y system NULL NULL NULL NULL 1
1 SIMPLE z system NULL NULL NULL NULL 1
Warnings:
Note 1003 select '2001-01-01 00:00:00' AS `a`,'2001-01-01 00:00:00' AS `a`,'2001-01-01 00:00:00' AS `a` from `test`.`t1` `x` join `test`.`t1` `y` join `test`.`t1` `z` where 1
End of 5.0 tests End of 5.0 tests
...@@ -3797,4 +3797,53 @@ SELECT 1 FROM t2 JOIN t1 ON 1=1 ...@@ -3797,4 +3797,53 @@ SELECT 1 FROM t2 JOIN t1 ON 1=1
DROP TABLE t1,t2; DROP TABLE t1,t2;
--echo #
--echo # Bug #49199: Optimizer handles incorrectly:
--echo # field='const1' AND field='const2' in some cases
--echo
CREATE TABLE t1(a DATETIME NOT NULL);
INSERT INTO t1 VALUES('2001-01-01');
SELECT * FROM t1 WHERE a='2001-01-01' AND a='2001-01-01 00:00:00';
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a='2001-01-01' AND a='2001-01-01 00:00:00';
DROP TABLE t1;
CREATE TABLE t1(a DATE NOT NULL);
INSERT INTO t1 VALUES('2001-01-01');
SELECT * FROM t1 WHERE a='2001-01-01' AND a='2001-01-01 00:00:00';
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a='2001-01-01' AND a='2001-01-01 00:00:00';
DROP TABLE t1;
CREATE TABLE t1(a TIMESTAMP NOT NULL);
INSERT INTO t1 VALUES('2001-01-01');
SELECT * FROM t1 WHERE a='2001-01-01' AND a='2001-01-01 00:00:00';
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a='2001-01-01' AND a='2001-01-01 00:00:00';
DROP TABLE t1;
CREATE TABLE t1(a DATETIME NOT NULL, b DATE NOT NULL);
INSERT INTO t1 VALUES('2001-01-01', '2001-01-01');
SELECT * FROM t1 WHERE a='2001-01-01' AND a=b AND b='2001-01-01 00:00:00';
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a='2001-01-01' AND a=b AND b='2001-01-01 00:00:00';
DROP TABLE t1;
CREATE TABLE t1(a DATETIME NOT NULL, b VARCHAR(20) NOT NULL);
INSERT INTO t1 VALUES('2001-01-01', '2001-01-01');
SELECT * FROM t1 WHERE a='2001-01-01' AND a=b AND b='2001-01-01 00:00:00';
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a='2001-01-01' AND a=b AND b='2001-01-01 00:00:00';
SELECT * FROM t1 WHERE a='2001-01-01 00:00:00' AND a=b AND b='2001-01-01';
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a='2001-01-01 00:00:00' AND a=b AND b='2001-01-01';
DROP TABLE t1;
CREATE TABLE t1(a DATETIME NOT NULL, b DATE NOT NULL);
INSERT INTO t1 VALUES('2001-01-01', '2001-01-01');
SELECT x.a, y.a, z.a FROM t1 x
JOIN t1 y ON x.a=y.a
JOIN t1 z ON y.a=z.a
WHERE x.a='2001-01-01' AND z.a='2001-01-01 00:00:00';
EXPLAIN EXTENDED SELECT x.a, y.a, z.a FROM t1 x
JOIN t1 y ON x.a=y.a
JOIN t1 z ON y.a=z.a
WHERE x.a='2001-01-01' AND z.a='2001-01-01 00:00:00';
--echo End of 5.0 tests --echo End of 5.0 tests
...@@ -4903,7 +4903,8 @@ Item *Item_bool_rowready_func2::negated_item() ...@@ -4903,7 +4903,8 @@ Item *Item_bool_rowready_func2::negated_item()
} }
Item_equal::Item_equal(Item_field *f1, Item_field *f2) Item_equal::Item_equal(Item_field *f1, Item_field *f2)
: Item_bool_func(), const_item(0), eval_item(0), cond_false(0) : Item_bool_func(), const_item(0), eval_item(0), cond_false(0),
compare_as_dates(FALSE)
{ {
const_item_cache= 0; const_item_cache= 0;
fields.push_back(f1); fields.push_back(f1);
...@@ -4916,6 +4917,7 @@ Item_equal::Item_equal(Item *c, Item_field *f) ...@@ -4916,6 +4917,7 @@ Item_equal::Item_equal(Item *c, Item_field *f)
const_item_cache= 0; const_item_cache= 0;
fields.push_back(f); fields.push_back(f);
const_item= c; const_item= c;
compare_as_dates= f->is_datetime();
} }
...@@ -4930,9 +4932,45 @@ Item_equal::Item_equal(Item_equal *item_equal) ...@@ -4930,9 +4932,45 @@ Item_equal::Item_equal(Item_equal *item_equal)
fields.push_back(item); fields.push_back(item);
} }
const_item= item_equal->const_item; const_item= item_equal->const_item;
compare_as_dates= item_equal->compare_as_dates;
cond_false= item_equal->cond_false; cond_false= item_equal->cond_false;
} }
void Item_equal::compare_const(Item *c)
{
if (compare_as_dates)
{
cmp.set_datetime_cmp_func(&c, &const_item);
cond_false= cmp.compare();
}
else
{
Item_func_eq *func= new Item_func_eq(c, const_item);
func->set_cmp_func();
func->quick_fix_field();
cond_false= !func->val_int();
}
if (cond_false)
const_item_cache= 1;
}
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) void Item_equal::add(Item *c)
{ {
if (cond_false) if (cond_false)
...@@ -4942,11 +4980,7 @@ void Item_equal::add(Item *c) ...@@ -4942,11 +4980,7 @@ void Item_equal::add(Item *c)
const_item= c; const_item= c;
return; return;
} }
Item_func_eq *func= new Item_func_eq(c, const_item); compare_const(c);
func->set_cmp_func();
func->quick_fix_field();
if ((cond_false= !func->val_int()))
const_item_cache= 1;
} }
void Item_equal::add(Item_field *f) void Item_equal::add(Item_field *f)
......
...@@ -1477,7 +1477,9 @@ class Item_equal: public Item_bool_func ...@@ -1477,7 +1477,9 @@ class Item_equal: public Item_bool_func
List<Item_field> fields; /* list of equal field items */ List<Item_field> fields; /* list of equal field items */
Item *const_item; /* optional constant item equal to fields items */ Item *const_item; /* optional constant item equal to fields items */
cmp_item *eval_item; cmp_item *eval_item;
Arg_comparator cmp;
bool cond_false; bool cond_false;
bool compare_as_dates;
public: public:
inline Item_equal() inline Item_equal()
: Item_bool_func(), const_item(0), eval_item(0), cond_false(0) : Item_bool_func(), const_item(0), eval_item(0), cond_false(0)
...@@ -1486,6 +1488,8 @@ class Item_equal: public Item_bool_func ...@@ -1486,6 +1488,8 @@ class Item_equal: public Item_bool_func
Item_equal(Item *c, Item_field *f); 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; } 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 *c);
void add(Item_field *f); void add(Item_field *f);
uint members(); uint members();
......
...@@ -7237,7 +7237,7 @@ static bool check_simple_equality(Item *left_item, Item *right_item, ...@@ -7237,7 +7237,7 @@ static bool check_simple_equality(Item *left_item, Item *right_item,
already contains a constant and its value is not equal to already contains a constant and its value is not equal to
the value of const_item. the value of const_item.
*/ */
item_equal->add(const_item); item_equal->add(const_item, field_item);
} }
else else
{ {
......
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