apache/shardingsphere · error · SQLFeatureNotSupportedException

cancelRowUpdates

Error message

cancelRowUpdates

What it means

cancelRowUpdates() — undoing pending updateXXX() edits on the current row — throws SQLFeatureNotSupportedException because the federation ResultSet is read-only and never accepts row updates in the first place. The method is final in AbstractUnsupportedOperationSQLFederationResultSet, so the rejection is unconditional.

Source

Thrown at kernel/sql-federation/core/src/main/java/org/apache/shardingsphere/sqlfederation/resultset/AbstractUnsupportedOperationSQLFederationResultSet.java:115

    
    @Override
    public final void updateRow() throws SQLException {
        throw new SQLFeatureNotSupportedException("updateRow");
    }
    
    @Override
    public final void deleteRow() throws SQLException {
        throw new SQLFeatureNotSupportedException("deleteRow");
    }
    
    @Override
    public final void refreshRow() throws SQLException {
        throw new SQLFeatureNotSupportedException("refreshRow");
    }
    
    @Override
    public final void cancelRowUpdates() throws SQLException {
        throw new SQLFeatureNotSupportedException("cancelRowUpdates");
    }
    
    @Override
    public final void moveToInsertRow() throws SQLException {
        throw new SQLFeatureNotSupportedException("moveToInsertRow");
    }
    
    @Override
    public final void moveToCurrentRow() throws SQLException {
        throw new SQLFeatureNotSupportedException("moveToCurrentRow");
    }
    
    @Override
    public final boolean rowInserted() throws SQLException {
        throw new SQLFeatureNotSupportedException("rowInserted");
    }
    
    @Override

View on GitHub (pinned to e952770a21)

Solutions

  1. Drop the cursor-edit pattern entirely: track pending edits in application objects and issue explicit UPDATE statements on save
  2. In UI editors, disable inline editing for federation connections so cancelRowUpdates is never reached
  3. Route the affected statement outside federation if cursor editing is a hard requirement

Example fix

// before
rs.updateString("name", draft);
if (!valid) { rs.cancelRowUpdates(); }

// after
if (valid) {
    try (PreparedStatement ps = conn.prepareStatement("UPDATE t SET name = ? WHERE id = ?")) {
        ps.setString(1, draft); ps.setLong(2, id); ps.executeUpdate();
    }
}
Defensive patterns

Strategy: try-catch

Validate before calling

if (rs.getConcurrency() == ResultSet.CONCUR_READ_ONLY) {
    // cancelRowUpdates() unreachable by design: edits were never accepted
}

Type guard

private boolean isUpdatable(final ResultSet rs) throws SQLException {
    return rs.getConcurrency() == ResultSet.CONCUR_UPDATABLE;
}

Try / catch

try {
    rs.cancelRowUpdates();
} catch (final SQLFeatureNotSupportedException e) {
    // read-only result set: nothing to cancel, discard local pending edits
    pendingEdits.clear();
}

Prevention

When it happens

Trigger: Calling rs.cancelRowUpdates() in an updatable-result-set edit flow (updateXXX ... then cancel) executed against a federation-routed statement.

Common situations: Cancel-edit actions in grid editors; rollback-on-validation-failure logic written for updatable cursors on a standalone database; the call usually follows earlier failed updateRow() usage, indicating the whole cursor-editing pattern must be replaced for federation datasources.

Related errors


AI-assisted analysis of apache/shardingsphere@e952770a21 (2026-08-14). Data as JSON: /api/errors/578257205b4f6efe. Report an issue: GitHub.