tursodatabase/turso · error · java.sql.SQLException

Exception while retrieving total number of changes

Error message

Exception while retrieving total number of changes

What it means

totalChanges() calls the native totalChanges(statementPointer), which returns -1 as its error sentinel; any other value is the change count. So this throw means the native side could not read the counter — typically a stale or invalid statement pointer (statement or connection already closed) rather than a data problem. The sibling changes() method uses the same -1 sentinel convention.

Solutions

  1. Call totalChanges() on a live statement immediately after execute/update, before any close
  2. Do not cache statement pointers across connection lifecycle events
  3. If it still fails on a fresh statement, treat it as an engine-level error and check the DB/disk

Example fix

// before
stmt.close();
long n = stmt.totalChanges(); // stale pointer -> throws

// after
long n = stmt.totalChanges(); // read while the statement is still open
stmt.close();
Defensive patterns

Strategy: try-catch

Try / catch

try {
  return stmt.totalChanges();
} catch (SQLException e) {
  // native returned the -1 sentinel: the statement is stale or the engine errored
  throw new IllegalStateException("totalChanges unavailable; statement no longer usable", e);
}

Prevention

When it happens

Trigger: Calling totalChanges() after the statement was closed or finalized; calling it after the connection closed; invoking it from a thread while another finalizes the statement.

Common situations: Reading change counts in cleanup/finally blocks after the statement was already closed; caching statements across connection lifecycle events; pooled-connection races.

Related errors


AI-assisted analysis of tursodatabase/turso@244cde92a7 (2026-08-20). Data as JSON: /api/errors/36b8b6e0856a0149. Report an issue: GitHub.

Appendix: source

Thrown at bindings/java/src/main/java/tech/turso/core/TursoStatement.java:252

      bindDouble(parameterIndex, (Float) x);
    } else if (x instanceof Double) {
      bindDouble(parameterIndex, (Double) x);
    } else if (x instanceof byte[]) {
      bindBlob(parameterIndex, (byte[]) x);
    } else {
      throw new SQLException("Unsupported object type in bindObject: " + x.getClass().getName());
    }
  }

  /**
   * Returns total number of changes.
   *
   * @throws SQLException If a database access error occurs
   */
  public long totalChanges() throws SQLException {
    final long result = totalChanges(statementPointer);
    if (result == -1) {
      throw new SQLException("Exception while retrieving total number of changes");
    }

    return result;
  }

  private native long totalChanges(long statementPointer) throws SQLException;

  /**
   * Returns number of changes.
   *
   * @throws SQLException If a database access error occurs
   */
  public long changes() throws SQLException {
    final long result = changes(statementPointer);
    if (result == -1) {
      throw new SQLException("Exception while retrieving number of changes");
    }

View on GitHub (pinned to 244cde92a7)