Skip to content

Commit 6771326

Browse files
authored
Fix #830, remove restriction on recursive CTE (#835)
* Fix #830, remove incorrect restriction on recursive CTE I tested this with sqlite and the queries execute successfully. It's possible that there are other incorrect behaviors that can be pre-emptively caught, perhaps those could be added in a new PR later. * Add test --------- Co-authored-by: Andrew Baxter <>
1 parent 81117a7 commit 6771326

File tree

2 files changed

+44
-9
lines changed

2 files changed

+44
-9
lines changed

src/backend/query_builder.rs

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -774,15 +774,6 @@ pub trait QueryBuilder:
774774
"Cannot build a with query that has no common table expression!"
775775
);
776776

777-
if with_clause.recursive {
778-
assert_eq!(
779-
with_clause.cte_expressions.len(),
780-
1,
781-
"Cannot build a recursive query with more than one common table! \
782-
A recursive with query must have a single cte inside it that has a union query of \
783-
two queries!"
784-
);
785-
}
786777
for cte in &with_clause.cte_expressions {
787778
if !cte_first {
788779
write!(sql, ", ").unwrap();

tests/sqlite/query.rs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1792,3 +1792,47 @@ fn sub_query_with_fn() {
17921792
r#"SELECT ARRAY((SELECT * FROM "character"))"#
17931793
);
17941794
}
1795+
1796+
#[test]
1797+
fn recursive_with_multiple_ctes() {
1798+
let sub_select1 = Query::select()
1799+
.column(Asterisk)
1800+
.from(Char::Table)
1801+
.to_owned();
1802+
let sub_select1_name = SeaRc::new(Alias::new("sub1"));
1803+
let mut sub_select1_cte = CommonTableExpression::new();
1804+
sub_select1_cte.table_name(sub_select1_name.clone());
1805+
sub_select1_cte.column(SeaRc::new(Alias::new("a")));
1806+
sub_select1_cte.query(sub_select1);
1807+
let sub_select2 = Query::select()
1808+
.column(Asterisk)
1809+
.from(Char::Table)
1810+
.to_owned();
1811+
let sub_select2_name = SeaRc::new(Alias::new("sub2"));
1812+
let mut sub_select2_cte = CommonTableExpression::new();
1813+
sub_select2_cte.table_name(sub_select2_name.clone());
1814+
sub_select2_cte.column(SeaRc::new(Alias::new("b")));
1815+
sub_select2_cte.query(sub_select2);
1816+
1817+
let mut with = WithClause::new();
1818+
with.recursive(true)
1819+
.cte(sub_select1_cte)
1820+
.cte(sub_select2_cte);
1821+
1822+
let mut main_sel2 = Query::select();
1823+
main_sel2
1824+
.expr(Expr::col(Asterisk))
1825+
.from(TableRef::Table(sub_select2_name));
1826+
let mut main_sel1 = Query::select();
1827+
main_sel1
1828+
.expr(Expr::col(Asterisk))
1829+
.from(TableRef::Table(sub_select1_name))
1830+
.union(UnionType::All, main_sel2);
1831+
1832+
let query = with.query(main_sel1);
1833+
1834+
assert_eq!(
1835+
query.to_string(SqliteQueryBuilder),
1836+
r#"WITH RECURSIVE "sub1" ("a") AS (SELECT * FROM "character") , "sub2" ("b") AS (SELECT * FROM "character") SELECT * FROM "sub1" UNION ALL SELECT * FROM "sub2""#
1837+
);
1838+
}

0 commit comments

Comments
 (0)