apache/shardingsphere · error · IllegalArgumentException
Expected blr_short NULL indicator, got: %s
Error message
Expected blr_short NULL indicator, got: %s
What it means
SQLFeatureNotSupportedException thrown by updateClob(int, Reader) on SQL federation ResultSets. This reader-based overload is one of six updateClob signatures, all implemented as final throwing methods in AbstractUnsupportedUpdateOperationSQLFederationResultSet. Since federated ResultSets are read-only in-memory merges, character data cannot be streamed into the current row; the Reader is never consumed and must be managed by the caller.
Source
Thrown at database/protocol/dialect/firebird/src/main/java/org/apache/shardingsphere/database/protocol/firebird/packet/command/query/batch/FirebirdParseBatchBlr.java:146
int blrType = buffer.readUnsignedByte();
FirebirdBatchColumnDescriptor descriptor = readDescriptor(buffer, blrType);
offset = alignTo(offset, alignmentOf(blrType));
final int fieldOffset = offset;
offset += descriptor.getLength();
netLength += isVarying(descriptor.getType())
? HEADER_LENGTH + alignTo(descriptor.getLength() - Short.BYTES, 4)
: alignTo(descriptor.getLength(), 4);
offset = appendNullIndicator(buffer, offset);
fields.add(new FirebirdBatchColumnDescriptor(descriptor.getType(), descriptor.getLength(), descriptor.getScale(), fieldOffset));
}
return new FirebirdParseBatchBlr(fields, offset, netLength);
}
private static int appendNullIndicator(final ByteBuf buffer, final int offset) {
int nullType = buffer.readUnsignedByte();
buffer.skipBytes(1);
if (BlrConstants.blr_short != nullType) {
throw new IllegalArgumentException("Expected blr_short NULL indicator, got: " + nullType);
}
return alignTo(offset, Short.BYTES) + Short.BYTES;
}
private static boolean isVarying(final FirebirdBinaryColumnType type) {
return FirebirdBinaryColumnType.VARYING == type || FirebirdBinaryColumnType.LEGACY_VARYING == type;
}
private static FirebirdBatchColumnDescriptor readDescriptor(final ByteBuf buffer, final int blrType) {
if (BlrConstants.blr_blob2 == blrType) {
buffer.skipBytes(4);
return new FirebirdBatchColumnDescriptor(FirebirdBinaryColumnType.BLOB, Long.BYTES, 0, 0);
}
if (BlrConstants.blr_quad == blrType) {
int scale = buffer.readByte();
return new FirebirdBatchColumnDescriptor(FirebirdBinaryColumnType.BLOB, Long.BYTES, scale, 0);
}
FirebirdBinaryColumnType type = FirebirdBinaryColumnType.valueOfBLRType(blrType);View on GitHub (pinned to e952770a21)
Solutions
- Replace with UPDATE ... SET col = ? WHERE ... using ps.setCharacterStream so the Reader feeds DML directly
- Ensure the Reader is closed by caller code since the throwing call does not consume it
- Check rs.getConcurrency() before editing and select the DML path for read-only cursors
- Keep editable statements out of federation via SQL rewrite or configuration
Example fix
// before
rs.updateClob(2, stringReader); // SQLFeatureNotSupportedException
rs.updateRow();
// after
try (PreparedStatement ps = conn.prepareStatement("UPDATE docs SET body = ? WHERE id = ?"); Reader r = stringReader) {
ps.setCharacterStream(1, r);
ps.setLong(2, rs.getLong("id"));
ps.executeUpdate();
} Defensive patterns
Strategy: try-catch
Validate before calling
if (rs.getConcurrency() != ResultSet.CONCUR_UPDATABLE) {
// reader-based CLOB write unsupported: use UPDATE + setCharacterStream
} Try / catch
try {
rs.updateClob(columnIndex, reader);
} catch (SQLFeatureNotSupportedException e) {
// reader not consumed: close it, then write via UPDATE DML
} Prevention
- Pipe Readers into setCharacterStream on PreparedStatement
- Always close readers yourself; the throwing call ignores them
- Keep text pipelines off federated cursors
When it happens
Trigger: Calling rs.updateClob(columnIndex, reader) on a federation ResultSet then rs.updateRow(). Typical when text is produced as a Reader (e.g. from a template engine or file) and piped into a CLOB column in place.
Common situations: Streaming text pipelines that previously ran on CONCUR_UPDATABLE ResultSets; ShardingSphere introduced into an existing application; code paths that mix read-then-edit within one iteration over a federated JOIN.
Related errors
AI-assisted analysis of apache/shardingsphere@e952770a21 (2026-08-14).
Data as JSON: /api/errors/3b1769a801b361f2.
Report an issue: GitHub.