test: cover droppingTheTableDropsItsTriggersToo
This commit is contained in:
1 parent
e4bac803db
commit
628235ed19
1 file changed
+178
@@ -157,3 +157,181 @@ class TriggerTest {
|
|||||||
assertFailsWith<KestrelException> { run("DROP TRIGGER log") }
|
assertFailsWith<KestrelException> { run("DROP TRIGGER log") }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun droppingTheTableDropsItsTriggersToo() {
|
||||||
|
run("CREATE TABLE t (id INTEGER)")
|
||||||
|
run("CREATE TRIGGER log AFTER INSERT ON t FOR EACH ROW BEGIN UPDATE t SET id = id; END")
|
||||||
|
run("DROP TABLE t")
|
||||||
|
assertFailsWith<KestrelException> { run("DROP TRIGGER log") }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun renamingTheTableKeepsItsTriggersFiring() {
|
||||||
|
run("CREATE TABLE t (id INTEGER)")
|
||||||
|
run("CREATE TABLE audit (id INTEGER)")
|
||||||
|
run("CREATE TRIGGER log AFTER INSERT ON t FOR EACH ROW BEGIN INSERT INTO audit VALUES (NEW.id); END")
|
||||||
|
run("ALTER TABLE t RENAME TO t2")
|
||||||
|
run("INSERT INTO t2 VALUES (42)")
|
||||||
|
assertEquals(listOf(listOf(int(42))), select("SELECT * FROM audit").rows)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun rollbackUndoesCreateTrigger() {
|
||||||
|
run("CREATE TABLE t (id INTEGER)")
|
||||||
|
run("BEGIN")
|
||||||
|
run("CREATE TRIGGER log AFTER INSERT ON t FOR EACH ROW BEGIN DELETE FROM t WHERE 1 = 0; END")
|
||||||
|
run("ROLLBACK")
|
||||||
|
assertFailsWith<KestrelException> { run("DROP TRIGGER log") }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun createTriggerRejectsUnknownTable() {
|
||||||
|
assertFailsWith<KestrelException> {
|
||||||
|
run("CREATE TRIGGER log AFTER INSERT ON missing FOR EACH ROW BEGIN DELETE FROM missing WHERE 1 = 0; END")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun createTriggerRejectsDuplicateName() {
|
||||||
|
run("CREATE TABLE t (id INTEGER)")
|
||||||
|
run("CREATE TRIGGER log AFTER INSERT ON t FOR EACH ROW BEGIN DELETE FROM t WHERE 1 = 0; END")
|
||||||
|
assertFailsWith<KestrelException> {
|
||||||
|
run("CREATE TRIGGER log AFTER INSERT ON t FOR EACH ROW BEGIN DELETE FROM t WHERE 1 = 0; END")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun whenClauseRejectsAnUnqualifiedColumn() {
|
||||||
|
run("CREATE TABLE t (id INTEGER)")
|
||||||
|
assertFailsWith<KestrelException> {
|
||||||
|
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() {
|
||||||
|
run("CREATE TABLE t (id INTEGER)")
|
||||||
|
assertFailsWith<KestrelException> {
|
||||||
|
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() {
|
||||||
|
run("CREATE TABLE t (id INTEGER)")
|
||||||
|
assertFailsWith<KestrelException> {
|
||||||
|
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() {
|
||||||
|
run("CREATE TABLE t (id INTEGER)")
|
||||||
|
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() {
|
||||||
|
run("CREATE TABLE t (id INTEGER)")
|
||||||
|
assertFailsWith<KestrelException> {
|
||||||
|
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() {
|
||||||
|
run("CREATE TABLE t (id INTEGER)")
|
||||||
|
assertFailsWith<KestrelException> {
|
||||||
|
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() {
|
||||||
|
run("CREATE TABLE t (id INTEGER)")
|
||||||
|
assertFailsWith<KestrelException> {
|
||||||
|
run("CREATE TRIGGER log AFTER INSERT ON t FOR EACH ROW BEGIN DELETE FROM missing WHERE 1 = 0; END")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun onConflictRowThatLandsWithNoConflictFiresInsertTriggers() {
|
||||||
|
run("CREATE TABLE t (id INTEGER PRIMARY KEY, x INTEGER)")
|
||||||
|
run("CREATE TABLE audit (id INTEGER)")
|
||||||
|
run("CREATE TRIGGER log AFTER INSERT ON t FOR EACH ROW BEGIN INSERT INTO audit VALUES (NEW.id); END")
|
||||||
|
run("INSERT INTO t VALUES (1, 1) ON CONFLICT (id) DO NOTHING")
|
||||||
|
assertEquals(listOf(listOf(int(1))), select("SELECT * FROM audit").rows)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun onConflictDoNothingFiresNoTriggerAtAllForTheConflictingRow() {
|
||||||
|
run("CREATE TABLE t (id INTEGER PRIMARY KEY, x INTEGER)")
|
||||||
|
run("INSERT INTO t VALUES (1, 1)")
|
||||||
|
run("CREATE TABLE audit (id INTEGER)")
|
||||||
|
run("CREATE TRIGGER log AFTER INSERT ON t FOR EACH ROW BEGIN INSERT INTO audit VALUES (NEW.id); END")
|
||||||
|
run("INSERT INTO t VALUES (1, 99) ON CONFLICT (id) DO NOTHING")
|
||||||
|
assertEquals(0, select("SELECT * FROM audit").rows.size)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun onConflictDoUpdateFiresUpdateTriggersNotInsertTriggers() {
|
||||||
|
run("CREATE TABLE accounts (id INTEGER PRIMARY KEY, balance INTEGER)")
|
||||||
|
run("INSERT INTO accounts VALUES (1, 100)")
|
||||||
|
run("CREATE TABLE inserts (id INTEGER)")
|
||||||
|
run("CREATE TABLE updates (id INTEGER, old_balance INTEGER, new_balance INTEGER)")
|
||||||
|
run("CREATE TRIGGER log_insert AFTER INSERT ON accounts FOR EACH ROW BEGIN INSERT INTO inserts VALUES (NEW.id); END")
|
||||||
|
run(
|
||||||
|
"CREATE TRIGGER log_update AFTER UPDATE ON accounts FOR EACH ROW " +
|
||||||
|
"BEGIN INSERT INTO updates VALUES (NEW.id, OLD.balance, NEW.balance); END"
|
||||||
|
)
|
||||||
|
run("INSERT INTO accounts VALUES (1, 999) ON CONFLICT (id) DO UPDATE SET balance = excluded.balance")
|
||||||
|
assertEquals(0, select("SELECT * FROM inserts").rows.size)
|
||||||
|
assertEquals(listOf(listOf(int(1), int(100), int(999))), select("SELECT * FROM updates").rows)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun onConflictBeforeUpdateTriggerCanRejectTheWholeStatement() {
|
||||||
|
run("CREATE TABLE accounts (id INTEGER PRIMARY KEY, balance INTEGER)")
|
||||||
|
run("INSERT INTO accounts VALUES (1, 100)")
|
||||||
|
run("CREATE TABLE guard (x INTEGER NOT NULL)")
|
||||||
|
run("CREATE TRIGGER reject BEFORE UPDATE ON accounts FOR EACH ROW BEGIN INSERT INTO guard VALUES (NULL); END")
|
||||||
|
assertFailsWith<KestrelException> {
|
||||||
|
run("INSERT INTO accounts VALUES (1, 999) ON CONFLICT (id) DO UPDATE SET balance = excluded.balance")
|
||||||
|
}
|
||||||
|
assertEquals(int(100), select("SELECT balance FROM accounts WHERE id = 1").rows[0][0])
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun onConflictMultiRowStatementFiresTheRightTriggerPerRow() {
|
||||||
|
run("CREATE TABLE t (id INTEGER PRIMARY KEY, hits INTEGER)")
|
||||||
|
run("INSERT INTO t VALUES (1, 10)")
|
||||||
|
run("CREATE TABLE inserts (id INTEGER)")
|
||||||
|
run("CREATE TABLE updates (id INTEGER)")
|
||||||
|
run("CREATE TRIGGER log_insert AFTER INSERT ON t FOR EACH ROW BEGIN INSERT INTO inserts VALUES (NEW.id); END")
|
||||||
|
run("CREATE TRIGGER log_update AFTER UPDATE ON t FOR EACH ROW BEGIN INSERT INTO updates VALUES (NEW.id); END")
|
||||||
|
run(
|
||||||
|
"""
|
||||||
|
INSERT INTO t VALUES (1, 1), (2, 2)
|
||||||
|
ON CONFLICT (id) DO UPDATE SET hits = t.hits + excluded.hits
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
assertEquals(listOf(listOf(int(2))), select("SELECT * FROM inserts").rows)
|
||||||
|
assertEquals(listOf(listOf(int(1))), select("SELECT * FROM updates").rows)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun bodyStatementInAnInsertTriggerCanOnlySeeNewNotOld() {
|
||||||
|
run("CREATE TABLE t (id INTEGER)")
|
||||||
|
run("CREATE TABLE audit (id INTEGER)")
|
||||||
|
run("CREATE TRIGGER log AFTER INSERT ON t FOR EACH ROW BEGIN INSERT INTO audit VALUES (NEW.id); END")
|
||||||
|
run("INSERT INTO t VALUES (5)")
|
||||||
|
assertEquals(listOf(listOf(int(5))), select("SELECT * FROM audit").rows)
|
||||||
|
// OLD is simply not bound for an INSERT trigger, so an OLD.id reference in the body falls
|
||||||
|
// through exactly like any other unresolvable column in an INSERT's VALUES list would.
|
||||||
|
run("CREATE TRIGGER bad AFTER INSERT ON t FOR EACH ROW BEGIN INSERT INTO audit VALUES (OLD.id); END")
|
||||||
|
assertFailsWith<KestrelException> { run("INSERT INTO t VALUES (6)") }
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in new issue
Block a user