Fix for BUG#10095: {wrong query results because of incorrect constant propagation}
The problem: base_list::remove didn't modify base_list::last when removing the last list element. The fix: If we remove the last element, find the element before it (by walking from the beginning of the list) and set base_list::last accordingly. The list gets corrupted in both 4.0 and 4.1. There are no visible problems in current 4.1 because current 4.1 doesn't call where_cond->fix_fields() after constant propagation step. mysql-test/r/select.result: Testcase for BUG#10095 mysql-test/t/select.test: Testcase for BUG#10095 sql/sql_list.h: Fix for BUG#10095: {wrong query results because of incorrect constant propagation} The problem: base_list::remove didn't modify base_list::last when removing the last list element. The fix: If we remove the last element, find the element before it (by walking from the beginning of the list) and set base_list::last accordingly.
This commit is contained in:
parent
ce41e0de81
commit
06736ab48a
@ -2377,3 +2377,57 @@ table type possible_keys key key_len ref rows Extra
|
|||||||
t1 ALL NULL NULL NULL NULL 5
|
t1 ALL NULL NULL NULL NULL 5
|
||||||
t2 ref a a 23 t1.a 5
|
t2 ref a a 23 t1.a 5
|
||||||
DROP TABLE t1, t2;
|
DROP TABLE t1, t2;
|
||||||
|
CREATE TABLE t1 (
|
||||||
|
kunde_intern_id int(10) unsigned NOT NULL default '0',
|
||||||
|
kunde_id int(10) unsigned NOT NULL default '0',
|
||||||
|
FK_firma_id int(10) unsigned NOT NULL default '0',
|
||||||
|
aktuell enum('Ja','Nein') NOT NULL default 'Ja',
|
||||||
|
vorname varchar(128) NOT NULL default '',
|
||||||
|
nachname varchar(128) NOT NULL default '',
|
||||||
|
geloescht enum('Ja','Nein') NOT NULL default 'Nein',
|
||||||
|
firma varchar(128) NOT NULL default ''
|
||||||
|
);
|
||||||
|
INSERT INTO t1 VALUES
|
||||||
|
(3964,3051,1,'Ja','Vorname1','1Nachname','Nein','Print Schau XXXX'),
|
||||||
|
(3965,3051111,1,'Ja','Vorname1111','1111Nachname','Nein','Print Schau XXXX');
|
||||||
|
SELECT kunde_id ,FK_firma_id ,aktuell, vorname, nachname, geloescht FROM t1
|
||||||
|
WHERE
|
||||||
|
(
|
||||||
|
(
|
||||||
|
( '' != '' AND firma LIKE CONCAT('%', '', '%'))
|
||||||
|
OR
|
||||||
|
(vorname LIKE CONCAT('%', 'Vorname1', '%') AND
|
||||||
|
nachname LIKE CONCAT('%', '1Nachname', '%') AND
|
||||||
|
'Vorname1' != '' AND 'xxxx' != '')
|
||||||
|
)
|
||||||
|
AND
|
||||||
|
(
|
||||||
|
aktuell = 'Ja' AND geloescht = 'Nein' AND FK_firma_id = 2
|
||||||
|
)
|
||||||
|
)
|
||||||
|
;
|
||||||
|
kunde_id FK_firma_id aktuell vorname nachname geloescht
|
||||||
|
SELECT kunde_id ,FK_firma_id ,aktuell, vorname, nachname,
|
||||||
|
geloescht FROM t1
|
||||||
|
WHERE
|
||||||
|
(
|
||||||
|
(
|
||||||
|
aktuell = 'Ja' AND geloescht = 'Nein' AND FK_firma_id = 2
|
||||||
|
)
|
||||||
|
AND
|
||||||
|
(
|
||||||
|
( '' != '' AND firma LIKE CONCAT('%', '', '%') )
|
||||||
|
OR
|
||||||
|
( vorname LIKE CONCAT('%', 'Vorname1', '%') AND
|
||||||
|
nachname LIKE CONCAT('%', '1Nachname', '%') AND 'Vorname1' != '' AND
|
||||||
|
'xxxx' != '')
|
||||||
|
)
|
||||||
|
)
|
||||||
|
;
|
||||||
|
kunde_id FK_firma_id aktuell vorname nachname geloescht
|
||||||
|
SELECT COUNT(*) FROM t1 WHERE
|
||||||
|
( 0 OR (vorname LIKE '%Vorname1%' AND nachname LIKE '%1Nachname%' AND 1))
|
||||||
|
AND FK_firma_id = 2;
|
||||||
|
COUNT(*)
|
||||||
|
0
|
||||||
|
drop table t1;
|
||||||
|
@ -1924,3 +1924,62 @@ EXPLAIN SELECT * FROM t1 LEFT JOIN t2 USE INDEX (a) ON t1.a=t2.a;
|
|||||||
EXPLAIN SELECT * FROM t1 LEFT JOIN t2 FORCE INDEX (a) ON t1.a=t2.a;
|
EXPLAIN SELECT * FROM t1 LEFT JOIN t2 FORCE INDEX (a) ON t1.a=t2.a;
|
||||||
|
|
||||||
DROP TABLE t1, t2;
|
DROP TABLE t1, t2;
|
||||||
|
|
||||||
|
# Test for BUG#10095
|
||||||
|
CREATE TABLE t1 (
|
||||||
|
kunde_intern_id int(10) unsigned NOT NULL default '0',
|
||||||
|
kunde_id int(10) unsigned NOT NULL default '0',
|
||||||
|
FK_firma_id int(10) unsigned NOT NULL default '0',
|
||||||
|
aktuell enum('Ja','Nein') NOT NULL default 'Ja',
|
||||||
|
vorname varchar(128) NOT NULL default '',
|
||||||
|
nachname varchar(128) NOT NULL default '',
|
||||||
|
geloescht enum('Ja','Nein') NOT NULL default 'Nein',
|
||||||
|
firma varchar(128) NOT NULL default ''
|
||||||
|
);
|
||||||
|
|
||||||
|
INSERT INTO t1 VALUES
|
||||||
|
(3964,3051,1,'Ja','Vorname1','1Nachname','Nein','Print Schau XXXX'),
|
||||||
|
(3965,3051111,1,'Ja','Vorname1111','1111Nachname','Nein','Print Schau XXXX');
|
||||||
|
|
||||||
|
|
||||||
|
SELECT kunde_id ,FK_firma_id ,aktuell, vorname, nachname, geloescht FROM t1
|
||||||
|
WHERE
|
||||||
|
(
|
||||||
|
(
|
||||||
|
( '' != '' AND firma LIKE CONCAT('%', '', '%'))
|
||||||
|
OR
|
||||||
|
(vorname LIKE CONCAT('%', 'Vorname1', '%') AND
|
||||||
|
nachname LIKE CONCAT('%', '1Nachname', '%') AND
|
||||||
|
'Vorname1' != '' AND 'xxxx' != '')
|
||||||
|
)
|
||||||
|
AND
|
||||||
|
(
|
||||||
|
aktuell = 'Ja' AND geloescht = 'Nein' AND FK_firma_id = 2
|
||||||
|
)
|
||||||
|
)
|
||||||
|
;
|
||||||
|
|
||||||
|
SELECT kunde_id ,FK_firma_id ,aktuell, vorname, nachname,
|
||||||
|
geloescht FROM t1
|
||||||
|
WHERE
|
||||||
|
(
|
||||||
|
(
|
||||||
|
aktuell = 'Ja' AND geloescht = 'Nein' AND FK_firma_id = 2
|
||||||
|
)
|
||||||
|
AND
|
||||||
|
(
|
||||||
|
( '' != '' AND firma LIKE CONCAT('%', '', '%') )
|
||||||
|
OR
|
||||||
|
( vorname LIKE CONCAT('%', 'Vorname1', '%') AND
|
||||||
|
nachname LIKE CONCAT('%', '1Nachname', '%') AND 'Vorname1' != '' AND
|
||||||
|
'xxxx' != '')
|
||||||
|
)
|
||||||
|
)
|
||||||
|
;
|
||||||
|
|
||||||
|
SELECT COUNT(*) FROM t1 WHERE
|
||||||
|
( 0 OR (vorname LIKE '%Vorname1%' AND nachname LIKE '%1Nachname%' AND 1))
|
||||||
|
AND FK_firma_id = 2;
|
||||||
|
|
||||||
|
drop table t1;
|
||||||
|
|
||||||
|
@ -110,10 +110,32 @@ public:
|
|||||||
void remove(list_node **prev)
|
void remove(list_node **prev)
|
||||||
{
|
{
|
||||||
list_node *node=(*prev)->next;
|
list_node *node=(*prev)->next;
|
||||||
|
if (&(*prev)->next == last)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
We're removing the last element from the list. Adjust "last" to point
|
||||||
|
to the previous element.
|
||||||
|
The other way to fix this would be to change this function to
|
||||||
|
remove_next() and have base_list_iterator save ptr to previous node
|
||||||
|
(one extra assignment in iterator++) but as the remove() of the last
|
||||||
|
element isn't a common operation it's faster to just walk through the
|
||||||
|
list from the beginning here.
|
||||||
|
*/
|
||||||
|
list_node *cur= first;
|
||||||
|
if (cur == *prev)
|
||||||
|
{
|
||||||
|
last= &first;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
while (cur->next != *prev)
|
||||||
|
cur= cur->next;
|
||||||
|
last= &(cur->next);
|
||||||
|
}
|
||||||
|
}
|
||||||
delete *prev;
|
delete *prev;
|
||||||
*prev=node;
|
*prev=node;
|
||||||
if (!--elements)
|
elements--;
|
||||||
last= &first;
|
|
||||||
}
|
}
|
||||||
inline void *pop(void)
|
inline void *pop(void)
|
||||||
{
|
{
|
||||||
@ -130,6 +152,54 @@ public:
|
|||||||
inline list_node *last_ref() { return &end_of_list; }
|
inline list_node *last_ref() { return &end_of_list; }
|
||||||
friend class base_list_iterator;
|
friend class base_list_iterator;
|
||||||
|
|
||||||
|
#ifdef LIST_EXTRA_DEBUG
|
||||||
|
/*
|
||||||
|
Check list invariants and print results into trace. Invariants are:
|
||||||
|
- (*last) points to end_of_list
|
||||||
|
- There are no NULLs in the list.
|
||||||
|
- base_list::elements is the number of elements in the list.
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
check_list()
|
||||||
|
name Name to print to trace file
|
||||||
|
|
||||||
|
RETURN
|
||||||
|
1 The list is Ok.
|
||||||
|
0 List invariants are not met.
|
||||||
|
*/
|
||||||
|
|
||||||
|
bool check_list(const char *name)
|
||||||
|
{
|
||||||
|
base_list *list= this;
|
||||||
|
list_node *node= first;
|
||||||
|
uint cnt= 0;
|
||||||
|
|
||||||
|
while (node->next != &end_of_list)
|
||||||
|
{
|
||||||
|
if (!node->info)
|
||||||
|
{
|
||||||
|
DBUG_PRINT("list_invariants",("%s: error: NULL element in the list",
|
||||||
|
name));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
node= node->next;
|
||||||
|
cnt++;
|
||||||
|
}
|
||||||
|
if (last != &(node->next))
|
||||||
|
{
|
||||||
|
DBUG_PRINT("list_invariants", ("%s: error: wrong last pointer", name));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
if (cnt+1 != elements)
|
||||||
|
{
|
||||||
|
DBUG_PRINT("list_invariants", ("%s: error: wrong element count", name));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
DBUG_PRINT("list_invariants", ("%s: list is ok", name));
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
#endif // LIST_EXTRA_DEBUG
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void after(void *info,list_node *node)
|
void after(void *info,list_node *node)
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user