apache/shardingsphere · error · SQLFeatureNotSupportedException

last

Error message

last

What it means

last() is not supported by the SQL Federation ResultSet. The federation engine returns a forward-only result stream, so the abstract base class overrides last() to throw SQLFeatureNotSupportedException instead of jumping the cursor to the final row. The throw is unconditional; it is not a data- or state-dependent failure.

Source

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

    
    @Override
    public void beforeFirst() throws SQLException {
        throw new SQLFeatureNotSupportedException("beforeFirst");
    }
    
    @Override
    public void afterLast() throws SQLException {
        throw new SQLFeatureNotSupportedException("afterLast");
    }
    
    @Override
    public boolean first() throws SQLException {
        throw new SQLFeatureNotSupportedException("first");
    }
    
    @Override
    public boolean last() throws SQLException {
        throw new SQLFeatureNotSupportedException("last");
    }
    
    @Override
    public boolean absolute(final int row) throws SQLException {
        throw new SQLFeatureNotSupportedException("absolute");
    }
    
    @Override
    public boolean relative(final int rows) throws SQLException {
        throw new SQLFeatureNotSupportedException("relative");
    }
    
    @Override
    public int getRow() throws SQLException {
        throw new SQLFeatureNotSupportedException("getRow");
    }
    
    @Override

View on GitHub (pinned to e952770a21)

Solutions

  1. Issue a separate SELECT COUNT(*) federated query for totals instead of last()/getRow()
  2. For the final row only, use ORDER BY <pk> DESC LIMIT 1 and read the single forward result
  3. Cache results in a scroll-insensitive client RowSet if last() navigation is unavoidable

Example fix

// before
rs.last();
int total = rs.getRow();
rs.beforeFirst();

// after
int total = executeCount(stmt.getConnection(), countSql);
Defensive patterns

Strategy: try-catch

Validate before calling

if (rs.getType() == ResultSet.TYPE_FORWARD_ONLY) {
    // last() unsupported: use a COUNT(*) query for totals
}

Type guard

private boolean supportsLast(final ResultSet rs) throws SQLException {
    return rs.getType() != ResultSet.TYPE_FORWARD_ONLY;
}

Try / catch

try {
    rs.last();
    total = rs.getRow();
} catch (final SQLFeatureNotSupportedException e) {
    total = countViaSql(conn, countSql); // fallback COUNT query
}

Prevention

When it happens

Trigger: Calling rs.last() (often followed by getRow()) on a federated query ResultSet to count rows or inspect the final row, e.g. pagination code that uses last()/getRow() to compute total result size.

Common situations: Row-counting idioms ported from MySQL Connector/J (where last()+getRow() is a common COUNT emulation); pagination helpers in older Struts/Spring JDBC code; switching a datasource URL from a native driver to ShardingSphere Proxy with sql-federation enabled for the affected statements.

Related errors


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