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

  1. Check isClosed() before reset() and skip or re-prepare instead of resetting a dead handle.
  2. Call reset() only while you still own the statement and before any close() in your control flow.
  3. If reset() fails on an open statement, catch SQLException, inspect any underlying native error, and fall back to closing and re-preparing the statement.
  4. Avoid reset() inside finally blocks that run after the normal close path; track statement ownership explicitly.
  5. 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

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


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)