Commit e3cecfd1 authored by unknown's avatar unknown

Fixed bug in MAX() optimization when used with JOIN and ON expressions

(Patch from 4.0.5)


mysql-test/r/group_by.result:
  Updated results
mysql-test/t/group_by.test:
  Test for bug
sql/item_cmpfunc.cc:
  Fixed bug in MAX() optimization when used with JOIN and ON expressions
sql/item_cmpfunc.h:
  Fixed bug in MAX() optimization when used with JOIN and ON expressions
sql/opt_sum.cc:
  Fixed bug in MAX() optimization when used with JOIN and ON expressions
parent a3f9f721
...@@ -84,3 +84,9 @@ xID xID1 Level ...@@ -84,3 +84,9 @@ xID xID1 Level
2 2 ** 2 2 **
3 134 *** 3 134 ***
4 185 **** 4 185 ****
pid c1id c2id value id active id active
1 1 NULL 1 1 Yes NULL NULL
1 NULL 3 3 NULL NULL 3 Yes
1 4 NULL 4 4 Yes NULL NULL
max(value)
4
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
# Test of group (Failed for Lars Hoss <lh@pbm.de>) # Test of group (Failed for Lars Hoss <lh@pbm.de>)
# #
drop table if exists t1,t2; drop table if exists t1,t2,t3;
CREATE TABLE t1 ( CREATE TABLE t1 (
spID int(10) unsigned, spID int(10) unsigned,
userID int(10) unsigned, userID int(10) unsigned,
...@@ -270,3 +270,42 @@ insert into t1 values (1,244,NULL),(2,243,NULL),(134,223,NULL),(185,186,NULL); ...@@ -270,3 +270,42 @@ insert into t1 values (1,244,NULL),(2,243,NULL),(134,223,NULL),(185,186,NULL);
select S.ID as xID, S.ID1 as xID1 from t1 as S left join t1 as yS on S.ID1 between yS.ID1 and yS.ID2; select S.ID as xID, S.ID1 as xID1 from t1 as S left join t1 as yS on S.ID1 between yS.ID1 and yS.ID2;
select S.ID as xID, S.ID1 as xID1, repeat('*',count(distinct yS.ID)) as Level from t1 as S left join t1 as yS on S.ID1 between yS.ID1 and yS.ID2 group by xID order by xID1; select S.ID as xID, S.ID1 as xID1, repeat('*',count(distinct yS.ID)) as Level from t1 as S left join t1 as yS on S.ID1 between yS.ID1 and yS.ID2 group by xID order by xID1;
drop table t1; drop table t1;
#
# Problem with MAX and LEFT JOIN
#
CREATE TABLE t1 (
pid int(11) unsigned NOT NULL default '0',
c1id int(11) unsigned default NULL,
c2id int(11) unsigned default NULL,
value int(11) unsigned NOT NULL default '0',
UNIQUE KEY pid2 (pid,c1id,c2id),
UNIQUE KEY pid (pid,value)
) TYPE=MyISAM;
INSERT INTO t1 VALUES (1, 1, NULL, 1),(1, 2, NULL, 2),(1, NULL, 3, 3),(1, 4, NULL, 4),(1, 5, NULL, 5);
CREATE TABLE t2 (
id int(11) unsigned NOT NULL default '0',
active enum('Yes','No') NOT NULL default 'Yes',
PRIMARY KEY (id)
) TYPE=MyISAM;
INSERT INTO t2 VALUES (1, 'Yes'),(2, 'No'),(4, 'Yes'),(5, 'No');
CREATE TABLE t3 (
id int(11) unsigned NOT NULL default '0',
active enum('Yes','No') NOT NULL default 'Yes',
PRIMARY KEY (id)
);
INSERT INTO t3 VALUES (3, 'Yes');
select * from t1 AS m LEFT JOIN t2 AS c1 ON m.c1id =
c1.id AND c1.active = 'Yes' LEFT JOIN t3 AS c2 ON m.c2id = c2.id AND
c2.active = 'Yes' WHERE m.pid=1 AND (c1.id IS NOT NULL OR c2.id IS NOT NULL);
select max(value) from t1 AS m LEFT JOIN t2 AS c1 ON
m.c1id = c1.id AND c1.active = 'Yes' LEFT JOIN t3 AS c2 ON m.c2id =
c2.id AND c2.active = 'Yes' WHERE m.pid=1 AND (c1.id IS NOT NULL OR c2.id IS
NOT NULL);
drop table t1,t2,t3;
...@@ -1207,6 +1207,45 @@ longlong Item_cond_or::val_int() ...@@ -1207,6 +1207,45 @@ longlong Item_cond_or::val_int()
return 0; return 0;
} }
/*
Create an AND expression from two expressions
SYNOPSIS
and_expressions()
a expression or NULL
b expression.
org_item Don't modify a if a == *org_item
If a == NULL, org_item is set to point at b,
to ensure that future calls will not modify b.
NOTES
This will not modify item pointed to by org_item or b
The idea is that one can call this in a loop and create and
'and' over all items without modifying any of the original items.
RETURN
NULL Error
Item
*/
Item *and_expressions(Item *a, Item *b, Item **org_item)
{
if (!a)
return (*org_item= (Item*) b);
if (a == *org_item)
{
Item_cond *res;
if ((res= new Item_cond_and(a, (Item*) b)))
res->used_tables_cache= a->used_tables() | b->used_tables();
return res;
}
if (((Item_cond_and*) a)->add((Item*) b))
return 0;
((Item_cond_and*) a)->used_tables_cache|= b->used_tables();
return a;
}
longlong Item_func_isnull::val_int() longlong Item_func_isnull::val_int()
{ {
/* /*
......
...@@ -573,3 +573,5 @@ inline Item *and_conds(Item *a,Item *b) ...@@ -573,3 +573,5 @@ inline Item *and_conds(Item *a,Item *b)
cond->update_used_tables(); cond->update_used_tables();
return cond; return cond;
} }
Item *and_expressions(Item *a, Item *b, Item **org_item);
...@@ -37,6 +37,19 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds) ...@@ -37,6 +37,19 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds)
bool recalc_const_item=0; bool recalc_const_item=0;
table_map removed_tables=0; table_map removed_tables=0;
Item *item; Item *item;
COND *org_conds= conds;
/* Add all ON conditions to WHERE condition */
for (TABLE_LIST *tl=tables; tl ; tl= tl->next)
{
if (tl->on_expr)
conds= and_expressions(conds, tl->on_expr, &org_conds);
}
/*
Iterate through item is select part and replace COUNT(), MIN() and MAX()
with constants (if possible)
*/
while ((item= it++)) while ((item= it++))
{ {
......
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