mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +03:00
Fixed LP bug #874006.
This bug manifested itself with queries containing non-correlated IN subqueries over materialized views/derived tables. The bug happened because the code of the function generate_derived_keys did not take into account that the function could be called twice when the optimizer was deciding whether in-exist transformation should be applied.
This commit is contained in:
@ -781,7 +781,7 @@ SELECT * FROM t3
|
|||||||
WHERE t3.a IN (SELECT v1.a FROM v1, t2 WHERE t2.a = v1.b);
|
WHERE t3.a IN (SELECT v1.a FROM v1, t2 WHERE t2.a = v1.b);
|
||||||
id select_type table type possible_keys key key_len ref rows filtered Extra
|
id select_type table type possible_keys key key_len ref rows filtered Extra
|
||||||
1 PRIMARY t3 ALL NULL NULL NULL NULL 4 100.00 Using where
|
1 PRIMARY t3 ALL NULL NULL NULL NULL 4 100.00 Using where
|
||||||
2 DEPENDENT SUBQUERY <derived3> ref key0 key0 5 func 2 100.00
|
2 DEPENDENT SUBQUERY <derived3> ref key1 key1 5 func 2 100.00
|
||||||
2 DEPENDENT SUBQUERY t2 ALL NULL NULL NULL NULL 3 100.00 Using where; Using join buffer (flat, BNL join)
|
2 DEPENDENT SUBQUERY t2 ALL NULL NULL NULL NULL 3 100.00 Using where; Using join buffer (flat, BNL join)
|
||||||
3 DERIVED t1 ALL NULL NULL NULL NULL 3 100.00 Using temporary; Using filesort
|
3 DERIVED t1 ALL NULL NULL NULL NULL 3 100.00 Using temporary; Using filesort
|
||||||
Warnings:
|
Warnings:
|
||||||
@ -1462,4 +1462,46 @@ b a
|
|||||||
9 2
|
9 2
|
||||||
7 2
|
7 2
|
||||||
DROP TABLE t1,t2,t3;
|
DROP TABLE t1,t2,t3;
|
||||||
|
#
|
||||||
|
# LP bug #874006: materialized view used in IN subquery
|
||||||
|
#
|
||||||
|
CREATE TABLE t3 (a int NOT NULL, b varchar(1), c varchar(1));
|
||||||
|
INSERT INTO t3 VALUES (19,NULL,NULL), (20,'r','r');
|
||||||
|
CREATE TABLE t1 (a int, b varchar(1) , c varchar(1));
|
||||||
|
INSERT INTO t1 VALUES (1,NULL,NULL), (5,'r','r'), (7,'y','y');
|
||||||
|
CREATE TABLE t2 (a int NOT NULL , b int, c varchar(1));
|
||||||
|
INSERT INTO t2 VALUES (4,3,'r');
|
||||||
|
CREATE ALGORITHM=TEMPTABLE VIEW v1 AS SELECT * FROM t1;
|
||||||
|
SET SESSION optimizer_switch='derived_with_keys=off';
|
||||||
|
EXPLAIN
|
||||||
|
SELECT * FROM t3
|
||||||
|
WHERE t3.b IN (SELECT v1.b FROM v1, t2
|
||||||
|
WHERE t2.c = v1.c AND t2.c = v1.b AND v1.b = t3.c);
|
||||||
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
|
1 PRIMARY t3 ALL NULL NULL NULL NULL 2 Using where
|
||||||
|
2 DEPENDENT SUBQUERY t2 system NULL NULL NULL NULL 1
|
||||||
|
2 DEPENDENT SUBQUERY <derived3> ALL NULL NULL NULL NULL 3 Using where
|
||||||
|
3 DERIVED t1 ALL NULL NULL NULL NULL 3
|
||||||
|
SELECT * FROM t3
|
||||||
|
WHERE t3.b IN (SELECT v1.b FROM v1, t2
|
||||||
|
WHERE t2.c = v1.c AND t2.c = v1.b AND v1.b = t3.c);
|
||||||
|
a b c
|
||||||
|
20 r r
|
||||||
|
SET SESSION optimizer_switch='derived_with_keys=on';
|
||||||
|
EXPLAIN
|
||||||
|
SELECT * FROM t3
|
||||||
|
WHERE t3.b IN (SELECT v1.b FROM v1, t2
|
||||||
|
WHERE t2.c = v1.c AND t2.c = v1.b AND v1.b = t3.c);
|
||||||
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
|
1 PRIMARY t3 ALL NULL NULL NULL NULL 2 Using where
|
||||||
|
2 DEPENDENT SUBQUERY t2 system NULL NULL NULL NULL 1
|
||||||
|
2 DEPENDENT SUBQUERY <derived3> ref key1 key1 10 const,const 0 Using where
|
||||||
|
3 DERIVED t1 ALL NULL NULL NULL NULL 3
|
||||||
|
SELECT * FROM t3
|
||||||
|
WHERE t3.b IN (SELECT v1.b FROM v1, t2
|
||||||
|
WHERE t2.c = v1.c AND t2.c = v1.b AND v1.b = t3.c);
|
||||||
|
a b c
|
||||||
|
20 r r
|
||||||
|
DROP VIEW v1;
|
||||||
|
DROP TABLE t1,t2,t3;
|
||||||
set optimizer_switch=@exit_optimizer_switch;
|
set optimizer_switch=@exit_optimizer_switch;
|
||||||
|
@ -910,5 +910,42 @@ SELECT * FROM t1 , t2
|
|||||||
|
|
||||||
DROP TABLE t1,t2,t3;
|
DROP TABLE t1,t2,t3;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # LP bug #874006: materialized view used in IN subquery
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
CREATE TABLE t3 (a int NOT NULL, b varchar(1), c varchar(1));
|
||||||
|
INSERT INTO t3 VALUES (19,NULL,NULL), (20,'r','r');
|
||||||
|
|
||||||
|
CREATE TABLE t1 (a int, b varchar(1) , c varchar(1));
|
||||||
|
INSERT INTO t1 VALUES (1,NULL,NULL), (5,'r','r'), (7,'y','y');
|
||||||
|
|
||||||
|
CREATE TABLE t2 (a int NOT NULL , b int, c varchar(1));
|
||||||
|
INSERT INTO t2 VALUES (4,3,'r');
|
||||||
|
|
||||||
|
CREATE ALGORITHM=TEMPTABLE VIEW v1 AS SELECT * FROM t1;
|
||||||
|
|
||||||
|
SET SESSION optimizer_switch='derived_with_keys=off';
|
||||||
|
EXPLAIN
|
||||||
|
SELECT * FROM t3
|
||||||
|
WHERE t3.b IN (SELECT v1.b FROM v1, t2
|
||||||
|
WHERE t2.c = v1.c AND t2.c = v1.b AND v1.b = t3.c);
|
||||||
|
SELECT * FROM t3
|
||||||
|
WHERE t3.b IN (SELECT v1.b FROM v1, t2
|
||||||
|
WHERE t2.c = v1.c AND t2.c = v1.b AND v1.b = t3.c);
|
||||||
|
|
||||||
|
SET SESSION optimizer_switch='derived_with_keys=on';
|
||||||
|
EXPLAIN
|
||||||
|
SELECT * FROM t3
|
||||||
|
WHERE t3.b IN (SELECT v1.b FROM v1, t2
|
||||||
|
WHERE t2.c = v1.c AND t2.c = v1.b AND v1.b = t3.c);
|
||||||
|
SELECT * FROM t3
|
||||||
|
WHERE t3.b IN (SELECT v1.b FROM v1, t2
|
||||||
|
WHERE t2.c = v1.c AND t2.c = v1.b AND v1.b = t3.c);
|
||||||
|
|
||||||
|
DROP VIEW v1;
|
||||||
|
DROP TABLE t1,t2,t3;
|
||||||
|
|
||||||
|
|
||||||
# The following command must be the last one the file
|
# The following command must be the last one the file
|
||||||
set optimizer_switch=@exit_optimizer_switch;
|
set optimizer_switch=@exit_optimizer_switch;
|
||||||
|
@ -8413,17 +8413,17 @@ bool generate_derived_keys_for_table(KEYUSE *keyuse, uint count, uint keys)
|
|||||||
TABLE *table= keyuse->table;
|
TABLE *table= keyuse->table;
|
||||||
if (table->alloc_keys(keys))
|
if (table->alloc_keys(keys))
|
||||||
return TRUE;
|
return TRUE;
|
||||||
uint keyno= 0;
|
uint key_count= 0;
|
||||||
KEYUSE *first_keyuse= keyuse;
|
KEYUSE *first_keyuse= keyuse;
|
||||||
uint prev_part= keyuse->keypart;
|
uint prev_part= keyuse->keypart;
|
||||||
uint parts= 0;
|
uint parts= 0;
|
||||||
uint i= 0;
|
uint i= 0;
|
||||||
|
|
||||||
for ( ; i < count && keyno < keys; )
|
for ( ; i < count && key_count < keys; )
|
||||||
{
|
{
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
keyuse->key= keyno;
|
keyuse->key= table->s->keys;
|
||||||
keyuse->keypart_map= (key_part_map) (1 << parts);
|
keyuse->keypart_map= (key_part_map) (1 << parts);
|
||||||
keyuse++;
|
keyuse++;
|
||||||
i++;
|
i++;
|
||||||
@ -8437,14 +8437,14 @@ bool generate_derived_keys_for_table(KEYUSE *keyuse, uint count, uint keys)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (table->add_tmp_key(keyno, parts,
|
if (table->add_tmp_key(table->s->keys, parts,
|
||||||
get_next_field_for_derived_key,
|
get_next_field_for_derived_key,
|
||||||
(uchar *) &first_keyuse,
|
(uchar *) &first_keyuse,
|
||||||
FALSE))
|
FALSE))
|
||||||
return TRUE;
|
return TRUE;
|
||||||
table->reginfo.join_tab->keys.set_bit(keyno);
|
table->reginfo.join_tab->keys.set_bit(table->s->keys);
|
||||||
first_keyuse= keyuse;
|
first_keyuse= keyuse;
|
||||||
keyno++;
|
key_count++;
|
||||||
parts= 0;
|
parts= 0;
|
||||||
prev_part= keyuse->keypart;
|
prev_part= keyuse->keypart;
|
||||||
}
|
}
|
||||||
@ -8471,12 +8471,23 @@ bool generate_derived_keys(DYNAMIC_ARRAY *keyuse_array)
|
|||||||
TABLE_LIST *derived= NULL;
|
TABLE_LIST *derived= NULL;
|
||||||
if (keyuse->table != prev_table)
|
if (keyuse->table != prev_table)
|
||||||
derived= keyuse->table->pos_in_table_list;
|
derived= keyuse->table->pos_in_table_list;
|
||||||
while (derived && derived->is_materialized_derived() &&
|
while (derived && derived->is_materialized_derived())
|
||||||
keyuse->key == MAX_KEY)
|
|
||||||
{
|
{
|
||||||
if (keyuse->table != prev_table)
|
if (keyuse->table != prev_table)
|
||||||
{
|
{
|
||||||
prev_table= keyuse->table;
|
prev_table= keyuse->table;
|
||||||
|
while (keyuse->table == prev_table && keyuse->key != MAX_KEY)
|
||||||
|
{
|
||||||
|
keyuse++;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
if (keyuse->table != prev_table)
|
||||||
|
{
|
||||||
|
keyuse--;
|
||||||
|
i--;
|
||||||
|
derived= NULL;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
first_table_keyuse= keyuse;
|
first_table_keyuse= keyuse;
|
||||||
last_used_tables= keyuse->used_tables;
|
last_used_tables= keyuse->used_tables;
|
||||||
count= 0;
|
count= 0;
|
||||||
@ -8489,11 +8500,13 @@ bool generate_derived_keys(DYNAMIC_ARRAY *keyuse_array)
|
|||||||
}
|
}
|
||||||
count++;
|
count++;
|
||||||
keyuse++;
|
keyuse++;
|
||||||
|
i++;
|
||||||
if (keyuse->table != prev_table)
|
if (keyuse->table != prev_table)
|
||||||
{
|
{
|
||||||
if (generate_derived_keys_for_table(first_table_keyuse, count, ++keys))
|
if (generate_derived_keys_for_table(first_table_keyuse, count, ++keys))
|
||||||
return TRUE;
|
return TRUE;
|
||||||
keyuse--;
|
keyuse--;
|
||||||
|
i--;
|
||||||
derived= NULL;
|
derived= NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -8524,12 +8537,13 @@ void JOIN::drop_unused_derived_keys()
|
|||||||
TABLE *table=tab->table;
|
TABLE *table=tab->table;
|
||||||
if (!table)
|
if (!table)
|
||||||
continue;
|
continue;
|
||||||
if (!table->pos_in_table_list->is_materialized_derived() ||
|
if (!table->pos_in_table_list->is_materialized_derived())
|
||||||
table->max_keys <= 1)
|
|
||||||
continue;
|
continue;
|
||||||
table->use_index(tab->ref.key);
|
if (table->max_keys > 1)
|
||||||
|
table->use_index(tab->ref.key);
|
||||||
if (table->s->keys)
|
if (table->s->keys)
|
||||||
tab->ref.key= 0;
|
tab->ref.key= 0;
|
||||||
|
tab->keys= (key_map) (table->s->keys ? 1 : 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
13
sql/table.cc
13
sql/table.cc
@ -5220,10 +5220,11 @@ void st_table::mark_virtual_columns_for_write(bool insert_fl)
|
|||||||
@brief
|
@brief
|
||||||
Allocate space for keys
|
Allocate space for keys
|
||||||
|
|
||||||
@param key_count number of keys to allocate
|
@param key_count number of keys to allocate additionally
|
||||||
|
|
||||||
@details
|
@details
|
||||||
The function allocates memory to fit 'key_count' keys for this table.
|
The function allocates memory to fit additionally 'key_count' keys
|
||||||
|
for this table.
|
||||||
|
|
||||||
@return FALSE space was successfully allocated
|
@return FALSE space was successfully allocated
|
||||||
@return TRUE an error occur
|
@return TRUE an error occur
|
||||||
@ -5231,9 +5232,11 @@ void st_table::mark_virtual_columns_for_write(bool insert_fl)
|
|||||||
|
|
||||||
bool TABLE::alloc_keys(uint key_count)
|
bool TABLE::alloc_keys(uint key_count)
|
||||||
{
|
{
|
||||||
key_info= s->key_info= (KEY*) alloc_root(&mem_root, sizeof(KEY)*key_count);
|
key_info= (KEY*) alloc_root(&mem_root, sizeof(KEY)*(s->keys+key_count));
|
||||||
s->keys= 0;
|
if (s->keys)
|
||||||
max_keys= key_count;
|
memmove(key_info, s->key_info, sizeof(KEY)*s->keys);
|
||||||
|
s->key_info= key_info;
|
||||||
|
max_keys= s->keys+key_count;
|
||||||
return !(key_info);
|
return !(key_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user