apache/shardingsphere · error · IllegalArgumentException
Expected blr_begin
Error message
Expected blr_begin
What it means
SQLFeatureNotSupportedException thrown by updateBlob(int, InputStream) on SQL federation ResultSets. This is the stream-based overload of updateBlob among six, all declared final and throwing in AbstractUnsupportedUpdateOperationSQLFederationResultSet. Federation returns CONCUR_READ_ONLY in-memory merged results, so streaming bytes into a column of the current row is not possible; the throw occurs immediately, before the stream is read.
Source
Thrown at database/protocol/dialect/firebird/src/main/java/org/apache/shardingsphere/database/protocol/firebird/packet/command/query/batch/FirebirdParseBatchBlr.java:84
* rejection happens later on the command/error path rather than as a codec-level channel close.</p>
*
* @param blr BLR buffer
* @param blrLength BLR length
* @return parsed message format
* @throws IllegalArgumentException when BLR format is structurally invalid
*/
public static FirebirdParseBatchBlr parseForFraming(final ByteBuf blr, final int blrLength) {
if (blrLength < HEADER_LENGTH) {
throw new IllegalArgumentException("BLR is too short: " + blrLength);
}
ByteBuf buffer = blr.duplicate();
final int startReaderIndex = buffer.readerIndex();
int version = buffer.readUnsignedByte();
if (BlrConstants.blr_version4 != version && BlrConstants.blr_version5 != version) {
throw new IllegalArgumentException("Unsupported BLR version: " + version);
}
if (BlrConstants.blr_begin != buffer.readUnsignedByte()) {
throw new IllegalArgumentException("Expected blr_begin");
}
if (BlrConstants.blr_message != buffer.readUnsignedByte()) {
throw new IllegalArgumentException("Expected blr_message");
}
buffer.skipBytes(1);
FirebirdParseBatchBlr result = parseFormat(buffer);
validateTermination(buffer, startReaderIndex, blrLength);
return result;
}
private static void validateTermination(final ByteBuf buffer, final int startReaderIndex, final int blrLength) {
if (remainingWithinBlr(buffer, startReaderIndex, blrLength) < 1 || BlrConstants.blr_end != buffer.readUnsignedByte()) {
throw new IllegalArgumentException("Expected blr_end");
}
if (remainingWithinBlr(buffer, startReaderIndex, blrLength) < 1 || BlrConstants.blr_eoc != buffer.readUnsignedByte()) {
throw new IllegalArgumentException("Expected blr_eoc");
}
if (0 != remainingWithinBlr(buffer, startReaderIndex, blrLength)) {View on GitHub (pinned to e952770a21)
Solutions
- Use an UPDATE with ps.setBinaryStream(index, stream) so the data flows through normal DML
- Close/skip the stream properly in error paths since the federation call never consumes it
- Check rs.getConcurrency() upfront and choose DML for read-only cursors
- Sidestep federation for this statement if updatable behavior is required
Example fix
// before
rs.updateBlob(2, uploadInputStream); // SQLFeatureNotSupportedException
rs.updateRow();
// after
try (PreparedStatement ps = conn.prepareStatement("UPDATE files SET content = ? WHERE id = ?")) {
ps.setBinaryStream(1, uploadInputStream);
ps.setLong(2, rs.getLong("id"));
ps.executeUpdate();
} Defensive patterns
Strategy: try-catch
Validate before calling
if (rs.getConcurrency() != ResultSet.CONCUR_UPDATABLE) {
// stream upload via UPDATE + setBinaryStream instead of updateBlob(index, stream)
} Try / catch
try {
rs.updateBlob(columnIndex, inputStream);
} catch (SQLFeatureNotSupportedException e) {
// caller must close/consume the stream; retry as UPDATE DML
} Prevention
- Remember the throwing call never reads the stream: close it yourself
- Use setBinaryStream on PreparedStatement for streaming uploads
- Check getConcurrency() before iterating with edit intent
When it happens
Trigger: Calling rs.updateBlob(columnIndex, inputStream) on a federation ResultSet and then rs.updateRow(). Seen in upload pipelines that stream a file straight into the current row.
Common situations: Web upload handlers streaming multipart data into BLOB columns via the cursor API; code ported from drivers where CONCUR_UPDATABLE ResultSets accepted streams; ShardingSphere adopted as a proxy in front of an existing app without auditing cursor-update usage.
Related errors
- Expected blr_message
- Expected blr_end
- Expected blr_eoc
- Unsupported BLR version: %s
- Expected blr_short NULL indicator, got: %s
AI-assisted analysis of apache/shardingsphere@e952770a21 (2026-08-14).
Data as JSON: /api/errors/c44a6ec470ad0a64.
Report an issue: GitHub.