{"record":{"id":"5989616c5d1e05b4","repo":"apache/shardingsphere","slug":"isbeforefirst","errorCode":null,"errorMessage":"isBeforeFirst","messagePattern":"isBeforeFirst","errorType":"exception","errorClass":"SQLFeatureNotSupportedException","httpStatus":null,"severity":"error","filePath":"jdbc/src/main/java/org/apache/shardingsphere/driver/jdbc/unsupported/AbstractUnsupportedOperationResultSet.java","lineNumber":40,"sourceCode":"import java.sql.Ref;\nimport java.sql.RowId;\nimport java.sql.SQLException;\nimport java.sql.SQLFeatureNotSupportedException;\nimport java.util.Map;\n\n/**\n * Unsupported {@code ResultSet} methods.\n */\npublic abstract class AbstractUnsupportedOperationResultSet extends AbstractUnsupportedUpdateOperationResultSet {\n    \n    @Override\n    public final boolean previous() throws SQLException {\n        throw new SQLFeatureNotSupportedException(\"previous\");\n    }\n    \n    @Override\n    public final boolean isBeforeFirst() throws SQLException {\n        throw new SQLFeatureNotSupportedException(\"isBeforeFirst\");\n    }\n    \n    @Override\n    public final boolean isAfterLast() throws SQLException {\n        throw new SQLFeatureNotSupportedException(\"isAfterLast\");\n    }\n    \n    @Override\n    public final boolean isFirst() throws SQLException {\n        throw new SQLFeatureNotSupportedException(\"isFirst\");\n    }\n    \n    @Override\n    public final boolean isLast() throws SQLException {\n        throw new SQLFeatureNotSupportedException(\"isLast\");\n    }\n    \n    @Override","sourceCodeStart":22,"sourceCodeEnd":58,"githubUrl":"https://github.com/apache/shardingsphere/blob/e952770a215630a3659c75d64369168cd3e26b82/jdbc/src/main/java/org/apache/shardingsphere/driver/jdbc/unsupported/AbstractUnsupportedOperationResultSet.java#L22-L58","documentation":"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.","triggerScenarios":"Calling rs.isBeforeFirst() on any ResultSet from a ShardingSphere-driver query — commonly as an empty-result check before the first next() call.","commonSituations":"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.","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."],"exampleFix":"// before\nResultSet rs = ps.executeQuery();\nif (!rs.isBeforeFirst()) { log.info(\"empty\"); } // throws\n\n// after\nResultSet rs = ps.executeQuery();\nboolean empty = !rs.next();\nif (empty) { log.info(\"empty\"); }","handlingStrategy":"validation","validationCode":"// emptiness must be derived from next(), never position probes\nif (rs.getType() == ResultSet.TYPE_FORWARD_ONLY) {\n    boolean empty = !rs.next(); // supported everywhere\n}","typeGuard":null,"tryCatchPattern":"try {\n    boolean before = rs.isBeforeFirst();\n} catch (SQLFeatureNotSupportedException e) {\n    boolean empty = !rs.next();\n}","preventionTips":["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."],"tags":["jdbc","resultset","cursor","position-check","forward-only"],"backgroundTag":null,"analyzedSha":"e952770a215630a3659c75d64369168cd3e26b82","analyzedAt":"2026-08-14T13:54:53.392Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}