From aae2ff034b5eb7e4091d0fb2db3300d21696a51c Mon Sep 17 00:00:00 2001 From: DualFroz Date: Fri, 11 Sep 2026 18:43:45 +0200 Subject: [PATCH] test(sql): cover explainOverACompoundQueryDescribesTheSetOperatorAndB... --- .../store/sql/DiskExecutorExplainTest.kt | 82 +++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/src/test/kotlin/kestrel/store/sql/DiskExecutorExplainTest.kt b/src/test/kotlin/kestrel/store/sql/DiskExecutorExplainTest.kt index e270dcc..3cd048c 100644 --- a/src/test/kotlin/kestrel/store/sql/DiskExecutorExplainTest.kt +++ b/src/test/kotlin/kestrel/store/sql/DiskExecutorExplainTest.kt @@ -314,3 +314,85 @@ class DiskExecutorExplainTest { assertEquals(" Offset 1", plan[1]) } + @Test + fun explainOverACompoundQueryDescribesTheSetOperatorAndBothSides() { + val db = newDatabase() + db.run("CREATE TABLE t1 (id INTEGER PRIMARY KEY, name TEXT NOT NULL)") + db.run("CREATE TABLE t2 (id INTEGER PRIMARY KEY, name TEXT NOT NULL)") + db.run("INSERT INTO t1 VALUES (1, 'ada')") + db.run("INSERT INTO t2 VALUES (2, 'linus')") + val plan = db.explain("EXPLAIN SELECT name FROM t1 UNION SELECT name FROM t2") + assertEquals("Union", plan.first()) + assertTrue(plan.any { it.trim() == "-> Seq Scan on t1" }) + assertTrue(plan.any { it.trim() == "-> Seq Scan on t2" }) + } + + @Test + fun explainOverAWithRecursiveQueryDescribesTheCteAndItsBody() { + val db = newDatabase() + db.run("CREATE TABLE dual (x INTEGER)") + db.run("INSERT INTO dual VALUES (1)") + val plan = db.explain( + "EXPLAIN WITH RECURSIVE counter(n) AS (" + + "SELECT 1 FROM dual UNION ALL SELECT n + 1 FROM counter WHERE n < 5" + + ") SELECT n FROM counter" + ) + assertTrue(plan.any { it == "CTE counter" }) + assertTrue(plan.any { it == "Seq Scan on counter" }) + } + + @Test + fun explainOverAViewDescribesTheOuterQueryAgainstTheViewsMaterializedSchema() { + val db = newDatabase() + db.seedUsers() + db.run("CREATE VIEW adults AS SELECT id, name FROM users WHERE age >= 40") + val plan = db.explain("EXPLAIN SELECT * FROM adults") + assertTrue(plan.any { it == "Seq Scan on adults" }) + } + + @Test + fun explainOverADerivedTableDescribesItByItsAlias() { + val db = newDatabase() + db.seedUsers() + val plan = db.explain("EXPLAIN SELECT s.name FROM (SELECT id, name FROM users) AS s") + assertTrue(plan.any { it == "Seq Scan on s" }) + } + + @Test + fun explainRejectsAWindowFunctionInWhereStructurallyWithoutRunningTheQuery() { + val db = newDatabase() + db.seedUsers() + val table = db.catalog.table("users") + val failure = assertFailsWith { + db.explain("EXPLAIN SELECT name FROM users WHERE ROW_NUMBER() OVER (ORDER BY id) > 1") + } + assertTrue(failure.message!!.contains("window functions are not allowed in WHERE")) + assertEquals(0, table.scanCount) + } + + @Test + fun explainRejectsAColumnMissingFromGroupByJustLikeRunningTheQueryWould() { + val db = newDatabase() + db.seedOrders() + val failure = assertFailsWith { + db.explain("EXPLAIN SELECT customer_id, amount FROM orders GROUP BY customer_id") + } + assertTrue(failure.message!!.contains("must appear in GROUP BY")) + } + + @Test + fun explainRejectsADuplicateTableAliasJustLikeRunningTheQueryWould() { + val db = newDatabase() + db.seedUsers() + val failure = assertFailsWith { + db.explain("EXPLAIN SELECT * FROM users u JOIN users u ON u.id = u.id") + } + assertTrue(failure.message!!.contains("duplicate table alias")) + } + + @Test + fun explainOnAMissingTableStillReportsNoSuchTable() { + val db = newDatabase() + assertFailsWith { db.explain("EXPLAIN SELECT * FROM missing") } + } +}