test: cover executeOfAnUnknownNameFails

This commit is contained in:
dualfroz committed 2026-09-09 20:57:44 +02:00
1 parent 061bc535e2
commit 11a53d1ec0
1 file changed
+81
@@ -154,3 +154,84 @@ class PreparedStatementTest {
assertFailsWith<KestrelException> { run("EXECUTE byId()") } assertFailsWith<KestrelException> { run("EXECUTE byId()") }
} }
@Test
fun executeOfAnUnknownNameFails() {
assertFailsWith<KestrelException> { run("EXECUTE nope(1)") }
}
@Test
fun preparingTheSameNameTwiceFails() {
seedAccounts()
run("PREPARE byId AS SELECT name FROM accounts WHERE id = \$1")
assertFailsWith<KestrelException> { run("PREPARE byId AS SELECT balance FROM accounts WHERE id = \$1") }
}
@Test
fun deallocateRemovesAPreparedStatementSoExecuteNoLongerFindsIt() {
seedAccounts()
run("PREPARE byId AS SELECT name FROM accounts WHERE id = \$1")
assertEquals(DeallocateResult("byId", all = false), run("DEALLOCATE byId").single())
assertFailsWith<KestrelException> { run("EXECUTE byId(1)") }
}
@Test
fun deallocatingAnUnknownNameFails() {
assertFailsWith<KestrelException> { run("DEALLOCATE nope") }
}
@Test
fun deallocateAllRemovesEveryPreparedStatement() {
seedAccounts()
run("PREPARE p1 AS SELECT name FROM accounts WHERE id = \$1")
run("PREPARE p2 AS SELECT balance FROM accounts WHERE id = \$1")
assertEquals(DeallocateResult(null, all = true), run("DEALLOCATE ALL").single())
assertFailsWith<KestrelException> { run("EXECUTE p1(1)") }
assertFailsWith<KestrelException> { run("EXECUTE p2(1)") }
}
@Test
fun aNameCanBeReparedAfterBeingDeallocated() {
seedAccounts()
run("PREPARE byId AS SELECT name FROM accounts WHERE id = \$1")
run("DEALLOCATE byId")
run("PREPARE byId AS SELECT balance FROM accounts WHERE id = \$1")
assertEquals(listOf(listOf(Value.IntegerValue(100))), select("EXECUTE byId(1)").rows)
}
@Test
fun preparedStatementsAreNotUndoneByRollback() {
seedAccounts()
run("BEGIN")
run("PREPARE byId AS SELECT name FROM accounts WHERE id = \$1")
run("ROLLBACK")
// Session-scoped, deliberately outside the transactional catalog snapshot - see
// PrepareStatement's own doc for why.
assertEquals(listOf(listOf(Value.TextValue("ada"))), select("EXECUTE byId(1)").rows)
}
@Test
fun executeArgumentsMustBeConstantNotColumnReferences() {
seedAccounts()
run("PREPARE byId AS SELECT name FROM accounts WHERE id = \$1")
assertFailsWith<KestrelException> { run("EXECUTE byId(id)") }
}
@Test
fun aParameterInTheSelectListDoesNotNeedToAppearInGroupBy() {
seedAccounts()
run("PREPARE report AS SELECT \$1, COUNT(*) FROM accounts GROUP BY name")
val result = select("EXECUTE report('label')")
assertEquals(3, result.rows.size)
result.rows.forEach { row -> assertEquals(Value.TextValue("label"), row[0]) }
}
@Test
fun aParameterTypedDirectlyOutsidePrepareParsesButOnlyFailsAtEvaluationTime() {
seedAccounts()
// $1 is structurally legal wherever any expression is (no PREPARE context exists at parse
// time to reject it) - GROUP BY validation lets it through exactly like a literal would, and
// it only fails once evaluation actually needs a real value for it.
val exception = assertFailsWith<KestrelException> { run("SELECT \$1, COUNT(*) FROM accounts GROUP BY name") }
assertTrue(exception.message!!.contains("parameter reference"), exception.message)
}
}