apache/shardingsphere · error · SQLFeatureNotSupportedException

previous

Error message

previous

What it means

ShardingSphere driver result sets are forward-only (TYPE_FORWARD_ONLY) merge results, so ResultSet.previous() — moving the cursor backward — is final and throws SQLFeatureNotSupportedException. Streaming merged results from multiple shards cannot be rewound without re-execution, hence the hard restriction.

Source

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

package org.apache.shardingsphere.driver.jdbc.unsupported;

import java.io.Reader;
import java.sql.NClob;
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

View on GitHub (pinned to e952770a21)

Solutions

  1. Restructure to a single forward pass: read everything you need from each row as rs.next() advances.
  2. Buffer rows into a List<Row> (or Apache Commons DbUtils RowSetDynaClass) and navigate the in-memory copy.
  3. If a scrollable cursor is genuinely required, execute the query on a direct (non-sharded) DataSource or via the ShardingSphere Proxy with a client/driver that materializes rows.
  4. Re-execute the query with different OFFSET/FETCH (LIMIT) instead of scrolling backward for pagination.

Example fix

// before
while (rs.next()) { process(rs); }
if (rs.previous()) { reprocess(rs); } // throws

// after
List<OrderRow> rows = new ArrayList<>();
while (rs.next()) { rows.add(mapRow(rs)); }
// navigate 'rows' backward freely
Defensive patterns

Strategy: validation

Validate before calling

int type = rs.getType();
if (type == ResultSet.TYPE_FORWARD_ONLY) {
    // do not call previous(): stream the rows forward or buffer them
}

Try / catch

try {
    rs.previous();
} catch (SQLFeatureNotSupportedException e) {
    // re-fetch or use buffered rows instead of scrolling back
}

Prevention

When it happens

Trigger: Calling rs.previous() on a ResultSet returned by a query executed through ShardingSphereDataSource, e.g. implementing a two-pass iteration or a bidirectional paginator directly on the ResultSet.

Common situations: Report/paging code that iterates once forward then steps back; generic ResultSet wrappers (exporters, CSV writers) that call previous() to peek; frameworks assuming scroll-insensitive result sets because the underlying MySQL/PostgreSQL driver supports them.

Related errors


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