Commit 6cb896a6 authored by Galina Shalygina's avatar Galina Shalygina

MDEV-29363: Constant subquery causing a crash in pushdown optimization

The crash is caused by the attempt to refix the constant subquery during
pushdown from HAVING into WHERE optimization.

Every condition that is going to be pushed into WHERE clause is first
cleaned up, then refixed. Constant subqueries are not cleaned or refixed
because they will remain the same after refixing, so this complicated
procedure can be omitted for them (introduced in MDEV-21184).
Constant subqueries are marked with flag IMMUTABLE_FL, that helps to miss
the cleanup stage for them. Also they are marked as fixed, so refixing is
also not done for them.
Because of the multiple equality propagation several references to the same
constant subquery can exist in the condition that is going to be pushed
into WHERE. Before this patch, the problem appeared in the following way.
After the first reference to the constant subquery is processed, the flag
IMMUTABLE_FL for the constant subquery is disabled.
So, when the second reference to this constant subquery is processed, the
flag is already disabled and the subquery goes through the procedure of
cleaning and refixing. That causes a crash.

To solve this problem, IMMUTABLE_FL should be disabled only after all
references to the constant subquery are processed, so after the whole
condition that is going to be pushed is cleaned up and refixed.

Approved by Igor Babaev <igor@maridb.com>
parent a4ef05d0
......@@ -4982,3 +4982,114 @@ a
0
DROP TABLE t1;
End of 10.4 tests
#
# MDEV-29363: Constant subquery causing a crash in pushdown optimization
#
CREATE TABLE t1 (a INT, b INT, c INT);
INSERT INTO t1 VALUES (3, 3, 4), (NULL, NULL, 2);
EXPLAIN FORMAT=JSON SELECT a,b,c FROM t1 GROUP BY a,b,c
HAVING a = (SELECT MIN(b) AS min_b FROM t1) and (a = b or a = c);
EXPLAIN
{
"query_block": {
"select_id": 1,
"filesort": {
"sort_key": "t1.b, t1.c",
"temporary_table": {
"table": {
"table_name": "t1",
"access_type": "ALL",
"rows": 2,
"filtered": 100,
"attached_condition": "t1.a = (subquery#2) and (t1.b = (subquery#2) or t1.c = (subquery#2))"
},
"subqueries": [
{
"query_block": {
"select_id": 2,
"table": {
"table_name": "t1",
"access_type": "ALL",
"rows": 2,
"filtered": 100
}
}
}
]
}
}
}
}
SELECT a,b,c FROM t1 GROUP BY a,b,c
HAVING a = (SELECT MIN(b) AS min_b FROM t1) and (a = b or a = c);
a b c
3 3 4
EXPLAIN FORMAT=JSON SELECT a FROM t1 GROUP BY a,b
HAVING a = (SELECT MIN(a) AS min_a FROM t1) AND (a = 3 or a > b);
EXPLAIN
{
"query_block": {
"select_id": 1,
"filesort": {
"sort_key": "t1.b",
"temporary_table": {
"table": {
"table_name": "t1",
"access_type": "ALL",
"rows": 2,
"filtered": 100,
"attached_condition": "t1.a = (subquery#2) and (1 or (subquery#2) > t1.b)"
},
"subqueries": [
{
"query_block": {
"select_id": 2,
"table": {
"table_name": "t1",
"access_type": "ALL",
"rows": 2,
"filtered": 100
}
}
}
]
}
}
}
}
SELECT a FROM t1 GROUP BY a,b
HAVING a = (SELECT MIN(a) AS min_a FROM t1) AND (a = 3 or a > b);
a
3
DROP TABLE t1;
#
# MDEV-32424: Pushdown: server crashes at JOIN::save_explain_data()
# (fixed by the patch for MDEV-29363)
#
CREATE TABLE t1 (a INT, b INT, c INT);
INSERT INTO t1 VALUES (1, 1, 3), (3, 2, 3);
SELECT a,b,c FROM t1 GROUP BY a,b,c
HAVING a = (SELECT MIN(b) AS min_b FROM t1) and a IN (b, c);
a b c
1 1 3
DROP TABLE t1;
#
# MDEV-32293: Pushdown: server crashes at check_simple_equality()
# (fixed by the patch for MDEV-29363)
#
CREATE VIEW v1 AS SELECT 1 AS a;
SELECT * FROM v1 GROUP BY a HAVING a = 'b' AND a = (a IS NULL);
a
Warnings:
Warning 1292 Truncated incorrect DECIMAL value: 'b'
DROP VIEW v1;
#
# MDEV-32304: Pushdown: server crashes at Item_field::used_tables()
# (fixed by the patch for MDEV-29363)
#
CREATE VIEW v1 AS SELECT 1 AS a;
SELECT * FROM v1
GROUP BY a HAVING a = (a IS NULL OR a IS NULL);
a
DROP VIEW v1;
End of 10.5 tests
......@@ -1498,3 +1498,64 @@ SELECT a FROM t1 GROUP BY a HAVING NOT a;
DROP TABLE t1;
--echo End of 10.4 tests
--echo #
--echo # MDEV-29363: Constant subquery causing a crash in pushdown optimization
--echo #
CREATE TABLE t1 (a INT, b INT, c INT);
INSERT INTO t1 VALUES (3, 3, 4), (NULL, NULL, 2);
let $q=
SELECT a,b,c FROM t1 GROUP BY a,b,c
HAVING a = (SELECT MIN(b) AS min_b FROM t1) and (a = b or a = c);
eval EXPLAIN FORMAT=JSON $q;
eval $q;
let $q=
SELECT a FROM t1 GROUP BY a,b
HAVING a = (SELECT MIN(a) AS min_a FROM t1) AND (a = 3 or a > b);
eval EXPLAIN FORMAT=JSON $q;
eval $q;
DROP TABLE t1;
--echo #
--echo # MDEV-32424: Pushdown: server crashes at JOIN::save_explain_data()
--echo # (fixed by the patch for MDEV-29363)
--echo #
CREATE TABLE t1 (a INT, b INT, c INT);
INSERT INTO t1 VALUES (1, 1, 3), (3, 2, 3);
SELECT a,b,c FROM t1 GROUP BY a,b,c
HAVING a = (SELECT MIN(b) AS min_b FROM t1) and a IN (b, c);
DROP TABLE t1;
--echo #
--echo # MDEV-32293: Pushdown: server crashes at check_simple_equality()
--echo # (fixed by the patch for MDEV-29363)
--echo #
CREATE VIEW v1 AS SELECT 1 AS a;
SELECT * FROM v1 GROUP BY a HAVING a = 'b' AND a = (a IS NULL);
DROP VIEW v1;
--echo #
--echo # MDEV-32304: Pushdown: server crashes at Item_field::used_tables()
--echo # (fixed by the patch for MDEV-29363)
--echo #
CREATE VIEW v1 AS SELECT 1 AS a;
SELECT * FROM v1
GROUP BY a HAVING a = (a IS NULL OR a IS NULL);
DROP VIEW v1;
--echo End of 10.5 tests
......@@ -11085,8 +11085,13 @@ bool Item::cleanup_excluding_immutables_processor (void *arg)
if (!(get_extraction_flag() == IMMUTABLE_FL))
return cleanup_processor(arg);
else
{
clear_extraction_flag();
return false;
}
}
bool Item::remove_immutable_flag_processor (void *arg)
{
if (get_extraction_flag() == IMMUTABLE_FL)
clear_extraction_flag();
return false;
}
......@@ -1990,6 +1990,7 @@ class Item: public Value_source,
virtual bool change_context_processor(void *arg) { return 0; }
virtual bool reset_query_id_processor(void *arg) { return 0; }
virtual bool is_expensive_processor(void *arg) { return 0; }
bool remove_immutable_flag_processor (void *arg);
// FIXME reduce the number of "add field to bitmap" processors
virtual bool add_field_to_set_processor(void *arg) { return 0; }
......
......@@ -11338,6 +11338,19 @@ Item *st_select_lex::pushdown_from_having_into_where(THD *thd, Item *having)
goto exit;
}
}
/*
Remove IMMUTABLE_FL only after all of the elements of the condition are processed.
*/
it.rewind();
while ((item=it++))
{
if (item->walk(&Item::remove_immutable_flag_processor, 0, STOP_PTR))
{
attach_to_conds.empty();
goto exit;
}
}
exit:
thd->lex->current_select= save_curr_select;
return having;
......
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