apache/shardingsphere · error · SQLFeatureNotSupportedException
isBeforeFirst
Error message
isBeforeFirst
What it means
isBeforeFirst() reports whether the cursor sits before the first row, but ShardingSphere's forward-only merged ResultSet implements it as a final method that throws SQLFeatureNotSupportedException. Position metadata outside the forward stream is not tracked for streaming merge results, so the driver rejects the query rather than guess.
Source
Thrown at jdbc/src/main/java/org/apache/shardingsphere/driver/jdbc/unsupported/AbstractUnsupportedOperationResultSet.java:40
import java.sql.Ref;
import java.sql.RowId;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.Map;
/**
* Unsupported {@code ResultSet} methods.
*/
public abstract class AbstractUnsupportedOperationResultSet extends AbstractUnsupportedUpdateOperationResultSet {
@Override
public final boolean previous() throws SQLException {
throw new SQLFeatureNotSupportedException("previous");
}
@Override
public final boolean isBeforeFirst() throws SQLException {
throw new SQLFeatureNotSupportedException("isBeforeFirst");
}
@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");
}
@OverrideView on GitHub (pinned to e952770a21)
Solutions
- Detect emptiness with the return value of the first rs.next() call instead.
- Count rows while iterating forward, or run SELECT COUNT(*) if you need the total.
- If you need position queries repeatedly, materialize rows into a List first and check isEmpty().
- Wrap third-party components that call isBeforeFirst() with a pre-materialized CachedRowSet.
Example fix
// before
ResultSet rs = ps.executeQuery();
if (!rs.isBeforeFirst()) { log.info("empty"); } // throws
// after
ResultSet rs = ps.executeQuery();
boolean empty = !rs.next();
if (empty) { log.info("empty"); } Defensive patterns
Strategy: validation
Validate before calling
// emptiness must be derived from next(), never position probes
if (rs.getType() == ResultSet.TYPE_FORWARD_ONLY) {
boolean empty = !rs.next(); // supported everywhere
} Try / catch
try {
boolean before = rs.isBeforeFirst();
} catch (SQLFeatureNotSupportedException e) {
boolean empty = !rs.next();
} Prevention
- Use the first next() result as the empty check; never position predicates.
- Keep a project rule: forward-only result sets are iterated exactly once.
- When integrating report libraries, materialize results into CachedRowSet first.
When it happens
Trigger: Calling rs.isBeforeFirst() on any ResultSet from a ShardingSphere-driver query — commonly as an empty-result check before the first next() call.
Common situations: Code that detects 'no rows' via isBeforeFirst()==false after a next(); libraries like Apache POI/JasperReports or home-grown exporters that probe cursor position; copying examples written for scrollable cursors.
Related errors
AI-assisted analysis of apache/shardingsphere@e952770a21 (2026-08-14).
Data as JSON: /api/errors/5989616c5d1e05b4.
Report an issue: GitHub.