This is an automated email from the ASF dual-hosted git repository.

zhangliang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shardingsphere.git


The following commit(s) were added to refs/heads/master by this push:
     new 821ebd1daec refactor Firebird fetch statement (#37073)
821ebd1daec is described below

commit 821ebd1daec3f2a7e8a40976965038a1489f74d6
Author: Timofey Sakharovsky <[email protected]>
AuthorDate: Wed Nov 12 05:56:41 2025 +0300

    refactor Firebird fetch statement (#37073)
---
 .../generic/FirebirdFetchResponsePacket.java       |  54 +++++++----
 .../packet/generic/FirebirdSQLResponsePacket.java  |   2 +-
 .../generic/FirebirdFetchResponsePacketTest.java   |  18 +++-
 .../frontend/firebird/FirebirdFrontendEngine.java  |   2 +
 .../FirebirdAuthenticationEngine.java              |   2 +
 .../command/FirebirdCommandExecutorFactory.java    |   6 +-
 .../query/FirebirdServerPreparedStatement.java     |  10 --
 .../FirebirdFetchStatementCommandExecutor.java     |  45 ---------
 .../FirebirdAllocateStatementCommandExecutor.java  |   3 +-
 .../FirebirdExecuteStatementCommandExecutor.java   |  40 ++------
 .../fetch/FirebirdFetchStatementCache.java         |  96 ++++++++++++++++++
 .../FirebirdFetchStatementCommandExecutor.java     |  79 +++++++++++++++
 .../FirebirdFreeStatementCommandExecutor.java      |   7 +-
 .../firebird/FirebirdFrontendEngineTest.java       |   4 +-
 .../FirebirdAuthenticationEngineTest.java          |   4 +-
 .../FirebirdCommandExecutorFactoryTest.java        |   6 +-
 .../FirebirdFetchStatementCommandExecutorTest.java |  51 ----------
 ...rebirdAllocateStatementCommandExecutorTest.java |   3 +-
 ...irebirdExecuteStatementCommandExecutorTest.java |  39 +++++---
 .../FirebirdFetchStatementCommandExecutorTest.java | 108 +++++++++++++++++++++
 .../FirebirdFreeStatementCommandExecutorTest.java  |  43 +++++++-
 21 files changed, 429 insertions(+), 193 deletions(-)

diff --git 
a/database/protocol/dialect/firebird/src/main/java/org/apache/shardingsphere/database/protocol/firebird/packet/generic/FirebirdFetchResponsePacket.java
 
b/database/protocol/dialect/firebird/src/main/java/org/apache/shardingsphere/database/protocol/firebird/packet/generic/FirebirdFetchResponsePacket.java
index 9bb723261e2..20da8d1b62f 100644
--- 
a/database/protocol/dialect/firebird/src/main/java/org/apache/shardingsphere/database/protocol/firebird/packet/generic/FirebirdFetchResponsePacket.java
+++ 
b/database/protocol/dialect/firebird/src/main/java/org/apache/shardingsphere/database/protocol/firebird/packet/generic/FirebirdFetchResponsePacket.java
@@ -18,6 +18,7 @@
 package org.apache.shardingsphere.database.protocol.firebird.packet.generic;
 
 import lombok.Getter;
+import lombok.RequiredArgsConstructor;
 import org.apache.shardingsphere.database.protocol.binary.BinaryCell;
 import org.apache.shardingsphere.database.protocol.binary.BinaryRow;
 import 
org.apache.shardingsphere.database.protocol.firebird.packet.FirebirdPacket;
@@ -31,44 +32,33 @@ import org.firebirdsql.gds.ISCConstants;
  * SQL fetch packet for Firebird.
  */
 @Getter
+@RequiredArgsConstructor
 public final class FirebirdFetchResponsePacket extends FirebirdPacket {
     
     private final int status;
     
     private final int count;
     
-    private final BinaryRow data;
-    
-    public FirebirdFetchResponsePacket(final BinaryRow row) {
-        status = ISCConstants.FETCH_OK;
-        count = 1;
-        data = row;
-    }
-    
-    public FirebirdFetchResponsePacket() {
-        status = ISCConstants.FETCH_NO_MORE_ROWS;
-        count = 0;
-        data = null;
-    }
+    private final BinaryRow row;
     
     @Override
     protected void write(final FirebirdPacketPayload payload) {
         payload.writeInt4(FirebirdCommandPacketType.FETCH_RESPONSE.getValue());
         payload.writeInt4(status);
         payload.writeInt4(count);
-        writeData(payload, data);
+        writeRowData(payload, row);
     }
     
-    static void writeData(final FirebirdPacketPayload payload, final BinaryRow 
data) {
-        if (data == null) {
+    static void writeRowData(final FirebirdPacketPayload payload, final 
BinaryRow row) {
+        if (row == null) {
             return;
         }
         int nullBitsStartIndex = payload.getByteBuf().writerIndex();
-        int nullBits = (data.getCells().size() + 7) / 8;
+        int nullBits = (row.getCells().size() + 7) / 8;
         nullBits += (4 - nullBits) & 3;
         payload.getByteBuf().writeZero(nullBits);
         int i = 0;
-        for (BinaryCell cell : data.getCells()) {
+        for (BinaryCell cell : row.getCells()) {
             if (null != cell.getData()) {
                 FirebirdBinaryProtocolValue type = 
FirebirdBinaryProtocolValueFactory.getBinaryProtocolValue(cell.getColumnType());
                 type.write(payload, cell.getData());
@@ -80,4 +70,32 @@ public final class FirebirdFetchResponsePacket extends 
FirebirdPacket {
             i++;
         }
     }
+    
+    /**
+     * Get fetch row response packet.
+     *
+     * @param row binary row
+     * @return fetch response packet
+     */
+    public static FirebirdFetchResponsePacket getFetchRowPacket(final 
BinaryRow row) {
+        return new FirebirdFetchResponsePacket(ISCConstants.FETCH_OK, 1, row);
+    }
+    
+    /**
+     * Get fetch no more rows response packet.
+     *
+     * @return fetch response packet
+     */
+    public static FirebirdFetchResponsePacket getFetchNoMoreRowsPacket() {
+        return new 
FirebirdFetchResponsePacket(ISCConstants.FETCH_NO_MORE_ROWS, 0, null);
+    }
+    
+    /**
+     * Get fetch end response packet.
+     *
+     * @return fetch response packet
+     */
+    public static FirebirdFetchResponsePacket getFetchEndPacket() {
+        return new FirebirdFetchResponsePacket(ISCConstants.FETCH_OK, 0, null);
+    }
 }
diff --git 
a/database/protocol/dialect/firebird/src/main/java/org/apache/shardingsphere/database/protocol/firebird/packet/generic/FirebirdSQLResponsePacket.java
 
b/database/protocol/dialect/firebird/src/main/java/org/apache/shardingsphere/database/protocol/firebird/packet/generic/FirebirdSQLResponsePacket.java
index 8b30aef35b6..d3afdabc0b0 100644
--- 
a/database/protocol/dialect/firebird/src/main/java/org/apache/shardingsphere/database/protocol/firebird/packet/generic/FirebirdSQLResponsePacket.java
+++ 
b/database/protocol/dialect/firebird/src/main/java/org/apache/shardingsphere/database/protocol/firebird/packet/generic/FirebirdSQLResponsePacket.java
@@ -47,6 +47,6 @@ public final class FirebirdSQLResponsePacket extends 
FirebirdPacket {
     protected void write(final FirebirdPacketPayload payload) {
         payload.writeInt4(FirebirdCommandPacketType.SQL_RESPONSE.getValue());
         payload.writeInt4(messageCount);
-        FirebirdFetchResponsePacket.writeData(payload, data);
+        FirebirdFetchResponsePacket.writeRowData(payload, data);
     }
 }
diff --git 
a/database/protocol/dialect/firebird/src/test/java/org/apache/shardingsphere/database/protocol/firebird/packet/generic/FirebirdFetchResponsePacketTest.java
 
b/database/protocol/dialect/firebird/src/test/java/org/apache/shardingsphere/database/protocol/firebird/packet/generic/FirebirdFetchResponsePacketTest.java
index 1e844babf27..b09c9b7a290 100644
--- 
a/database/protocol/dialect/firebird/src/test/java/org/apache/shardingsphere/database/protocol/firebird/packet/generic/FirebirdFetchResponsePacketTest.java
+++ 
b/database/protocol/dialect/firebird/src/test/java/org/apache/shardingsphere/database/protocol/firebird/packet/generic/FirebirdFetchResponsePacketTest.java
@@ -36,6 +36,7 @@ import java.util.Collections;
 
 import static org.mockito.Mockito.mockStatic;
 import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -52,14 +53,14 @@ class FirebirdFetchResponsePacketTest {
     private FirebirdBinaryProtocolValue protocolValue;
     
     @Test
-    void assertWriteWithRow() {
+    void assertWriteRow() {
         when(payload.getByteBuf()).thenReturn(byteBuf);
         when(byteBuf.writerIndex()).thenReturn(0);
         when(byteBuf.writeZero(4)).thenReturn(byteBuf);
         BinaryRow row = new BinaryRow(Collections.singleton(new 
BinaryCell(FirebirdBinaryColumnType.LONG, 123)));
         try (MockedStatic<FirebirdBinaryProtocolValueFactory> mocked = 
mockStatic(FirebirdBinaryProtocolValueFactory.class)) {
             mocked.when(() -> 
FirebirdBinaryProtocolValueFactory.getBinaryProtocolValue(FirebirdBinaryColumnType.LONG)).thenReturn(protocolValue);
-            FirebirdFetchResponsePacket packet = new 
FirebirdFetchResponsePacket(row);
+            FirebirdFetchResponsePacket packet = 
FirebirdFetchResponsePacket.getFetchRowPacket(row);
             packet.write(payload);
             
verify(payload).writeInt4(FirebirdCommandPacketType.FETCH_RESPONSE.getValue());
             verify(payload).writeInt4(ISCConstants.FETCH_OK);
@@ -70,12 +71,21 @@ class FirebirdFetchResponsePacketTest {
     }
     
     @Test
-    void assertWriteWithoutRow() {
-        FirebirdFetchResponsePacket packet = new FirebirdFetchResponsePacket();
+    void assertWriteNoMoreRows() {
+        FirebirdFetchResponsePacket packet = 
FirebirdFetchResponsePacket.getFetchNoMoreRowsPacket();
         packet.write(payload);
         
verify(payload).writeInt4(FirebirdCommandPacketType.FETCH_RESPONSE.getValue());
         verify(payload).writeInt4(ISCConstants.FETCH_NO_MORE_ROWS);
         verify(payload).writeInt4(0);
         verify(payload, never()).getByteBuf();
     }
+    
+    @Test
+    void assertWriteEnd() {
+        FirebirdFetchResponsePacket packet = 
FirebirdFetchResponsePacket.getFetchEndPacket();
+        packet.write(payload);
+        
verify(payload).writeInt4(FirebirdCommandPacketType.FETCH_RESPONSE.getValue());
+        verify(payload, times(2)).writeInt4(0);
+        verify(payload, never()).getByteBuf();
+    }
 }
diff --git 
a/proxy/frontend/dialect/firebird/src/main/java/org/apache/shardingsphere/proxy/frontend/firebird/FirebirdFrontendEngine.java
 
b/proxy/frontend/dialect/firebird/src/main/java/org/apache/shardingsphere/proxy/frontend/firebird/FirebirdFrontendEngine.java
index d9de4521f4e..49bb2e25ab3 100644
--- 
a/proxy/frontend/dialect/firebird/src/main/java/org/apache/shardingsphere/proxy/frontend/firebird/FirebirdFrontendEngine.java
+++ 
b/proxy/frontend/dialect/firebird/src/main/java/org/apache/shardingsphere/proxy/frontend/firebird/FirebirdFrontendEngine.java
@@ -27,6 +27,7 @@ import 
org.apache.shardingsphere.proxy.frontend.authentication.AuthenticationEng
 import 
org.apache.shardingsphere.proxy.frontend.firebird.authentication.FirebirdAuthenticationEngine;
 import 
org.apache.shardingsphere.proxy.frontend.firebird.command.FirebirdCommandExecuteEngine;
 import 
org.apache.shardingsphere.proxy.frontend.firebird.command.query.statement.FirebirdStatementIdGenerator;
+import 
org.apache.shardingsphere.proxy.frontend.firebird.command.query.statement.fetch.FirebirdFetchStatementCache;
 import 
org.apache.shardingsphere.proxy.frontend.firebird.command.query.transaction.FirebirdTransactionIdGenerator;
 import 
org.apache.shardingsphere.proxy.frontend.spi.DatabaseProtocolFrontendEngine;
 
@@ -47,6 +48,7 @@ public final class FirebirdFrontendEngine implements 
DatabaseProtocolFrontendEng
         
FirebirdStatementIdGenerator.getInstance().unregisterConnection(connectionSession.getConnectionId());
         
FirebirdTransactionIdGenerator.getInstance().unregisterConnection(connectionSession.getConnectionId());
         
FirebirdConnectionProtocolVersion.getInstance().unsetProtocolVersion(connectionSession.getConnectionId());
+        
FirebirdFetchStatementCache.getInstance().unregisterConnection(connectionSession.getConnectionId());
     }
     
     @Override
diff --git 
a/proxy/frontend/dialect/firebird/src/main/java/org/apache/shardingsphere/proxy/frontend/firebird/authentication/FirebirdAuthenticationEngine.java
 
b/proxy/frontend/dialect/firebird/src/main/java/org/apache/shardingsphere/proxy/frontend/firebird/authentication/FirebirdAuthenticationEngine.java
index 8ef8ad2d446..6fdb248d0e2 100644
--- 
a/proxy/frontend/dialect/firebird/src/main/java/org/apache/shardingsphere/proxy/frontend/firebird/authentication/FirebirdAuthenticationEngine.java
+++ 
b/proxy/frontend/dialect/firebird/src/main/java/org/apache/shardingsphere/proxy/frontend/firebird/authentication/FirebirdAuthenticationEngine.java
@@ -47,6 +47,7 @@ import 
org.apache.shardingsphere.proxy.frontend.authentication.AuthenticationEng
 import 
org.apache.shardingsphere.proxy.frontend.connection.ConnectionIdGenerator;
 import 
org.apache.shardingsphere.proxy.frontend.firebird.authentication.authenticator.FirebirdAuthenticatorType;
 import 
org.apache.shardingsphere.proxy.frontend.firebird.command.query.statement.FirebirdStatementIdGenerator;
+import 
org.apache.shardingsphere.proxy.frontend.firebird.command.query.statement.fetch.FirebirdFetchStatementCache;
 import 
org.apache.shardingsphere.proxy.frontend.firebird.command.query.transaction.FirebirdTransactionIdGenerator;
 
 import java.util.Arrays;
@@ -70,6 +71,7 @@ public final class FirebirdAuthenticationEngine implements 
AuthenticationEngine
         connectionId = ConnectionIdGenerator.getInstance().nextId();
         
FirebirdTransactionIdGenerator.getInstance().registerConnection(connectionId);
         
FirebirdStatementIdGenerator.getInstance().registerConnection(connectionId);
+        
FirebirdFetchStatementCache.getInstance().registerConnection(connectionId);
         return connectionId;
     }
     
diff --git 
a/proxy/frontend/dialect/firebird/src/main/java/org/apache/shardingsphere/proxy/frontend/firebird/command/FirebirdCommandExecutorFactory.java
 
b/proxy/frontend/dialect/firebird/src/main/java/org/apache/shardingsphere/proxy/frontend/firebird/command/FirebirdCommandExecutorFactory.java
index 1ec5d964c68..d35c18ce7e5 100644
--- 
a/proxy/frontend/dialect/firebird/src/main/java/org/apache/shardingsphere/proxy/frontend/firebird/command/FirebirdCommandExecutorFactory.java
+++ 
b/proxy/frontend/dialect/firebird/src/main/java/org/apache/shardingsphere/proxy/frontend/firebird/command/FirebirdCommandExecutorFactory.java
@@ -49,9 +49,9 @@ import 
org.apache.shardingsphere.proxy.frontend.firebird.command.query.blob.Fire
 import 
org.apache.shardingsphere.proxy.frontend.firebird.command.admin.FirebirdUnsupportedCommandExecutor;
 import 
org.apache.shardingsphere.proxy.frontend.firebird.command.query.info.FirebirdDatabaseInfoExecutor;
 import 
org.apache.shardingsphere.proxy.frontend.firebird.command.query.info.FirebirdSQLInfoExecutor;
-import 
org.apache.shardingsphere.proxy.frontend.firebird.command.query.statement.FirebirdAllocateStatementCommandExecutor;
-import 
org.apache.shardingsphere.proxy.frontend.firebird.command.query.statement.FirebirdFetchStatementCommandExecutor;
-import 
org.apache.shardingsphere.proxy.frontend.firebird.command.query.statement.FirebirdFreeStatementCommandExecutor;
+import 
org.apache.shardingsphere.proxy.frontend.firebird.command.query.statement.allocate.FirebirdAllocateStatementCommandExecutor;
+import 
org.apache.shardingsphere.proxy.frontend.firebird.command.query.statement.fetch.FirebirdFetchStatementCommandExecutor;
+import 
org.apache.shardingsphere.proxy.frontend.firebird.command.query.statement.free.FirebirdFreeStatementCommandExecutor;
 import 
org.apache.shardingsphere.proxy.frontend.firebird.command.query.statement.execute.FirebirdExecuteStatementCommandExecutor;
 import 
org.apache.shardingsphere.proxy.frontend.firebird.command.query.statement.prepare.FirebirdPrepareStatementCommandExecutor;
 import 
org.apache.shardingsphere.proxy.frontend.firebird.command.query.transaction.FirebirdCommitTransactionCommandExecutor;
diff --git 
a/proxy/frontend/dialect/firebird/src/main/java/org/apache/shardingsphere/proxy/frontend/firebird/command/query/FirebirdServerPreparedStatement.java
 
b/proxy/frontend/dialect/firebird/src/main/java/org/apache/shardingsphere/proxy/frontend/firebird/command/query/FirebirdServerPreparedStatement.java
index 16f65ac7fe3..4fe7daef3a5 100644
--- 
a/proxy/frontend/dialect/firebird/src/main/java/org/apache/shardingsphere/proxy/frontend/firebird/command/query/FirebirdServerPreparedStatement.java
+++ 
b/proxy/frontend/dialect/firebird/src/main/java/org/apache/shardingsphere/proxy/frontend/firebird/command/query/FirebirdServerPreparedStatement.java
@@ -19,16 +19,10 @@ package 
org.apache.shardingsphere.proxy.frontend.firebird.command.query;
 
 import lombok.Getter;
 import lombok.RequiredArgsConstructor;
-import 
org.apache.shardingsphere.database.protocol.firebird.packet.command.query.FirebirdBinaryColumnType;
 import 
org.apache.shardingsphere.infra.binder.context.statement.SQLStatementContext;
 import org.apache.shardingsphere.infra.hint.HintValueContext;
 import org.apache.shardingsphere.proxy.backend.session.ServerPreparedStatement;
 
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.CopyOnWriteArrayList;
-
 /**
  * Prepared statement for Firebird.
  */
@@ -41,8 +35,4 @@ public final class FirebirdServerPreparedStatement implements 
ServerPreparedStat
     private final SQLStatementContext sqlStatementContext;
     
     private final HintValueContext hintValueContext;
-    
-    private final List<FirebirdBinaryColumnType> parameterTypes = new 
CopyOnWriteArrayList<>();
-    
-    private final Map<Integer, byte[]> longData = new ConcurrentHashMap<>();
 }
diff --git 
a/proxy/frontend/dialect/firebird/src/main/java/org/apache/shardingsphere/proxy/frontend/firebird/command/query/statement/FirebirdFetchStatementCommandExecutor.java
 
b/proxy/frontend/dialect/firebird/src/main/java/org/apache/shardingsphere/proxy/frontend/firebird/command/query/statement/FirebirdFetchStatementCommandExecutor.java
deleted file mode 100644
index 71e13a7d171..00000000000
--- 
a/proxy/frontend/dialect/firebird/src/main/java/org/apache/shardingsphere/proxy/frontend/firebird/command/query/statement/FirebirdFetchStatementCommandExecutor.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package 
org.apache.shardingsphere.proxy.frontend.firebird.command.query.statement;
-
-import lombok.RequiredArgsConstructor;
-import 
org.apache.shardingsphere.database.protocol.firebird.packet.command.query.statement.FirebirdFetchStatementPacket;
-import 
org.apache.shardingsphere.database.protocol.firebird.packet.generic.FirebirdFetchResponsePacket;
-import org.apache.shardingsphere.database.protocol.packet.DatabasePacket;
-import org.apache.shardingsphere.proxy.backend.session.ConnectionSession;
-import 
org.apache.shardingsphere.proxy.frontend.command.executor.CommandExecutor;
-
-import java.sql.SQLException;
-import java.util.Collection;
-import java.util.Collections;
-
-/**
- * Firebird fetch statement command executor.
- */
-@RequiredArgsConstructor
-public final class FirebirdFetchStatementCommandExecutor implements 
CommandExecutor {
-    
-    private final FirebirdFetchStatementPacket packet;
-    
-    private final ConnectionSession connectionSession;
-    
-    @Override
-    public Collection<DatabasePacket> execute() throws SQLException {
-        return Collections.singleton(new FirebirdFetchResponsePacket());
-    }
-}
diff --git 
a/proxy/frontend/dialect/firebird/src/main/java/org/apache/shardingsphere/proxy/frontend/firebird/command/query/statement/FirebirdAllocateStatementCommandExecutor.java
 
b/proxy/frontend/dialect/firebird/src/main/java/org/apache/shardingsphere/proxy/frontend/firebird/command/query/statement/allocate/FirebirdAllocateStatementCommandExecutor.java
similarity index 93%
rename from 
proxy/frontend/dialect/firebird/src/main/java/org/apache/shardingsphere/proxy/frontend/firebird/command/query/statement/FirebirdAllocateStatementCommandExecutor.java
rename to 
proxy/frontend/dialect/firebird/src/main/java/org/apache/shardingsphere/proxy/frontend/firebird/command/query/statement/allocate/FirebirdAllocateStatementCommandExecutor.java
index c8faf363c2b..3b7cf234a92 100644
--- 
a/proxy/frontend/dialect/firebird/src/main/java/org/apache/shardingsphere/proxy/frontend/firebird/command/query/statement/FirebirdAllocateStatementCommandExecutor.java
+++ 
b/proxy/frontend/dialect/firebird/src/main/java/org/apache/shardingsphere/proxy/frontend/firebird/command/query/statement/allocate/FirebirdAllocateStatementCommandExecutor.java
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-package 
org.apache.shardingsphere.proxy.frontend.firebird.command.query.statement;
+package 
org.apache.shardingsphere.proxy.frontend.firebird.command.query.statement.allocate;
 
 import lombok.RequiredArgsConstructor;
 import 
org.apache.shardingsphere.database.protocol.firebird.packet.command.query.statement.FirebirdAllocateStatementPacket;
@@ -23,6 +23,7 @@ import 
org.apache.shardingsphere.database.protocol.firebird.packet.generic.Fireb
 import org.apache.shardingsphere.database.protocol.packet.DatabasePacket;
 import org.apache.shardingsphere.proxy.backend.session.ConnectionSession;
 import 
org.apache.shardingsphere.proxy.frontend.command.executor.CommandExecutor;
+import 
org.apache.shardingsphere.proxy.frontend.firebird.command.query.statement.FirebirdStatementIdGenerator;
 
 import java.sql.SQLException;
 import java.util.Collection;
diff --git 
a/proxy/frontend/dialect/firebird/src/main/java/org/apache/shardingsphere/proxy/frontend/firebird/command/query/statement/execute/FirebirdExecuteStatementCommandExecutor.java
 
b/proxy/frontend/dialect/firebird/src/main/java/org/apache/shardingsphere/proxy/frontend/firebird/command/query/statement/execute/FirebirdExecuteStatementCommandExecutor.java
index aa75a056e50..96ffd931904 100644
--- 
a/proxy/frontend/dialect/firebird/src/main/java/org/apache/shardingsphere/proxy/frontend/firebird/command/query/statement/execute/FirebirdExecuteStatementCommandExecutor.java
+++ 
b/proxy/frontend/dialect/firebird/src/main/java/org/apache/shardingsphere/proxy/frontend/firebird/command/query/statement/execute/FirebirdExecuteStatementCommandExecutor.java
@@ -22,10 +22,8 @@ import lombok.RequiredArgsConstructor;
 import org.apache.shardingsphere.database.connector.core.type.DatabaseType;
 import org.apache.shardingsphere.database.protocol.binary.BinaryCell;
 import org.apache.shardingsphere.database.protocol.binary.BinaryRow;
-import 
org.apache.shardingsphere.database.protocol.firebird.packet.FirebirdPacket;
 import 
org.apache.shardingsphere.database.protocol.firebird.packet.command.query.FirebirdBinaryColumnType;
 import 
org.apache.shardingsphere.database.protocol.firebird.packet.command.query.statement.execute.FirebirdExecuteStatementPacket;
-import 
org.apache.shardingsphere.database.protocol.firebird.packet.generic.FirebirdFetchResponsePacket;
 import 
org.apache.shardingsphere.database.protocol.firebird.packet.generic.FirebirdGenericResponsePacket;
 import 
org.apache.shardingsphere.database.protocol.firebird.packet.generic.FirebirdSQLResponsePacket;
 import org.apache.shardingsphere.database.protocol.packet.DatabasePacket;
@@ -41,9 +39,10 @@ import 
org.apache.shardingsphere.proxy.backend.response.data.QueryResponseRow;
 import org.apache.shardingsphere.proxy.backend.response.header.ResponseHeader;
 import 
org.apache.shardingsphere.proxy.backend.response.header.query.QueryResponseHeader;
 import org.apache.shardingsphere.proxy.backend.session.ConnectionSession;
-import 
org.apache.shardingsphere.proxy.frontend.command.executor.QueryCommandExecutor;
+import 
org.apache.shardingsphere.proxy.frontend.command.executor.CommandExecutor;
 import org.apache.shardingsphere.proxy.frontend.command.executor.ResponseType;
 import 
org.apache.shardingsphere.proxy.frontend.firebird.command.query.FirebirdServerPreparedStatement;
+import 
org.apache.shardingsphere.proxy.frontend.firebird.command.query.statement.fetch.FirebirdFetchStatementCache;
 
 import java.sql.SQLException;
 import java.util.ArrayList;
@@ -55,7 +54,7 @@ import java.util.List;
  * Firebird execute statement command executor.
  */
 @RequiredArgsConstructor
-public final class FirebirdExecuteStatementCommandExecutor implements 
QueryCommandExecutor {
+public final class FirebirdExecuteStatementCommandExecutor implements 
CommandExecutor {
     
     private final FirebirdExecuteStatementPacket packet;
     
@@ -68,9 +67,8 @@ public final class FirebirdExecuteStatementCommandExecutor 
implements QueryComma
     
     @Override
     public Collection<DatabasePacket> execute() throws SQLException {
-        FirebirdServerPreparedStatement preparedStatement = 
updateAndGetPreparedStatement();
+        FirebirdServerPreparedStatement preparedStatement = 
connectionSession.getServerPreparedStatementRegistry().getPreparedStatement(packet.getStatementId());
         List<Object> params = packet.getParameterValues();
-        preparedStatement.getLongData().forEach(params::set);
         SQLStatementContext sqlStatementContext = 
preparedStatement.getSqlStatementContext();
         if (sqlStatementContext instanceof ParameterAware) {
             ((ParameterAware) sqlStatementContext).bindParameters(params);
@@ -81,26 +79,19 @@ public final class FirebirdExecuteStatementCommandExecutor 
implements QueryComma
         ResponseHeader responseHeader = proxyBackendHandler.execute();
         if (responseHeader instanceof QueryResponseHeader) {
             responseType = ResponseType.QUERY;
+            
FirebirdFetchStatementCache.getInstance().registerStatement(connectionSession.getConnectionId(),
 packet.getStatementId(), proxyBackendHandler);
+            
connectionSession.getDatabaseConnectionManager().markResourceInUse(proxyBackendHandler);
         } else {
             responseType = ResponseType.UPDATE;
         }
         Collection<DatabasePacket> result = new LinkedList<>();
-        if (packet.isStoredProcedure() && next()) {
+        if (packet.isStoredProcedure() && proxyBackendHandler.next()) {
             result.add(getSQLResponse());
         }
         result.add(new FirebirdGenericResponsePacket());
         return result;
     }
     
-    private FirebirdServerPreparedStatement updateAndGetPreparedStatement() {
-        FirebirdServerPreparedStatement result = 
connectionSession.getServerPreparedStatementRegistry().getPreparedStatement(packet.getStatementId());
-        if (!packet.getParameterTypes().isEmpty()) {
-            result.getParameterTypes().clear();
-            result.getParameterTypes().addAll(packet.getParameterTypes());
-        }
-        return result;
-    }
-    
     private FirebirdSQLResponsePacket getSQLResponse() throws SQLException {
         QueryResponseRow queryResponseRow = proxyBackendHandler.getRowData();
         BinaryRow row = createBinaryRow(queryResponseRow);
@@ -114,21 +105,4 @@ public final class FirebirdExecuteStatementCommandExecutor 
implements QueryComma
         }
         return new BinaryRow(result);
     }
-    
-    @Override
-    public boolean next() throws SQLException {
-        return proxyBackendHandler.next();
-    }
-    
-    @Override
-    public FirebirdPacket getQueryRowPacket() throws SQLException {
-        QueryResponseRow queryResponseRow = proxyBackendHandler.getRowData();
-        BinaryRow row = createBinaryRow(queryResponseRow);
-        return new FirebirdFetchResponsePacket(row);
-    }
-    
-    @Override
-    public void close() throws SQLException {
-        proxyBackendHandler.close();
-    }
 }
diff --git 
a/proxy/frontend/dialect/firebird/src/main/java/org/apache/shardingsphere/proxy/frontend/firebird/command/query/statement/fetch/FirebirdFetchStatementCache.java
 
b/proxy/frontend/dialect/firebird/src/main/java/org/apache/shardingsphere/proxy/frontend/firebird/command/query/statement/fetch/FirebirdFetchStatementCache.java
new file mode 100644
index 00000000000..8f3e3320c48
--- /dev/null
+++ 
b/proxy/frontend/dialect/firebird/src/main/java/org/apache/shardingsphere/proxy/frontend/firebird/command/query/statement/fetch/FirebirdFetchStatementCache.java
@@ -0,0 +1,96 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package 
org.apache.shardingsphere.proxy.frontend.firebird.command.query.statement.fetch;
+
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import org.apache.shardingsphere.proxy.backend.handler.ProxyBackendHandler;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * Statement ID generator for Firebird.
+ */
+@NoArgsConstructor(access = AccessLevel.NONE)
+public final class FirebirdFetchStatementCache {
+    
+    private static final FirebirdFetchStatementCache INSTANCE = new 
FirebirdFetchStatementCache();
+    
+    private final Map<Integer, Map<Integer, ProxyBackendHandler>> 
statementRegistry = new ConcurrentHashMap<>();
+    
+    /**
+     * Get fetch statement registry instance.
+     *
+     * @return fetch statement registry instance
+     */
+    public static FirebirdFetchStatementCache getInstance() {
+        return INSTANCE;
+    }
+    
+    /**
+     * Register connection.
+     *
+     * @param connectionId connection ID
+     */
+    public void registerConnection(final int connectionId) {
+        statementRegistry.put(connectionId, new LinkedHashMap<>());
+    }
+    
+    /**
+     * Register statement.
+     *
+     * @param connectionId connection ID
+     * @param statementId statement ID
+     * @param proxyBackendHandler proxy backend handler
+     */
+    public void registerStatement(final int connectionId, final int 
statementId, final ProxyBackendHandler proxyBackendHandler) {
+        statementRegistry.get(connectionId).put(statementId, 
proxyBackendHandler);
+    }
+    
+    /**
+     * Get fetch response packets for statement ID.
+     *
+     * @param connectionId connection ID
+     * @param statementId statement ID
+     * @return fetch response packets
+     */
+    public ProxyBackendHandler getFetchBackendHandler(final int connectionId, 
final int statementId) {
+        return statementRegistry.get(connectionId).get(statementId);
+    }
+    
+    /**
+     * Unregister statement.
+     *
+     * @param connectionId connection ID
+     * @param statementId statement ID
+     */
+    public void unregisterStatement(final int connectionId, final int 
statementId) {
+        statementRegistry.get(connectionId).remove(statementId);
+    }
+    
+    /**
+     * Unregister connection.
+     *
+     * @param connectionId connection ID
+     */
+    public void unregisterConnection(final int connectionId) {
+        statementRegistry.remove(connectionId);
+    }
+}
diff --git 
a/proxy/frontend/dialect/firebird/src/main/java/org/apache/shardingsphere/proxy/frontend/firebird/command/query/statement/fetch/FirebirdFetchStatementCommandExecutor.java
 
b/proxy/frontend/dialect/firebird/src/main/java/org/apache/shardingsphere/proxy/frontend/firebird/command/query/statement/fetch/FirebirdFetchStatementCommandExecutor.java
new file mode 100644
index 00000000000..3b1bd35c37d
--- /dev/null
+++ 
b/proxy/frontend/dialect/firebird/src/main/java/org/apache/shardingsphere/proxy/frontend/firebird/command/query/statement/fetch/FirebirdFetchStatementCommandExecutor.java
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package 
org.apache.shardingsphere.proxy.frontend.firebird.command.query.statement.fetch;
+
+import lombok.RequiredArgsConstructor;
+import org.apache.shardingsphere.database.protocol.binary.BinaryCell;
+import org.apache.shardingsphere.database.protocol.binary.BinaryRow;
+import 
org.apache.shardingsphere.database.protocol.firebird.packet.command.query.FirebirdBinaryColumnType;
+import 
org.apache.shardingsphere.database.protocol.firebird.packet.command.query.statement.FirebirdFetchStatementPacket;
+import 
org.apache.shardingsphere.database.protocol.firebird.packet.generic.FirebirdFetchResponsePacket;
+import org.apache.shardingsphere.database.protocol.packet.DatabasePacket;
+import org.apache.shardingsphere.proxy.backend.handler.ProxyBackendHandler;
+import org.apache.shardingsphere.proxy.backend.response.data.QueryResponseCell;
+import org.apache.shardingsphere.proxy.backend.response.data.QueryResponseRow;
+import org.apache.shardingsphere.proxy.backend.session.ConnectionSession;
+import 
org.apache.shardingsphere.proxy.frontend.command.executor.CommandExecutor;
+
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Firebird fetch statement command executor.
+ */
+@RequiredArgsConstructor
+public final class FirebirdFetchStatementCommandExecutor implements 
CommandExecutor {
+    
+    private final FirebirdFetchStatementPacket packet;
+    
+    private final ConnectionSession connectionSession;
+    
+    @Override
+    public Collection<DatabasePacket> execute() throws SQLException {
+        Collection<DatabasePacket> result = new LinkedList<>();
+        ProxyBackendHandler proxyBackendHandler = 
FirebirdFetchStatementCache.getInstance().getFetchBackendHandler(connectionSession.getConnectionId(),
 packet.getStatementId());
+        if (null == proxyBackendHandler) {
+            result.add(FirebirdFetchResponsePacket.getFetchNoMoreRowsPacket());
+            return result;
+        }
+        for (int i = 0; i < packet.getFetchSize(); i++) {
+            if (proxyBackendHandler.next()) {
+                QueryResponseRow queryResponseRow = 
proxyBackendHandler.getRowData();
+                BinaryRow row = createBinaryRow(queryResponseRow);
+                result.add(FirebirdFetchResponsePacket.getFetchRowPacket(row));
+            } else {
+                
connectionSession.getDatabaseConnectionManager().unmarkResourceInUse(proxyBackendHandler);
+                
result.add(FirebirdFetchResponsePacket.getFetchNoMoreRowsPacket());
+                return result;
+            }
+        }
+        result.add(FirebirdFetchResponsePacket.getFetchEndPacket());
+        return result;
+    }
+    
+    private BinaryRow createBinaryRow(final QueryResponseRow queryResponseRow) 
{
+        List<BinaryCell> result = new 
ArrayList<>(queryResponseRow.getCells().size());
+        for (QueryResponseCell each : queryResponseRow.getCells()) {
+            result.add(new 
BinaryCell(FirebirdBinaryColumnType.valueOfJDBCType(each.getJdbcType()), 
each.getData()));
+        }
+        return new BinaryRow(result);
+    }
+}
diff --git 
a/proxy/frontend/dialect/firebird/src/main/java/org/apache/shardingsphere/proxy/frontend/firebird/command/query/statement/FirebirdFreeStatementCommandExecutor.java
 
b/proxy/frontend/dialect/firebird/src/main/java/org/apache/shardingsphere/proxy/frontend/firebird/command/query/statement/free/FirebirdFreeStatementCommandExecutor.java
similarity index 79%
rename from 
proxy/frontend/dialect/firebird/src/main/java/org/apache/shardingsphere/proxy/frontend/firebird/command/query/statement/FirebirdFreeStatementCommandExecutor.java
rename to 
proxy/frontend/dialect/firebird/src/main/java/org/apache/shardingsphere/proxy/frontend/firebird/command/query/statement/free/FirebirdFreeStatementCommandExecutor.java
index 6688ee5a96b..da786481834 100644
--- 
a/proxy/frontend/dialect/firebird/src/main/java/org/apache/shardingsphere/proxy/frontend/firebird/command/query/statement/FirebirdFreeStatementCommandExecutor.java
+++ 
b/proxy/frontend/dialect/firebird/src/main/java/org/apache/shardingsphere/proxy/frontend/firebird/command/query/statement/free/FirebirdFreeStatementCommandExecutor.java
@@ -15,15 +15,17 @@
  * limitations under the License.
  */
 
-package 
org.apache.shardingsphere.proxy.frontend.firebird.command.query.statement;
+package 
org.apache.shardingsphere.proxy.frontend.firebird.command.query.statement.free;
 
 import lombok.RequiredArgsConstructor;
 import 
org.apache.shardingsphere.database.protocol.firebird.exception.FirebirdProtocolException;
 import 
org.apache.shardingsphere.database.protocol.firebird.packet.command.query.statement.FirebirdFreeStatementPacket;
 import 
org.apache.shardingsphere.database.protocol.firebird.packet.generic.FirebirdGenericResponsePacket;
 import org.apache.shardingsphere.database.protocol.packet.DatabasePacket;
+import org.apache.shardingsphere.proxy.backend.handler.ProxyBackendHandler;
 import org.apache.shardingsphere.proxy.backend.session.ConnectionSession;
 import 
org.apache.shardingsphere.proxy.frontend.command.executor.CommandExecutor;
+import 
org.apache.shardingsphere.proxy.frontend.firebird.command.query.statement.fetch.FirebirdFetchStatementCache;
 
 import java.sql.SQLException;
 import java.util.Collection;
@@ -48,6 +50,9 @@ public final class FirebirdFreeStatementCommandExecutor 
implements CommandExecut
                 break;
             case FirebirdFreeStatementPacket.CLOSE:
                 connectionSession.getConnectionContext().clearCursorContext();
+                ProxyBackendHandler proxyBackendHandler = 
FirebirdFetchStatementCache.getInstance().getFetchBackendHandler(connectionSession.getConnectionId(),
 packet.getStatementId());
+                
connectionSession.getDatabaseConnectionManager().unmarkResourceInUse(proxyBackendHandler);
+                
FirebirdFetchStatementCache.getInstance().unregisterStatement(connectionSession.getConnectionId(),
 packet.getStatementId());
                 break;
             default:
                 throw new FirebirdProtocolException("Unknown DSQL option type 
%d", packet.getOption());
diff --git 
a/proxy/frontend/dialect/firebird/src/test/java/org/apache/shardingsphere/proxy/frontend/firebird/FirebirdFrontendEngineTest.java
 
b/proxy/frontend/dialect/firebird/src/test/java/org/apache/shardingsphere/proxy/frontend/firebird/FirebirdFrontendEngineTest.java
index aec99aafabc..7b3aaed4f62 100644
--- 
a/proxy/frontend/dialect/firebird/src/test/java/org/apache/shardingsphere/proxy/frontend/firebird/FirebirdFrontendEngineTest.java
+++ 
b/proxy/frontend/dialect/firebird/src/test/java/org/apache/shardingsphere/proxy/frontend/firebird/FirebirdFrontendEngineTest.java
@@ -21,6 +21,7 @@ import 
org.apache.shardingsphere.database.protocol.firebird.constant.protocol.Fi
 import org.apache.shardingsphere.proxy.backend.context.ProxyContext;
 import org.apache.shardingsphere.proxy.backend.session.ConnectionSession;
 import 
org.apache.shardingsphere.proxy.frontend.firebird.command.query.statement.FirebirdStatementIdGenerator;
+import 
org.apache.shardingsphere.proxy.frontend.firebird.command.query.statement.fetch.FirebirdFetchStatementCache;
 import 
org.apache.shardingsphere.proxy.frontend.firebird.command.query.transaction.FirebirdTransactionIdGenerator;
 import 
org.apache.shardingsphere.test.infra.framework.extension.mock.AutoMockExtension;
 import 
org.apache.shardingsphere.test.infra.framework.extension.mock.StaticMockSettings;
@@ -33,7 +34,7 @@ import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 @ExtendWith(AutoMockExtension.class)
-@StaticMockSettings({ProxyContext.class, FirebirdStatementIdGenerator.class, 
FirebirdTransactionIdGenerator.class, FirebirdConnectionProtocolVersion.class})
+@StaticMockSettings({ProxyContext.class, FirebirdStatementIdGenerator.class, 
FirebirdTransactionIdGenerator.class, FirebirdConnectionProtocolVersion.class, 
FirebirdFetchStatementCache.class})
 class FirebirdFrontendEngineTest {
     
     @Mock
@@ -54,5 +55,6 @@ class FirebirdFrontendEngineTest {
         
verify(FirebirdStatementIdGenerator.getInstance()).unregisterConnection(connectionId);
         
verify(FirebirdTransactionIdGenerator.getInstance()).unregisterConnection(connectionId);
         
verify(FirebirdConnectionProtocolVersion.getInstance()).unsetProtocolVersion(connectionId);
+        
verify(FirebirdFetchStatementCache.getInstance()).unregisterConnection(connectionId);
     }
 }
diff --git 
a/proxy/frontend/dialect/firebird/src/test/java/org/apache/shardingsphere/proxy/frontend/firebird/authentication/FirebirdAuthenticationEngineTest.java
 
b/proxy/frontend/dialect/firebird/src/test/java/org/apache/shardingsphere/proxy/frontend/firebird/authentication/FirebirdAuthenticationEngineTest.java
index 556ce6f41fb..f4463a718d9 100644
--- 
a/proxy/frontend/dialect/firebird/src/test/java/org/apache/shardingsphere/proxy/frontend/firebird/authentication/FirebirdAuthenticationEngineTest.java
+++ 
b/proxy/frontend/dialect/firebird/src/test/java/org/apache/shardingsphere/proxy/frontend/firebird/authentication/FirebirdAuthenticationEngineTest.java
@@ -20,6 +20,7 @@ package 
org.apache.shardingsphere.proxy.frontend.firebird.authentication;
 import io.netty.channel.ChannelHandlerContext;
 import 
org.apache.shardingsphere.proxy.frontend.connection.ConnectionIdGenerator;
 import 
org.apache.shardingsphere.proxy.frontend.firebird.command.query.statement.FirebirdStatementIdGenerator;
+import 
org.apache.shardingsphere.proxy.frontend.firebird.command.query.statement.fetch.FirebirdFetchStatementCache;
 import 
org.apache.shardingsphere.proxy.frontend.firebird.command.query.transaction.FirebirdTransactionIdGenerator;
 import 
org.apache.shardingsphere.test.infra.framework.extension.mock.AutoMockExtension;
 import 
org.apache.shardingsphere.test.infra.framework.extension.mock.StaticMockSettings;
@@ -34,7 +35,7 @@ import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 @ExtendWith(AutoMockExtension.class)
-@StaticMockSettings({ConnectionIdGenerator.class, 
FirebirdTransactionIdGenerator.class, FirebirdStatementIdGenerator.class})
+@StaticMockSettings({ConnectionIdGenerator.class, 
FirebirdTransactionIdGenerator.class, FirebirdStatementIdGenerator.class, 
FirebirdFetchStatementCache.class})
 class FirebirdAuthenticationEngineTest {
     
     @Mock(answer = Answers.RETURNS_DEEP_STUBS)
@@ -51,6 +52,7 @@ class FirebirdAuthenticationEngineTest {
         assertThat(engine.handshake(context), is(1));
         
verify(FirebirdTransactionIdGenerator.getInstance()).registerConnection(1);
         
verify(FirebirdStatementIdGenerator.getInstance()).registerConnection(1);
+        
verify(FirebirdFetchStatementCache.getInstance()).registerConnection(1);
     }
     
     // TODO Implement tests for authenticate() method for the following cases: 
CONNECT, ATTACH, Cont_Auth (when implemented), Unknown Option
diff --git 
a/proxy/frontend/dialect/firebird/src/test/java/org/apache/shardingsphere/proxy/frontend/firebird/command/FirebirdCommandExecutorFactoryTest.java
 
b/proxy/frontend/dialect/firebird/src/test/java/org/apache/shardingsphere/proxy/frontend/firebird/command/FirebirdCommandExecutorFactoryTest.java
index b3a9ded09d7..a183954dd19 100644
--- 
a/proxy/frontend/dialect/firebird/src/test/java/org/apache/shardingsphere/proxy/frontend/firebird/command/FirebirdCommandExecutorFactoryTest.java
+++ 
b/proxy/frontend/dialect/firebird/src/test/java/org/apache/shardingsphere/proxy/frontend/firebird/command/FirebirdCommandExecutorFactoryTest.java
@@ -46,9 +46,9 @@ import 
org.apache.shardingsphere.proxy.frontend.firebird.command.query.blob.Fire
 import 
org.apache.shardingsphere.proxy.frontend.firebird.command.query.blob.FirebirdOpenBlobCommandExecutor;
 import 
org.apache.shardingsphere.proxy.frontend.firebird.command.query.blob.FirebirdPutBlobSegmentCommandExecutor;
 import 
org.apache.shardingsphere.proxy.frontend.firebird.command.query.blob.FirebirdSeekBlobCommandExecutor;
-import 
org.apache.shardingsphere.proxy.frontend.firebird.command.query.statement.FirebirdAllocateStatementCommandExecutor;
-import 
org.apache.shardingsphere.proxy.frontend.firebird.command.query.statement.FirebirdFetchStatementCommandExecutor;
-import 
org.apache.shardingsphere.proxy.frontend.firebird.command.query.statement.FirebirdFreeStatementCommandExecutor;
+import 
org.apache.shardingsphere.proxy.frontend.firebird.command.query.statement.allocate.FirebirdAllocateStatementCommandExecutor;
+import 
org.apache.shardingsphere.proxy.frontend.firebird.command.query.statement.fetch.FirebirdFetchStatementCommandExecutor;
+import 
org.apache.shardingsphere.proxy.frontend.firebird.command.query.statement.free.FirebirdFreeStatementCommandExecutor;
 import 
org.apache.shardingsphere.proxy.frontend.firebird.command.query.statement.execute.FirebirdExecuteStatementCommandExecutor;
 import 
org.apache.shardingsphere.proxy.frontend.firebird.command.query.statement.prepare.FirebirdPrepareStatementCommandExecutor;
 import 
org.apache.shardingsphere.proxy.frontend.firebird.command.query.transaction.FirebirdCommitTransactionCommandExecutor;
diff --git 
a/proxy/frontend/dialect/firebird/src/test/java/org/apache/shardingsphere/proxy/frontend/firebird/command/query/statement/FirebirdFetchStatementCommandExecutorTest.java
 
b/proxy/frontend/dialect/firebird/src/test/java/org/apache/shardingsphere/proxy/frontend/firebird/command/query/statement/FirebirdFetchStatementCommandExecutorTest.java
deleted file mode 100644
index 743f1ae5b6d..00000000000
--- 
a/proxy/frontend/dialect/firebird/src/test/java/org/apache/shardingsphere/proxy/frontend/firebird/command/query/statement/FirebirdFetchStatementCommandExecutorTest.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package 
org.apache.shardingsphere.proxy.frontend.firebird.command.query.statement;
-
-import 
org.apache.shardingsphere.database.protocol.firebird.packet.command.query.statement.FirebirdFetchStatementPacket;
-import 
org.apache.shardingsphere.database.protocol.firebird.packet.generic.FirebirdFetchResponsePacket;
-import org.apache.shardingsphere.database.protocol.packet.DatabasePacket;
-import org.apache.shardingsphere.proxy.backend.session.ConnectionSession;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.ExtendWith;
-import org.mockito.Answers;
-import org.mockito.Mock;
-import org.mockito.junit.jupiter.MockitoExtension;
-
-import java.sql.SQLException;
-import java.util.Collection;
-
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.Matchers.isA;
-
-@ExtendWith(MockitoExtension.class)
-class FirebirdFetchStatementCommandExecutorTest {
-    
-    @Mock
-    private FirebirdFetchStatementPacket packet;
-    
-    @Mock(answer = Answers.RETURNS_DEEP_STUBS)
-    private ConnectionSession connectionSession;
-    
-    @Test
-    void assertExecute() throws SQLException {
-        FirebirdFetchStatementCommandExecutor executor = new 
FirebirdFetchStatementCommandExecutor(packet, connectionSession);
-        Collection<DatabasePacket> actual = executor.execute();
-        assertThat(actual.iterator().next(), 
isA(FirebirdFetchResponsePacket.class));
-    }
-}
diff --git 
a/proxy/frontend/dialect/firebird/src/test/java/org/apache/shardingsphere/proxy/frontend/firebird/command/query/statement/FirebirdAllocateStatementCommandExecutorTest.java
 
b/proxy/frontend/dialect/firebird/src/test/java/org/apache/shardingsphere/proxy/frontend/firebird/command/query/statement/allocate/FirebirdAllocateStatementCommandExecutorTest.java
similarity index 95%
rename from 
proxy/frontend/dialect/firebird/src/test/java/org/apache/shardingsphere/proxy/frontend/firebird/command/query/statement/FirebirdAllocateStatementCommandExecutorTest.java
rename to 
proxy/frontend/dialect/firebird/src/test/java/org/apache/shardingsphere/proxy/frontend/firebird/command/query/statement/allocate/FirebirdAllocateStatementCommandExecutorTest.java
index b5abf036523..36bea2138c2 100644
--- 
a/proxy/frontend/dialect/firebird/src/test/java/org/apache/shardingsphere/proxy/frontend/firebird/command/query/statement/FirebirdAllocateStatementCommandExecutorTest.java
+++ 
b/proxy/frontend/dialect/firebird/src/test/java/org/apache/shardingsphere/proxy/frontend/firebird/command/query/statement/allocate/FirebirdAllocateStatementCommandExecutorTest.java
@@ -15,12 +15,13 @@
  * limitations under the License.
  */
 
-package 
org.apache.shardingsphere.proxy.frontend.firebird.command.query.statement;
+package 
org.apache.shardingsphere.proxy.frontend.firebird.command.query.statement.allocate;
 
 import 
org.apache.shardingsphere.database.protocol.firebird.packet.command.query.statement.FirebirdAllocateStatementPacket;
 import 
org.apache.shardingsphere.database.protocol.firebird.packet.generic.FirebirdGenericResponsePacket;
 import org.apache.shardingsphere.database.protocol.packet.DatabasePacket;
 import org.apache.shardingsphere.proxy.backend.session.ConnectionSession;
+import 
org.apache.shardingsphere.proxy.frontend.firebird.command.query.statement.FirebirdStatementIdGenerator;
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
diff --git 
a/proxy/frontend/dialect/firebird/src/test/java/org/apache/shardingsphere/proxy/frontend/firebird/command/query/statement/execute/FirebirdExecuteStatementCommandExecutorTest.java
 
b/proxy/frontend/dialect/firebird/src/test/java/org/apache/shardingsphere/proxy/frontend/firebird/command/query/statement/execute/FirebirdExecuteStatementCommandExecutorTest.java
index a4c8190935d..361b82d4ea1 100644
--- 
a/proxy/frontend/dialect/firebird/src/test/java/org/apache/shardingsphere/proxy/frontend/firebird/command/query/statement/execute/FirebirdExecuteStatementCommandExecutorTest.java
+++ 
b/proxy/frontend/dialect/firebird/src/test/java/org/apache/shardingsphere/proxy/frontend/firebird/command/query/statement/execute/FirebirdExecuteStatementCommandExecutorTest.java
@@ -18,9 +18,7 @@
 package 
org.apache.shardingsphere.proxy.frontend.firebird.command.query.statement.execute;
 
 import org.apache.shardingsphere.database.connector.core.type.DatabaseType;
-import 
org.apache.shardingsphere.database.protocol.firebird.packet.FirebirdPacket;
 import 
org.apache.shardingsphere.database.protocol.firebird.packet.command.query.statement.execute.FirebirdExecuteStatementPacket;
-import 
org.apache.shardingsphere.database.protocol.firebird.packet.generic.FirebirdFetchResponsePacket;
 import 
org.apache.shardingsphere.database.protocol.firebird.packet.generic.FirebirdGenericResponsePacket;
 import 
org.apache.shardingsphere.database.protocol.firebird.packet.generic.FirebirdSQLResponsePacket;
 import org.apache.shardingsphere.database.protocol.packet.DatabasePacket;
@@ -43,8 +41,10 @@ import 
org.apache.shardingsphere.proxy.backend.session.ConnectionSession;
 import 
org.apache.shardingsphere.proxy.backend.session.ServerPreparedStatementRegistry;
 import org.apache.shardingsphere.proxy.frontend.command.executor.ResponseType;
 import 
org.apache.shardingsphere.proxy.frontend.firebird.command.query.FirebirdServerPreparedStatement;
+import 
org.apache.shardingsphere.proxy.frontend.firebird.command.query.statement.fetch.FirebirdFetchStatementCache;
 import 
org.apache.shardingsphere.test.infra.framework.extension.mock.AutoMockExtension;
 import 
org.apache.shardingsphere.test.infra.framework.extension.mock.StaticMockSettings;
+import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
@@ -61,13 +61,12 @@ import java.util.Collections;
 import java.util.Iterator;
 
 import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.nullValue;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.isA;
 import static org.junit.jupiter.api.Assertions.assertFalse;
-import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 @ExtendWith(AutoMockExtension.class)
@@ -75,7 +74,11 @@ import static org.mockito.Mockito.when;
 @MockitoSettings(strictness = Strictness.LENIENT)
 class FirebirdExecuteStatementCommandExecutorTest {
     
-    private final DatabaseType databaseType = 
TypedSPILoader.getService(DatabaseType.class, "Firebird");
+    private static final DatabaseType DATABASE_TYPE = 
TypedSPILoader.getService(DatabaseType.class, "Firebird");
+    
+    private static final int CONNECTION_ID = 1;
+    
+    private static final int STATEMENT_ID = 1;
     
     @Mock
     private FirebirdExecuteStatementPacket packet;
@@ -100,16 +103,25 @@ class FirebirdExecuteStatementCommandExecutorTest {
     
     @BeforeEach
     void setUp() {
+        
FirebirdFetchStatementCache.getInstance().registerConnection(CONNECTION_ID);
+        when(connectionSession.getConnectionId()).thenReturn(CONNECTION_ID);
+        when(packet.getStatementId()).thenReturn(STATEMENT_ID);
         ServerPreparedStatementRegistry registry = new 
ServerPreparedStatementRegistry();
         
when(connectionSession.getServerPreparedStatementRegistry()).thenReturn(registry);
         
when(connectionSession.getConnectionContext()).thenReturn(connectionContext);
         
when(ProxyContext.getInstance().getContextManager().getMetaDataContexts().getMetaData()).thenReturn(new
 ShardingSphereMetaData());
-        when(selectContext.getSqlStatement()).thenReturn(new 
org.apache.shardingsphere.sql.parser.statement.core.statement.type.dml.SelectStatement(databaseType));
+        when(selectContext.getSqlStatement()).thenReturn(new 
org.apache.shardingsphere.sql.parser.statement.core.statement.type.dml.SelectStatement(DATABASE_TYPE));
         registry.addPreparedStatement(1, new 
FirebirdServerPreparedStatement("SELECT * FROM tbl", selectContext, new 
HintValueContext()));
-        when(updateContext.getSqlStatement()).thenReturn(new 
org.apache.shardingsphere.sql.parser.statement.core.statement.type.dml.UpdateStatement(databaseType));
+        when(updateContext.getSqlStatement()).thenReturn(new 
org.apache.shardingsphere.sql.parser.statement.core.statement.type.dml.UpdateStatement(DATABASE_TYPE));
         registry.addPreparedStatement(2, new 
FirebirdServerPreparedStatement("UPDATE tbl SET col=1", updateContext, new 
HintValueContext()));
     }
     
+    @AfterEach
+    void tearDown() {
+        
FirebirdFetchStatementCache.getInstance().unregisterStatement(CONNECTION_ID, 
STATEMENT_ID);
+        
FirebirdFetchStatementCache.getInstance().unregisterConnection(CONNECTION_ID);
+    }
+    
     @Test
     void assertIsQueryResponse() throws SQLException {
         when(packet.getStatementId()).thenReturn(1);
@@ -121,18 +133,14 @@ class FirebirdExecuteStatementCommandExecutorTest {
         when(proxyBackendHandler.next()).thenReturn(true, true);
         QueryResponseRow row = new 
QueryResponseRow(Collections.singletonList(new QueryResponseCell(Types.INTEGER, 
1)));
         when(proxyBackendHandler.getRowData()).thenReturn(row, row);
-        when(ProxyBackendHandlerFactory.newInstance(eq(databaseType), 
any(QueryContext.class), eq(connectionSession), 
eq(true))).thenReturn(proxyBackendHandler);
+        when(ProxyBackendHandlerFactory.newInstance(eq(DATABASE_TYPE), 
any(QueryContext.class), eq(connectionSession), 
eq(true))).thenReturn(proxyBackendHandler);
         Collection<DatabasePacket> actual = executor.execute();
         Iterator<DatabasePacket> iterator = actual.iterator();
         assertThat(executor.getResponseType(), is(ResponseType.QUERY));
         assertThat(iterator.next(), isA(FirebirdSQLResponsePacket.class));
         assertThat(iterator.next(), isA(FirebirdGenericResponsePacket.class));
         assertFalse(iterator.hasNext());
-        assertTrue(executor.next());
-        FirebirdPacket rowPacket = executor.getQueryRowPacket();
-        assertThat(rowPacket, isA(FirebirdFetchResponsePacket.class));
-        executor.close();
-        verify(proxyBackendHandler).close();
+        
assertThat(FirebirdFetchStatementCache.getInstance().getFetchBackendHandler(CONNECTION_ID,
 STATEMENT_ID), is(proxyBackendHandler));
     }
     
     @Test
@@ -141,10 +149,11 @@ class FirebirdExecuteStatementCommandExecutorTest {
         when(packet.getParameterTypes()).thenReturn(Collections.emptyList());
         when(packet.getParameterValues()).thenReturn(new ArrayList<>());
         FirebirdExecuteStatementCommandExecutor executor = new 
FirebirdExecuteStatementCommandExecutor(packet, connectionSession);
-        when(proxyBackendHandler.execute()).thenReturn(new 
UpdateResponseHeader(new 
org.apache.shardingsphere.sql.parser.statement.core.statement.type.dml.UpdateStatement(databaseType)));
-        when(ProxyBackendHandlerFactory.newInstance(eq(databaseType), 
any(QueryContext.class), eq(connectionSession), 
eq(true))).thenReturn(proxyBackendHandler);
+        when(proxyBackendHandler.execute()).thenReturn(new 
UpdateResponseHeader(new 
org.apache.shardingsphere.sql.parser.statement.core.statement.type.dml.UpdateStatement(DATABASE_TYPE)));
+        when(ProxyBackendHandlerFactory.newInstance(eq(DATABASE_TYPE), 
any(QueryContext.class), eq(connectionSession), 
eq(true))).thenReturn(proxyBackendHandler);
         Collection<DatabasePacket> actual = executor.execute();
         assertThat(executor.getResponseType(), is(ResponseType.UPDATE));
         assertThat(actual.iterator().next(), 
isA(FirebirdGenericResponsePacket.class));
+        
assertThat(FirebirdFetchStatementCache.getInstance().getFetchBackendHandler(CONNECTION_ID,
 STATEMENT_ID), nullValue());
     }
 }
diff --git 
a/proxy/frontend/dialect/firebird/src/test/java/org/apache/shardingsphere/proxy/frontend/firebird/command/query/statement/fetch/FirebirdFetchStatementCommandExecutorTest.java
 
b/proxy/frontend/dialect/firebird/src/test/java/org/apache/shardingsphere/proxy/frontend/firebird/command/query/statement/fetch/FirebirdFetchStatementCommandExecutorTest.java
new file mode 100644
index 00000000000..3be58d2591a
--- /dev/null
+++ 
b/proxy/frontend/dialect/firebird/src/test/java/org/apache/shardingsphere/proxy/frontend/firebird/command/query/statement/fetch/FirebirdFetchStatementCommandExecutorTest.java
@@ -0,0 +1,108 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package 
org.apache.shardingsphere.proxy.frontend.firebird.command.query.statement.fetch;
+
+import 
org.apache.shardingsphere.database.protocol.firebird.packet.command.query.statement.FirebirdFetchStatementPacket;
+import 
org.apache.shardingsphere.database.protocol.firebird.packet.generic.FirebirdFetchResponsePacket;
+import org.apache.shardingsphere.database.protocol.packet.DatabasePacket;
+import org.apache.shardingsphere.proxy.backend.handler.ProxyBackendHandler;
+import org.apache.shardingsphere.proxy.backend.response.data.QueryResponseCell;
+import org.apache.shardingsphere.proxy.backend.response.data.QueryResponseRow;
+import org.apache.shardingsphere.proxy.backend.session.ConnectionSession;
+import org.firebirdsql.gds.ISCConstants;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Answers;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import java.sql.SQLException;
+import java.sql.Types;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.notNullValue;
+import static org.hamcrest.Matchers.nullValue;
+import static org.mockito.Mockito.when;
+
+@ExtendWith(MockitoExtension.class)
+class FirebirdFetchStatementCommandExecutorTest {
+    
+    private static final int CONNECTION_ID = 1;
+    
+    private static final int STATEMENT_ID = 1;
+    
+    @Mock
+    private FirebirdFetchStatementPacket packet;
+    
+    @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+    private ConnectionSession connectionSession;
+    
+    @Mock
+    private ProxyBackendHandler proxyBackendHandler;
+    
+    @BeforeEach
+    void setup() {
+        
FirebirdFetchStatementCache.getInstance().registerConnection(CONNECTION_ID);
+        
FirebirdFetchStatementCache.getInstance().registerStatement(CONNECTION_ID, 
STATEMENT_ID, proxyBackendHandler);
+        when(connectionSession.getConnectionId()).thenReturn(CONNECTION_ID);
+        when(packet.getStatementId()).thenReturn(STATEMENT_ID);
+        when(packet.getFetchSize()).thenReturn(1);
+    }
+    
+    @AfterEach
+    void tearDown() {
+        
FirebirdFetchStatementCache.getInstance().unregisterStatement(CONNECTION_ID, 
STATEMENT_ID);
+        
FirebirdFetchStatementCache.getInstance().unregisterConnection(CONNECTION_ID);
+    }
+    
+    @Test
+    void assertExecute() throws SQLException {
+        when(proxyBackendHandler.next()).thenReturn(true);
+        QueryResponseRow row = new 
QueryResponseRow(Collections.singletonList(new QueryResponseCell(Types.INTEGER, 
1)));
+        when(proxyBackendHandler.getRowData()).thenReturn(row, row);
+        FirebirdFetchStatementCommandExecutor executor = new 
FirebirdFetchStatementCommandExecutor(packet, connectionSession);
+        Collection<DatabasePacket> actual = executor.execute();
+        Iterator<DatabasePacket> iterator = actual.iterator();
+        FirebirdFetchResponsePacket first = (FirebirdFetchResponsePacket) 
iterator.next();
+        assertThat(first.getStatus(), equalTo(ISCConstants.FETCH_OK));
+        assertThat(first.getCount(), equalTo(1));
+        assertThat(first.getRow(), notNullValue());
+        FirebirdFetchResponsePacket second = (FirebirdFetchResponsePacket) 
iterator.next();
+        assertThat(second.getStatus(), equalTo(ISCConstants.FETCH_OK));
+        assertThat(second.getCount(), equalTo(0));
+        assertThat(second.getRow(), nullValue());
+    }
+    
+    @Test
+    void assertExecuteNoMoreRows() throws SQLException {
+        when(proxyBackendHandler.next()).thenReturn(false);
+        FirebirdFetchStatementCommandExecutor executor = new 
FirebirdFetchStatementCommandExecutor(packet, connectionSession);
+        Collection<DatabasePacket> actual = executor.execute();
+        Iterator<DatabasePacket> iterator = actual.iterator();
+        FirebirdFetchResponsePacket packet = (FirebirdFetchResponsePacket) 
iterator.next();
+        assertThat(packet.getStatus(), 
equalTo(ISCConstants.FETCH_NO_MORE_ROWS));
+        assertThat(packet.getCount(), equalTo(0));
+        assertThat(packet.getRow(), nullValue());
+    }
+}
diff --git 
a/proxy/frontend/dialect/firebird/src/test/java/org/apache/shardingsphere/proxy/frontend/firebird/command/query/statement/FirebirdFreeStatementCommandExecutorTest.java
 
b/proxy/frontend/dialect/firebird/src/test/java/org/apache/shardingsphere/proxy/frontend/firebird/command/query/statement/free/FirebirdFreeStatementCommandExecutorTest.java
similarity index 69%
rename from 
proxy/frontend/dialect/firebird/src/test/java/org/apache/shardingsphere/proxy/frontend/firebird/command/query/statement/FirebirdFreeStatementCommandExecutorTest.java
rename to 
proxy/frontend/dialect/firebird/src/test/java/org/apache/shardingsphere/proxy/frontend/firebird/command/query/statement/free/FirebirdFreeStatementCommandExecutorTest.java
index bc995d57921..5ae99fcdb86 100644
--- 
a/proxy/frontend/dialect/firebird/src/test/java/org/apache/shardingsphere/proxy/frontend/firebird/command/query/statement/FirebirdFreeStatementCommandExecutorTest.java
+++ 
b/proxy/frontend/dialect/firebird/src/test/java/org/apache/shardingsphere/proxy/frontend/firebird/command/query/statement/free/FirebirdFreeStatementCommandExecutorTest.java
@@ -15,32 +15,45 @@
  * limitations under the License.
  */
 
-package 
org.apache.shardingsphere.proxy.frontend.firebird.command.query.statement;
+package 
org.apache.shardingsphere.proxy.frontend.firebird.command.query.statement.free;
 
 import 
org.apache.shardingsphere.database.protocol.firebird.exception.FirebirdProtocolException;
 import 
org.apache.shardingsphere.database.protocol.firebird.packet.command.query.statement.FirebirdFreeStatementPacket;
 import 
org.apache.shardingsphere.database.protocol.firebird.packet.generic.FirebirdGenericResponsePacket;
 import org.apache.shardingsphere.database.protocol.packet.DatabasePacket;
+import 
org.apache.shardingsphere.proxy.backend.connector.ProxyDatabaseConnectionManager;
+import org.apache.shardingsphere.proxy.backend.handler.ProxyBackendHandler;
 import org.apache.shardingsphere.proxy.backend.session.ConnectionSession;
 import 
org.apache.shardingsphere.proxy.backend.session.ServerPreparedStatementRegistry;
+import 
org.apache.shardingsphere.proxy.frontend.firebird.command.query.statement.fetch.FirebirdFetchStatementCache;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
 import org.mockito.Answers;
 import org.mockito.Mock;
 import org.mockito.junit.jupiter.MockitoExtension;
+import org.mockito.junit.jupiter.MockitoSettings;
+import org.mockito.quality.Strictness;
 
 import java.sql.SQLException;
 import java.util.Collection;
 
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.isA;
+import static org.hamcrest.Matchers.nullValue;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 @ExtendWith(MockitoExtension.class)
+@MockitoSettings(strictness = Strictness.LENIENT)
 class FirebirdFreeStatementCommandExecutorTest {
     
+    private static final int CONNECTION_ID = 1;
+    
+    private static final int STATEMENT_ID = 1;
+    
     @Mock
     private FirebirdFreeStatementPacket packet;
     
@@ -50,11 +63,31 @@ class FirebirdFreeStatementCommandExecutorTest {
     @Mock
     private ServerPreparedStatementRegistry registry;
     
+    @Mock
+    private ProxyDatabaseConnectionManager connectionManager;
+    
+    @Mock
+    private ProxyBackendHandler proxyBackendHandler;
+    
+    @BeforeEach
+    void setUp() {
+        
FirebirdFetchStatementCache.getInstance().registerConnection(CONNECTION_ID);
+        
FirebirdFetchStatementCache.getInstance().registerStatement(CONNECTION_ID, 
STATEMENT_ID, proxyBackendHandler);
+        when(packet.getStatementId()).thenReturn(STATEMENT_ID);
+        when(connectionSession.getConnectionId()).thenReturn(CONNECTION_ID);
+        
when(connectionSession.getServerPreparedStatementRegistry()).thenReturn(registry);
+        
when(connectionSession.getDatabaseConnectionManager()).thenReturn(connectionManager);
+    }
+    
+    @AfterEach
+    void tearDown() {
+        
FirebirdFetchStatementCache.getInstance().unregisterStatement(CONNECTION_ID, 
STATEMENT_ID);
+        
FirebirdFetchStatementCache.getInstance().unregisterConnection(CONNECTION_ID);
+    }
+    
     @Test
     void assertExecuteWithDrop() throws SQLException {
-        
when(connectionSession.getServerPreparedStatementRegistry()).thenReturn(registry);
         when(packet.getOption()).thenReturn(FirebirdFreeStatementPacket.DROP);
-        when(packet.getStatementId()).thenReturn(1);
         FirebirdFreeStatementCommandExecutor executor = new 
FirebirdFreeStatementCommandExecutor(packet, connectionSession);
         Collection<DatabasePacket> actual = executor.execute();
         assertThat(actual.iterator().next(), 
isA(FirebirdGenericResponsePacket.class));
@@ -63,9 +96,7 @@ class FirebirdFreeStatementCommandExecutorTest {
     
     @Test
     void assertExecuteWithUnprepare() throws SQLException {
-        
when(connectionSession.getServerPreparedStatementRegistry()).thenReturn(registry);
         
when(packet.getOption()).thenReturn(FirebirdFreeStatementPacket.UNPREPARE);
-        when(packet.getStatementId()).thenReturn(1);
         FirebirdFreeStatementCommandExecutor executor = new 
FirebirdFreeStatementCommandExecutor(packet, connectionSession);
         Collection<DatabasePacket> actual = executor.execute();
         assertThat(actual.iterator().next(), 
isA(FirebirdGenericResponsePacket.class));
@@ -78,6 +109,8 @@ class FirebirdFreeStatementCommandExecutorTest {
         FirebirdFreeStatementCommandExecutor executor = new 
FirebirdFreeStatementCommandExecutor(packet, connectionSession);
         executor.execute();
         verify(connectionSession.getConnectionContext()).clearCursorContext();
+        verify(connectionManager).unmarkResourceInUse(proxyBackendHandler);
+        
assertThat(FirebirdFetchStatementCache.getInstance().getFetchBackendHandler(CONNECTION_ID,
 STATEMENT_ID), nullValue());
     }
     
     @Test

Reply via email to