From bdf167469ed1e7546810261eb23a90167c3fcbfb Mon Sep 17 00:00:00 2001 From: DualFroz Date: Tue, 8 Sep 2026 20:43:27 +0200 Subject: [PATCH] test: cover cteWithExplicitColumnListRenamesOutputColumns --- src/test/kotlin/kestrel/CompoundQueryTest.kt | 92 ++++++++++++++++++++ 1 file changed, 92 insertions(+) diff --git a/src/test/kotlin/kestrel/CompoundQueryTest.kt b/src/test/kotlin/kestrel/CompoundQueryTest.kt index e856f11..8bc6333 100644 --- a/src/test/kotlin/kestrel/CompoundQueryTest.kt +++ b/src/test/kotlin/kestrel/CompoundQueryTest.kt @@ -160,3 +160,95 @@ class CompoundQueryTest { assertEquals(listOf(listOf(text("linus"))), result.rows) } + @Test + fun cteWithExplicitColumnListRenamesOutputColumns() { + seed() + val result = select("WITH renamed(label) AS (SELECT name FROM t1) SELECT label FROM renamed ORDER BY label") + assertEquals(listOf(listOf(text("ada")), listOf(text("linus"))), result.rows) + } + + @Test + fun cteColumnListSizeMustMatchQueryColumnCount() { + seed() + assertFailsWith { + select("WITH bad(a, b, c) AS (SELECT id FROM t1) SELECT * FROM bad") + } + } + + @Test + fun recursiveCteGeneratesABoundedSequence() { + seed() + val result = select( + "WITH RECURSIVE counter(n) AS (" + + "SELECT 1 FROM dual " + + "UNION ALL " + + "SELECT n + 1 FROM counter WHERE n < 5" + + ") SELECT n FROM counter ORDER BY n" + ) + assertEquals((1..5).map { listOf(int(it.toLong())) }, result.rows) + } + + @Test + fun recursiveCteAccumulatesARunningTotal() { + seed() + val result = select( + "WITH RECURSIVE sums(n, total) AS (" + + "SELECT 1, 1 FROM dual " + + "UNION ALL " + + "SELECT n + 1, total + n + 1 FROM sums WHERE n < 5" + + ") SELECT total FROM sums WHERE n = 5" + ) + assertEquals(listOf(listOf(int(15))), result.rows) + } + + @Test + fun recursiveCteWithUnionDeduplicatesAndTerminatesOnACycle() { + seed() + run("CREATE TABLE edges (from_node INTEGER, to_node INTEGER)") + run("INSERT INTO edges VALUES (1, 2), (2, 3), (3, 1), (3, 4)") + val result = select( + "WITH RECURSIVE reachable(node) AS (" + + "SELECT 1 FROM dual " + + "UNION " + + "SELECT edges.to_node FROM edges JOIN reachable ON edges.from_node = reachable.node" + + ") SELECT node FROM reachable ORDER BY node" + ) + assertEquals(listOf(1L, 2L, 3L, 4L).map { listOf(int(it)) }, result.rows) + } + + @Test + fun recursiveCteWithoutSelfReferenceBehavesAsAPlainCompoundQuery() { + seed() + val result = select( + "WITH RECURSIVE notActuallyRecursive AS (SELECT 1 AS n FROM dual UNION ALL SELECT 2 FROM dual) " + + "SELECT n FROM notActuallyRecursive ORDER BY n" + ) + assertEquals(listOf(listOf(int(1)), listOf(int(2))), result.rows) + } + + @Test + fun recursiveCteReferencingItselfOnBothSidesFails() { + seed() + assertFailsWith { + select( + "WITH RECURSIVE bad(n) AS (" + + "SELECT n FROM bad UNION ALL SELECT n FROM bad" + + ") SELECT n FROM bad" + ) + } + } + + @Test + fun nonTerminatingRecursiveCteFailsInsteadOfLoopingForever() { + seed() + assertFailsWith { + select( + "WITH RECURSIVE counter(n) AS (" + + "SELECT 1 FROM dual " + + "UNION ALL " + + "SELECT n + 1 FROM counter" + + ") SELECT n FROM counter" + ) + } + } +}