prestodb/presto · error · SQLFeatureNotSupportedException
Result set concurrency must be CONCUR_READ_ONLY
Error message
Result set concurrency must be CONCUR_READ_ONLY
What it means
PrestoConnection.checkResultSet() throws SQLFeatureNotSupportedException when resultSetConcurrency is not ResultSet.CONCUR_READ_ONLY. Presto result sets are read-only streams; updatable cursors (CONCUR_UPDATABLE) would require write-back to the result source, which the protocol does not support. Note this message is only reached when the type check at line 894 already passed.
Source
Thrown at presto-jdbc/src/main/java/com/facebook/presto/jdbc/PrestoConnection.java:897
throw new SQLException("Connection is closed");
}
}
private void initializeQueryInterceptors()
{
for (QueryInterceptor interceptor : this.queryInterceptorInstances) {
interceptor.init(this.sessionProperties);
}
}
private static void checkResultSet(int resultSetType, int resultSetConcurrency)
throws SQLFeatureNotSupportedException
{
if (resultSetType != ResultSet.TYPE_FORWARD_ONLY) {
throw new SQLFeatureNotSupportedException("Result set type must be TYPE_FORWARD_ONLY");
}
if (resultSetConcurrency != ResultSet.CONCUR_READ_ONLY) {
throw new SQLFeatureNotSupportedException("Result set concurrency must be CONCUR_READ_ONLY");
}
}
private static void checkHoldability(int resultSetHoldability)
throws SQLFeatureNotSupportedException
{
if (resultSetHoldability != ResultSet.HOLD_CURSORS_OVER_COMMIT) {
throw new SQLFeatureNotSupportedException("Result set holdability must be HOLD_CURSORS_OVER_COMMIT");
}
}
private static String getIsolationLevel(int level)
throws SQLException
{
switch (level) {
case TRANSACTION_READ_UNCOMMITTED:
return "READ UNCOMMITTED";
case TRANSACTION_READ_COMMITTED:View on GitHub (pinned to 55bb57d202)
Solutions
- Pass ResultSet.CONCUR_READ_ONLY as the concurrency argument
- Perform modifications with explicit UPDATE/INSERT/DELETE SQL statements instead of ResultSet.updateRow()
- Use prepareStatement(sql) defaults which are read-only
Example fix
// before
Statement stmt = conn.createStatement(
ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_UPDATABLE);
// after
Statement stmt = conn.createStatement(
ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); Defensive patterns
Strategy: validation
Validate before calling
if (concurrency != ResultSet.CONCUR_READ_ONLY) {
concurrency = ResultSet.CONCUR_READ_ONLY; // coerce before calling driver
} Try / catch
try {
stmt = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY, concurrency);
} catch (SQLFeatureNotSupportedException e) {
stmt = conn.createStatement();
} Prevention
- Never request CONCUR_UPDATABLE with Presto; use SQL DML for writes
- Audit framework configs for updatable-result-set options
- Centralize statement creation with fixed read-only concurrency
When it happens
Trigger: createStatement(anyType, ResultSet.CONCUR_UPDATABLE) or prepareStatement(sql, type, ResultSet.CONCUR_UPDATABLE) with a forward-only type.
Common situations: Framework-generated JDBC code that requests updatable result sets to allow row updates; porting legacy CRUD code that relied on updatable cursors from MySQL/PostgreSQL.
Related errors
- Result set type must be TYPE_FORWARD_ONLY
- Result set holdability must be HOLD_CURSORS_OVER_COMMIT
- privileges not supported
- row identifiers not supported
- version columns not supported
AI-assisted analysis of prestodb/presto@55bb57d202 (2026-09-04).
Data as JSON: /api/errors/759318a35110e4c7.
Report an issue: GitHub.