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");
    }
    
    @Override

View on GitHub (pinned to e952770a21)

Solutions

  1. Stop using ResultSet.updateLong on federation results: read values with getLong and write changes through a separate UPDATE statement (PreparedStatement.executeUpdate).
  2. 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.
  3. 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.
  4. 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

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.