{"record":{"id":"3b1769a801b361f2","repo":"apache/shardingsphere","slug":"expected-blr-short-null-indicator-got-s","errorCode":null,"errorMessage":"Expected blr_short NULL indicator, got: %s","messagePattern":"Expected blr_short NULL indicator, got: (.+?)","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"database/protocol/dialect/firebird/src/main/java/org/apache/shardingsphere/database/protocol/firebird/packet/command/query/batch/FirebirdParseBatchBlr.java","lineNumber":146,"sourceCode":"            int blrType = buffer.readUnsignedByte();\n            FirebirdBatchColumnDescriptor descriptor = readDescriptor(buffer, blrType);\n            offset = alignTo(offset, alignmentOf(blrType));\n            final int fieldOffset = offset;\n            offset += descriptor.getLength();\n            netLength += isVarying(descriptor.getType())\n                    ? HEADER_LENGTH + alignTo(descriptor.getLength() - Short.BYTES, 4)\n                    : alignTo(descriptor.getLength(), 4);\n            offset = appendNullIndicator(buffer, offset);\n            fields.add(new FirebirdBatchColumnDescriptor(descriptor.getType(), descriptor.getLength(), descriptor.getScale(), fieldOffset));\n        }\n        return new FirebirdParseBatchBlr(fields, offset, netLength);\n    }\n    \n    private static int appendNullIndicator(final ByteBuf buffer, final int offset) {\n        int nullType = buffer.readUnsignedByte();\n        buffer.skipBytes(1);\n        if (BlrConstants.blr_short != nullType) {\n            throw new IllegalArgumentException(\"Expected blr_short NULL indicator, got: \" + nullType);\n        }\n        return alignTo(offset, Short.BYTES) + Short.BYTES;\n    }\n    \n    private static boolean isVarying(final FirebirdBinaryColumnType type) {\n        return FirebirdBinaryColumnType.VARYING == type || FirebirdBinaryColumnType.LEGACY_VARYING == type;\n    }\n    \n    private static FirebirdBatchColumnDescriptor readDescriptor(final ByteBuf buffer, final int blrType) {\n        if (BlrConstants.blr_blob2 == blrType) {\n            buffer.skipBytes(4);\n            return new FirebirdBatchColumnDescriptor(FirebirdBinaryColumnType.BLOB, Long.BYTES, 0, 0);\n        }\n        if (BlrConstants.blr_quad == blrType) {\n            int scale = buffer.readByte();\n            return new FirebirdBatchColumnDescriptor(FirebirdBinaryColumnType.BLOB, Long.BYTES, scale, 0);\n        }\n        FirebirdBinaryColumnType type = FirebirdBinaryColumnType.valueOfBLRType(blrType);","sourceCodeStart":128,"sourceCodeEnd":164,"githubUrl":"https://github.com/apache/shardingsphere/blob/e952770a215630a3659c75d64369168cd3e26b82/database/protocol/dialect/firebird/src/main/java/org/apache/shardingsphere/database/protocol/firebird/packet/command/query/batch/FirebirdParseBatchBlr.java#L128-L164","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nrs.updateClob(2, stringReader); // SQLFeatureNotSupportedException\nrs.updateRow();\n\n// after\ntry (PreparedStatement ps = conn.prepareStatement(\"UPDATE docs SET body = ? WHERE id = ?\"); Reader r = stringReader) {\n    ps.setCharacterStream(1, r);\n    ps.setLong(2, rs.getLong(\"id\"));\n    ps.executeUpdate();\n}","handlingStrategy":"try-catch","validationCode":"if (rs.getConcurrency() != ResultSet.CONCUR_UPDATABLE) {\n    // reader-based CLOB write unsupported: use UPDATE + setCharacterStream\n}","typeGuard":null,"tryCatchPattern":"try {\n    rs.updateClob(columnIndex, reader);\n} catch (SQLFeatureNotSupportedException e) {\n    // reader not consumed: close it, then write via UPDATE DML\n}","preventionTips":["Pipe Readers into setCharacterStream on PreparedStatement","Always close readers yourself; the throwing call ignores them","Keep text pipelines off federated cursors"],"tags":["jdbc","resultset","sql-federation","read-only","clob","streaming"],"backgroundTag":null,"analyzedSha":"e952770a215630a3659c75d64369168cd3e26b82","analyzedAt":"2026-08-14T13:54:53.392Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}