1
0
mirror of https://github.com/MariaDB/server.git synced 2025-09-02 09:41:40 +03:00

Fixed many problems in the code of With_element::check_unrestricted_recursive().

Added the check whether there are set functions in the specifications of recursive CTE.
Added the check whether there are recursive references in subqueries.
Introduced boolean system variable 'standards_compliant_cte'. By default it's set to 'on'.
When it's set to 'off' non-standard compliant CTE can be executed.
This commit is contained in:
Galina Shalygina
2016-05-19 22:07:53 +03:00
parent 3b47632bfc
commit 46a2e41398
13 changed files with 675 additions and 52 deletions

View File

@@ -30,7 +30,8 @@ insert into folks values
(9, 'Grandma Ann', '1941-10-15', null, null),
(25, 'Uncle Jim', '1968-11-18', 8, 7),
(98, 'Sister Amy', '2001-06-20', 20, 30),
(8, 'Grandma Sally', '1943-08-23', 5, 6),
(7, 'Grandma Sally', '1943-08-23', null, 6),
(8, 'Grandpa Ben', '1940-10-21', null, null),
(6, 'Grandgrandma Martha', '1923-05-17', null, null),
(67, 'Cousin Eddie', '1992-02-28', 25, 27),
(27, 'Auntie Melinda', '1971-03-29', null, null);
@@ -53,7 +54,8 @@ id name dob father mother
30 Mom 1975-03-03 8 7
10 Grandpa Bill 1940-04-05 NULL NULL
9 Grandma Ann 1941-10-15 NULL NULL
8 Grandma Sally 1943-08-23 5 6
7 Grandma Sally 1943-08-23 NULL 6
8 Grandpa Ben 1940-10-21 NULL NULL
6 Grandgrandma Martha 1923-05-17 NULL NULL
with recursive
ancestors
@@ -74,7 +76,8 @@ id name dob father mother
30 Mom 1975-03-03 8 7
10 Grandpa Bill 1940-04-05 NULL NULL
9 Grandma Ann 1941-10-15 NULL NULL
8 Grandma Sally 1943-08-23 5 6
7 Grandma Sally 1943-08-23 NULL 6
8 Grandpa Ben 1940-10-21 NULL NULL
6 Grandgrandma Martha 1923-05-17 NULL NULL
with recursive
ancestors
@@ -93,7 +96,8 @@ id name dob father mother
67 Cousin Eddie 1992-02-28 25 27
25 Uncle Jim 1968-11-18 8 7
27 Auntie Melinda 1971-03-29 NULL NULL
8 Grandma Sally 1943-08-23 5 6
7 Grandma Sally 1943-08-23 NULL 6
8 Grandpa Ben 1940-10-21 NULL NULL
6 Grandgrandma Martha 1923-05-17 NULL NULL
with recursive
ancestors
@@ -115,7 +119,8 @@ id name dob father mother
30 Mom 1975-03-03 8 7
10 Grandpa Bill 1940-04-05 NULL NULL
9 Grandma Ann 1941-10-15 NULL NULL
8 Grandma Sally 1943-08-23 5 6
7 Grandma Sally 1943-08-23 NULL 6
8 Grandpa Ben 1940-10-21 NULL NULL
6 Grandgrandma Martha 1923-05-17 NULL NULL
with recursive
prev_gen
@@ -150,6 +155,7 @@ Mom 1975-03-03
Grandpa Bill 1940-04-05
Grandma Ann 1941-10-15
Grandma Sally 1943-08-23
Grandpa Ben 1940-10-21
Grandgrandma Martha 1923-05-17
with recursive
descendants
@@ -183,7 +189,7 @@ where d.id=folks.father or d.id=folks.mother
)
select * from descendants;
id name dob father mother
8 Grandma Sally 1943-08-23 5 6
7 Grandma Sally 1943-08-23 NULL 6
30 Mom 1975-03-03 8 7
25 Uncle Jim 1968-11-18 8 7
100 Vasya 2000-01-01 20 30
@@ -208,6 +214,7 @@ where a.father=t1.id AND a.mother=t2.id);
id name dob father mother id name dob father mother
20 Dad 1970-02-02 10 9 30 Mom 1975-03-03 8 7
10 Grandpa Bill 1940-04-05 NULL NULL 9 Grandma Ann 1941-10-15 NULL NULL
8 Grandpa Ben 1940-10-21 NULL NULL 7 Grandma Sally 1943-08-23 NULL 6
with
ancestor_couples(husband, h_dob, wife, w_dob)
as
@@ -233,6 +240,7 @@ select * from ancestor_couples;
husband h_dob wife w_dob
Dad 1970-02-02 Mom 1975-03-03
Grandpa Bill 1940-04-05 Grandma Ann 1941-10-15
Grandpa Ben 1940-10-21 Grandma Sally 1943-08-23
with recursive
ancestors
as
@@ -256,7 +264,8 @@ id name dob father mother
30 Mom 1975-03-03 8 7
9 Grandma Ann 1941-10-15 NULL NULL
10 Grandpa Bill 1940-04-05 NULL NULL
8 Grandma Sally 1943-08-23 5 6
8 Grandpa Ben 1940-10-21 NULL NULL
7 Grandma Sally 1943-08-23 NULL 6
6 Grandgrandma Martha 1923-05-17 NULL NULL
with recursive
ancestor_couples(h_id, h_name, h_dob, h_father, h_mother,
@@ -286,6 +295,7 @@ from ancestor_couples;
h_name h_dob w_name w_dob
Dad 1970-02-02 Mom 1975-03-03
Grandpa Bill 1940-04-05 Grandma Ann 1941-10-15
Grandpa Ben 1940-10-21 Grandma Sally 1943-08-23
prepare stmt1 from "
with recursive
ancestors
@@ -308,7 +318,8 @@ id name dob father mother
30 Mom 1975-03-03 8 7
10 Grandpa Bill 1940-04-05 NULL NULL
9 Grandma Ann 1941-10-15 NULL NULL
8 Grandma Sally 1943-08-23 5 6
7 Grandma Sally 1943-08-23 NULL 6
8 Grandpa Ben 1940-10-21 NULL NULL
6 Grandgrandma Martha 1923-05-17 NULL NULL
execute stmt1;
id name dob father mother
@@ -317,7 +328,8 @@ id name dob father mother
30 Mom 1975-03-03 8 7
10 Grandpa Bill 1940-04-05 NULL NULL
9 Grandma Ann 1941-10-15 NULL NULL
8 Grandma Sally 1943-08-23 5 6
7 Grandma Sally 1943-08-23 NULL 6
8 Grandpa Ben 1940-10-21 NULL NULL
6 Grandgrandma Martha 1923-05-17 NULL NULL
deallocate prepare stmt1;
create view v1 as
@@ -344,7 +356,8 @@ id name dob father mother
30 Mom 1975-03-03 8 7
10 Grandpa Bill 1940-04-05 NULL NULL
9 Grandma Ann 1941-10-15 NULL NULL
8 Grandma Sally 1943-08-23 5 6
7 Grandma Sally 1943-08-23 NULL 6
8 Grandpa Ben 1940-10-21 NULL NULL
6 Grandgrandma Martha 1923-05-17 NULL NULL
create view v2 as
with recursive
@@ -374,7 +387,8 @@ id name dob father mother
30 Mom 1975-03-03 8 7
9 Grandma Ann 1941-10-15 NULL NULL
10 Grandpa Bill 1940-04-05 NULL NULL
8 Grandma Sally 1943-08-23 5 6
8 Grandpa Ben 1940-10-21 NULL NULL
7 Grandma Sally 1943-08-23 NULL 6
6 Grandgrandma Martha 1923-05-17 NULL NULL
drop view v1,v2;
explain extended
@@ -392,11 +406,314 @@ where p.id = a.father or p.id = a.mother
)
select * from ancestors;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY <derived2> ALL NULL NULL NULL NULL 132 100.00
2 SUBQUERY folks ALL NULL NULL NULL NULL 11 100.00 Using where
3 UNCACHEABLE UNION p ALL NULL NULL NULL NULL 11 100.00
3 UNCACHEABLE UNION <derived2> ALL NULL NULL NULL NULL 11 100.00 Using where; Using join buffer (flat, BNL join)
1 PRIMARY <derived2> ALL NULL NULL NULL NULL 156 100.00
2 SUBQUERY folks ALL NULL NULL NULL NULL 12 100.00 Using where
3 UNCACHEABLE UNION p ALL NULL NULL NULL NULL 12 100.00
3 UNCACHEABLE UNION <derived2> ALL NULL NULL NULL NULL 12 100.00 Using where; Using join buffer (flat, BNL join)
NULL UNION RESULT <union2,3> ALL NULL NULL NULL NULL NULL NULL
Warnings:
Note 1003 with recursive ancestors as (select `test`.`folks`.`id` AS `id`,`test`.`folks`.`name` AS `name`,`test`.`folks`.`dob` AS `dob`,`test`.`folks`.`father` AS `father`,`test`.`folks`.`mother` AS `mother` from `test`.`folks` where ((`test`.`folks`.`name` = 'Vasya') and (`test`.`folks`.`dob` = DATE'2000-01-01')) union select `p`.`id` AS `id`,`p`.`name` AS `name`,`p`.`dob` AS `dob`,`p`.`father` AS `father`,`p`.`mother` AS `mother` from `test`.`folks` `p` join `ancestors` `a` where ((`a`.`father` = `p`.`id`) or (`a`.`mother` = `p`.`id`)))select `ancestors`.`id` AS `id`,`ancestors`.`name` AS `name`,`ancestors`.`dob` AS `dob`,`ancestors`.`father` AS `father`,`ancestors`.`mother` AS `mother` from `ancestors`
with recursive
ancestor_ids (id)
as
(
select father from folks where name = 'Vasya'
union
select mother from folks where name = 'Vasya'
union
select father from folks, ancestor_ids a where folks.id = a.id
union
select mother from folks, ancestor_ids a where folks.id = a.id
),
ancestors
as
(
select p.* from folks as p, ancestor_ids as a
where p.id = a.id
)
select * from ancestors;
id name dob father mother
20 Dad 1970-02-02 10 9
30 Mom 1975-03-03 8 7
10 Grandpa Bill 1940-04-05 NULL NULL
8 Grandpa Ben 1940-10-21 NULL NULL
9 Grandma Ann 1941-10-15 NULL NULL
7 Grandma Sally 1943-08-23 NULL 6
6 Grandgrandma Martha 1923-05-17 NULL NULL
with recursive
ancestors
as
(
select *
from folks
where name = 'Vasya'
union all
select p.*
from folks as p, ancestors as fa
where p.id = fa.father
union all
select p.*
from folks as p, ancestors as ma
where p.id = ma.mother
)
select * from ancestors;
id name dob father mother
100 Vasya 2000-01-01 20 30
20 Dad 1970-02-02 10 9
30 Mom 1975-03-03 8 7
9 Grandma Ann 1941-10-15 NULL NULL
10 Grandpa Bill 1940-04-05 NULL NULL
8 Grandpa Ben 1940-10-21 NULL NULL
9 Grandma Ann 1941-10-15 NULL NULL
7 Grandma Sally 1943-08-23 NULL 6
6 Grandgrandma Martha 1923-05-17 NULL NULL
with recursive
ancestor_ids (id, generation)
as
(
select father, 1 from folks where name = 'Vasya' and father is not null
union all
select mother, 1 from folks where name = 'Vasya' and mother is not null
union all
select father, fa.generation+1 from folks, ancestor_ids fa
where folks.id = fa.id and (father not in (select id from ancestor_ids))
union all
select mother, ma.generation+1 from folks, ancestor_ids ma
where folks.id = ma.id and (mother not in (select id from ancestor_ids))
)
select generation, name from ancestor_ids a, folks
where a.id = folks.id;
ERROR HY000: Restrictions imposed on recursive definitions are violated for table 'ancestor_ids'
set standards_compliant_cte=0;
set optimizer_switch='materialization=off,subquery_cache=off';
with recursive
ancestor_ids (id, generation)
as
(
select father from folks where name = 'Vasya' and father is not null
union all
select mother from folks where name = 'Vasya' and mother is not null
union all
select father, fa.generation+1 from folks, ancestor_ids fa
where folks.id = fa.id and (father not in (select id from ancestor_ids))
union all
select mother, ma.generation+1 from folks, ancestor_ids ma
where folks.id = ma.id and (mother not in (select id from ancestor_ids))
)
select generation, name from ancestor_ids a, folks
where a.id = folks.id;
ERROR HY000: WITH column list and SELECT field list have different column counts
with recursive
ancestor_ids (id, generation)
as
(
select father, 1 from folks where name = 'Vasya' and father is not null
union all
select mother, 1 from folks where name = 'Vasya' and mother is not null
union all
select father, fa.generation+1 from folks, ancestor_ids fa
where folks.id = fa.id and father is not null and
(father not in (select id from ancestor_ids))
union all
select mother, ma.generation+1 from folks, ancestor_ids ma
where folks.id = ma.id and mother is not null and
(mother not in (select id from ancestor_ids))
)
select generation, name from ancestor_ids a, folks
where a.id = folks.id;
generation name
1 Dad
1 Mom
2 Grandpa Bill
2 Grandpa Ben
2 Grandma Ann
2 Grandma Sally
3 Grandgrandma Martha
set optimizer_switch=default;
set standards_compliant_cte=1;
with recursive
coupled_ancestor_ids (id)
as
(
select father from folks where name = 'Vasya' and father is not null
union
select mother from folks where name = 'Vasya' and mother is not null
union
select n.father
from folks, coupled_ancestor_ids fa, coupled_ancestor_ids ma, folks n
where folks.father = fa.id and folks.mother = ma.id and
(fa.id = n.id or ma.id = n.id) and
n.father is not null and n.mother is not null
union
select n.mother
from folks, coupled_ancestor_ids fa, coupled_ancestor_ids ma, folks n
where folks.father = fa.id and folks.mother = ma.id and
(fa.id = n.id or ma.id = n.id) and
n.father is not null and n.mother is not null
)
select p.* from coupled_ancestor_ids a, folks p
where a.id = p.id;
ERROR HY000: Restrictions imposed on recursive definitions are violated for table 'coupled_ancestor_ids'
set statement standards_compliant_cte=0 for
with recursive
coupled_ancestor_ids (id)
as
(
select father from folks where name = 'Vasya' and father is not null
union
select mother from folks where name = 'Vasya' and mother is not null
union
select n.father
from folks, coupled_ancestor_ids fa, coupled_ancestor_ids ma, folks n
where folks.father = fa.id and folks.mother = ma.id and
(fa.id = n.id or ma.id = n.id) and
n.father is not null and n.mother is not null
union
select n.mother
from folks, coupled_ancestor_ids fa, coupled_ancestor_ids ma, folks n
where folks.father = fa.id and folks.mother = ma.id and
(fa.id = n.id or ma.id = n.id) and
n.father is not null and n.mother is not null
)
select p.* from coupled_ancestor_ids a, folks p
where a.id = p.id;
id name dob father mother
20 Dad 1970-02-02 10 9
30 Mom 1975-03-03 8 7
10 Grandpa Bill 1940-04-05 NULL NULL
8 Grandpa Ben 1940-10-21 NULL NULL
9 Grandma Ann 1941-10-15 NULL NULL
7 Grandma Sally 1943-08-23 NULL 6
with recursive
ancestor_ids (id)
as
(
select father from folks where name = 'Vasya'
union
select mother from folks where name = 'Vasya'
union
select father from folks left join ancestor_ids a on folks.id = a.id
union
select mother from folks left join ancestor_ids a on folks.id = a.id
),
ancestors
as
(
select p.* from folks as p, ancestor_ids as a
where p.id = a.id
)
select * from ancestors;
ERROR HY000: Restrictions imposed on recursive definitions are violated for table 'ancestor_ids'
set statement standards_compliant_cte=0 for
with recursive
ancestor_ids (id)
as
(
select father from folks where name = 'Vasya'
union
select mother from folks where name = 'Vasya'
union
select father from folks left join ancestor_ids a on folks.id = a.id
union
select mother from folks left join ancestor_ids a on folks.id = a.id
),
ancestors
as
(
select p.* from folks as p, ancestor_ids as a
where p.id = a.id
)
select * from ancestors;
id name dob father mother
20 Dad 1970-02-02 10 9
30 Mom 1975-03-03 8 7
10 Grandpa Bill 1940-04-05 NULL NULL
8 Grandpa Ben 1940-10-21 NULL NULL
25 Uncle Jim 1968-11-18 8 7
9 Grandma Ann 1941-10-15 NULL NULL
7 Grandma Sally 1943-08-23 NULL 6
6 Grandgrandma Martha 1923-05-17 NULL NULL
27 Auntie Melinda 1971-03-29 NULL NULL
with recursive
ancestor_ids (id, generation)
as
(
select father, 1 from folks where name = 'Vasya'
union
select mother, 1 from folks where name = 'Vasya'
union
select father, a.generation+1 from folks, ancestor_ids a
where folks.id = a.id
union
select mother, a.generation+1 from folks, ancestor_ids a
where folks.id = a.id
),
ancestors
as
(
select generation, name from folks as p, ancestor_ids as a
where p.id = a.id
)
select * from ancestors;
generation name
1 Dad
1 Mom
2 Grandpa Bill
2 Grandpa Ben
2 Grandma Ann
2 Grandma Sally
3 Grandgrandma Martha
with recursive
ancestor_ids (id, generation)
as
(
select father, 1 from folks where name = 'Vasya'
union
select mother, 1 from folks where name = 'Vasya'
union
select max(father), max(a.generation)+1 from folks, ancestor_ids a
where folks.id = a.id
group by a.generation
union
select max(mother), max(a.generation)+1 from folks, ancestor_ids a
where folks.id = a.id
group by a.generation
),
ancestors
as
(
select generation, name from folks as p, ancestor_ids as a
where p.id = a.id
)
select * from ancestors;
ERROR HY000: Restrictions imposed on recursive definitions are violated for table 'ancestor_ids'
set statement standards_compliant_cte=0 for
with recursive
ancestor_ids (id, generation)
as
(
select father, 1 from folks where name = 'Vasya'
union
select mother, 1 from folks where name = 'Vasya'
union
select max(father), a.generation+1 from folks, ancestor_ids a
where folks.id = a.id
group by a.generation
union
select max(mother), a.generation+1 from folks, ancestor_ids a
where folks.id = a.id
group by a.generation
),
ancestors
as
(
select generation, name from folks as p, ancestor_ids as a
where p.id = a.id
)
select * from ancestors;
generation name
1 Dad
1 Mom
2 Grandpa Bill
2 Grandma Ann
drop table folks;