mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 12:02:42 +01:00
Fixed bug in MAX() optimization when used with JOIN and ON expressions
sql/item_cmpfunc.cc: Create an AND expression from two expressions sql/item_cmpfunc.h: Create an AND expression from two expressions
This commit is contained in:
parent
34d29fca2d
commit
b3a8b8bd19
5 changed files with 131 additions and 2 deletions
|
@ -1,4 +1,4 @@
|
|||
drop table if exists t1,t2;
|
||||
drop table if exists t1,t2,t3;
|
||||
CREATE TABLE t1 (
|
||||
spID int(10) unsigned,
|
||||
userID int(10) unsigned,
|
||||
|
@ -417,3 +417,38 @@ xID xID1 Level
|
|||
3 134 ***
|
||||
4 185 ****
|
||||
drop table t1;
|
||||
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);
|
||||
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
|
||||
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);
|
||||
max(value)
|
||||
4
|
||||
drop table t1,t2,t3;
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
# 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 (
|
||||
spID int(10) unsigned,
|
||||
userID int(10) unsigned,
|
||||
|
@ -312,3 +312,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, 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;
|
||||
|
||||
#
|
||||
# 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;
|
||||
|
|
|
@ -1236,6 +1236,45 @@ longlong Item_cond_or::val_int()
|
|||
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()
|
||||
{
|
||||
/*
|
||||
|
|
|
@ -621,3 +621,6 @@ public:
|
|||
longlong val_int();
|
||||
const char *func_name() const { return "xor"; }
|
||||
};
|
||||
|
||||
|
||||
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)
|
|||
bool recalc_const_item=0;
|
||||
table_map removed_tables=0;
|
||||
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++))
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue