test: cover compositeUniqueIndexSurvivesReopenAfterCheckpointAndKeeps...

This commit is contained in:
dualfroz committed 2026-09-09 18:29:22 +02:00
1 parent 9c87f22cbb
commit 69d45e0362
1 file changed
+173
+173
View File
@@ -372,4 +372,177 @@ class PersistenceTest {
CREATE UNIQUE INDEX idx_email ON users (email); CREATE UNIQUE INDEX idx_email ON users (email);
.exit .exit
""".trimIndent() """.trimIndent()
)
val afterReopen = runScript(
dir,
"""
INSERT INTO users VALUES (2, 'ada@example.com');
EXPLAIN SELECT id FROM users WHERE email = 'ada@example.com';
.schema users
.exit
""".trimIndent()
)
assertContains(afterReopen, "Error")
assertContains(afterReopen, "UNIQUE constraint")
assertContains(afterReopen, "Index Scan using idx_email")
assertContains(afterReopen, "CREATE UNIQUE INDEX idx_email ON users (email);")
}
@Test
fun compositeUniqueIndexSurvivesReopenAfterCheckpointAndKeepsEnforcingAndAccelerating() {
val dir = tempDir()
runScript(
dir,
"""
CREATE TABLE orders (id INTEGER PRIMARY KEY, region TEXT, seq INTEGER);
INSERT INTO orders VALUES (1, 'EU', 1);
CREATE UNIQUE INDEX idx_region_seq ON orders (region, seq);
.exit
""".trimIndent()
)
val afterReopen = runScript(
dir,
"""
INSERT INTO orders VALUES (2, 'EU', 1);
INSERT INTO orders VALUES (3, 'US', 1);
EXPLAIN SELECT id FROM orders WHERE region = 'EU' AND seq = 1;
.schema orders
.exit
""".trimIndent()
)
assertContains(afterReopen, "Error")
assertContains(afterReopen, "UNIQUE constraint")
assertContains(afterReopen, "Index Scan using idx_region_seq")
assertContains(afterReopen, "CREATE UNIQUE INDEX idx_region_seq ON orders (region, seq);")
}
@Test
fun compositePrimaryKeyAndForeignKeySurviveReopenAfterCheckpoint() {
val dir = tempDir()
runScript(
dir,
"""
CREATE TABLE orders (region TEXT, order_no INTEGER, PRIMARY KEY (region, order_no));
CREATE TABLE line_items (region TEXT, order_no INTEGER, sku TEXT, FOREIGN KEY (region, order_no) REFERENCES orders (region, order_no) ON DELETE CASCADE);
INSERT INTO orders VALUES ('eu', 1);
INSERT INTO line_items VALUES ('eu', 1, 'SKU1');
.exit
""".trimIndent()
)
val duplicateRejected = runScript(dir, "INSERT INTO orders VALUES ('eu', 1);\n.exit\n")
assertContains(duplicateRejected, "Error")
assertContains(duplicateRejected, "UNIQUE constraint")
val afterCascade = runScript(
dir,
"""
DELETE FROM orders WHERE region = 'eu';
SELECT * FROM line_items;
.exit
""".trimIndent()
)
assertTrue(!afterCascade.contains("SKU1"), "cascade delete across a composite FK must survive reopen")
}
@Test
fun alterTableAddColumnSurvivesReopenAfterCheckpointAndBackfillsAndDefaultsFutureInserts() {
val dir = tempDir()
runScript(
dir,
"""
CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT NOT NULL);
INSERT INTO users VALUES (1, 'ada'), (2, 'linus');
ALTER TABLE users ADD COLUMN status TEXT NOT NULL DEFAULT 'active';
INSERT INTO users (id, name) VALUES (3, 'grace');
.exit
""".trimIndent()
)
val reopened = runScript(dir, "SELECT name, status FROM users ORDER BY id ASC;\n.exit\n")
assertContains(reopened, "ada")
assertContains(reopened, "active")
val statusCount = Regex("active").findAll(reopened).count()
assertEquals(3, statusCount, "all three rows (backfilled and freshly inserted) must carry the DEFAULT")
}
@Test
fun generatedColumnSurvivesReopenAfterCheckpointAndKeepsComputingFutureInserts() {
val dir = tempDir()
runScript(
dir,
"""
CREATE TABLE t (a INTEGER, b INTEGER GENERATED ALWAYS AS (a * 2) STORED);
INSERT INTO t (a) VALUES (5);
.exit
""".trimIndent()
)
runScript(dir, "INSERT INTO t (a) VALUES (7);\n.exit\n")
val reopened = runScript(dir, "SELECT b FROM t ORDER BY a ASC;\n.exit\n")
assertContains(reopened, "10")
assertContains(reopened, "14")
}
@Test
fun generatedColumnSurvivesReopenWithoutACheckpointViaWalReplay() {
val dir = tempDir()
val persistence = Persistence(dir)
persistence.appendWal(
listOf(
"CREATE TABLE t (a INTEGER, b INTEGER GENERATED ALWAYS AS (a * 2) STORED);",
"INSERT INTO t (a) VALUES (5);"
)
)
val output = StringBuilder()
Repl(output, output, Persistence(dir)).run("SELECT b FROM t WHERE a = 5;\n.exit\n".reader().buffered())
assertContains(output.toString(), "10")
}
@Test
fun alterTableRenameAndDropColumnSurviveReopenWithoutACheckpointViaWalReplay() {
val dir = tempDir()
val persistence = Persistence(dir)
persistence.appendWal(
listOf(
"CREATE TABLE t (id INTEGER PRIMARY KEY, bio TEXT, scratch TEXT);",
"INSERT INTO t VALUES (1, 'mathematician', 'temp');",
"ALTER TABLE t RENAME COLUMN bio TO biography;",
"ALTER TABLE t DROP COLUMN scratch;"
)
)
val output = StringBuilder()
Repl(output, output, Persistence(dir)).run("SELECT biography FROM t WHERE id = 1;\n.exit\n".reader().buffered())
assertContains(output.toString(), "mathematician")
}
@Test
fun alterTableRenameToSurvivesReopenWithoutACheckpointViaWalReplay() {
val dir = tempDir()
val persistence = Persistence(dir)
persistence.appendWal(
listOf(
"CREATE TABLE t (id INTEGER PRIMARY KEY, name TEXT);",
"INSERT INTO t VALUES (1, 'ada');",
"ALTER TABLE t RENAME TO people;"
)
)
val output = StringBuilder()
Repl(output, output, Persistence(dir)).run("SELECT name FROM people WHERE id = 1;\n.tables\n.exit\n".reader().buffered())
val text = output.toString()
assertContains(text, "ada")
val tableLines = text.lines().map { it.trim() }
assertTrue(tableLines.contains("people"), "renamed table must appear in .tables")
assertTrue(tableLines.none { it.equals("t", ignoreCase = true) }, "old table name must not linger in .tables")
}
@Test
fun alterTableRenameToPropagatesIntoADependentViewAcrossACheckpointReopen() {
val dir = tempDir()
runScript(
dir,
"""
CREATE TABLE departments (id INTEGER PRIMARY KEY, name TEXT);
INSERT INTO departments VALUES (1, 'eng');
CREATE VIEW v AS SELECT id, name FROM departments;
ALTER TABLE departments RENAME TO divisions;
.exit
""".trimIndent()
} }