test: cover dumpAfterAlterTableAddColumnReflectsTheNewShape

This commit is contained in:
dualfroz committed 2026-09-10 14:56:57 +02:00
1 parent 074f8aabbe
commit b5f8b44728
1 file changed
+159
+159
View File
@@ -643,3 +643,162 @@ class SqlWriterTest {
// (not just the value 10 already sitting in the dump's INSERT statement). // (not just the value 10 already sitting in the dump's INSERT statement).
freshExecutor.execute(Parser(Lexer("INSERT INTO t (a) VALUES (7)").tokenize()).parseProgram().single()) freshExecutor.execute(Parser(Lexer("INSERT INTO t (a) VALUES (7)").tokenize()).parseProgram().single())
val result = freshExecutor.execute(
Parser(Lexer("SELECT b FROM t ORDER BY a ASC").tokenize()).parseProgram().single()
) as SelectResult
assertEquals(listOf(listOf(Value.IntegerValue(10)), listOf(Value.IntegerValue(14))), result.rows)
}
@Test
fun dumpAfterAlterTableAddColumnReflectsTheNewShape() {
seed()
run("ALTER TABLE t ADD COLUMN status TEXT DEFAULT 'new'")
val dump = SqlWriter.dump(catalog)
assertTrue(dump.contains("status TEXT DEFAULT 'new'"))
val freshCatalog = Catalog()
val freshExecutor = Executor(freshCatalog)
Parser(Lexer(dump).tokenize()).parseProgram().forEach { freshExecutor.execute(it) }
val result = freshExecutor.execute(
Parser(Lexer("SELECT status FROM t WHERE id = 1").tokenize()).parseProgram().single()
) as SelectResult
assertEquals(listOf(listOf(text("new"))), result.rows)
}
@Test
fun dumpAndReplayAfterAlterTableAddColumnGeneratedPreservesTheExpressionAndBackfilledValues() {
run("CREATE TABLE t (a INTEGER)")
run("INSERT INTO t (a) VALUES (5)")
run("ALTER TABLE t ADD COLUMN b INTEGER GENERATED ALWAYS AS (a * 2) STORED")
val dump = SqlWriter.dump(catalog)
assertTrue(dump.contains("GENERATED ALWAYS AS"), dump)
val freshCatalog = Catalog()
val freshExecutor = Executor(freshCatalog)
Parser(Lexer(dump).tokenize()).parseProgram().forEach { freshExecutor.execute(it) }
// A row inserted only AFTER replay proves the GENERATED expression itself round-tripped,
// not just the value backfilled into row a=5 before the dump was taken.
freshExecutor.execute(Parser(Lexer("INSERT INTO t (a) VALUES (7)").tokenize()).parseProgram().single())
val result = freshExecutor.execute(
Parser(Lexer("SELECT b FROM t ORDER BY a ASC").tokenize()).parseProgram().single()
) as SelectResult
assertEquals(listOf(listOf(Value.IntegerValue(10)), listOf(Value.IntegerValue(14))), result.rows)
}
@Test
fun createCompositeUniqueIndexRoundTripsThroughSqlWriter() {
run("CREATE TABLE t (id INTEGER PRIMARY KEY, a INTEGER, b INTEGER)")
writeThenReplay("CREATE UNIQUE INDEX idx_ab ON t (a, b)")
run("INSERT INTO t VALUES (1, 1, 1)")
assertFailsWith<KestrelException> { run("INSERT INTO t VALUES (2, 1, 1)") }
run("INSERT INTO t VALUES (3, 1, 2)")
}
@Test
fun dumpAndReplayPreservesACompositeUniqueIndex() {
run("CREATE TABLE t (id INTEGER PRIMARY KEY, a INTEGER, b INTEGER)")
run("CREATE UNIQUE INDEX idx_ab ON t (a, b)")
run("INSERT INTO t VALUES (1, 1, 1)")
val dump = SqlWriter.dump(catalog)
assertTrue(dump.contains("CREATE UNIQUE INDEX idx_ab ON t (a, b);"))
val freshCatalog = Catalog()
val freshExecutor = Executor(freshCatalog)
Parser(Lexer(dump).tokenize()).parseProgram().forEach { freshExecutor.execute(it) }
assertFailsWith<KestrelException> {
Parser(Lexer("INSERT INTO t VALUES (2, 1, 1)").tokenize()).parseProgram()
.forEach { freshExecutor.execute(it) }
}
}
@Test
fun createViewOverAWindowFunctionRoundTripsThroughSqlWriter() {
run("CREATE TABLE employees (id INTEGER PRIMARY KEY, dept TEXT, salary INTEGER)")
run(
"INSERT INTO employees VALUES (1, 'eng', 300), (2, 'eng', 400), (3, 'sales', 150)"
)
val statement = parseOne(
"CREATE VIEW ranked AS SELECT id, dept, " +
"RANK() OVER (PARTITION BY dept ORDER BY salary DESC) AS r FROM employees"
)
val rendered = SqlWriter.write(statement)
assertTrue(rendered.contains("OVER (PARTITION BY dept ORDER BY salary DESC)"), rendered)
run(rendered)
val result = select("SELECT id, r FROM ranked ORDER BY id ASC")
assertEquals(
listOf(
listOf(Value.IntegerValue(1), Value.IntegerValue(2)),
listOf(Value.IntegerValue(2), Value.IntegerValue(1)),
listOf(Value.IntegerValue(3), Value.IntegerValue(1))
),
result.rows
)
}
@Test
fun dumpAndReplayOfAWindowFunctionViewPreservesTheOverClause() {
run("CREATE TABLE employees (id INTEGER PRIMARY KEY, dept TEXT, salary INTEGER)")
run("INSERT INTO employees VALUES (1, 'eng', 300), (2, 'eng', 400)")
run(
"CREATE VIEW totals AS SELECT id, SUM(salary) OVER (PARTITION BY dept) AS deptTotal FROM employees"
)
val dump = SqlWriter.dump(catalog)
assertTrue(dump.contains("OVER (PARTITION BY dept)"), dump)
val freshCatalog = Catalog()
val freshExecutor = Executor(freshCatalog)
Parser(Lexer(dump).tokenize()).parseProgram().forEach { freshExecutor.execute(it) }
val result = Parser(Lexer("SELECT deptTotal FROM totals ORDER BY id ASC").tokenize()).parseProgram().single()
.let { freshExecutor.execute(it) } as SelectResult
assertEquals(listOf(listOf(Value.IntegerValue(700)), listOf(Value.IntegerValue(700))), result.rows)
}
@Test
fun createViewOverLagWithOffsetAndDefaultRoundTripsThroughSqlWriter() {
run("CREATE TABLE employees (id INTEGER PRIMARY KEY, dept TEXT, salary INTEGER)")
run("INSERT INTO employees VALUES (1, 'eng', 400), (2, 'eng', 300)")
val statement = parseOne(
"CREATE VIEW withPrev AS SELECT id, dept, " +
"LAG(salary, 1, 0) OVER (PARTITION BY dept ORDER BY salary DESC) AS prevSalary FROM employees"
)
val rendered = SqlWriter.write(statement)
assertTrue(rendered.contains("LAG(salary, 1, 0) OVER (PARTITION BY dept ORDER BY salary DESC)"), rendered)
run(rendered)
val result = select("SELECT id, prevSalary FROM withPrev ORDER BY id ASC")
assertEquals(
listOf(
listOf(Value.IntegerValue(1), Value.IntegerValue(0)),
listOf(Value.IntegerValue(2), Value.IntegerValue(400))
),
result.rows
)
}
@Test
fun createViewOverAnExplicitRowsFrameRoundTripsThroughSqlWriter() {
run("CREATE TABLE employees (id INTEGER PRIMARY KEY, dept TEXT, salary INTEGER)")
run("INSERT INTO employees VALUES (1, 'eng', 300), (2, 'eng', 400), (3, 'eng', 100)")
val statement = parseOne(
"CREATE VIEW moving AS SELECT id, dept, " +
"SUM(salary) OVER (PARTITION BY dept ORDER BY id ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) AS s " +
"FROM employees"
)
val rendered = SqlWriter.write(statement)
assertTrue(
rendered.contains("OVER (PARTITION BY dept ORDER BY id ROWS BETWEEN 1 PRECEDING AND CURRENT ROW)"),
rendered
)
run(rendered)
val result = select("SELECT id, s FROM moving ORDER BY id ASC")
assertEquals(
listOf(
listOf(Value.IntegerValue(1), Value.IntegerValue(300)),
listOf(Value.IntegerValue(2), Value.IntegerValue(700)),
listOf(Value.IntegerValue(3), Value.IntegerValue(500))
),
result.rows
)
}