Invalid JDBC Parameter or Column Index

ID

kotlin.preparedstatement_resultset_methods_called_valid

Severity

critical

Remediation Complexity

trivial

Remediation Risk

low

Remediation Effort

low

Resource

Reliability

Language

Kotlin

Tags

reliability

Description

Reports a PreparedStatement setter (setString, setInt, setDate, …​) or a ResultSet getter (getString, getInt, getDate, …​) called with a statically resolvable index below 1.

The receiver’s resolved type has to be java.sql.PreparedStatement or java.sql.ResultSet, so zero-based APIs that share a method name — MutableList.set(index, value), or Statement.setFetchSize(rows), which configures the statement rather than binding a parameter — are not flagged. A receiver Kotlin’s type resolver cannot type, such as an untyped lambda parameter of a use { } block, is left alone rather than guessed at.

Rationale

Both PreparedStatement parameters and ResultSet columns are numbered starting at 1, not 0. Calling one of these methods with index 0 or a negative value always throws SQLException at runtime, regardless of how many parameters or columns the statement actually has:

val insert: PreparedStatement = connection.prepareStatement("INSERT INTO users (name) VALUES (?)")
insert.setString(0, name)   // always throws SQLException

val rows: ResultSet = insert.executeQuery()
rows.getString(0)           // always throws SQLException

The mistake is easy to make in Kotlin because every other indexed API the language offers — lists, arrays, strings — is zero-based, so 0 is the reflex for "the first one".

Remediation

Start indexing parameters and columns at 1:

val insert: PreparedStatement = connection.prepareStatement("INSERT INTO users (name) VALUES (?)")
insert.setString(1, name)

val rows: ResultSet = insert.executeQuery()
rows.getString(1)

An index that is not a compile-time constant is never reported, so a loop that binds a variable number of parameters is unaffected. Where the column layout is worth naming, read columns by label (rows.getString("name")) instead of by position.

© 2026 Xygeni. All rights reserved