apache/shardingsphere · error · SQLFeatureNotSupportedException

beforeFirst

Error message

beforeFirst

What it means

beforeFirst() would reposition the cursor before the first row for a second pass, which ShardingSphere's forward-only merge result cannot do — the underlying streams from multiple shards are consumed once. The driver implements it as a final method throwing SQLFeatureNotSupportedException.

Source

Thrown at jdbc/src/main/java/org/apache/shardingsphere/driver/jdbc/unsupported/AbstractUnsupportedOperationResultSet.java:60

    
    @Override
    public final boolean isAfterLast() throws SQLException {
        throw new SQLFeatureNotSupportedException("isAfterLast");
    }
    
    @Override
    public final boolean isFirst() throws SQLException {
        throw new SQLFeatureNotSupportedException("isFirst");
    }
    
    @Override
    public final boolean isLast() throws SQLException {
        throw new SQLFeatureNotSupportedException("isLast");
    }
    
    @Override
    public final void beforeFirst() throws SQLException {
        throw new SQLFeatureNotSupportedException("beforeFirst");
    }
    
    @Override
    public final void afterLast() throws SQLException {
        throw new SQLFeatureNotSupportedException("afterLast");
    }
    
    @Override
    public final boolean first() throws SQLException {
        throw new SQLFeatureNotSupportedException("first");
    }
    
    @Override
    public final boolean last() throws SQLException {
        throw new SQLFeatureNotSupportedException("last");
    }
    
    @Override

View on GitHub (pinned to e952770a21)

Solutions

  1. Collect rows into a List during the first pass and iterate the List again.
  2. If two passes over server data are truly needed, execute the query twice (each execution re-routes to shards).
  3. Use a CachedRowSet (RowSetProvider.newFactory().createCachedRowSet()) populated from the result for repeatable navigation.
  4. Restructure to a single pass that carries computed state forward.

Example fix

// before
while (rs.next()) { total += rs.getDouble(2); }
rs.beforeFirst(); // throws
while (rs.next()) { write(rs, total); }

// after
List<Object[]> rows = new ArrayList<>();
while (rs.next()) { total += rs.getDouble(2); rows.add(new Object[]{rs.getObject(1), rs.getDouble(2)}); }
for (Object[] r : rows) { write(r, total); }
Defensive patterns

Strategy: fallback

Validate before calling

if (rs.getType() == ResultSet.TYPE_FORWARD_ONLY) {
    List<Object[]> rows = new ArrayList<>();
    while (rs.next()) { rows.add(mapRow(rs)); }
    // iterate 'rows' as many passes as needed — never call beforeFirst()
}

Try / catch

try {
    rs.beforeFirst();
} catch (SQLFeatureNotSupportedException e) {
    // second pass impossible: re-execute the query or use the buffered copy
}

Prevention

When it happens

Trigger: Calling rs.beforeFirst() after an iteration to loop over the same ResultSet again — the classic 'second pass' pattern — on any ShardingSphere-driver query result.

Common situations: Two-phase algorithms (compute totals, then details); serializers that validate first and write second; JDBC tutorial examples; code that worked on MySQL Connector/J scrollable result sets before introducing sharding.

Related errors


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