{"record":{"id":"a3c5e330fd293388","repo":"apache/shardingsphere","slug":"blob-fields-are-not-supported-in-firebird-batch-op","errorCode":null,"errorMessage":"BLOB fields are not supported in Firebird batch operations","messagePattern":"BLOB fields are not supported in Firebird batch operations","errorType":"exception","errorClass":"FirebirdProtocolException","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":115,"sourceCode":"            throw new IllegalArgumentException(\"Expected blr_end\");\n        }\n        if (remainingWithinBlr(buffer, startReaderIndex, blrLength) < 1 || BlrConstants.blr_eoc != buffer.readUnsignedByte()) {\n            throw new IllegalArgumentException(\"Expected blr_eoc\");\n        }\n        if (0 != remainingWithinBlr(buffer, startReaderIndex, blrLength)) {\n            throw new IllegalArgumentException(\"Unexpected trailing bytes in BLR\");\n        }\n    }\n    \n    private static int remainingWithinBlr(final ByteBuf buffer, final int startReaderIndex, final int blrLength) {\n        return blrLength - (buffer.readerIndex() - startReaderIndex);\n    }\n    \n    private static void validateSupported(final List<FirebirdBatchColumnDescriptor> fields) {\n        for (FirebirdBatchColumnDescriptor each : fields) {\n            if (FirebirdBinaryColumnType.BLOB == each.getType()) {\n                // TODO Implement BATCH_REGBLOB, BATCH_BLOB_STREAM and BATCH_SET_BPB before accepting BLOB fields.\n                throw new FirebirdProtocolException(\"BLOB fields are not supported in Firebird batch operations\");\n            }\n        }\n    }\n    \n    private static FirebirdParseBatchBlr parseFormat(final ByteBuf buffer) {\n        int count = buffer.readUnsignedByte();\n        count += buffer.readUnsignedByte() << 8;\n        int columnCount = count / 2;\n        List<FirebirdBatchColumnDescriptor> fields = new ArrayList<>(columnCount);\n        int offset = 0;\n        int netLength = 0;\n        for (int i = 0; i < columnCount; i++) {\n            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())","sourceCodeStart":97,"sourceCodeEnd":133,"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#L97-L133","documentation":"SQLFeatureNotSupportedException thrown by updateClob(String, Clob) on SQL federation ResultSets. The column-label overload of updateClob is final and throws in AbstractUnsupportedUpdateOperationSQLFederationResultSet, matching the index overload. SQL federation only materializes read-only merged results, so attaching a Clob to a named column of the current row cannot be honored.","triggerScenarios":"Calling rs.updateClob(\"body\", clob) on a federated ResultSet and then rs.updateRow(). Encountered in label-based text persistence code.","commonSituations":"CMS or auditing features patching large text columns in place; frameworks mapping fields by label during flush; driver/proxy migration to ShardingSphere without auditing updatable-ResultSet usage.","solutions":["Use PreparedStatement UPDATE with setClob/setCharacterStream bound by column name in SQL","Guard cursor-edit paths with rs.getConcurrency() and fall back to DML when read-only","Rewrite the query or federation config so the statement is not federated when edits are needed"],"exampleFix":"// before\nrs.updateClob(\"body\", clob); // SQLFeatureNotSupportedException\n\n// after\ntry (PreparedStatement ps = conn.prepareStatement(\"UPDATE docs SET body = ? WHERE id = ?\")) {\n    ps.setClob(1, clob);\n    ps.setLong(2, rs.getLong(\"id\"));\n    ps.executeUpdate();\n}","handlingStrategy":"try-catch","validationCode":"if (rs.getConcurrency() == ResultSet.CONCUR_READ_ONLY) {\n    // label-based updateClob unsupported: use UPDATE + setClob\n}","typeGuard":null,"tryCatchPattern":"try {\n    rs.updateClob(\"body\", clob);\n} catch (SQLFeatureNotSupportedException e) {\n    // fall back to UPDATE DML keyed by primary key\n}","preventionTips":["Map label-based CLOB edits to generated UPDATE SQL","Audit CMS/audit features for cursor mutation when adding a proxy","Verify getConcurrency() in integration tests"],"tags":["jdbc","resultset","sql-federation","read-only","clob"],"backgroundTag":null,"analyzedSha":"e952770a215630a3659c75d64369168cd3e26b82","analyzedAt":"2026-08-14T13:54:53.392Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}