apache/shardingsphere · error · SQLFeatureNotSupportedException
updateLong
Error message
updateLong
What it means
ShardingSphere's SQL federation query engine returns a read-only ResultSet. AbstractUnsupportedUpdateOperationSQLFederationResultSet implements every JDBC row-update method (updateInt, updateLong, ...) as 'throw new SQLFeatureNotSupportedException(...)', and the concrete federation result sets inherit these final overrides. The message 'updateLong' names the JDBC method that was rejected. The class exists so that programs which try to modify rows through a federated query fail fast and explicitly instead of silently doing nothing.
Source
Thrown at kernel/sql-federation/core/src/main/java/org/apache/shardingsphere/sqlfederation/resultset/AbstractUnsupportedUpdateOperationSQLFederationResultSet.java:94
@Override
public final void updateShort(final String columnLabel, final short x) throws SQLException {
throw new SQLFeatureNotSupportedException("updateShort");
}
@Override
public final void updateInt(final int columnIndex, final int x) throws SQLException {
throw new SQLFeatureNotSupportedException("updateInt");
}
@Override
public final void updateInt(final String columnLabel, final int x) throws SQLException {
throw new SQLFeatureNotSupportedException("updateInt");
}
@Override
public final void updateLong(final int columnIndex, final long x) throws SQLException {
throw new SQLFeatureNotSupportedException("updateLong");
}
@Override
public final void updateLong(final String columnLabel, final long x) throws SQLException {
throw new SQLFeatureNotSupportedException("updateLong");
}
@Override
public final void updateFloat(final int columnIndex, final float x) throws SQLException {
throw new SQLFeatureNotSupportedException("updateFloat");
}
@Override
public final void updateFloat(final String columnLabel, final float x) throws SQLException {
throw new SQLFeatureNotSupportedException("updateFloat");
}
@OverrideView on GitHub (pinned to e952770a21)
Solutions
- Stop using ResultSet.updateLong on federation results: read values with getLong and write changes through a separate UPDATE statement (PreparedStatement.executeUpdate).
- If you do not need federation for this statement, disable SQL federation for it (rule sql_federation scope / sqlFederationEnabled=false) so the driver-backed ResultSet is returned with its native concurrency.
- Guard the call site: check rs.getConcurrency() == ResultSet.CONCUR_READ_ONLY (or DatabaseMetaData.supportsResultSetConcurrency) before entering any updateXxx code path, and route read-only result sets to the UPDATE-statement strategy.
- Wrap the federation query path in a component that only exposes read operations, so update-capable code never receives a federation ResultSet.
Example fix
// before
ResultSet rs = federatedStmt.executeQuery(sql);
rs.next();
rs.updateLong(1, 42L); // SQLFeatureNotSupportedException: updateLong
rs.updateRow();
// after
ResultSet rs = federatedStmt.executeQuery(sql);
rs.next();
long id = rs.getLong(1);
try (PreparedStatement upd = conn.prepareStatement("UPDATE t SET v = ? WHERE id = ?")) {
upd.setLong(1, 42L);
upd.setLong(2, id);
upd.executeUpdate();
} Defensive patterns
Strategy: try-catch
Validate before calling
if (rs.getConcurrency() != ResultSet.CONCUR_UPDATABLE) {
// read-only federation ResultSet: use UPDATE statements instead of updateXxx
} Type guard
private static boolean isReadOnlyFederationResultSet(final ResultSet rs) throws SQLException {
return rs.getConcurrency() == ResultSet.CONCUR_READ_ONLY
&& rs.getClass().getName().startsWith("org.apache.shardingsphere.sqlfederation");
} Try / catch
try {
rs.updateLong(1, value);
} catch (final SQLFeatureNotSupportedException ignored) {
// federation ResultSet is read-only: fall back to a keyed UPDATE statement
try (PreparedStatement upd = conn.prepareStatement("UPDATE t SET v = ? WHERE id = ?")) {
upd.setLong(1, value);
upd.setLong(2, rs.getLong(1));
upd.executeUpdate();
}
} Prevention
- Treat every sql_federation result set as read-only; design write paths around UPDATE statements from the start.
- Check rs.getConcurrency() before entering any updateRow-based code path.
- Keep federation queries behind read-only repository methods so update-capable layers never receive them.
When it happens
Trigger: Calling ResultSet.updateLong(int columnIndex, long x) on a ResultSet produced by a SQL federation query (sql_federation enabled, e.g. cross-shard JOIN / subquery / federated SELECT). This happens when application code is handed a generic ResultSet and is written against an updatable cursor contract, or when an ORM row-mapping layer attempts to write back to the current row.
Common situations: Upgrading from a direct JDBC driver or a non-federated ShardingSphere query (where updateLong may have worked on an updatable cursor) to a federated query; generic data-access utility code that calls updateXxx on any ResultSet it receives; enabling sql_federation for cross-database queries and reusing existing updatable-resultset code paths.
Related errors
AI-assisted analysis of apache/shardingsphere@e952770a21 (2026-08-14).
Data as JSON: /api/errors/2e5cc447a031c0ed.
Report an issue: GitHub.