test(sql): cover DiskExecutorExplainTest and tempFile

This commit is contained in:
dualfroz committed 2026-09-11 17:50:37 +02:00
1 parent 7bed867433
commit b35dadfe6f
1 file changed
+158
@@ -0,0 +1,158 @@
package kestrel.store.sql
import kestrel.engine.ExplainResult
import kestrel.sql.ast.Statement
import kestrel.sql.lexer.Lexer
import kestrel.sql.parser.Parser
import kestrel.storage.Value
import java.io.File
import java.nio.file.Files
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertFailsWith
import kotlin.test.assertTrue
/**
* Closes the "this executor has no `explain`" scope cut documented on [DiskExecutor.executeCreateView]:
* proves EXPLAIN on the disk-backed executor both describes the right plan shape (Seq Scan/Primary Key
* Scan/Index Scan/Nested Loop/GroupAggregate/Sort/Limit/CTE/UNION) AND - the part a plan-text assertion
* alone cannot show - never touches a single row of real table data to produce it, verified against the
* same [DiskTable] access counters [DiskExecutorTest] itself uses to prove index pushdown really happens.
*/
class DiskExecutorExplainTest {
private fun tempFile(prefix: String): File = Files.createTempFile(prefix, ".db").toFile().also { it.deleteOnExit() }
private fun parse(sql: String): List<Statement> = Parser(Lexer(sql).tokenize()).parseProgram()
private fun int(value: Long) = Value.IntegerValue(value)
private inner class Database(dataFile: File, walFile: File) {
val catalog = DiskCatalog.open(dataFile, walFile)
val executor = DiskExecutor(catalog)
fun run(sql: String): List<kestrel.engine.StatementResult> = parse(sql).map { executor.execute(it) }
fun explain(sql: String): List<String> = (run(sql).single() as ExplainResult).plan
}
private fun newDatabase(): Database = Database(tempFile("kestrel-disk-explain-data"), tempFile("kestrel-disk-explain-wal"))
private fun Database.seedUsers() {
run("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT NOT NULL, age INTEGER)")
run("INSERT INTO users VALUES (1, 'ada', 36), (2, 'linus', 54), (3, 'grace', 85)")
}
private fun Database.seedOrders() {
run("CREATE TABLE customers (id INTEGER PRIMARY KEY, name TEXT NOT NULL)")
run("INSERT INTO customers VALUES (1, 'ada'), (2, 'linus'), (3, 'grace')")
run("CREATE TABLE orders (id INTEGER PRIMARY KEY, customer_id INTEGER NOT NULL, amount INTEGER NOT NULL)")
run("INSERT INTO orders VALUES (1, 1, 100), (2, 1, 50), (3, 2, 200)")
}
@Test
fun explainOnAnUnindexedWhereReportsASeqScanAndTouchesNoRowData() {
val db = newDatabase()
db.seedUsers()
val table = db.catalog.table("users")
val plan = db.explain("EXPLAIN SELECT name FROM users WHERE name = 'linus'")
assertTrue(plan.any { it == "Seq Scan on users" })
assertEquals(0, table.scanCount)
}
@Test
fun explainOnAPrimaryKeyEqualityReportsAPrimaryKeyScanAndTouchesNoRowData() {
val db = newDatabase()
db.seedUsers()
val table = db.catalog.table("users")
val plan = db.explain("EXPLAIN SELECT name FROM users WHERE id = 2")
assertTrue(plan.any { it == "Primary Key Scan on users (id = 2)" })
assertEquals(0, table.pointLookupCount)
assertEquals(0, table.scanCount)
}
@Test
fun explainOnAPrimaryKeyRangeReportsAPrimaryKeyRangeScanAndTouchesNoRowData() {
val db = newDatabase()
db.seedUsers()
val table = db.catalog.table("users")
val plan = db.explain("EXPLAIN SELECT name FROM users WHERE id > 1 AND id <= 3")
assertTrue(plan.any { it == "Primary Key Range Scan on users (id > 1 AND id <= 3)" })
assertEquals(0, table.rangeScanCount)
assertEquals(0, table.scanCount)
}
@Test
fun explainOnACompositePrimaryKeyEqualityReportsAPrimaryKeyScan() {
val db = newDatabase()
db.run("CREATE TABLE order_lines (order_id INTEGER, line_no INTEGER, sku TEXT, PRIMARY KEY (order_id, line_no))")
db.run("INSERT INTO order_lines VALUES (1, 1, 'widget'), (1, 2, 'gadget')")
val table = db.catalog.table("order_lines")
val plan = db.explain("EXPLAIN SELECT sku FROM order_lines WHERE order_id = 1 AND line_no = 2")
assertTrue(plan.any { it == "Primary Key Scan on order_lines (order_id = 1 AND line_no = 2)" })
assertEquals(0, table.pointLookupCount)
}
@Test
fun explainOnACompositePrimaryKeyRangeReportsAPrimaryKeyRangeScan() {
val db = newDatabase()
db.run("CREATE TABLE order_lines (order_id INTEGER, line_no INTEGER, sku TEXT, PRIMARY KEY (order_id, line_no))")
db.run("INSERT INTO order_lines VALUES (1, 1, 'widget'), (1, 2, 'gadget')")
val table = db.catalog.table("order_lines")
val plan = db.explain("EXPLAIN SELECT sku FROM order_lines WHERE order_id = 1 AND line_no > 1")
assertTrue(plan.any { it == "Primary Key Range Scan on order_lines (order_id = 1 AND line_no > 1)" })
assertEquals(0, table.rangeScanCount)
assertEquals(0, table.scanCount)
}
@Test
fun explainOnASecondaryIndexEqualityNamesTheIndexAndTouchesNoRowData() {
val db = newDatabase()
db.seedUsers()
db.run("CREATE INDEX idx_age ON users(age)")
val table = db.catalog.table("users")
val lookupsBeforeExplain = table.secondaryLookupCount
val scansBeforeExplain = table.scanCount
val plan = db.explain("EXPLAIN SELECT name FROM users WHERE age = 54")
assertTrue(plan.any { it == "Index Scan using idx_age on users (age = 54)" })
assertEquals(lookupsBeforeExplain, table.secondaryLookupCount)
assertEquals(scansBeforeExplain, table.scanCount)
}
@Test
fun explainOnASecondaryIndexRangeNamesTheIndexAndTouchesNoRowData() {
val db = newDatabase()
db.seedUsers()
db.run("CREATE INDEX idx_age ON users(age)")
val table = db.catalog.table("users")
val rangeScansBeforeExplain = table.rangeScanCount
val scansBeforeExplain = table.scanCount
val plan = db.explain("EXPLAIN SELECT name FROM users WHERE age > 40 AND age <= 85")
assertTrue(plan.any { it == "Index Range Scan using idx_age on users (age > 40 AND age <= 85)" })
assertEquals(rangeScansBeforeExplain, table.rangeScanCount)
assertEquals(scansBeforeExplain, table.scanCount)
}
@Test
fun explainOnACompositeSecondaryIndexPrefixRangeNamesBothThePrefixEqualityAndTheRange() {
val db = newDatabase()
db.run("CREATE TABLE order_lines (order_id INTEGER, line_no INTEGER, sku TEXT)")
db.run("INSERT INTO order_lines VALUES (1, 1, 'apple'), (1, 2, 'mango'), (2, 1, 'kiwi')")
db.run("CREATE INDEX idx_order_sku ON order_lines(order_id, sku)")
val table = db.catalog.table("order_lines")
val rangeScansBeforeExplain = table.rangeScanCount
val scansBeforeExplain = table.scanCount
val plan = db.explain("EXPLAIN SELECT line_no FROM order_lines WHERE order_id = 1 AND sku > 'apple'")
assertTrue(plan.any { it == "Index Range Scan using idx_order_sku on order_lines (order_id = 1 AND sku > 'apple')" })
assertEquals(rangeScansBeforeExplain, table.rangeScanCount)
assertEquals(scansBeforeExplain, table.scanCount)
}
@Test
fun explainRevertsToASeqScanAfterTheIndexItWasUsingIsDropped() {
val db = newDatabase()
db.seedUsers()
db.run("CREATE INDEX idx_age ON users(age)")
db.run("DROP INDEX idx_age")
val plan = db.explain("EXPLAIN SELECT name FROM users WHERE age = 54")
assertTrue(plan.any { it == "Seq Scan on users" })
}