summaryrefslogtreecommitdiff
path: root/mysql-test/main/cte_recursive.test
diff options
context:
space:
mode:
authorMichael Widenius <monty@mariadb.org>2018-03-09 14:05:35 +0200
committerMonty <monty@mariadb.org>2018-03-29 13:59:44 +0300
commita7abddeffa6a760ce948c2dfb007cdf3f1a369d5 (patch)
tree70eb743fa965a17380bbc0ac88ae79ca1075b896 /mysql-test/main/cte_recursive.test
parentab1941266c59a19703a74b5593cf3f508a5752d7 (diff)
downloadmariadb-git-a7abddeffa6a760ce948c2dfb007cdf3f1a369d5.tar.gz
Create 'main' test directory and move 't' and 'r' there
Diffstat (limited to 'mysql-test/main/cte_recursive.test')
-rw-r--r--mysql-test/main/cte_recursive.test2310
1 files changed, 2310 insertions, 0 deletions
diff --git a/mysql-test/main/cte_recursive.test b/mysql-test/main/cte_recursive.test
new file mode 100644
index 00000000000..7ed55a1daaa
--- /dev/null
+++ b/mysql-test/main/cte_recursive.test
@@ -0,0 +1,2310 @@
+create table t1 (a int, b varchar(32));
+insert into t1 values
+(4,'aaaa' ), (7,'bb'), (1,'ccc'), (4,'dd');
+insert into t1 values
+(3,'eee'), (7,'bb'), (1,'fff'), (4,'ggg');
+
+--ERROR ER_UNACCEPTABLE_MUTUAL_RECURSION
+with recursive
+t as
+(
+ select * from t1 where t1.b >= 'c'
+ union
+ select * from r
+),
+r as
+(
+ select * from t
+ union
+ select t1.* from t1,r where r.a+1 = t1.a
+)
+select * from r;
+
+
+--ERROR ER_UNACCEPTABLE_MUTUAL_RECURSION
+with recursive
+a1(a,b) as
+(select * from t1 where t1.a>3
+union
+select * from b1 where b1.a >3
+union
+select * from c1 where c1.a>3),
+b1(a,b) as
+(select * from a1 where a1.b > 'ccc'
+union
+select * from c1 where c1.b > 'ddd'),
+c1(a,b) as
+(select * from a1 where a1.a<6 and a1.b< 'zz'
+union
+select * from b1 where b1.b > 'auu')
+select * from c1;
+
+drop table t1;
+
+
+--echo # WITH RECURSIVE vs just WITH
+
+create table t1 (a int);
+insert into t1 values
+ (0), (1), (2), (3), (4);
+create table t2 (a int);
+insert into t2 values
+ (1), (2), (3), (4), (5);
+
+
+--echo # just WITH : s refers to t defined after s
+--ERROR ER_NO_SUCH_TABLE
+with
+ s(a) as (select t.a + 10 from t),
+ t(a) as (select t1.a from t1)
+select * from s;
+
+--echo # WITH RECURSIVE: s refers to t defined after s
+with recursive
+ s(a) as (select t.a + 10 from t),
+ t(a) as (select t1.a from t1)
+select * from s;
+
+--echo # just WITH : defined t1 is non-recursive and uses base tables t1,t2
+with
+t1 as
+(
+select a from t2 where t2.a=3
+union
+select t2.a from t1,t2 where t1.a+1=t2.a
+)
+select * from t1;
+
+explain
+with
+t1 as
+(
+select a from t2 where t2.a=3
+union
+select t2.a from t1,t2 where t1.a+1=t2.a
+)
+select * from t1;
+
+
+--echo #WITH RECURSIVE : defined t1 is recursive and uses only base table t2
+with recursive
+t1 as
+(
+select a from t2 where t2.a=3
+union
+select t2.a from t1,t2 where t1.a+1=t2.a
+)
+select * from t1;
+
+explain
+with recursive
+t1 as
+(
+select a from t2 where t2.a=3
+union
+select t2.a from t1,t2 where t1.a+1=t2.a
+)
+select * from t1;
+
+--echo # just WITH : types of t1 columns are determined by all parts of union
+
+create view v1 as
+with
+t1 as
+(
+select a from t2 where t2.a=3
+union
+select t2.a+1 from t1,t2 where t1.a=t2.a
+)
+select * from t1;
+
+show columns from v1;
+
+
+--echo # WITH RECURSIVE : types of t1 columns are determined by anchor parts
+
+create view v2 as
+with recursive
+t1 as
+(
+select a from t2 where t2.a=3
+union
+select t2.a+1 from t1,t2 where t1.a=t2.a
+)
+select * from t1;
+
+show columns from v2;
+
+drop view v1,v2;
+
+drop table t1,t2;
+
+
+create table folks(id int, name char(32), dob date, father int, mother int);
+
+insert into folks values
+(100, 'Me', '2000-01-01', 20, 30),
+(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),
+(25, 'Uncle Jim', '1968-11-18', 8, 7),
+(98, 'Sister Amy', '2001-06-20', 20, 30),
+(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);
+
+--echo # simple recursion with one anchor and one recursive select
+--echo # the anchor is the first select in the specification
+with recursive
+ancestors
+as
+(
+ select *
+ from folks
+ where name = 'Me' and dob = '2000-01-01'
+ union
+ select p.id, p.name, p.dob, p.father, p.mother
+ from folks as p, ancestors AS a
+ where p.id = a.father or p.id = a.mother
+)
+select * from ancestors;
+
+--echo # simple recursion with one anchor and one recursive select
+--echo # the anchor is the last select in the specification
+with recursive
+ancestors
+as
+(
+ select p.*
+ from folks as p, ancestors AS a
+ where p.id = a.father or p.id = a.mother
+ union
+ select *
+ from folks
+ where name = 'Me' and dob = '2000-01-01'
+)
+select * from ancestors;
+
+--echo # simple recursion with one anchor and one recursive select
+--echo # the anchor is the first select in the specification
+with recursive
+ancestors
+as
+(
+ select *
+ from folks
+ where name = 'Cousin Eddie'
+ union
+ select p.*
+ from folks as p, ancestors as a
+ where p.id = a.father or p.id = a.mother
+)
+select * from ancestors;
+
+--echo # simple recursion with or in anchor and or in recursive part
+with recursive
+ancestors
+as
+(
+ select *
+ from folks
+ where name = 'Me' or name='Sister Amy'
+ union
+ select p.*
+ from folks as p, ancestors as a
+ where p.id = a.father or p.id = a.mother
+)
+select * from ancestors;
+
+--echo # two recursive definition, one uses another
+with recursive
+prev_gen
+as
+(
+ select folks.*
+ from folks, prev_gen
+ where folks.id=prev_gen.father or folks.id=prev_gen.mother
+ union
+ select *
+ from folks
+ where name='Me'
+),
+ancestors
+as
+(
+ select *
+ from folks
+ where name='Me'
+ union
+ select *
+ from ancestors
+ union
+ select *
+ from prev_gen
+)
+select ancestors.name, ancestors.dob from ancestors;
+
+--echo # recursive definition with two attached non-recursive
+with recursive
+ancestors(id,name,dob)
+as
+(
+ with
+ father(child_id,id,name,dob)
+ as
+ (
+ select folks.id, f.id, f.name, f.dob
+ from folks, folks f
+ where folks.father=f.id
+
+ ),
+ mother(child_id,id,name,dob)
+ as
+ (
+ select folks.id, m.id, m.name, m.dob
+ from folks, folks m
+ where folks.mother=m.id
+
+ )
+ select folks.id, folks.name, folks.dob
+ from folks
+ where name='Me'
+ union
+ select f.id, f.name, f.dob
+ from ancestors a, father f
+ where f.child_id=a.id
+ union
+ select m.id, m.name, m.dob
+ from ancestors a, mother m
+ where m.child_id=a.id
+
+)
+select ancestors.name, ancestors.dob from ancestors;
+
+--echo # simple recursion with one anchor and one recursive select
+--echo # the anchor is the first select in the specification
+with recursive
+descendants
+as
+(
+ select *
+ from folks
+ where name = 'Grandpa Bill'
+ union
+ select folks.*
+ from folks, descendants as d
+ where d.id=folks.father or d.id=folks.mother
+)
+select * from descendants;
+
+--echo # simple recursion with one anchor and one recursive select
+--echo # the anchor is the first select in the specification
+with recursive
+descendants
+as
+(
+ select *
+ from folks
+ where name = 'Grandma Sally'
+ union
+ select folks.*
+ from folks, descendants as d
+ where d.id=folks.father or d.id=folks.mother
+)
+select * from descendants;
+
+
+--echo # simple recursive table used three times in the main query
+with recursive
+ancestors
+as
+(
+ select *
+ from folks
+ where name = 'Me' and dob = '2000-01-01'
+ union
+ select p.*
+ from folks as p, ancestors AS a
+ where p.id = a.father OR p.id = a.mother
+)
+select *
+ from ancestors t1, ancestors t2
+ where exists (select * from ancestors a
+ where a.father=t1.id AND a.mother=t2.id);
+
+
+--echo # simple recursive table used three times in the main query
+with
+ancestor_couples(husband, h_dob, wife, w_dob)
+as
+(
+with recursive
+ancestors
+as
+(
+ select *
+ from folks
+ where name = 'Me'
+ union
+ select p.*
+ from folks as p, ancestors AS a
+ where p.id = a.father OR p.id = a.mother
+)
+select t1.name, t1.dob, t2.name, t2.dob
+ from ancestors t1, ancestors t2
+ where exists (select * from ancestors a
+ where a.father=t1.id AND a.mother=t2.id)
+)
+select * from ancestor_couples;
+
+
+--echo # simple recursion with two selects in recursive part
+with recursive
+ancestors
+as
+(
+ select *
+ from folks
+ where name = 'Me'
+ union
+ select p.*
+ from folks as p, ancestors as fa
+ where p.id = fa.father
+ union
+ select p.*
+ from folks as p, ancestors as ma
+ where p.id = ma.mother
+)
+select * from ancestors;
+
+
+--echo # mutual recursion with renaming
+with recursive
+ancestor_couples(h_id, h_name, h_dob, h_father, h_mother,
+ w_id, w_name, w_dob, w_father, w_mother)
+as
+(
+ select h.*, w.*
+ from folks h, folks w, coupled_ancestors a
+ where a.father = h.id AND a.mother = w.id
+ union
+ select h.*, w.*
+ from folks v, folks h, folks w
+ where v.name = 'Me' and
+ (v.father = h.id AND v.mother= w.id)
+),
+coupled_ancestors (id, name, dob, father, mother)
+as
+(
+ select h_id, h_name, h_dob, h_father, h_mother
+ from ancestor_couples
+ union
+ select w_id, w_name, w_dob, w_father, w_mother
+ from ancestor_couples
+)
+select h_name, h_dob, w_name, w_dob
+ from ancestor_couples;
+
+
+--echo # mutual recursion with union all
+with recursive
+ancestor_couples(h_id, h_name, h_dob, h_father, h_mother,
+ w_id, w_name, w_dob, w_father, w_mother)
+as
+(
+ select h.*, w.*
+ from folks h, folks w, coupled_ancestors a
+ where a.father = h.id AND a.mother = w.id
+ union
+ select h.*, w.*
+ from folks v, folks h, folks w
+ where v.name = 'Me' and
+ (v.father = h.id AND v.mother= w.id)
+),
+coupled_ancestors (id, name, dob, father, mother)
+as
+(
+ select h_id, h_name, h_dob, h_father, h_mother
+ from ancestor_couples
+ union all
+ select w_id, w_name, w_dob, w_father, w_mother
+ from ancestor_couples
+)
+select h_name, h_dob, w_name, w_dob
+ from ancestor_couples;
+
+
+--echo # mutual recursion with renaming
+with recursive
+ancestor_couples(h_id, h_name, h_dob, h_father, h_mother,
+ w_id, w_name, w_dob, w_father, w_mother)
+as
+(
+ select h.*, w.*
+ from folks h, folks w, coupled_ancestors a
+ where a.father = h.id AND a.mother = w.id
+ union
+ select h.*, w.*
+ from folks v, folks h, folks w
+ where v.name = 'Me' and
+ (v.father = h.id AND v.mother= w.id)
+),
+coupled_ancestors (id, name, dob, father, mother)
+as
+(
+ select h_id, h_name, h_dob, h_father, h_mother
+ from ancestor_couples
+ union
+ select w_id, w_name, w_dob, w_father, w_mother
+ from ancestor_couples
+)
+select h_name, h_dob, w_name, w_dob
+ from ancestor_couples;
+
+
+--echo # mutual recursion with union all
+with recursive
+ancestor_couples(h_id, h_name, h_dob, h_father, h_mother,
+ w_id, w_name, w_dob, w_father, w_mother)
+as
+(
+ select h.*, w.*
+ from folks h, folks w, coupled_ancestors a
+ where a.father = h.id AND a.mother = w.id
+),
+coupled_ancestors (id, name, dob, father, mother)
+as
+(
+ select *
+ from folks
+ where name = 'Me'
+ union all
+ select h_id, h_name, h_dob, h_father, h_mother
+ from ancestor_couples
+ union all
+ select w_id, w_name, w_dob, w_father, w_mother
+ from ancestor_couples
+)
+select h_name, h_dob, w_name, w_dob
+ from ancestor_couples;
+
+--echo # mutual recursion with one select in the first definition
+with recursive
+ancestor_couple_ids(h_id, w_id)
+as
+(
+ select a.father, a.mother
+ from coupled_ancestors a
+ where a.father is not null and a.mother is not null
+),
+coupled_ancestors (id, name, dob, father, mother)
+as
+(
+ select *
+ from folks
+ where name = 'Me'
+ union all
+ select p.*
+ from folks p, ancestor_couple_ids fa
+ where p.id = fa.h_id
+ union all
+ select p.*
+ from folks p, ancestor_couple_ids ma
+ where p.id = ma.w_id
+)
+select *
+ from ancestor_couple_ids;
+
+
+--echo # join of a mutually recursive table with base tables
+with recursive
+ancestor_couple_ids(h_id, w_id)
+as
+(
+ select a.father, a.mother
+ from coupled_ancestors a
+ where a.father is not null and a.mother is not null
+),
+coupled_ancestors (id, name, dob, father, mother)
+as
+(
+ select *
+ from folks
+ where name = 'Me'
+ union all
+ select p.*
+ from folks p, ancestor_couple_ids fa
+ where p.id = fa.h_id
+ union all
+ select p.*
+ from folks p, ancestor_couple_ids ma
+ where p.id = ma.w_id
+)
+select h.name, h.dob, w.name, w.dob
+ from ancestor_couple_ids c, folks h, folks w
+ where c.h_id = h.id and c.w_id= w.id;
+
+
+--echo # join of two mutually recursive tables
+with recursive
+ancestor_couple_ids(h_id, w_id)
+as
+(
+ select a.father, a.mother
+ from coupled_ancestors a
+ where a.father is not null and a.mother is not null
+),
+coupled_ancestors (id, name, dob, father, mother)
+as
+(
+ select *
+ from folks
+ where name = 'Me'
+ union all
+ select p.*
+ from folks p, ancestor_couple_ids fa
+ where p.id = fa.h_id
+ union all
+ select p.*
+ from folks p, ancestor_couple_ids ma
+ where p.id = ma.w_id
+)
+select h.name, h.dob, w.name, w.dob
+ from ancestor_couple_ids c, coupled_ancestors h, coupled_ancestors w
+ where c.h_id = h.id and c.w_id= w.id;
+
+explain extended
+with recursive
+ancestor_couple_ids(h_id, w_id)
+as
+(
+ select a.father, a.mother
+ from coupled_ancestors a
+ where a.father is not null and a.mother is not null
+),
+coupled_ancestors (id, name, dob, father, mother)
+as
+(
+ select *
+ from folks
+ where name = 'Me'
+ union all
+ select p.*
+ from folks p, ancestor_couple_ids fa
+ where p.id = fa.h_id
+ union all
+ select p.*
+ from folks p, ancestor_couple_ids ma
+ where p.id = ma.w_id
+)
+select h.name, h.dob, w.name, w.dob
+ from ancestor_couple_ids c, coupled_ancestors h, coupled_ancestors w
+ where c.h_id = h.id and c.w_id= w.id;
+
+
+--echo # simple mutual recursion
+with recursive
+ancestor_couple_ids(h_id, w_id)
+as
+(
+ select a.father, a.mother
+ from coupled_ancestors a
+),
+coupled_ancestors (id, name, dob, father, mother)
+as
+(
+ select *
+ from folks
+ where name = 'Me'
+ union all
+ select p.*
+ from folks p, ancestor_couple_ids fa
+ where p.id = fa.h_id
+ union all
+ select p.*
+ from folks p, ancestor_couple_ids ma
+ where p.id = ma.w_id
+)
+select *
+ from ancestor_couple_ids;
+
+
+--echo # join of two mutually recursive tables
+with recursive
+ancestor_couple_ids(h_id, w_id)
+as
+(
+ select a.father, a.mother
+ from coupled_ancestors a
+),
+coupled_ancestors (id, name, dob, father, mother)
+as
+(
+ select *
+ from folks
+ where name = 'Me'
+ union all
+ select p.*
+ from folks p, ancestor_couple_ids fa
+ where p.id = fa.h_id
+ union all
+ select p.*
+ from folks p, ancestor_couple_ids ma
+ where p.id = ma.w_id
+)
+select h.name, h.dob, w.name, w.dob
+ from ancestor_couple_ids c, coupled_ancestors h, coupled_ancestors w
+ where c.h_id = h.id and c.w_id= w.id;
+
+
+--echo # execution of prepared query using a recursive table
+prepare stmt1 from "
+with recursive
+ancestors
+as
+(
+ select *
+ from folks
+ where name = 'Me' and dob = '2000-01-01'
+ union
+ select p.id, p.name, p.dob, p.father, p.mother
+ from folks as p, ancestors AS a
+ where p.id = a.father or p.id = a.mother
+)
+select * from ancestors;
+";
+
+execute stmt1;
+execute stmt1;
+
+deallocate prepare stmt1;
+
+
+--echo # view using a recursive table
+create view v1 as
+with recursive
+ancestors
+as
+(
+ select *
+ from folks
+ where name = 'Me' and dob = '2000-01-01'
+ union
+ select p.id, p.name, p.dob, p.father, p.mother
+ from folks as p, ancestors AS a
+ where p.id = a.father or p.id = a.mother
+)
+select * from ancestors;
+
+show create view v1;
+
+select * from v1;
+
+create view v2 as
+with recursive
+ancestors
+as
+(
+ select *
+ from folks
+ where name = 'Me'
+ union
+ select p.*
+ from folks as p, ancestors as fa
+ where p.id = fa.father
+ union
+ select p.*
+ from folks as p, ancestors as ma
+ where p.id = ma.mother
+)
+select * from ancestors;
+
+show create view v2;
+
+select * from v2;
+
+drop view v1,v2;
+
+
+explain extended
+with recursive
+ancestors
+as
+(
+ select *
+ from folks
+ where name = 'Me' and dob = '2000-01-01'
+ union
+ select p.id, p.name, p.dob, p.father, p.mother
+ from folks as p, ancestors AS a
+ where p.id = a.father or p.id = a.mother
+)
+select * from ancestors;
+
+
+--echo # recursive spec with two anchor selects and two recursive ones
+with recursive
+ancestor_ids (id)
+as
+(
+ select father from folks where name = 'Me'
+ union
+ select mother from folks where name = 'Me'
+ 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;
+
+
+--echo # recursive spec using union all
+with recursive
+ancestors
+as
+(
+ select *
+ from folks
+ where name = 'Me'
+ 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;
+
+
+--ERROR ER_NOT_STANDARD_COMPLIANT_RECURSIVE
+with recursive
+ancestor_ids (id, generation)
+as
+(
+ select father, 1 from folks where name = 'Me' and father is not null
+ union all
+ select mother, 1 from folks where name = 'Me' 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;
+
+set standard_compliant_cte=0;
+
+--ERROR ER_WITH_COL_WRONG_LIST
+with recursive
+ancestor_ids (id, generation)
+as
+(
+ select father from folks where name = 'Me' and father is not null
+ union all
+ select mother from folks where name = 'Me' 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;
+
+with recursive
+ancestor_ids (id, generation)
+as
+(
+ select father, 1 from folks where name = 'Me' and father is not null
+ union all
+ select mother, 1 from folks where name = 'Me' 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;
+
+set standard_compliant_cte=1;
+
+--ERROR ER_NOT_STANDARD_COMPLIANT_RECURSIVE
+with recursive
+coupled_ancestor_ids (id)
+as
+(
+ select father from folks where name = 'Me' and father is not null
+ union
+ select mother from folks where name = 'Me' 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;
+
+set statement standard_compliant_cte=0 for
+with recursive
+coupled_ancestor_ids (id)
+as
+(
+ select father from folks where name = 'Me' and father is not null
+ union
+ select mother from folks where name = 'Me' 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 ER_NOT_STANDARD_COMPLIANT_RECURSIVE
+with recursive
+ancestor_ids (id)
+as
+(
+ select father from folks where name = 'Me'
+ union
+ select mother from folks where name = 'Me'
+ 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;
+
+set statement standard_compliant_cte=0 for
+with recursive
+ancestor_ids (id)
+as
+(
+ select father from folks where name = 'Me'
+ union
+ select mother from folks where name = 'Me'
+ 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;
+
+with recursive
+ancestor_ids (id, generation)
+as
+(
+ select father, 1 from folks where name = 'Me'
+ union
+ select mother, 1 from folks where name = 'Me'
+ 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;
+
+--ERROR ER_NOT_STANDARD_COMPLIANT_RECURSIVE
+with recursive
+ancestor_ids (id, generation)
+as
+(
+ select father, 1 from folks where name = 'Me'
+ union
+ select mother, 1 from folks where name = 'Me'
+ 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;
+
+set statement standard_compliant_cte=0 for
+with recursive
+ancestor_ids (id, generation)
+as
+(
+ select father, 1 from folks where name = 'Me'
+ union
+ select mother, 1 from folks where name = 'Me'
+ 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;
+
+set statement max_recursive_iterations=1 for
+with recursive
+ancestor_ids (id, generation)
+as
+(
+ select father, 1 from folks where name = 'Me'
+ union
+ select mother, 1 from folks where name = 'Me'
+ 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;
+
+--echo # query with recursive tables using key access
+
+alter table folks add primary key (id);
+
+explain
+with recursive
+ancestors
+as
+(
+ select *
+ from folks
+ where name = 'Me'
+ union
+ select p.*
+ from folks as p, ancestors as fa
+ where p.id = fa.father
+ union
+ select p.*
+ from folks as p, ancestors as ma
+ where p.id = ma.mother
+)
+select * from ancestors;
+
+
+with recursive
+ancestors
+as
+(
+ select *
+ from folks
+ where name = 'Me'
+ union
+ select p.*
+ from folks as p, ancestors as fa
+ where p.id = fa.father
+ union
+ select p.*
+ from folks as p, ancestors as ma
+ where p.id = ma.mother
+)
+select * from ancestors;
+
+
+--echo #
+--echo # EXPLAIN FORMAT=JSON on a query where one recursive CTE uses another:
+--echo #
+explain
+with recursive
+prev_gen
+as
+(
+ select folks.*
+ from folks, prev_gen
+ where folks.id=prev_gen.father or folks.id=prev_gen.mother
+ union
+ select *
+ from folks
+ where name='Me'
+),
+ancestors
+as
+(
+ select *
+ from folks
+ where name='Me'
+ union
+ select *
+ from ancestors
+ union
+ select *
+ from prev_gen
+)
+select ancestors.name, ancestors.dob from ancestors;
+
+explain FORMAT=JSON
+with recursive
+prev_gen
+as
+(
+ select folks.*
+ from folks, prev_gen
+ where folks.id=prev_gen.father or folks.id=prev_gen.mother
+ union
+ select *
+ from folks
+ where name='Me'
+),
+ancestors
+as
+(
+ select *
+ from folks
+ where name='Me2'
+ union
+ select *
+ from ancestors where id < 234
+ union
+ select *
+ from prev_gen where id < 345
+)
+select ancestors.name, ancestors.dob from ancestors;
+
+--echo #
+explain format=json
+with recursive
+ancestor_couples(h_id, h_name, h_dob, h_father, h_mother,
+ w_id, w_name, w_dob, w_father, w_mother)
+as
+(
+ select h.*, w.*
+ from folks h, folks w, coupled_ancestors a
+ where a.father = h.id AND a.mother = w.id
+ union
+ select h.*, w.*
+ from folks v, folks h, folks w
+ where v.name = 'Me' and
+ (v.father = h.id AND v.mother= w.id)
+),
+coupled_ancestors (id, name, dob, father, mother)
+as
+(
+ select h_id, h_name, h_dob, h_father, h_mother
+ from ancestor_couples
+ union all
+ select w_id, w_name, w_dob, w_father, w_mother
+ from ancestor_couples
+)
+select h_name, h_dob, w_name, w_dob
+ from ancestor_couples;
+
+
+create table my_ancestors
+with recursive
+ancestor_ids (id)
+as
+(
+ select father from folks where name = 'Me'
+ union
+ select mother from folks where name = 'Me'
+ 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
+)
+select p.* from folks as p, ancestor_ids as a where p.id = a.id;
+
+select * from my_ancestors;
+
+delete from my_ancestors;
+
+insert into my_ancestors
+with recursive
+ancestor_ids (id)
+as
+(
+ select father from folks where name = 'Me'
+ union
+ select mother from folks where name = 'Me'
+ 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
+)
+select p.* from folks as p, ancestor_ids as a where p.id = a.id;
+
+select * from my_ancestors;
+
+drop table my_ancestors;
+
+--echo #
+--echo # MDEV-10883: execution of prepared statement from SELECT
+--echo # with recursive CTE that renames columns
+--echo #
+
+prepare stmt from"
+with recursive
+ancestor_ids (id)
+as
+(
+ select father from folks where name = 'Me'
+ union
+ select mother from folks where name = 'Me'
+ 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
+)
+select p.* from folks as p, ancestor_ids as a where p.id = a.id;
+";
+execute stmt;
+deallocate prepare stmt;
+
+--echo #
+--echo # MDEV-10881: execution of prepared statement from
+--echo # CREATE ... SELECT, INSERT ... SELECT
+--echo #
+
+prepare stmt from"
+create table my_ancestors
+with recursive
+ancestor_ids (id)
+as
+(
+ select father from folks where name = 'Me'
+ union
+ select mother from folks where name = 'Me'
+ 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
+)
+select p.* from folks as p, ancestor_ids as a where p.id = a.id;
+";
+execute stmt;
+deallocate prepare stmt;
+select * from my_ancestors;
+
+delete from my_ancestors;
+
+prepare stmt from"
+insert into my_ancestors
+with recursive
+ancestor_ids (id)
+as
+(
+ select father from folks where name = 'Me'
+ union
+ select mother from folks where name = 'Me'
+ 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
+)
+select p.* from folks as p, ancestor_ids as a where p.id = a.id;
+";
+execute stmt;
+deallocate prepare stmt;
+select * from my_ancestors;
+
+drop table my_ancestors;
+
+--echo #
+--echo # MDEV-10933: WITH clause together with SELECT in parenthesis
+--echo # CREATE SELECT
+--echo #
+
+create table my_ancestors
+(
+with recursive
+ancestor_ids (id)
+as
+(
+ select father from folks where name = 'Me'
+ union
+ select mother from folks where name = 'Me'
+ 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
+)
+select p.* from folks as p, ancestor_ids as a where p.id = a.id
+);
+select * from my_ancestors;
+drop table my_ancestors;
+
+drop table folks;
+
+--echo #
+--echo # MDEV-10372: [bb-10.2-mdev9864 tree] EXPLAIN with recursive CTE enters endless recursion
+--echo #
+create table t1(a int);
+insert into t1 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
+
+explain format=json
+with recursive t as (select a from t1 union select a+10 from t where a < 1000)
+select * from t;
+
+drop table t1;
+
+
+--echo #
+--echo # MDEV-10737: recursive union with several anchors at the end
+--echo #
+
+WITH RECURSIVE cte(n) AS
+ ( SELECT n+1 FROM cte WHERE n < 5 UNION SELECT 1 UNION SELECT 1 )
+SELECT * FROM cte;
+
+--echo #
+--echo # MDEV-10736: recursive definition with anchor over a table with blob
+--echo #
+
+CREATE TABLE t1 (f VARCHAR(1024));
+WITH RECURSIVE cte(f) AS
+ (SELECT t1.f FROM t1 UNION ALL SELECT cte.f FROM cte)
+SELECT * FROM cte as t;
+DROP TABLE t1;
+
+--echo #
+--echo # MDEV-10899: mergeable derived in the spec of recursive CTE
+--echo #
+
+create table t1 (a int);
+insert into t1 values
+ (0), (1), (2), (3), (4);
+create table t2 (a int);
+insert into t2 values
+ (1), (2), (3), (4), (5);
+
+with recursive
+t1 as
+(
+select x.a from (select a from t2 where t2.a=3) x
+union
+select t2.a from t1,t2 where t1.a+1=t2.a
+)
+select * from t1;
+
+explain
+with recursive
+t1 as
+(
+select x.a from (select a from t2 where t2.a=3) x
+union
+select t2.a from t1,t2 where t1.a+1=t2.a
+)
+select * from t1;
+
+drop table t1,t2;
+
+--echo #
+--echo # MDEV-11278: non-mergeable view in the spec of recursive CTE
+--echo #
+
+create table t1 (a int);
+insert into t1 values
+ (0), (1), (2), (3), (4);
+create table t2 (a int);
+insert into t2 values
+ (1), (2), (3), (4), (5);
+
+create view v1 as
+ select a from t2 where a < 3
+ union
+ select a from t2 where a > 4;
+
+with recursive
+t1 as
+(
+select a from v1 where a=1
+union
+select v1.a from t1,v1 where t1.a+1=v1.a
+)
+select * from t1;
+
+drop view v1;
+drop table t1,t2;
+
+
+--echo #
+--echo # MDEV-11259: recursive CTE with concatenation operation
+--echo #
+
+DROP TABLE IF EXISTS edges;
+CREATE TABLE edges(
+ a int(10) unsigned NOT NULL,
+ b int(10) unsigned NOT NULL,
+ PRIMARY KEY (a,b),
+ KEY b(b)
+);
+
+INSERT INTO edges
+ VALUES (1,3),(2,1),(2,4),(3,4),(3,5),(3,6),(4,7),(5,1),(5,6),(6,1);
+
+DROP TABLE IF EXISTS edges2;
+CREATE VIEW edges2 (a, b) AS
+ SELECT a, b FROM edges UNION ALL SELECT b, a FROM edges;
+
+--sorted_result
+WITH RECURSIVE transitive_closure(a, b, distance, path_string) AS
+( SELECT a, b, 1 AS distance,
+ concat(a, '.', b, '.') AS path_string
+ FROM edges
+
+ UNION ALL
+
+ SELECT tc.a, e.b, tc.distance + 1,
+ concat(tc.path_string, e.b, '.') AS path_string
+ FROM edges AS e
+ JOIN transitive_closure AS tc
+ ON e.a = tc.b
+ WHERE tc.path_string NOT LIKE concat('%', e.b, '.%')
+)
+SELECT * FROM transitive_closure
+ORDER BY a, b, distance;
+
+--sorted_result
+WITH RECURSIVE transitive_closure(a, b, distance, path_string) AS
+( SELECT a, b, 1 AS distance,
+ concat(a, '.', b, '.') AS path_string
+ FROM edges
+ WHERE a = 1 -- source
+
+ UNION ALL
+
+ SELECT tc.a, e.b, tc.distance + 1,
+ concat(tc.path_string, e.b, '.') AS path_string
+ FROM edges AS e
+ JOIN transitive_closure AS tc ON e.a = tc.b
+ WHERE tc.path_string NOT LIKE concat('%', e.b, '.%')
+)
+ SELECT * FROM transitive_closure
+ WHERE b = 6 -- destination
+ORDER BY a, b, distance;
+
+--sorted_result
+WITH RECURSIVE transitive_closure(a, b, distance, path_string) AS
+( SELECT a, b, 1 AS distance,
+ concat(a, '.', b, '.') AS path_string
+ FROM edges2
+
+ UNION ALL
+
+ SELECT tc.a, e.b, tc.distance + 1,
+ concat(tc.path_string, e.b, '.') AS path_string
+ FROM edges2 AS e
+ JOIN transitive_closure AS tc ON e.a = tc.b
+ WHERE tc.path_string NOT LIKE concat('%', e.b, '.%')
+)
+SELECT * FROM transitive_closure
+ORDER BY a, b, distance;
+
+--sorted_result
+WITH RECURSIVE transitive_closure(a, b, distance, path_string)
+AS
+( SELECT a, b, 1 AS distance,
+ concat(a, '.', b, '.') AS path_string
+ FROM edges2
+
+ UNION ALL
+
+ SELECT tc.a, e.b, tc.distance + 1,
+ concat(tc.path_string, e.b, '.') AS path_string
+ FROM edges2 AS e
+ JOIN transitive_closure AS tc ON e.a = tc.b
+ WHERE tc.path_string NOT LIKE concat('%', e.b, '.%')
+)
+SELECT a, b, min(distance) AS dist FROM transitive_closure
+GROUP BY a, b
+ORDER BY a, dist, b;
+
+DROP VIEW edges2;
+DROP TABLE edges;
+
+
+--echo #
+--echo # MDEV-11674: recursive CTE table that cannot be stored
+--echo # in a heap table
+--echo #
+
+create table t1 (id int, test_data varchar(36));
+
+insert into t1(id, test_data)
+select id, test_data
+ from (
+ with recursive data_generator(id, test_data) as (
+ select 1 as id, uuid() as test_data
+ union all
+ select id + 1, uuid() from data_generator where id < 150000
+ )
+ select * from data_generator
+ ) as a;
+
+drop table t1;
+
+--echo #
+--echo # MDEV-10773: ANALYZE for query with recursive CTE
+--echo #
+
+--source include/analyze-format.inc
+analyze format=json
+with recursive src(counter) as
+(select 1
+ union
+ select counter+1 from src where counter<10
+) select * from src;
+
+--echo #
+--echo # mdev-12360: recursive reference in left operand of LEFT JOIN
+--echo #
+
+create table folks(id int, name char(32), dob date, father int, mother int);
+
+insert into folks values
+(100, 'Me', '2000-01-01', 20, 30),
+(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),
+(25, 'Uncle Jim', '1968-11-18', 8, 7),
+(98, 'Sister Amy', '2001-06-20', 20, 30),
+(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);
+
+with recursive
+ancestor_ids (id)
+as
+(
+ select father from folks where name = 'Me'
+ union
+ select mother from folks where name = 'Me'
+ union
+ select father from ancestor_ids as a left join folks on folks.id = a.id
+ union
+ select mother from ancestor_ids as a left join folks 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;
+
+drop table folks;
+
+--echo #
+--echo # mdev-12368: crash with mutually recursive CTE
+--echo # that arenot Standard compliant
+--echo #
+
+create table value_nodes (v char(4));
+create table module_nodes(m char(4));
+create table module_arguments(m char(4), v char(4));
+create table module_results(m char(4), v char(4));
+
+--ERROR ER_NOT_STANDARD_COMPLIANT_RECURSIVE
+with recursive
+reached_values as
+(
+ select v from value_nodes where v in ('v3','v7','v9')
+ union
+ select module_results.v from module_results, applied_modules
+ where module_results.m = applied_modules.m
+),
+applied_modules as
+(
+ select module_nodes.m
+ from
+ module_nodes
+ left join
+ (
+ module_arguments
+ left join
+ reached_values
+ on module_arguments.v = reached_values.v
+ )
+ on reached_values.v is null and
+ module_nodes.m = module_arguments.m
+ where module_arguments.m is null
+)
+select * from reached_values;
+
+drop table value_nodes, module_nodes, module_arguments, module_results;
+
+--echo #
+--echo # mdev-12375: query using one of two mutually recursive CTEs
+--echo # whose non-recursive part returns an empty set
+--echo #
+
+create table value_nodes (v char(4));
+insert into value_nodes values
+ ('v1'), ('v2'), ('v3'), ('v4'), ('v5'), ('v6'), ('v7'), ('v8'), ('v9'),
+ ('v10'), ('v11'), ('v12'), ('v13'), ('v14'), ('v15'), ('v16');
+create table module_nodes(m char(4));
+insert into module_nodes values
+ ('m1'), ('m2'), ('m3'), ('m4'), ('m5'), ('m6'), ('m7');
+create table module_arguments(m char(4), v char(4));
+insert into module_arguments values
+ ('m1','v3'), ('m1','v9'),
+ ('m2','v4'), ('m2','v3'), ('m2','v7'),
+ ('m3','v6'),
+ ('m4','v4'), ('m4','v1'),
+ ('m5','v10'), ('m5','v8'), ('m5','v3'),
+ ('m6','v8'), ('m6','v1'),
+ ('m7','v11'), ('m7','v12');
+create table module_results(m char(4), v char(4));
+insert into module_results values
+ ('m1','v4'),
+ ('m2','v1'), ('m2','v6'),
+ ('m3','v10'),
+ ('m4','v8'),
+ ('m5','v11'), ('m5','v9'),
+ ('m6','v12'), ('m6','v4'),
+ ('m7','v2');
+
+set statement max_recursive_iterations=2, standard_compliant_cte=0 for
+with recursive
+reached_values as
+(
+ select v from value_nodes where v in ('v3','v7','v9')
+ union
+ select module_results.v from module_results, applied_modules
+ where module_results.m = applied_modules.m
+),
+applied_modules as
+(
+ select * from module_nodes where 1=0
+ union
+ select module_nodes.m
+ from
+ module_nodes
+ left join
+ (
+ module_arguments
+ left join
+ reached_values
+ on module_arguments.v = reached_values.v
+ )
+ on reached_values.v is null and
+ module_nodes.m = module_arguments.m
+ where module_arguments.m is null
+)
+select * from applied_modules;
+
+drop table value_nodes, module_nodes, module_arguments, module_results;
+
+--echo #
+--echo # mdev-12519: recursive references in subqueries
+--echo #
+
+create table t1 (lp char(4) not null, rp char(4) not null);
+insert into t1 values
+ ('p1','p2'), ('p2','p3'), ('p3','p4'), ('p4','p5'),
+ ('p2','p7'), ('p7','p8'), ('p8','p3'), ('p8','p4');
+
+set standard_compliant_cte=0;
+
+with recursive
+reachables(p) as
+(
+ select lp from t1 where lp = 'p1'
+ union
+ select t1.rp from reachables, t1
+ where t1.lp = reachables.p
+)
+select * from reachables;
+
+with recursive
+reachables(p) as
+(
+ select lp from t1 where lp = 'p1'
+ union
+ select t1.rp from reachables, t1
+ where 'p3' not in (select * from reachables) and
+ t1.lp = reachables.p
+)
+select * from reachables;
+
+with recursive
+reachables(p) as
+(
+ select lp from t1 where lp = 'p1'
+ union
+ select t1.rp from reachables, t1
+ where 'p3' not in (select p from reachables where p <= 'p5'
+ union
+ select p from reachables where p > 'p5') and
+ t1.lp = reachables.p
+)
+select * from reachables;
+
+prepare stmt from "
+with recursive
+reachables(p) as
+(
+ select lp from t1 where lp = 'p1'
+ union
+ select t1.rp from reachables, t1
+ where 'p3' not in (select p from reachables where p <= 'p5'
+ union
+ select p from reachables where p > 'p5') and
+ t1.lp = reachables.p
+)
+select * from reachables;
+";
+
+execute stmt;
+execute stmt;
+
+deallocate prepare stmt;
+
+drop table t1;
+
+create table objects(v char(4) not null);
+insert into objects values
+ ('v1'), ('v2'), ('v3'), ('v4'), ('v5'),
+ ('v6'), ('v7'), ('v8'), ('v9'), ('v10');
+
+create table modules(m char(4) not null);
+insert into modules values
+ ('m1'), ('m2'), ('m3'), ('m4');
+
+create table module_arguments(m char(4) not null, v char(4) not null);
+insert into module_arguments values
+ ('m1','v3'), ('m1','v9'),
+ ('m2','v4'), ('m2','v7'),
+ ('m3','v6'), ('m4','v2');
+
+create table module_results(m char(4) not null, v char(4) not null);
+insert into module_results values
+ ('m1','v4'),
+ ('m2','v1'), ('m2','v6'),
+ ('m3','v10'), ('m4','v7');
+
+set standard_compliant_cte=0;
+
+with recursive
+reached_objects as
+(
+ select v, 'init' as m from objects where v in ('v3','v7','v9')
+ union
+ select module_results.v, module_results.m from module_results, applied_modules
+ where module_results.m = applied_modules.m
+),
+applied_modules as
+(
+ select * from modules where 1=0
+ union
+ select modules.m
+ from
+ modules
+ where
+ not exists (select * from module_arguments
+ where module_arguments.m = modules.m and
+ module_arguments.v not in
+ (select v from reached_objects))
+)
+select * from reached_objects;
+
+with recursive
+reached_objects as
+(
+ select v, 'init' as m from objects where v in ('v3','v7','v9')
+ union
+ select module_results.v, module_results.m from module_results, applied_modules
+ where module_results.m = applied_modules.m
+),
+applied_modules as
+(
+ select * from modules where 1=0
+ union
+ select modules.m
+ from
+ modules
+ where
+ 'v6' not in (select v from reached_objects) and
+ not exists (select * from module_arguments
+ where module_arguments.m = modules.m and
+ module_arguments.v not in
+ (select v from reached_objects))
+)
+select * from reached_objects;
+
+prepare stmt from "
+with recursive
+reached_objects as
+(
+ select v, 'init' as m from objects where v in ('v3','v7','v9')
+ union
+ select module_results.v, module_results.m from module_results, applied_modules
+ where module_results.m = applied_modules.m
+),
+applied_modules as
+(
+ select * from modules where 1=0
+ union
+ select modules.m
+ from
+ modules
+ where
+ 'v6' not in (select v from reached_objects) and
+ not exists (select * from module_arguments
+ where module_arguments.m = modules.m and
+ module_arguments.v not in
+ (select v from reached_objects))
+)
+select * from reached_objects;
+";
+
+execute stmt;
+execute stmt;
+
+deallocate prepare stmt;
+
+drop table objects, modules, module_arguments, module_results;
+
+set standard_compliant_cte=default;
+select @@standard_compliant_cte;
+
+--echo #
+--echo # mdev-12554: impossible where in recursive select
+--echo #
+
+CREATE TABLE t1 (i int);
+INSERT INTO t1 VALUES (1),(2);
+
+WITH RECURSIVE
+cte(f) AS ( SELECT i FROM t1 UNION SELECT f FROM t1, cte WHERE 1=0 )
+SELECT * FROM cte;
+
+DROP TABLE t1;
+
+--echo #
+--echo # mdev-12556: recursive execution uses Aria temporary tables
+--echo #
+
+CREATE TABLE t (c1 varchar(255), c2 tinytext);
+INSERT INTO t VALUES ('a','a'),('b','b'),('c','c'),('d','d');
+
+let $q1=
+WITH RECURSIVE cte(f) AS (
+ SELECT c1 FROM t
+ UNION
+ SELECT c1 FROM t, cte
+) SELECT COUNT(*) FROM cte;
+
+let $q2=
+WITH RECURSIVE cte(f) AS (
+ SELECT c2 FROM t
+ UNION
+ SELECT c2 FROM t, cte
+) SELECT COUNT(*) FROM cte;
+
+eval ANALYZE $q1;
+eval $q1;
+
+eval ANALYZE $q2;
+eval $q2;
+
+DROP TABLE t;
+
+--echo #
+--echo # mdev-12563: no recursive references on the top level of the CTE spec
+--echo #
+
+CREATE TABLE t (i int);
+INSERT INTO t VALUES (3), (1),(2);
+
+SET standard_compliant_cte=0;
+
+WITH RECURSIVE cte(f) AS (
+ SELECT i FROM t
+ UNION
+ SELECT i FROM t WHERE i NOT IN ( SELECT * FROM cte )
+) SELECT * FROM cte;
+
+WITH RECURSIVE cte(f) AS (
+ SELECT i FROM t
+ UNION
+ SELECT i FROM t WHERE i NOT IN ( SELECT * FROM cte WHERE i < 2 )
+ UNION
+ SELECT i FROM t WHERE i NOT IN ( SELECT * FROM cte WHERE i > 2 )
+) SELECT * FROM cte;
+
+WITH RECURSIVE cte(f) AS (
+ SELECT i FROM t
+ UNION
+ SELECT i FROM t
+ WHERE i NOT IN ( SELECT * FROM cte WHERE i < 2
+ UNION
+ SELECT * FROM cte WHERE i > 2)
+) SELECT * FROM cte;
+
+WITH RECURSIVE cte(f) AS (
+ SELECT i FROM t
+ UNION
+ SELECT i FROM t
+ WHERE i NOT IN ( SELECT * FROM t
+ WHERE i IN ( SELECT * FROM cte ) GROUP BY i )
+) SELECT * FROM cte;
+
+WITH RECURSIVE cte(f) AS (
+ SELECT i FROM t
+ UNION
+ SELECT i FROM t WHERE i NOT IN ( SELECT * FROM cte )
+ UNION
+ SELECT * FROM cte WHERE f > 2
+) SELECT * FROM cte;
+
+set standard_compliant_cte=default;
+
+DROP TABLE t;
+
+--echo #
+--echo # mdev-14184: recursive CTE embedded into CTE with multiple references
+--echo #
+
+WITH
+cte1 AS (
+ SELECT n FROM (
+ WITH RECURSIVE rec_cte(n) AS (
+ SELECT 1 as n1
+ UNION ALL
+ SELECT n+1 as n2 FROM rec_cte WHERE n < 3
+ ) SELECT n FROM rec_cte
+ ) AS X
+),
+cte2 as (
+ SELECT 2 FROM cte1
+)
+SELECT *
+FROM cte1;
+
+--echo #
+--echo # mdev-14629: a user-defined variable is defined by the recursive CTE
+--echo #
+
+set @var=
+(
+ with recursive cte_tab(a) as (
+ select 1
+ union
+ select a+1 from cte_tab
+ where a<3)
+ select count(*) from cte_tab
+);
+
+select @var;
+
+create table t1(a int, b int);
+insert into t1 values (3,8),(1,5),(5,7),(7,4),(4,3);
+
+set @var=
+(
+ with recursive summ(a,s) as (
+ select 1, 0 union
+ select t1.b, t1.b+summ.s from summ, t1
+ where summ.a=t1.a)
+ select s from summ
+ order by a desc
+ limit 1
+);
+
+select @var;
+
+--ERROR ER_UNACCEPTABLE_MUTUAL_RECURSION
+set @var=
+(
+ with recursive
+ cte_1 as (
+ select 1
+ union
+ select * from cte_2),
+ cte_2 as (
+ select * from cte_1
+ union
+ select a from t1, cte_2
+ where t1.a=cte_2.a)
+ select * from cte_2
+ limit 1
+);
+
+drop table t1;
+
+--echo #
+--echo # mdev-14777: crash caused by the same as in mdev-14755
+--echo #
+
+--source include/have_sequence.inc
+
+CREATE TABLE t1 (i1 int NOT NULL, i2 int);
+CREATE TABLE t2 (d1 int NOT NULL PRIMARY KEY);
+CREATE TABLE t3 (i int );
+
+insert into t1 select seq,seq from seq_1_to_100000;
+insert into t2 select seq from seq_1000_to_100000;
+insert into t3 select seq from seq_1_to_1000;
+
+SELECT *
+FROM
+(
+ SELECT *
+ FROM
+ (
+ WITH RECURSIVE rt AS
+ (
+ SELECT i2 P, i1 C FROM t1 WHERE i1 IN (SELECT d1 FROM t2)
+ UNION
+ SELECT t1.i2 P, rt.C C FROM t1, rt
+ )
+ SELECT C,P
+ FROM ( SELECT P,C FROM rt WHERE NOT EXISTS (SELECT 1 FROM t1) ) Y
+ ) X
+ WHERE 1 = 1
+) K, t3;
+
+drop table t1,t2,t3;
+
+--echo #
+--echo # mdev-14879: subquery with recursive reference in WHERE of CTE
+--echo #
+
+create table flights
+(departure varchar(32),
+ arrival varchar(32),
+ carrier varchar(20),
+ flight_number char(7));
+
+insert into flights values
+('Seattle', 'Frankfurt', 'Lufthansa', 'LH 491'),
+('Seattle', 'Chicago', 'American', 'AA 2573'),
+('Seattle', 'Los Angeles', 'Alaska Air', 'AS 410'),
+('Chicago', 'New York', 'American', 'AA 375'),
+('Chicago', 'Montreal', 'Air Canada', 'AC 3053'),
+('Los Angeles', 'New York', 'Delta', 'DL 1197'),
+('Moscow', 'Tokyo', 'Aeroflot', 'SU 264'),
+('New York', 'Paris', 'Air France', 'AF 23'),
+('Frankfurt', 'Moscow', 'Lufthansa', 'LH 1444'),
+('Tokyo', 'Seattle', 'ANA', 'NH 178'),
+('Los Angeles', 'Tokyo', 'ANA', 'NH 175'),
+('Moscow', 'Los Angeles', 'Aeroflot', 'SU 106'),
+('Montreal', 'Paris', 'Air Canada', 'AC 870'),
+('Cairo', 'Paris', 'Air France', 'AF 503'),
+('New York', 'Seattle', 'American', 'AA 45'),
+('Paris', 'Chicago', 'Air France', 'AF 6734');
+
+with recursive destinations (city) as
+( select a.arrival from flights a where a.departure='Cairo'
+ union
+ select b.arrival from destinations r, flights b where r.city=b.departure)
+select * from destinations;
+
+set standard_compliant_cte=0;
+
+let $q=
+with recursive destinations (city, legs) as
+(
+ select a.arrival, 1 from flights a where a.departure='Cairo'
+ union
+ select b.arrival, r.legs + 1 from destinations r, flights b
+ where r.city=b.departure and b.arrival not in (select city from destinations)
+)
+select * from destinations;
+
+eval $q;
+eval explain extended $q;
+
+set standard_compliant_cte=default;
+
+drop table flights;
+
+--echo #
+--echo # MDEV-15162: Setting user variable in recursive CTE
+--echo #
+
+SET @c=1;
+
+WITH RECURSIVE cte AS
+ (SELECT 5
+ UNION
+ SELECT @c:=@c+1 FROM cte WHERE @c<3)
+SELECT * FROM cte;
+
+
+--echo #
+--echo # MDEV-14217 [db crash] Recursive CTE when SELECT includes new field
+--echo #
+
+CREATE TEMPORARY TABLE a_tbl (
+ a VARCHAR(33) PRIMARY KEY,
+ b VARCHAR(33)
+);
+
+INSERT INTO a_tbl VALUES ('block0', 'block0'), ('block1', NULL);
+
+--error ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT
+WITH RECURSIVE Q0 AS (
+ SELECT T0.a, T0.b, 5
+ FROM a_tbl T0
+ WHERE b IS NULL
+ UNION ALL
+ SELECT T1.a, T1.b
+ FROM Q0
+ JOIN a_tbl T1
+ ON T1.a=Q0.a
+) SELECT distinct(Q0.a), Q0.b
+ FROM Q0;
+DROP TABLE a_tbl;
+
+--error ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT
+WITH RECURSIVE x AS (SELECT 1,2 UNION ALL SELECT 1 FROM x) SELECT * FROM x;
+
+--echo #
+--echo # MDEV-15162: Setting user variable in recursive CTE
+--echo #
+
+SET @c=1;
+
+WITH RECURSIVE cte AS
+ (SELECT 5
+ UNION
+ SELECT @c:=@c+1 FROM cte WHERE @c<3)
+SELECT * FROM cte;
+
+--echo #
+--echo # MDEV-14883: recursive references in operands of INTERSECT / EXCEPT
+--echo #
+
+create table flights
+(departure varchar(32),
+ arrival varchar(32),
+ carrier varchar(20),
+ flight_number char(7));
+
+insert into flights values
+('Seattle', 'Frankfurt', 'Lufthansa', 'LH 491'),
+('Seattle', 'Amsterdam', 'KLM', 'KL 6032'),
+('Seattle', 'Chicago', 'American', 'AA 2573'),
+('Seattle', 'Los Angeles', 'Alaska Air', 'AS 410'),
+('Chicago', 'New York', 'American', 'AA 375'),
+('Chicago', 'Montreal', 'Air Canada', 'AC 3053'),
+('Los Angeles', 'New York', 'Delta', 'DL 1197'),
+('New York', 'London', 'British Airways', 'BA 1511'),
+('London', 'Moscow', 'British Airways', 'BA 233'),
+('Moscow', 'Tokyo', 'Aeroflot', 'SU 264'),
+('Moscow', 'Dubai', 'Emirates', 'EK 2421'),
+('Dubai', 'Tokyo', 'Emirates', 'EK 318'),
+('Dubai', 'Bangkok', 'Emirates', 'EK 2142'),
+('Beijing', 'Bangkok', 'Air China', 'CA 757'),
+('Beijing', 'Tokyo', 'Air China', 'CA 6653'),
+('Moscow', 'Bangkok', 'Aeroflot', 'SU 270'),
+('New York', 'Reykjavik', 'Icelandair', 'FL 416'),
+('New York', 'Paris', 'Air France', 'AF 23'),
+('Amsterdam', 'Moscow', 'KLM', 'KL 903'),
+('Frankfurt', 'Dubai', 'Lufthansa', 'LH 630'),
+('Frankfurt', 'Moscow', 'Lufthansa', 'LH 1444'),
+('Reykjavik', 'London', 'British Airways', 'BA 2229'),
+('Frankfurt', 'Beijing', 'Air China', 'CA 966'),
+('Tokyo', 'Seattle', 'ANA', 'NH 178'),
+('Los Angeles', 'Tokyo', 'ANA', 'NH 175'),
+('Moscow', 'Los Angeles', 'Aeroflot', 'SU 106'),
+('Montreal', 'Paris', 'Air Canada', 'AC 870'),
+('London', 'Delhi', 'British Airways', 'BA 143'),
+('Delhi', 'Bangkok', 'Air India', 'AI 306'),
+('Delhi', 'Dubai', 'Air India', 'AI 995'),
+('Dubai', 'Cairo', 'Emirates', 'EK 927'),
+('Cairo', 'Paris', 'Air France', 'AF 503'),
+('Amsterdam', 'New York', 'Delta', 'DL 47'),
+('New York', 'Seattle', 'American', 'AA 45'),
+('Paris', 'Chicago', 'Air France', 'AF 6734');
+
+create table distances
+(city1 varchar(32),
+ city2 varchar(32),
+ dist int);
+
+insert into distances values
+('Seattle', 'Frankfurt', 5080),
+('Seattle', 'Amsterdam', 4859),
+('Seattle', 'Chicago', 1733),
+('Seattle', 'Los Angeles', 960),
+('Chicago', 'New York', 712),
+('Chicago', 'Montreal', 746),
+('Los Angeles', 'New York', 2446),
+('New York', 'London', 3459),
+('London', 'Moscow', 1554),
+('Moscow', 'Tokyo', 4647),
+('Moscow', 'Dubai', 2298),
+('Dubai', 'Tokyo', 4929),
+('Dubai', 'Bangkok', 3050),
+('Beijing', 'Bangkok', 2046),
+('Beijing', 'Tokyo', 1301),
+('Moscow', 'Bangkok', 4390),
+('New York', 'Reykjavik', 2613),
+('New York', 'Paris', 3625),
+('Amsterdam', 'Moscow', 1334),
+('Frankfurt', 'Dubai', 3003),
+('Frankfurt', 'Moscow', 1256),
+('Reykjavik', 'London', 1173),
+('Frankfurt', 'Beijing', 4836),
+('Tokyo', 'Seattle', 4783),
+('Los Angeles', 'Tokyo', 5479),
+('Moscow', 'Los Angeles', 6071),
+('Moscow', 'Reykjavik', 2052),
+('Montreal', 'Paris', 3425),
+('London', 'Delhi', 4159),
+('London', 'Paris', 214),
+('Delhi', 'Bangkok', 1810),
+('Delhi', 'Dubai', 1369),
+('Delhi', 'Beijing', 2350),
+('Dubai', 'Cairo', 1501),
+('Cairo', 'Paris', 1992),
+('Amsterdam', 'New York', 3643),
+('New York', 'Seattle', 2402),
+('Paris', 'Chicago', 4136),
+('Paris', 'Los Angeles', 5647);
+
+with recursive destinations (city) as
+(
+ select a.arrival from flights a where a.departure = 'Seattle'
+ union
+ select b.arrival from destinations r, flights b where r.city = b.departure
+)
+select * from destinations;
+
+with recursive destinations (city) as
+(
+ select a.arrival from flights a, distances d
+ where a.departure = 'Seattle' and
+ a.departure = d.city1 and a.arrival = d.city2 and
+ d.dist < 4000
+ union
+ select b.arrival from destinations r, flights b, distances d
+ where r.city = b.departure and
+ b.departure = d.city1 and b.arrival = d.city2 and
+ d.dist < 4000
+)
+select * from destinations;
+
+set standard_compliant_cte=0;
+
+with recursive legs_to_destinations
+ (departure, arrival, dist, leg_no, acc_mileage) as
+(
+ select a.departure, a.arrival, d.dist, 1, d.dist
+ from flights a, distances d
+ where a.departure = 'Seattle' and
+ a.departure = d.city1 and a.arrival = d.city2 and
+ d.dist < 4000
+ union all
+ select b.departure, b.arrival, d.dist, r.leg_no + 1, r.acc_mileage + d.dist
+ from legs_to_destinations r, flights b, distances d
+ where r.arrival = b.departure and
+ b.departure = d.city1 and b.arrival = d.city2 and
+ d.dist < 4000 and
+ b.arrival not in (select arrival from legs_to_destinations)
+)
+select * from legs_to_destinations;
+
+set standard_compliant_cte=default;
+
+with recursive destinations (city) as
+(
+ select a.arrival from flights a, distances d
+ where a.departure = 'Seattle' and
+ a.departure = d.city1 and a.arrival = d.city2 and
+ d.dist < 4000
+ union
+ select b.arrival from destinations r, flights b
+ where r.city = b.departure
+ intersect
+ select city2 from destinations s, distances d
+ where s.city = d.city1 and d.dist < 4000
+)
+select * from destinations;
+
+with recursive destinations (city) as
+(
+ select a.arrival from flights a where a.departure = 'Seattle'
+ union
+ select * from
+ (
+ select b.arrival from destinations r, flights b
+ where r.city = b.departure
+ except
+ select arrival from flights
+ where arrival in
+ ('New York', 'London', 'Moscow', 'Dubai', 'Cairo', 'Tokyo')
+ ) t
+)
+select * from destinations;
+
+drop table flights, distances;