mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +03:00
MDEV-17201 dropped anchor rows with non-null recursion query
The function st_select_lex_unit::exec_recursive() missed resetting of select_limit_cnt and offset_limit_cnt before execution of union parts. As a result recursive CTEs specified by UNIONs whose SELECTs contained LIMIT/OFFSET could return wrong sets of records.
This commit is contained in:
@ -3393,3 +3393,51 @@ select * from cte1, cte2 where cte1.c1 = 3;
|
|||||||
c1 c2
|
c1 c2
|
||||||
drop procedure p;
|
drop procedure p;
|
||||||
drop table t1,t2;
|
drop table t1,t2;
|
||||||
|
#
|
||||||
|
# MDEV-17201: recursive part with LIMIT
|
||||||
|
#
|
||||||
|
CREATE TABLE purchases (
|
||||||
|
id int unsigned NOT NULL AUTO_INCREMENT,
|
||||||
|
pdate date NOT NULL,
|
||||||
|
quantity int unsigned NOT NULL,
|
||||||
|
p_id int unsigned NOT NULL,
|
||||||
|
PRIMARY KEY (id)
|
||||||
|
);
|
||||||
|
INSERT INTO purchases(pdate, quantity, p_id) VALUES
|
||||||
|
('2014-11-01',5 ,1),('2014-11-03', 3 ,1),
|
||||||
|
('2014-11-01',2 ,2),('2014-11-03', 4 ,2);
|
||||||
|
CREATE TABLE expired (
|
||||||
|
edate date NOT NULL,
|
||||||
|
quantity int unsigned NOT NULL,
|
||||||
|
p_id int unsigned NOT NULL,
|
||||||
|
PRIMARY KEY (edate,p_id)
|
||||||
|
);
|
||||||
|
INSERT INTO expired VALUES ('2014-11-12', 5 ,1),('2014-11-08', 1 ,2);
|
||||||
|
WITH RECURSIVE expired_map AS (
|
||||||
|
SELECT edate AS expired_date,
|
||||||
|
CAST(NULL AS date) AS purchase_date,
|
||||||
|
0 AS quantity,
|
||||||
|
e.p_id,
|
||||||
|
(SELECT MAX(id)+1 FROM purchases p
|
||||||
|
WHERE pdate <= edate AND p.p_id =p_id) AS purchase_processed,
|
||||||
|
quantity AS unresolved
|
||||||
|
FROM expired e
|
||||||
|
UNION
|
||||||
|
( SELECT expired_date,
|
||||||
|
pdate,
|
||||||
|
IF(p.quantity < m.unresolved, p.quantity, m.unresolved),
|
||||||
|
p.p_id,
|
||||||
|
p.id,
|
||||||
|
IF(p.quantity < m.unresolved, m.unresolved - p.quantity, 0)
|
||||||
|
FROM purchases p JOIN expired_map m ON p.p_id = m.p_id
|
||||||
|
WHERE p.id < m.purchase_processed AND m.unresolved > 0
|
||||||
|
ORDER BY p.id DESC
|
||||||
|
LIMIT 1
|
||||||
|
)
|
||||||
|
)
|
||||||
|
SELECT * FROM expired_map;
|
||||||
|
expired_date purchase_date quantity p_id purchase_processed unresolved
|
||||||
|
2014-11-12 NULL 0 1 5 5
|
||||||
|
2014-11-08 NULL 0 2 5 1
|
||||||
|
2014-11-08 2014-11-03 1 2 4 0
|
||||||
|
DROP TABLE purchases, expired;
|
||||||
|
@ -2390,3 +2390,53 @@ eval $q3;
|
|||||||
|
|
||||||
drop procedure p;
|
drop procedure p;
|
||||||
drop table t1,t2;
|
drop table t1,t2;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # MDEV-17201: recursive part with LIMIT
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
CREATE TABLE purchases (
|
||||||
|
id int unsigned NOT NULL AUTO_INCREMENT,
|
||||||
|
pdate date NOT NULL,
|
||||||
|
quantity int unsigned NOT NULL,
|
||||||
|
p_id int unsigned NOT NULL,
|
||||||
|
PRIMARY KEY (id)
|
||||||
|
);
|
||||||
|
INSERT INTO purchases(pdate, quantity, p_id) VALUES
|
||||||
|
('2014-11-01',5 ,1),('2014-11-03', 3 ,1),
|
||||||
|
('2014-11-01',2 ,2),('2014-11-03', 4 ,2);
|
||||||
|
|
||||||
|
CREATE TABLE expired (
|
||||||
|
edate date NOT NULL,
|
||||||
|
quantity int unsigned NOT NULL,
|
||||||
|
p_id int unsigned NOT NULL,
|
||||||
|
PRIMARY KEY (edate,p_id)
|
||||||
|
);
|
||||||
|
|
||||||
|
INSERT INTO expired VALUES ('2014-11-12', 5 ,1),('2014-11-08', 1 ,2);
|
||||||
|
|
||||||
|
WITH RECURSIVE expired_map AS (
|
||||||
|
SELECT edate AS expired_date,
|
||||||
|
CAST(NULL AS date) AS purchase_date,
|
||||||
|
0 AS quantity,
|
||||||
|
e.p_id,
|
||||||
|
(SELECT MAX(id)+1 FROM purchases p
|
||||||
|
WHERE pdate <= edate AND p.p_id =p_id) AS purchase_processed,
|
||||||
|
quantity AS unresolved
|
||||||
|
FROM expired e
|
||||||
|
UNION
|
||||||
|
( SELECT expired_date,
|
||||||
|
pdate,
|
||||||
|
IF(p.quantity < m.unresolved, p.quantity, m.unresolved),
|
||||||
|
p.p_id,
|
||||||
|
p.id,
|
||||||
|
IF(p.quantity < m.unresolved, m.unresolved - p.quantity, 0)
|
||||||
|
FROM purchases p JOIN expired_map m ON p.p_id = m.p_id
|
||||||
|
WHERE p.id < m.purchase_processed AND m.unresolved > 0
|
||||||
|
ORDER BY p.id DESC
|
||||||
|
LIMIT 1
|
||||||
|
)
|
||||||
|
)
|
||||||
|
SELECT * FROM expired_map;
|
||||||
|
|
||||||
|
DROP TABLE purchases, expired;
|
||||||
|
@ -1274,6 +1274,7 @@ bool st_select_lex_unit::exec_recursive()
|
|||||||
for (st_select_lex *sl= start ; sl != end; sl= sl->next_select())
|
for (st_select_lex *sl= start ; sl != end; sl= sl->next_select())
|
||||||
{
|
{
|
||||||
thd->lex->current_select= sl;
|
thd->lex->current_select= sl;
|
||||||
|
set_limit(sl);
|
||||||
sl->join->exec();
|
sl->join->exec();
|
||||||
saved_error= sl->join->error;
|
saved_error= sl->join->error;
|
||||||
if (!saved_error)
|
if (!saved_error)
|
||||||
|
Reference in New Issue
Block a user