apache/shardingsphere · error · SQLFeatureNotSupportedException
rowDeleted
Error message
rowDeleted
What it means
rowDeleted() throws SQLFeatureNotSupportedException in the SQL Federation ResultSet. JDBC delete-visibility detection requires an updatable cursor implementation; the federation ResultSet is read-only and final, so it rejects all calls to rowDeleted() regardless of data or state.
Source
Thrown at kernel/sql-federation/core/src/main/java/org/apache/shardingsphere/sqlfederation/resultset/AbstractUnsupportedOperationSQLFederationResultSet.java:140
@Override
public final void moveToCurrentRow() throws SQLException {
throw new SQLFeatureNotSupportedException("moveToCurrentRow");
}
@Override
public final boolean rowInserted() throws SQLException {
throw new SQLFeatureNotSupportedException("rowInserted");
}
@Override
public final boolean rowUpdated() throws SQLException {
throw new SQLFeatureNotSupportedException("rowUpdated");
}
@Override
public final boolean rowDeleted() throws SQLException {
throw new SQLFeatureNotSupportedException("rowDeleted");
}
@Override
public final String getCursorName() throws SQLException {
throw new SQLFeatureNotSupportedException("getCursorName");
}
@Override
public final int getHoldability() throws SQLException {
throw new SQLFeatureNotSupportedException("getHoldability");
}
@Override
public final NClob getNClob(final int columnIndex) throws SQLException {
throw new SQLFeatureNotSupportedException("getNClob");
}
@OverrideView on GitHub (pinned to e952770a21)
Solutions
- Use logical-delete flags (deleted=1 / deleted_at) in the schema and filter with WHERE conditions instead of rowDeleted()
- Maintain a delete ledger in application state when your own code deletes rows and the loop must skip them
- Remove visibility-method usage from shared row-iteration helpers before enabling SQL Federation
Example fix
// before
while (rs.next()) { if (rs.rowDeleted()) continue; process(rs); }
// after
ResultSet rs = stmt.executeQuery("SELECT ... FROM t WHERE deleted = 0");
while (rs.next()) { process(rs); } Defensive patterns
Strategy: try-catch
Validate before calling
try { rs.rowDeleted(); /* supported */ }
catch (final SQLFeatureNotSupportedException e) { /* visibility unsupported: use logical-delete flags */ } Type guard
private boolean isFederationVisibilitySupported(final ResultSet rs) {
return rs.getClass().getName().startsWith("org.apache.shardingsphere.sqlfederation") == false;
} Try / catch
boolean deleted;
try { deleted = rs.rowDeleted(); }
catch (final SQLFeatureNotSupportedException e) { deleted = rs.getBoolean("deleted_flag"); } Prevention
- Model deletes as logical-delete columns
- Maintain an application-side delete ledger
- Filter with WHERE deleted = 0 instead of visibility checks
When it happens
Trigger: Calling rs.rowDeleted() in a row loop over a federated ResultSet, e.g. skipping logically deleted rows via if (rs.rowDeleted()) continue;, often alongside rowInserted()/rowUpdated() visibility checks.
Common situations: ETL/replication jobs distinguishing soft deletes; GUIs collapsing rows deleted by other sessions; code originally validated on a single-node driver (PostgreSQL updatable cursors raise errors, MySQL supports visibility flags) and then moved behind federation without auditing these calls.
Related errors
AI-assisted analysis of apache/shardingsphere@e952770a21 (2026-08-14).
Data as JSON: /api/errors/6ebe2b0aaaeb7774.
Report an issue: GitHub.