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
- Pass ResultSet.CLOSE_CURSORS_AT_COMMIT as the holdability argument
- Drop the 3-arg overload and use createStatement(type, concurrency) or the no-arg createStatement() — driver defaults never trip this check
- 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
- Use the shorter createStatement/prepareStatement overloads unless holdability is genuinely required
- Drain result sets before committing instead of holding cursors across commits
- Strip HOLD_CURSORS_OVER_COMMIT from code ported from J2EE-era drivers
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
- SQLite only supports TYPE_FORWARD_ONLY cursors
- SQLite only supports CONCUR_READ_ONLY cursors
- The result set is not open
- The resultSet is not open
- step() returned invalid result: " + errorMessage
AI-assisted analysis of tursodatabase/turso@bad083fafb (2026-08-16).
Data as JSON: /api/errors/12093592de906e40.
Report an issue: GitHub.