Commit ea270178 authored by Igor Babaev's avatar Igor Babaev Committed by Oleksandr Byelkin

MDEV-30052 Crash with a query containing nested WINDOW clauses

Use SELECT_LEX to save lists for ORDER BY and GROUP BY before parsing
WINDOW clauses / specifications. This is needed for proper parsing
of a nested WINDOW clause when a WINDOW clause is used in a subquery
contained in another WINDOW clause.

Fix assignment of empty SQL_I_List to another one (in case of empty list
next shoud point on first).
parent 6fe882cd
...@@ -24,3 +24,66 @@ pk count(a) over (order by pk rows between 2 preceding and 2 following) ...@@ -24,3 +24,66 @@ pk count(a) over (order by pk rows between 2 preceding and 2 following)
28 5 28 5
27 5 27 5
drop table t0,t1; drop table t0,t1;
#
# MDEV-30052: Crash with a query containing nested WINDOW clauses
#
CREATE TABLE t1 (c INT);
insert into t1 values (1),(2);
UPDATE t1 SET c=1
WHERE c=2
ORDER BY
(1 IN ((
SELECT *
FROM (SELECT * FROM t1) AS v1
GROUP BY c
WINDOW v2 AS (ORDER BY
(SELECT *
FROM t1
GROUP BY c
WINDOW v3 AS (PARTITION BY c)
)
)
))
);
drop table t1;
#
# MDEV-29359: Server crashed with heap-use-after-free in
# Field::is_null(long long) const (Just testcase)
#
CREATE TABLE t1 (id int);
INSERT INTO t1 VALUES (-1),(0),(84);
SELECT
id IN (SELECT id
FROM t1
WINDOW w AS (ORDER BY (SELECT 1
FROM t1
WHERE
EXISTS ( SELECT id
FROM t1
GROUP BY id
WINDOW w2 AS (ORDER BY id)
)
)
)
)
FROM t1;
id IN (SELECT id
FROM t1
WINDOW w AS (ORDER BY (SELECT 1
FROM t1
WHERE
EXISTS ( SELECT id
FROM t1
GROUP BY id
WINDOW w2 AS (ORDER BY id)
)
)
)
)
1
1
1
DROP TABLE t1;
#
# End of 10.3 tests
#
...@@ -33,3 +33,58 @@ limit 4; ...@@ -33,3 +33,58 @@ limit 4;
--disable_view_protocol --disable_view_protocol
drop table t0,t1; drop table t0,t1;
--echo #
--echo # MDEV-30052: Crash with a query containing nested WINDOW clauses
--echo #
CREATE TABLE t1 (c INT);
insert into t1 values (1),(2);
UPDATE t1 SET c=1
WHERE c=2
ORDER BY
(1 IN ((
SELECT *
FROM (SELECT * FROM t1) AS v1
GROUP BY c
WINDOW v2 AS (ORDER BY
(SELECT *
FROM t1
GROUP BY c
WINDOW v3 AS (PARTITION BY c)
)
)
))
);
drop table t1;
--echo #
--echo # MDEV-29359: Server crashed with heap-use-after-free in
--echo # Field::is_null(long long) const (Just testcase)
--echo #
CREATE TABLE t1 (id int);
INSERT INTO t1 VALUES (-1),(0),(84);
SELECT
id IN (SELECT id
FROM t1
WINDOW w AS (ORDER BY (SELECT 1
FROM t1
WHERE
EXISTS ( SELECT id
FROM t1
GROUP BY id
WINDOW w2 AS (ORDER BY id)
)
)
)
)
FROM t1;
DROP TABLE t1;
--echo #
--echo # End of 10.3 tests
--echo #
...@@ -755,8 +755,6 @@ void LEX::start(THD *thd_arg) ...@@ -755,8 +755,6 @@ void LEX::start(THD *thd_arg)
stmt_var_list.empty(); stmt_var_list.empty();
proc_list.elements=0; proc_list.elements=0;
save_group_list.empty();
save_order_list.empty();
win_ref= NULL; win_ref= NULL;
win_frame= NULL; win_frame= NULL;
frame_top_bound= NULL; frame_top_bound= NULL;
...@@ -2389,9 +2387,8 @@ void st_select_lex::init_select() ...@@ -2389,9 +2387,8 @@ void st_select_lex::init_select()
ftfunc_list_alloc.empty(); ftfunc_list_alloc.empty();
inner_sum_func_list= 0; inner_sum_func_list= 0;
ftfunc_list= &ftfunc_list_alloc; ftfunc_list= &ftfunc_list_alloc;
order_list.elements= 0; order_list.empty();
order_list.first= 0;
order_list.next= &order_list.first;
/* Set limit and offset to default values */ /* Set limit and offset to default values */
select_limit= 0; /* denotes the default limit = HA_POS_ERROR */ select_limit= 0; /* denotes the default limit = HA_POS_ERROR */
offset_limit= 0; /* denotes the default offset = 0 */ offset_limit= 0; /* denotes the default offset = 0 */
......
...@@ -975,6 +975,7 @@ class st_select_lex: public st_select_lex_node ...@@ -975,6 +975,7 @@ class st_select_lex: public st_select_lex_node
group_list_ptrs, and re-establish the original list before each execution. group_list_ptrs, and re-establish the original list before each execution.
*/ */
SQL_I_List<ORDER> group_list; SQL_I_List<ORDER> group_list;
SQL_I_List<ORDER> save_group_list;
Group_list_ptrs *group_list_ptrs; Group_list_ptrs *group_list_ptrs;
List<Item> item_list; /* list of fields & expressions */ List<Item> item_list; /* list of fields & expressions */
...@@ -1040,6 +1041,7 @@ class st_select_lex: public st_select_lex_node ...@@ -1040,6 +1041,7 @@ class st_select_lex: public st_select_lex_node
const char *type; /* type of select for EXPLAIN */ const char *type; /* type of select for EXPLAIN */
SQL_I_List<ORDER> order_list; /* ORDER clause */ SQL_I_List<ORDER> order_list; /* ORDER clause */
SQL_I_List<ORDER> save_order_list;
SQL_I_List<ORDER> gorder_list; SQL_I_List<ORDER> gorder_list;
Item *select_limit, *offset_limit; /* LIMIT clause parameters */ Item *select_limit, *offset_limit; /* LIMIT clause parameters */
...@@ -1249,9 +1251,7 @@ class st_select_lex: public st_select_lex_node ...@@ -1249,9 +1251,7 @@ class st_select_lex: public st_select_lex_node
void set_lock_for_tables(thr_lock_type lock_type, bool for_update); void set_lock_for_tables(thr_lock_type lock_type, bool for_update);
inline void init_order() inline void init_order()
{ {
order_list.elements= 0; order_list.empty();
order_list.first= 0;
order_list.next= &order_list.first;
} }
/* /*
This method created for reiniting LEX in mysql_admin_table() and can be This method created for reiniting LEX in mysql_admin_table() and can be
...@@ -3215,8 +3215,6 @@ struct LEX: public Query_tables_list ...@@ -3215,8 +3215,6 @@ struct LEX: public Query_tables_list
} }
SQL_I_List<ORDER> save_group_list;
SQL_I_List<ORDER> save_order_list;
LEX_CSTRING *win_ref; LEX_CSTRING *win_ref;
Window_frame *win_frame; Window_frame *win_frame;
Window_frame_bound *frame_top_bound; Window_frame_bound *frame_top_bound;
......
...@@ -53,7 +53,7 @@ class SQL_I_List :public Sql_alloc ...@@ -53,7 +53,7 @@ class SQL_I_List :public Sql_alloc
{ {
elements= tmp.elements; elements= tmp.elements;
first= tmp.first; first= tmp.first;
next= tmp.next; next= elements ? tmp.next : &first;;
return *this; return *this;
} }
......
...@@ -8662,8 +8662,8 @@ TABLE_LIST *st_select_lex::convert_right_join() ...@@ -8662,8 +8662,8 @@ TABLE_LIST *st_select_lex::convert_right_join()
void st_select_lex::prepare_add_window_spec(THD *thd) void st_select_lex::prepare_add_window_spec(THD *thd)
{ {
LEX *lex= thd->lex; LEX *lex= thd->lex;
lex->save_group_list= group_list; save_group_list= group_list;
lex->save_order_list= order_list; save_order_list= order_list;
lex->win_ref= NULL; lex->win_ref= NULL;
lex->win_frame= NULL; lex->win_frame= NULL;
lex->frame_top_bound= NULL; lex->frame_top_bound= NULL;
...@@ -8690,8 +8690,8 @@ bool st_select_lex::add_window_def(THD *thd, ...@@ -8690,8 +8690,8 @@ bool st_select_lex::add_window_def(THD *thd,
win_part_list_ptr, win_part_list_ptr,
win_order_list_ptr, win_order_list_ptr,
win_frame); win_frame);
group_list= thd->lex->save_group_list; group_list= save_group_list;
order_list= thd->lex->save_order_list; order_list= save_order_list;
if (parsing_place != SELECT_LIST) if (parsing_place != SELECT_LIST)
{ {
fields_in_window_functions+= win_part_list_ptr->elements + fields_in_window_functions+= win_part_list_ptr->elements +
...@@ -8717,8 +8717,8 @@ bool st_select_lex::add_window_spec(THD *thd, ...@@ -8717,8 +8717,8 @@ bool st_select_lex::add_window_spec(THD *thd,
win_part_list_ptr, win_part_list_ptr,
win_order_list_ptr, win_order_list_ptr,
win_frame); win_frame);
group_list= thd->lex->save_group_list; group_list= save_group_list;
order_list= thd->lex->save_order_list; order_list= save_order_list;
if (parsing_place != SELECT_LIST) if (parsing_place != SELECT_LIST)
{ {
fields_in_window_functions+= win_part_list_ptr->elements + fields_in_window_functions+= win_part_list_ptr->elements +
......
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