{"record":{"id":"e7b406ea9876af4e","repo":"apache/shardingsphere","slug":"statement-used-in-batch-must-have-parameters","errorCode":null,"errorMessage":"Statement used in batch must have parameters","messagePattern":"Statement used in batch must have parameters","errorType":"exception","errorClass":"BatchParametersRequiredException","httpStatus":null,"severity":"error","filePath":"proxy/frontend/dialect/firebird/src/main/java/org/apache/shardingsphere/proxy/frontend/firebird/command/query/batch/FirebirdBatchCreateCommandExecutor.java","lineNumber":86,"sourceCode":"    private final FirebirdBatchCreateCommandPacket packet;\n    \n    private final ConnectionSession connectionSession;\n    \n    @Override\n    public Collection<DatabasePacket> execute() throws SQLException {\n        int connectionId = connectionSession.getConnectionId();\n        int statementId = packet.getStatementHandle();\n        if (null == connectionSession.getServerPreparedStatementRegistry().getPreparedStatement(statementId)) {\n            throw new InvalidStatementHandleException(statementId);\n        }\n        if (null != FirebirdBatchRegistry.getInstance().getBatchStatement(connectionId, statementId)) {\n            throw new BatchAlreadyOpenedException(statementId);\n        }\n        ByteBuf batchBlr = packet.getBatchBlr();\n        int blrLength = batchBlr.readableBytes();\n        FirebirdParseBatchBlr messageFormat = FirebirdParseBatchBlr.parse(batchBlr, blrLength);\n        if (messageFormat.getFields().isEmpty()) {\n            throw new BatchParametersRequiredException(statementId);\n        }\n        if (packet.getBatchMessageLength() != messageFormat.getMessageLength()) {\n            throw new InvalidBatchMessageFormatException(\n                    String.format(\"invalid message length: computed %d from BLR but client sent %d\", messageFormat.getMessageLength(), packet.getBatchMessageLength()));\n        }\n        ByteBuf batchParametersBuffer = packet.getBatchParametersBuffer();\n        BatchParameters batchParameters = BatchParameters.parse(batchParametersBuffer);\n        FirebirdBatchRegistry.getInstance().registerBatchStatement(connectionId, statementId,\n                new FirebirdBatchStatement(statementId, messageFormat.getFields(), batchParameters.getBufferSize(), batchParameters.isRecordCounts(), batchParameters.isMultiError()));\n        return Collections.singleton(new FirebirdGenericResponsePacket().setHandle(statementId));\n    }\n    \n    @Getter\n    @RequiredArgsConstructor\n    static final class BatchParameters {\n        \n        private final int version;\n        ","sourceCodeStart":68,"sourceCodeEnd":104,"githubUrl":"https://github.com/apache/shardingsphere/blob/e952770a215630a3659c75d64369168cd3e26b82/proxy/frontend/dialect/firebird/src/main/java/org/apache/shardingsphere/proxy/frontend/firebird/command/query/batch/FirebirdBatchCreateCommandExecutor.java#L68-L104","documentation":"BatchParametersRequiredException ('Statement used in batch must have parameters') thrown when the BLR (binary literal representation) sent with CREATE BATCH parses to zero fields. Firebird batches only make sense for parameterized statements; a BLR describing no parameter slots means the client is trying to batch a statement with no placeholders.","triggerScenarios":"FirebirdParseBatchBlr.parse(batchBlr, blrLength) returns a messageFormat whose getFields() is empty; typically because the prepared SQL has no '?' parameters and the client still built a batch BLR for it.","commonSituations":"client prepares a plain SELECT/DDL with no bind parameters and calls addBatch/executeBatch; generated code always wraps statements in batch API regardless of parameter presence; mismatch between the prepared statement's BLR and the batch BLR after re-preparing different SQL under the same handle.","solutions":["Only use batch API for statements that actually contain parameter markers ('?'); execute non-parameterized statements directly.","If the statement should have parameters, verify the BLR sent in CREATE BATCH is the describe-bind BLR returned for the current prepared statement, not a stale one.","Re-prepare the statement after changing its SQL so handle and BLR stay consistent."],"exampleFix":"-- before: batched statement with no parameters\nINSERT INTO t SELECT * FROM src\n\n-- after: parameterized statement suitable for batching\nINSERT INTO t (a, b) VALUES (?, ?)","handlingStrategy":"validation","validationCode":"// Only batch SQL that contains parameter markers\nif (!sql.contains(\"?\")) { executeDirect(sql); } else { prepareAndBatch(sql); }","typeGuard":null,"tryCatchPattern":"catch (SQLException e) {\n    if (e.getMessage().contains(\"must have parameters\")) { executeDirect(sql); } else throw e;\n}","preventionTips":["Reserve batch APIs for INSERT/UPDATE/DELETE with bind parameters.","Guard the batch path with a parameter-count check from describe-bind."],"tags":["firebird","batch","blr","parameters"],"backgroundTag":null,"analyzedSha":"e952770a215630a3659c75d64369168cd3e26b82","analyzedAt":"2026-08-14T13:54:53.392Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}