test(sql): cover cascadingTriggerFiresATriggerOnADifferentTable
This commit is contained in:
1 parent
ed8fc6576d
commit
e4195113f1
1 file changed
+158
@@ -154,3 +154,161 @@ class DiskExecutorTriggerTest {
|
|||||||
assertEquals(listOf(listOf(text("first")), listOf(text("second"))), db.select("SELECT * FROM audit").rows)
|
assertEquals(listOf(listOf(text("first")), listOf(text("second"))), db.select("SELECT * FROM audit").rows)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun cascadingTriggerFiresATriggerOnADifferentTable() {
|
||||||
|
val db = newDatabase()
|
||||||
|
db.run("CREATE TABLE a (id INTEGER)")
|
||||||
|
db.run("CREATE TABLE b (id INTEGER)")
|
||||||
|
db.run("CREATE TABLE c (id INTEGER)")
|
||||||
|
db.run("CREATE TRIGGER a_to_b AFTER INSERT ON a FOR EACH ROW BEGIN INSERT INTO b VALUES (NEW.id); END")
|
||||||
|
db.run("CREATE TRIGGER b_to_c AFTER INSERT ON b FOR EACH ROW BEGIN INSERT INTO c VALUES (NEW.id); END")
|
||||||
|
db.run("INSERT INTO a VALUES (7)")
|
||||||
|
assertEquals(listOf(listOf(int(7))), db.select("SELECT * FROM b").rows)
|
||||||
|
assertEquals(listOf(listOf(int(7))), db.select("SELECT * FROM c").rows)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun recursiveTriggerHitsTheDepthGuardInsteadOfLoopingForeverAndRollsBackCleanly() {
|
||||||
|
val db = newDatabase()
|
||||||
|
db.run("CREATE TABLE t (id INTEGER)")
|
||||||
|
db.run("CREATE TRIGGER loopy AFTER INSERT ON t FOR EACH ROW BEGIN INSERT INTO t VALUES (NEW.id + 1); END")
|
||||||
|
val exception = assertFailsWith<KestrelException> { db.run("INSERT INTO t VALUES (1)") }
|
||||||
|
assertTrue(exception.message!!.contains("recursion", ignoreCase = true), exception.message!!)
|
||||||
|
assertEquals(0, db.select("SELECT * FROM t").rows.size)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun dropTriggerStopsItFromFiringAndCannotBeDroppedTwice() {
|
||||||
|
val db = newDatabase()
|
||||||
|
db.run("CREATE TABLE t (id INTEGER)")
|
||||||
|
db.run("CREATE TABLE audit (id INTEGER)")
|
||||||
|
db.run("CREATE TRIGGER log AFTER INSERT ON t FOR EACH ROW BEGIN INSERT INTO audit VALUES (NEW.id); END")
|
||||||
|
db.run("DROP TRIGGER log")
|
||||||
|
db.run("INSERT INTO t VALUES (1)")
|
||||||
|
assertEquals(0, db.select("SELECT * FROM audit").rows.size)
|
||||||
|
assertFailsWith<KestrelException> { db.run("DROP TRIGGER log") }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun droppingTheTableDropsItsTriggersToo() {
|
||||||
|
val db = newDatabase()
|
||||||
|
db.run("CREATE TABLE t (id INTEGER)")
|
||||||
|
db.run("CREATE TRIGGER log AFTER INSERT ON t FOR EACH ROW BEGIN UPDATE t SET id = id; END")
|
||||||
|
db.run("DROP TABLE t")
|
||||||
|
assertFailsWith<KestrelException> { db.run("DROP TRIGGER log") }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun renamingTheTableKeepsItsTriggersFiring() {
|
||||||
|
val db = newDatabase()
|
||||||
|
db.run("CREATE TABLE t (id INTEGER)")
|
||||||
|
db.run("CREATE TABLE audit (id INTEGER)")
|
||||||
|
db.run("CREATE TRIGGER log AFTER INSERT ON t FOR EACH ROW BEGIN INSERT INTO audit VALUES (NEW.id); END")
|
||||||
|
db.run("ALTER TABLE t RENAME TO t2")
|
||||||
|
db.run("INSERT INTO t2 VALUES (42)")
|
||||||
|
assertEquals(listOf(listOf(int(42))), db.select("SELECT * FROM audit").rows)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun createTriggerRejectsUnknownTable() {
|
||||||
|
val db = newDatabase()
|
||||||
|
assertFailsWith<KestrelException> {
|
||||||
|
db.run("CREATE TRIGGER log AFTER INSERT ON missing FOR EACH ROW BEGIN DELETE FROM missing WHERE 1 = 0; END")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun createTriggerRejectsDuplicateName() {
|
||||||
|
val db = newDatabase()
|
||||||
|
db.run("CREATE TABLE t (id INTEGER)")
|
||||||
|
db.run("CREATE TRIGGER log AFTER INSERT ON t FOR EACH ROW BEGIN DELETE FROM t WHERE 1 = 0; END")
|
||||||
|
assertFailsWith<KestrelException> {
|
||||||
|
db.run("CREATE TRIGGER log AFTER INSERT ON t FOR EACH ROW BEGIN DELETE FROM t WHERE 1 = 0; END")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun whenClauseRejectsAnUnqualifiedColumn() {
|
||||||
|
val db = newDatabase()
|
||||||
|
db.run("CREATE TABLE t (id INTEGER)")
|
||||||
|
assertFailsWith<KestrelException> {
|
||||||
|
db.run("CREATE TRIGGER log AFTER INSERT ON t FOR EACH ROW WHEN id > 0 BEGIN DELETE FROM t WHERE 1 = 0; END")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun whenClauseRejectsNewOnADeleteTrigger() {
|
||||||
|
val db = newDatabase()
|
||||||
|
db.run("CREATE TABLE t (id INTEGER)")
|
||||||
|
assertFailsWith<KestrelException> {
|
||||||
|
db.run("CREATE TRIGGER log BEFORE DELETE ON t FOR EACH ROW WHEN NEW.id > 0 BEGIN DELETE FROM t WHERE 1 = 0; END")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun whenClauseRejectsOldOnAnInsertTrigger() {
|
||||||
|
val db = newDatabase()
|
||||||
|
db.run("CREATE TABLE t (id INTEGER)")
|
||||||
|
assertFailsWith<KestrelException> {
|
||||||
|
db.run("CREATE TRIGGER log BEFORE INSERT ON t FOR EACH ROW WHEN OLD.id > 0 BEGIN DELETE FROM t WHERE 1 = 0; END")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun whenClauseAcceptsBothSidesOnAnUpdateTrigger() {
|
||||||
|
val db = newDatabase()
|
||||||
|
db.run("CREATE TABLE t (id INTEGER)")
|
||||||
|
db.run("CREATE TRIGGER log BEFORE UPDATE ON t FOR EACH ROW WHEN NEW.id > OLD.id BEGIN DELETE FROM t WHERE 1 = 0; END")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun whenClauseRejectsAnUnknownColumn() {
|
||||||
|
val db = newDatabase()
|
||||||
|
db.run("CREATE TABLE t (id INTEGER)")
|
||||||
|
assertFailsWith<KestrelException> {
|
||||||
|
db.run("CREATE TRIGGER log AFTER INSERT ON t FOR EACH ROW WHEN NEW.nope > 0 BEGIN DELETE FROM t WHERE 1 = 0; END")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun whenClauseRejectsASubquery() {
|
||||||
|
val db = newDatabase()
|
||||||
|
db.run("CREATE TABLE t (id INTEGER)")
|
||||||
|
assertFailsWith<KestrelException> {
|
||||||
|
db.run(
|
||||||
|
"CREATE TRIGGER log AFTER INSERT ON t FOR EACH ROW WHEN EXISTS (SELECT 1 FROM t) " +
|
||||||
|
"BEGIN DELETE FROM t WHERE 1 = 0; END"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun bodyStatementRejectsAnUnknownTargetTable() {
|
||||||
|
val db = newDatabase()
|
||||||
|
db.run("CREATE TABLE t (id INTEGER)")
|
||||||
|
assertFailsWith<KestrelException> {
|
||||||
|
db.run("CREATE TRIGGER log AFTER INSERT ON t FOR EACH ROW BEGIN DELETE FROM missing WHERE 1 = 0; END")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun onConflictRowThatLandsWithNoConflictFiresInsertTriggers() {
|
||||||
|
val db = newDatabase()
|
||||||
|
db.run("CREATE TABLE t (id INTEGER PRIMARY KEY, x INTEGER)")
|
||||||
|
db.run("CREATE TABLE audit (id INTEGER)")
|
||||||
|
db.run("CREATE TRIGGER log AFTER INSERT ON t FOR EACH ROW BEGIN INSERT INTO audit VALUES (NEW.id); END")
|
||||||
|
db.run("INSERT INTO t VALUES (1, 1) ON CONFLICT (id) DO NOTHING")
|
||||||
|
assertEquals(listOf(listOf(int(1))), db.select("SELECT * FROM audit").rows)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun onConflictDoNothingFiresNoTriggerAtAllForTheConflictingRow() {
|
||||||
|
val db = newDatabase()
|
||||||
|
db.run("CREATE TABLE t (id INTEGER PRIMARY KEY, x INTEGER)")
|
||||||
|
db.run("INSERT INTO t VALUES (1, 1)")
|
||||||
|
db.run("CREATE TABLE audit (id INTEGER)")
|
||||||
|
db.run("CREATE TRIGGER log AFTER INSERT ON t FOR EACH ROW BEGIN INSERT INTO audit VALUES (NEW.id); END")
|
||||||
|
db.run("INSERT INTO t VALUES (1, 99) ON CONFLICT (id) DO NOTHING")
|
||||||
|
assertEquals(0, db.select("SELECT * FROM audit").rows.size)
|
||||||
|
}
|
||||||
|
|
||||||
Reference in new issue
Block a user