apache/shardingsphere · error · SQLFeatureNotSupportedException

first

Error message

first

What it means

first() moves the cursor to row 1 and reports success; ShardingSphere's forward-only merged ResultSet cannot jump backward to the first row, so the method is final and throws SQLFeatureNotSupportedException. Row 1 may already have been consumed from the shard merge stream.

Source

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

    
    @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
    public final boolean absolute(final int row) throws SQLException {
        throw new SQLFeatureNotSupportedException("absolute");
    }
    
    @Override
    public final boolean relative(final int rows) throws SQLException {
        throw new SQLFeatureNotSupportedException("relative");
    }
    
    @Override

View on GitHub (pinned to e952770a21)

Solutions

  1. Use rs.next() to position on the first row — it is the supported forward move and returns false when empty.
  2. For guaranteed-single-row queries, still check next() and optionally assert !rs.next() again.
  3. If you need random access later, copy rows into a List while iterating.
  4. Configure tools that call first() (report engines, mappers) to use next()-based iteration or give them a CachedRowSet.

Example fix

// before
if (rs.first()) { name = rs.getString(1); } // throws

// after
if (rs.next()) { name = rs.getString(1); }
Defensive patterns

Strategy: validation

Validate before calling

if (rs.getType() == ResultSet.TYPE_FORWARD_ONLY) {
    boolean hasRow = rs.next(); // use next() instead of first()
}

Try / catch

try {
    if (rs.first()) { read(rs); }
} catch (SQLFeatureNotSupportedException e) {
    if (rs.next()) { read(rs); }
}

Prevention

When it happens

Trigger: Calling rs.first() — e.g. to fetch a single expected row — on a ResultSet from ShardingSphereDataSource instead of next().

Common situations: Single-row lookups written as if (rs.first()) { ... }; code migrated from Oracle/DB2 style; generic DAO helpers that call first() before reading columns.

Related errors


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