tursodatabase/turso · error · SQLException

SQLite only supports closing cursors at commit

Error message

SQLite only supports closing cursors at commit

What it means

The third guard in TursoConnection.checkCursor(): cursors only exist while a statement steps rows, so ResultSet.HOLD_CURSORS_OVER_COMMIT is meaningless. Only ResultSet.CLOSE_CURSORS_AT_COMMIT is accepted when a holdability argument is supplied.

Source

Thrown at bindings/java/src/main/java/tech/turso/core/TursoConnection.java:166

   *   <li>type: {@link ResultSet#TYPE_FORWARD_ONLY}
   *   <li>concurrency: {@link ResultSet#CONCUR_READ_ONLY})
   *   <li>holdability: {@link ResultSet#CLOSE_CURSORS_AT_COMMIT}
   * </ul>
   *
   * @param resultSetType the type setting.
   * @param resultSetConcurrency the concurrency setting.
   * @param resultSetHoldability the holdability setting.
   */
  public void checkCursor(int resultSetType, int resultSetConcurrency, int resultSetHoldability)
      throws SQLException {
    if (resultSetType != ResultSet.TYPE_FORWARD_ONLY) {
      throw new SQLException("SQLite only supports TYPE_FORWARD_ONLY cursors");
    }
    if (resultSetConcurrency != ResultSet.CONCUR_READ_ONLY) {
      throw new SQLException("SQLite only supports CONCUR_READ_ONLY cursors");
    }
    if (resultSetHoldability != ResultSet.CLOSE_CURSORS_AT_COMMIT) {
      throw new SQLException("SQLite only supports closing cursors at commit");
    }
  }

  /**
   * Sets the auto-commit mode for this connection.
   *
   * <p>When auto-commit is enabled (the default), each SQL statement is committed automatically
   * upon completion. When auto-commit is disabled, statements are grouped into transactions that
   * must be explicitly committed or rolled back.
   *
   * <p>If this method is called to enable auto-commit while a transaction is active, the current
   * transaction is committed first.
   *
   * @param autoCommit true to enable auto-commit mode; false to disable it
   * @throws SQLException if a database access error occurs or the connection is closed
   */
  public void setAutoCommit(boolean autoCommit) throws SQLException {
    synchronized (transactionLock) {

View on GitHub (pinned to bad083fafb)

Solutions

  1. Pass ResultSet.CLOSE_CURSORS_AT_COMMIT as the holdability argument
  2. Drop the 3-arg overload and use createStatement(type, concurrency) or the no-arg createStatement() — driver defaults never trip this check
  3. Consume result sets fully before committing rather than holding them open

Example fix

// before
Statement st = conn.createStatement(
    ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY,
    ResultSet.HOLD_CURSORS_OVER_COMMIT);

// after
Statement st = conn.createStatement(
    ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY,
    ResultSet.CLOSE_CURSORS_AT_COMMIT);
Defensive patterns

Strategy: validation

Validate before calling

int holdability = ResultSet.CLOSE_CURSORS_AT_COMMIT;
if (holdability != ResultSet.CLOSE_CURSORS_AT_COMMIT) {
  holdability = ResultSet.CLOSE_CURSORS_AT_COMMIT;
}
Statement st = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, holdability);

Type guard

static boolean isSupportedHoldability(int resultSetHoldability) {
  return resultSetHoldability == ResultSet.CLOSE_CURSORS_AT_COMMIT;
}

Try / catch

try {
  st = conn.createStatement(type, concurrency, reqHoldability);
} catch (SQLException e) {
  if (e.getMessage() != null && e.getMessage().contains("closing cursors at commit")) {
    st = conn.createStatement(type, concurrency);
  } else {
    throw e;
  }
}

Prevention

When it happens

Trigger: Calling createStatement(type, concurrency, holdability) or prepareStatement(sql, type, concurrency, holdability) with holdability = ResultSet.HOLD_CURSORS_OVER_COMMIT (1) instead of CLOSE_CURSORS_AT_COMMIT (2).

Common situations: Frameworks or boilerplate copied from J2EE code that explicitly holds cursors across commits; porting from DB2/Oracle where holdability matters; code that passes all three constants defensively without knowing the driver's defaults.

Related errors


AI-assisted analysis of tursodatabase/turso@bad083fafb (2026-08-16). Data as JSON: /api/errors/12093592de906e40. Report an issue: GitHub.