tursodatabase/turso · error · java.sql.SQLException
Exception while resetting statement
Error message
Exception while resetting statement
What it means
TursoStatement.reset() calls the native reset(pointer) JNI method (bindings/java/rs_src/turso_statement.rs:347) to clear bindings and prepare the statement for re-execution; on success the wrapper also rebuilds its resultSet. The native method returns -1 both when the statement pointer is invalid (closed statement) and when the underlying stmt.reset() itself fails, and TursoStatement.java:297 converts that -1 into this SQLException. So it fires either on a dead handle or on a genuine engine-level reset failure.
Solutions
- Check isClosed() before reset() and skip or re-prepare instead of resetting a dead handle.
- Call reset() only while you still own the statement and before any close() in your control flow.
- If reset() fails on an open statement, catch SQLException, inspect any underlying native error, and fall back to closing and re-preparing the statement.
- Avoid reset() inside finally blocks that run after the normal close path; track statement ownership explicitly.
- Upgrade the turso bindings if an open, freshly used statement keeps failing to reset - that is an engine-level bug worth reporting.
Example fix
// before
finally {
stmt.reset(); // runs even after close() -> SQLException
}
// after
finally {
if (!stmt.isClosed()) {
stmt.reset();
}
} Defensive patterns
Strategy: try-catch
Validate before calling
if (stmt != null && !stmt.isClosed()) {
stmt.reset();
} Try / catch
try {
stmt.reset();
} catch (SQLException e) {
// fall back: close and re-prepare instead of resetting
stmt.close();
stmt = conn.prepare(sql);
} Prevention
- Call reset() only while you own the statement and no close() has run.
- Do not call reset() in finally blocks that execute after the normal close path.
- Prefer re-preparing over resetting pooled or long-lived statements when in doubt.
- Check isClosed() before reset in reuse loops.
When it happens
Trigger: Calling reset() after statement.close(); calling reset() after the connection was closed; re-execution loops (batch runners, connection pools resetting statements for reuse) that hit an engine error during reset; interleaving reset() with an active ResultSet iteration on the same statement.
Common situations: Manual statement-reuse code that calls reset() in a finally block after cleanup already ran; pool implementations (DBCP2) that call reset/clearBindings on returned statements; long-lived statements that get invalidated when the parent connection is closed by a health check; porting sqlite-jdbc reuse patterns to turso.
Related errors
- Exception while retrieving number of changes
- Exception while retrieving parameter count
- turso does not support stored procedures
- createBlob not supported
- createClob not supported
AI-assisted analysis of tursodatabase/turso@244cde92a7 (2026-08-20).
Data as JSON: /api/errors/35d9d42dfa9e40e8.
Report an issue: GitHub.
Appendix: source
Thrown at bindings/java/src/main/java/tech/turso/core/TursoStatement.java:297
*
* @throws SQLException If a database access error occurs
*/
public int parameterCount() throws SQLException {
final int result = parameterCount(statementPointer);
if (result == -1) {
throw new SQLException("Exception while retrieving parameter count");
}
return result;
}
private native int parameterCount(long statementPointer) throws SQLException;
/** Resets this statement so it's ready for re-execution */
public void reset() throws SQLException {
final int result = reset(statementPointer);
if (result == -1) {
throw new SQLException("Exception while resetting statement");
}
this.resultSet = TursoResultSet.of(this);
}
private native int reset(long statementPointer) throws SQLException;
/**
* Checks if the statement is closed.
*
* @return true if the statement is closed, false otherwise.
*/
public boolean isClosed() {
return closed;
}
@Override
public String toString() {
return ("tursoStatement{"View on GitHub (pinned to 244cde92a7)