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

terrymanu 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 7e63199751c Fix nullable metadata consumers and JDBC statement 
initialization (#40300)
7e63199751c is described below

commit 7e63199751c4c5143f4fd82fbd10ea04bf77bb1a
Author: Liang Zhang <[email protected]>
AuthorDate: Wed Oct 21 01:01:57 2026 +0800

    Fix nullable metadata consumers and JDBC statement initialization (#40300)
    
    * Fix nullable metadata consumers and JDBC statement initialization
    
    * Fix nullable metadata consumer test fixtures
    
    * Fix Firebird describe schema consistency during metadata refresh
---
 .../PostgreSQLPgClassTableStatisticsCollector.java |   6 +-
 ...tgreSQLPgNamespaceTableStatisticsCollector.java |   6 +-
 ...tgreSQLPgClassTableStatisticsCollectorTest.java |   8 +
 ...SQLPgNamespaceTableStatisticsCollectorTest.java |  15 ++
 .../export/ExportStorageNodesExecutor.java         |  16 +-
 .../metadata/RefreshTableMetaDataExecutor.java     |  24 ++-
 .../statement/ShardingSpherePreparedStatement.java |   4 +
 .../core/statement/ShardingSphereStatement.java    |   5 +
 .../ShardingSpherePreparedStatementTest.java       |  56 ++++++
 .../statement/ShardingSphereStatementTest.java     |  91 ++++++++++
 .../statistics/StatisticsRefreshEngine.java        |  11 +-
 .../statistics/StatisticsRefreshEngineTest.java    | 115 ++++++++++++
 .../connector/jdbc/executor/ProxyJDBCExecutor.java |   4 +-
 .../jdbc/executor/ProxyJDBCExecutorTest.java       |  58 +++++-
 .../DistSQLUpdateProxyBackendHandlerTest.java      |   4 +-
 .../export/ExportStorageNodesExecutorTest.java     |  13 +-
 .../refresh/RefreshTableMetaDataExecutorTest.java  |  17 +-
 .../FirebirdPrepareStatementCommandExecutor.java   |  72 ++++----
 ...irebirdPrepareStatementCommandExecutorTest.java | 202 +++++++++++++++++++++
 19 files changed, 658 insertions(+), 69 deletions(-)

diff --git 
a/infra/common/src/main/java/org/apache/shardingsphere/infra/metadata/statistics/collector/postgresql/table/PostgreSQLPgClassTableStatisticsCollector.java
 
b/infra/common/src/main/java/org/apache/shardingsphere/infra/metadata/statistics/collector/postgresql/table/PostgreSQLPgClassTableStatisticsCollector.java
index 3d090e5a27f..1ac968a4af3 100644
--- 
a/infra/common/src/main/java/org/apache/shardingsphere/infra/metadata/statistics/collector/postgresql/table/PostgreSQLPgClassTableStatisticsCollector.java
+++ 
b/infra/common/src/main/java/org/apache/shardingsphere/infra/metadata/statistics/collector/postgresql/table/PostgreSQLPgClassTableStatisticsCollector.java
@@ -18,7 +18,9 @@
 package 
org.apache.shardingsphere.infra.metadata.statistics.collector.postgresql.table;
 
 import com.cedarsoftware.util.CaseInsensitiveMap;
+import org.apache.shardingsphere.infra.exception.ShardingSpherePreconditions;
 import org.apache.shardingsphere.infra.metadata.ShardingSphereMetaData;
+import 
org.apache.shardingsphere.infra.metadata.database.ShardingSphereDatabase;
 import 
org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereSchema;
 import 
org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereTable;
 import 
org.apache.shardingsphere.infra.metadata.statistics.collector.postgresql.PostgreSQLTableStatisticsCollector;
@@ -36,8 +38,10 @@ public final class PostgreSQLPgClassTableStatisticsCollector 
implements PostgreS
     
     @Override
     public Collection<Map<String, Object>> collect(final String databaseName, 
final String schemaName, final String tableName, final ShardingSphereMetaData 
metaData) {
+        ShardingSphereDatabase database = metaData.getDatabase(databaseName);
+        ShardingSpherePreconditions.checkNotNull(database, () -> new 
IllegalStateException(String.format("Database '%s' does not exist.", 
databaseName)));
         Collection<Map<String, Object>> result = new LinkedList<>();
-        ShardingSphereSchema publicSchema = 
metaData.getDatabase(databaseName).getSchema(PUBLIC_SCHEMA);
+        ShardingSphereSchema publicSchema = database.getSchema(PUBLIC_SCHEMA);
         if (null != publicSchema) {
             for (ShardingSphereTable each : publicSchema.getAllTables()) {
                 Map<String, Object> columnValues = new CaseInsensitiveMap<>(4, 
1F);
diff --git 
a/infra/common/src/main/java/org/apache/shardingsphere/infra/metadata/statistics/collector/postgresql/table/PostgreSQLPgNamespaceTableStatisticsCollector.java
 
b/infra/common/src/main/java/org/apache/shardingsphere/infra/metadata/statistics/collector/postgresql/table/PostgreSQLPgNamespaceTableStatisticsCollector.java
index 5820f70eeda..3e9f95d19e3 100644
--- 
a/infra/common/src/main/java/org/apache/shardingsphere/infra/metadata/statistics/collector/postgresql/table/PostgreSQLPgNamespaceTableStatisticsCollector.java
+++ 
b/infra/common/src/main/java/org/apache/shardingsphere/infra/metadata/statistics/collector/postgresql/table/PostgreSQLPgNamespaceTableStatisticsCollector.java
@@ -18,7 +18,9 @@
 package 
org.apache.shardingsphere.infra.metadata.statistics.collector.postgresql.table;
 
 import com.cedarsoftware.util.CaseInsensitiveMap;
+import org.apache.shardingsphere.infra.exception.ShardingSpherePreconditions;
 import org.apache.shardingsphere.infra.metadata.ShardingSphereMetaData;
+import 
org.apache.shardingsphere.infra.metadata.database.ShardingSphereDatabase;
 import 
org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereSchema;
 import 
org.apache.shardingsphere.infra.metadata.statistics.collector.postgresql.PostgreSQLTableStatisticsCollector;
 
@@ -37,9 +39,11 @@ public final class 
PostgreSQLPgNamespaceTableStatisticsCollector implements Post
     
     @Override
     public Collection<Map<String, Object>> collect(final String databaseName, 
final String schemaName, final String tableName, final ShardingSphereMetaData 
metaData) {
+        ShardingSphereDatabase database = metaData.getDatabase(databaseName);
+        ShardingSpherePreconditions.checkNotNull(database, () -> new 
IllegalStateException(String.format("Database '%s' does not exist.", 
databaseName)));
         Collection<Map<String, Object>> result = new LinkedList<>();
         long oid = 1L;
-        for (ShardingSphereSchema each : 
metaData.getDatabase(databaseName).getAllSchemas()) {
+        for (ShardingSphereSchema each : database.getAllSchemas()) {
             Map<String, Object> columnValues = new CaseInsensitiveMap<>(2, 1F);
             columnValues.put("oid", 
PUBLIC_SCHEMA.equalsIgnoreCase(each.getName()) ? PUBLIC_SCHEMA_OID : oid++);
             columnValues.put("nspname", each.getName());
diff --git 
a/infra/common/src/test/java/org/apache/shardingsphere/infra/metadata/statistics/collector/postgresql/table/PostgreSQLPgClassTableStatisticsCollectorTest.java
 
b/infra/common/src/test/java/org/apache/shardingsphere/infra/metadata/statistics/collector/postgresql/table/PostgreSQLPgClassTableStatisticsCollectorTest.java
index 5f32bb819c2..047a9d07afc 100644
--- 
a/infra/common/src/test/java/org/apache/shardingsphere/infra/metadata/statistics/collector/postgresql/table/PostgreSQLPgClassTableStatisticsCollectorTest.java
+++ 
b/infra/common/src/test/java/org/apache/shardingsphere/infra/metadata/statistics/collector/postgresql/table/PostgreSQLPgClassTableStatisticsCollectorTest.java
@@ -33,6 +33,7 @@ import java.util.Map;
 
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.is;
+import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
@@ -66,6 +67,13 @@ class PostgreSQLPgClassTableStatisticsCollectorTest {
         assertTrue(actual.isEmpty());
     }
     
+    @Test
+    void assertCollectWithDatabaseNotExists() {
+        when(metaData.getDatabase("foo_db")).thenReturn(null);
+        IllegalStateException actual = 
assertThrows(IllegalStateException.class, () -> collector.collect("foo_db", 
"pg_catalog", "pg_class", metaData));
+        assertThat(actual.getMessage(), is("Database 'foo_db' does not 
exist."));
+    }
+    
     @Test
     void assertGetSchemaName() {
         assertThat(collector.getSchemaName(), is("pg_catalog"));
diff --git 
a/infra/common/src/test/java/org/apache/shardingsphere/infra/metadata/statistics/collector/postgresql/table/PostgreSQLPgNamespaceTableStatisticsCollectorTest.java
 
b/infra/common/src/test/java/org/apache/shardingsphere/infra/metadata/statistics/collector/postgresql/table/PostgreSQLPgNamespaceTableStatisticsCollectorTest.java
index 392e241db2a..0ee993754df 100644
--- 
a/infra/common/src/test/java/org/apache/shardingsphere/infra/metadata/statistics/collector/postgresql/table/PostgreSQLPgNamespaceTableStatisticsCollectorTest.java
+++ 
b/infra/common/src/test/java/org/apache/shardingsphere/infra/metadata/statistics/collector/postgresql/table/PostgreSQLPgNamespaceTableStatisticsCollectorTest.java
@@ -37,6 +37,8 @@ import java.util.stream.Collectors;
 
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.is;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
 class PostgreSQLPgNamespaceTableStatisticsCollectorTest {
     
@@ -62,6 +64,19 @@ class PostgreSQLPgNamespaceTableStatisticsCollectorTest {
         assertThat(actualResults.get("bar_schema").get("nspname"), 
is("bar_schema"));
     }
     
+    @Test
+    void assertCollectWithNoSchemas() {
+        assertTrue(collector.collect("foo_db", "pg_catalog", "pg_namespace", 
createMetaData(Collections.emptyList())).isEmpty());
+    }
+    
+    @Test
+    void assertCollectWithDatabaseNotExists() {
+        ShardingSphereMetaData metaData = 
createMetaData(Collections.emptyList());
+        metaData.dropDatabase("foo_db");
+        IllegalStateException actual = 
assertThrows(IllegalStateException.class, () -> collector.collect("foo_db", 
"pg_catalog", "pg_namespace", metaData));
+        assertThat(actual.getMessage(), is("Database 'foo_db' does not 
exist."));
+    }
+    
     @Test
     void assertGetSchemaName() {
         assertThat(collector.getSchemaName(), is("pg_catalog"));
diff --git 
a/infra/distsql-handler/src/main/java/org/apache/shardingsphere/distsql/handler/executor/configuration/export/ExportStorageNodesExecutor.java
 
b/infra/distsql-handler/src/main/java/org/apache/shardingsphere/distsql/handler/executor/configuration/export/ExportStorageNodesExecutor.java
index 3a89039c37c..347856361c9 100644
--- 
a/infra/distsql-handler/src/main/java/org/apache/shardingsphere/distsql/handler/executor/configuration/export/ExportStorageNodesExecutor.java
+++ 
b/infra/distsql-handler/src/main/java/org/apache/shardingsphere/distsql/handler/executor/configuration/export/ExportStorageNodesExecutor.java
@@ -52,7 +52,6 @@ public final class ExportStorageNodesExecutor implements 
DistSQLQueryExecutor<Ex
     
     @Override
     public Collection<LocalDataQueryResultRow> getRows(final 
ExportStorageNodesStatement sqlStatement, final ContextManager contextManager) {
-        checkSQLStatement(contextManager.getMetaDataContexts().getMetaData(), 
sqlStatement);
         String exportedData = 
generateExportData(contextManager.getMetaDataContexts().getMetaData(), 
sqlStatement);
         if (sqlStatement.getFilePath().isPresent()) {
             String filePath = sqlStatement.getFilePath().get();
@@ -64,16 +63,15 @@ public final class ExportStorageNodesExecutor implements 
DistSQLQueryExecutor<Ex
                 new 
LocalDataQueryResultRow(contextManager.getComputeNodeInstanceContext().getInstance().getMetaData().getId(),
 LocalDateTime.now(), exportedData));
     }
     
-    private void checkSQLStatement(final ShardingSphereMetaData metaData, 
final ExportStorageNodesStatement sqlStatement) {
-        ShardingSpherePreconditions.checkState(null == 
sqlStatement.getDatabaseName() || null != 
metaData.getDatabase(sqlStatement.getDatabaseName()),
-                () -> new IllegalArgumentException(String.format("database %s 
is not existed", sqlStatement.getDatabaseName())));
-    }
-    
     private String generateExportData(final ShardingSphereMetaData metaData, 
final ExportStorageNodesStatement sqlStatement) {
         ExportedStorageNodes storageNodes = new ExportedStorageNodes();
-        storageNodes.setStorageNodes(null == sqlStatement.getDatabaseName()
-                ? getAllStorageNodes(metaData)
-                : 
generateDatabaseExportStorageNodesData(metaData.getDatabase(sqlStatement.getDatabaseName())));
+        if (null == sqlStatement.getDatabaseName()) {
+            storageNodes.setStorageNodes(getAllStorageNodes(metaData));
+        } else {
+            ShardingSphereDatabase database = 
metaData.getDatabase(sqlStatement.getDatabaseName());
+            ShardingSpherePreconditions.checkNotNull(database, () -> new 
IllegalArgumentException(String.format("database %s is not existed", 
sqlStatement.getDatabaseName())));
+            
storageNodes.setStorageNodes(generateDatabaseExportStorageNodesData(database));
+        }
         return JsonEngine.marshal(storageNodes);
     }
     
diff --git 
a/infra/distsql-handler/src/main/java/org/apache/shardingsphere/distsql/handler/executor/metadata/RefreshTableMetaDataExecutor.java
 
b/infra/distsql-handler/src/main/java/org/apache/shardingsphere/distsql/handler/executor/metadata/RefreshTableMetaDataExecutor.java
index 56bd68af816..8c7826f1a7f 100644
--- 
a/infra/distsql-handler/src/main/java/org/apache/shardingsphere/distsql/handler/executor/metadata/RefreshTableMetaDataExecutor.java
+++ 
b/infra/distsql-handler/src/main/java/org/apache/shardingsphere/distsql/handler/executor/metadata/RefreshTableMetaDataExecutor.java
@@ -28,6 +28,7 @@ import 
org.apache.shardingsphere.infra.exception.kernel.metadata.resource.storag
 import 
org.apache.shardingsphere.infra.exception.kernel.metadata.resource.storageunit.MissingRequiredStorageUnitsException;
 import 
org.apache.shardingsphere.infra.metadata.database.ShardingSphereDatabase;
 import 
org.apache.shardingsphere.infra.metadata.database.resource.unit.StorageUnit;
+import 
org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereSchema;
 import org.apache.shardingsphere.mode.manager.ContextManager;
 import 
org.apache.shardingsphere.sql.parser.statement.core.value.identifier.IdentifierValue;
 
@@ -45,9 +46,9 @@ public final class RefreshTableMetaDataExecutor implements 
DistSQLUpdateExecutor
     @Override
     public void executeUpdate(final RefreshTableMetaDataStatement 
sqlStatement, final ContextManager contextManager) {
         IdentifierValue schemaName = getSchemaName(sqlStatement);
-        checkBeforeUpdate(sqlStatement, schemaName);
+        ShardingSphereSchema schema = checkBeforeUpdate(sqlStatement, 
schemaName);
         if (sqlStatement.getStorageUnitName().isPresent()) {
-            String actualSchemaName = database.getSchema(schemaName).getName();
+            String actualSchemaName = schema.getName();
             if (sqlStatement.getTableName().isPresent()) {
                 contextManager.reloadTable(database, actualSchemaName, 
sqlStatement.getStorageUnitName().get(), sqlStatement.getTableName().get());
             } else {
@@ -56,7 +57,7 @@ public final class RefreshTableMetaDataExecutor implements 
DistSQLUpdateExecutor
             return;
         }
         if (sqlStatement.getTableName().isPresent()) {
-            contextManager.reloadTable(database, 
database.getSchema(schemaName).getName(), sqlStatement.getTableName().get());
+            contextManager.reloadTable(database, schema.getName(), 
sqlStatement.getTableName().get());
         } else {
             contextManager.reloadDatabase(database);
         }
@@ -66,10 +67,11 @@ public final class RefreshTableMetaDataExecutor implements 
DistSQLUpdateExecutor
         return sqlStatement.getSchemaName().orElseGet(() -> new 
IdentifierValue(database.getDefaultSchemaName()));
     }
     
-    private void checkBeforeUpdate(final RefreshTableMetaDataStatement 
sqlStatement, final IdentifierValue schemaName) {
+    private ShardingSphereSchema checkBeforeUpdate(final 
RefreshTableMetaDataStatement sqlStatement, final IdentifierValue schemaName) {
         checkStorageUnit(database.getResourceMetaData().getStorageUnits(), 
sqlStatement);
-        checkSchema(schemaName);
-        checkTable(sqlStatement, schemaName);
+        ShardingSphereSchema result = checkSchema(schemaName);
+        checkTable(sqlStatement, result);
+        return result;
     }
     
     private void checkStorageUnit(final Map<String, StorageUnit> storageUnits, 
final RefreshTableMetaDataStatement sqlStatement) {
@@ -80,14 +82,16 @@ public final class RefreshTableMetaDataExecutor implements 
DistSQLUpdateExecutor
         }
     }
     
-    private void checkSchema(final IdentifierValue schemaName) {
-        
ShardingSpherePreconditions.checkState(database.containsSchema(schemaName), () 
-> new SchemaNotFoundException(schemaName.getValue()));
+    private ShardingSphereSchema checkSchema(final IdentifierValue schemaName) 
{
+        ShardingSphereSchema result = database.getSchema(schemaName);
+        ShardingSpherePreconditions.checkNotNull(result, () -> new 
SchemaNotFoundException(schemaName.getValue()));
+        return result;
     }
     
-    private void checkTable(final RefreshTableMetaDataStatement sqlStatement, 
final IdentifierValue schemaName) {
+    private void checkTable(final RefreshTableMetaDataStatement sqlStatement, 
final ShardingSphereSchema schema) {
         if (sqlStatement.getTableName().isPresent()) {
             IdentifierValue tableName = sqlStatement.getTableName().get();
-            
ShardingSpherePreconditions.checkState(database.getSchema(schemaName).containsTable(tableName),
 () -> new TableNotFoundException(tableName.getValue()));
+            
ShardingSpherePreconditions.checkState(schema.containsTable(tableName), () -> 
new TableNotFoundException(tableName.getValue()));
         }
     }
     
diff --git 
a/jdbc/src/main/java/org/apache/shardingsphere/driver/jdbc/core/statement/ShardingSpherePreparedStatement.java
 
b/jdbc/src/main/java/org/apache/shardingsphere/driver/jdbc/core/statement/ShardingSpherePreparedStatement.java
index 3ba1dd62bda..52c2d7ee184 100644
--- 
a/jdbc/src/main/java/org/apache/shardingsphere/driver/jdbc/core/statement/ShardingSpherePreparedStatement.java
+++ 
b/jdbc/src/main/java/org/apache/shardingsphere/driver/jdbc/core/statement/ShardingSpherePreparedStatement.java
@@ -22,6 +22,7 @@ import lombok.Getter;
 import 
org.apache.shardingsphere.database.connector.core.metadata.database.metadata.option.keygen.DialectGeneratedKeyOption;
 import 
org.apache.shardingsphere.database.connector.core.type.DatabaseTypeRegistry;
 import 
org.apache.shardingsphere.database.exception.core.SQLExceptionTransformEngine;
+import 
org.apache.shardingsphere.database.exception.core.exception.syntax.database.UnknownDatabaseException;
 import org.apache.shardingsphere.distsql.statement.DistSQLStatement;
 import 
org.apache.shardingsphere.driver.executor.callback.add.StatementAddCallback;
 import 
org.apache.shardingsphere.driver.executor.callback.replay.StatementReplayCallback;
@@ -148,6 +149,8 @@ public final class ShardingSpherePreparedStatement extends 
AbstractPreparedState
         sql = SQLHintUtils.removeHint(originSQL);
         hintValueContext = SQLHintUtils.extractHint(originSQL);
         ShardingSphereDatabase currentDatabase = 
metaData.getDatabase(connection.getCurrentDatabaseName());
+        ShardingSpherePreconditions.checkNotNull(currentDatabase,
+                () -> SQLExceptionTransformEngine.toSQLException(new 
UnknownDatabaseException(connection.getCurrentDatabaseName()), 
metaData.getProtocolType()));
         SQLStatement sqlStatement = 
metaData.getGlobalRuleMetaData().getSingleRule(SQLParserRule.class).getSQLParserEngine(currentDatabase.getProtocolType()).parse(sql,
 true);
         sqlStatementContext = sqlStatement instanceof DistSQLStatement
                 ? new CommonSQLStatementContext(sqlStatement)
@@ -155,6 +158,7 @@ public final class ShardingSpherePreparedStatement extends 
AbstractPreparedState
         String usedDatabaseName = 
sqlStatementContext.getTablesContext().getDatabaseName().orElse(connection.getCurrentDatabaseName());
         
connection.getDatabaseConnectionManager().getConnectionContext().setCurrentDatabaseName(connection.getCurrentDatabaseName());
         usedDatabase = metaData.getDatabase(usedDatabaseName);
+        ShardingSpherePreconditions.checkNotNull(usedDatabase, () -> 
SQLExceptionTransformEngine.toSQLException(new 
UnknownDatabaseException(usedDatabaseName), currentDatabase.getProtocolType()));
         statementOption = returnGeneratedKeys ? new StatementOption(true, 
columns) : new StatementOption(resultSetType, resultSetConcurrency, 
resultSetHoldability);
         statementManager = new StatementManager();
         connection.registerStatementManager(statementManager);
diff --git 
a/jdbc/src/main/java/org/apache/shardingsphere/driver/jdbc/core/statement/ShardingSphereStatement.java
 
b/jdbc/src/main/java/org/apache/shardingsphere/driver/jdbc/core/statement/ShardingSphereStatement.java
index c90c8cb7c0a..635a3273b26 100644
--- 
a/jdbc/src/main/java/org/apache/shardingsphere/driver/jdbc/core/statement/ShardingSphereStatement.java
+++ 
b/jdbc/src/main/java/org/apache/shardingsphere/driver/jdbc/core/statement/ShardingSphereStatement.java
@@ -25,6 +25,7 @@ import 
org.apache.shardingsphere.database.connector.core.type.DatabaseTypeRegist
 import 
org.apache.shardingsphere.database.exception.core.SQLExceptionTransformEngine;
 import 
org.apache.shardingsphere.database.exception.core.exception.SQLDialectException;
 import 
org.apache.shardingsphere.database.exception.core.exception.protocol.DatabaseProtocolException;
+import 
org.apache.shardingsphere.database.exception.core.exception.syntax.database.UnknownDatabaseException;
 import org.apache.shardingsphere.distsql.statement.DistSQLStatement;
 import 
org.apache.shardingsphere.driver.executor.callback.add.StatementAddCallback;
 import 
org.apache.shardingsphere.driver.executor.callback.execute.StatementExecuteCallback;
@@ -300,6 +301,7 @@ public final class ShardingSphereStatement extends 
AbstractStatementAdapter {
         HintValueContext hintValueContext = 
SQLHintUtils.extractHint(originSQL);
         String sql = SQLHintUtils.removeHint(originSQL);
         ShardingSphereDatabase currentDatabase = 
metaData.getDatabase(usedDatabaseName);
+        ShardingSpherePreconditions.checkNotNull(currentDatabase, () -> 
SQLExceptionTransformEngine.toSQLException(new 
UnknownDatabaseException(usedDatabaseName), metaData.getProtocolType()));
         DatabaseType databaseType = currentDatabase.getProtocolType();
         SQLStatement sqlStatement = 
metaData.getGlobalRuleMetaData().getSingleRule(SQLParserRule.class).getSQLParserEngine(databaseType).parse(sql,
 false);
         SQLStatementContext sqlStatementContext = sqlStatement instanceof 
DistSQLStatement
@@ -422,6 +424,9 @@ public final class ShardingSphereStatement extends 
AbstractStatementAdapter {
     }
     
     private Optional<GeneratedKeyContext> findGeneratedKey() {
+        if (null == queryContext) {
+            return Optional.empty();
+        }
         SQLStatementContext sqlStatementContext = 
queryContext.getSqlStatementContext();
         return sqlStatementContext instanceof InsertStatementContext ? 
((InsertStatementContext) sqlStatementContext).getGeneratedKeyContext() : 
Optional.empty();
     }
diff --git 
a/jdbc/src/test/java/org/apache/shardingsphere/driver/jdbc/core/statement/ShardingSpherePreparedStatementTest.java
 
b/jdbc/src/test/java/org/apache/shardingsphere/driver/jdbc/core/statement/ShardingSpherePreparedStatementTest.java
index 91d667207ae..2523751697b 100644
--- 
a/jdbc/src/test/java/org/apache/shardingsphere/driver/jdbc/core/statement/ShardingSpherePreparedStatementTest.java
+++ 
b/jdbc/src/test/java/org/apache/shardingsphere/driver/jdbc/core/statement/ShardingSpherePreparedStatementTest.java
@@ -21,7 +21,9 @@ import lombok.SneakyThrows;
 import 
org.apache.shardingsphere.database.connector.core.metadata.database.metadata.DialectDatabaseMetaData;
 import org.apache.shardingsphere.database.connector.core.type.DatabaseType;
 import 
org.apache.shardingsphere.database.connector.core.type.DatabaseTypeRegistry;
+import 
org.apache.shardingsphere.database.exception.core.SQLExceptionTransformEngine;
 import 
org.apache.shardingsphere.database.exception.core.exception.syntax.database.UnknownDatabaseException;
+import org.apache.shardingsphere.distsql.statement.type.rul.sql.ParseStatement;
 import 
org.apache.shardingsphere.driver.executor.engine.facade.DriverExecutorFacade;
 import 
org.apache.shardingsphere.driver.jdbc.core.connection.ShardingSphereConnection;
 import 
org.apache.shardingsphere.driver.jdbc.core.resultset.GeneratedKeysResultSet;
@@ -45,6 +47,7 @@ import org.junit.jupiter.params.ParameterizedTest;
 import org.junit.jupiter.params.provider.Arguments;
 import org.junit.jupiter.params.provider.MethodSource;
 import org.mockito.MockedConstruction;
+import org.mockito.MockedStatic;
 import org.mockito.internal.configuration.plugins.Plugins;
 
 import java.lang.reflect.Field;
@@ -70,15 +73,68 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.ArgumentMatchers.same;
+import static org.mockito.Mockito.CALLS_REAL_METHODS;
 import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.mockConstruction;
+import static org.mockito.Mockito.mockStatic;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 class ShardingSpherePreparedStatementTest {
     
+    @Test
+    void assertCreatePreparedStatementAfterDatabaseRemoved() {
+        DatabaseType databaseType = 
TypedSPILoader.getService(DatabaseType.class, "MySQL");
+        ShardingSphereMetaData metaData = createMetaData(databaseType);
+        ShardingSphereConnection connection = 
mock(ShardingSphereConnection.class, RETURNS_DEEP_STUBS);
+        
when(connection.getContextManager().getMetaDataContexts().getMetaData()).thenReturn(metaData);
+        when(connection.getCurrentDatabaseName()).thenReturn("foo_db");
+        when(metaData.getProtocolType()).thenReturn(databaseType);
+        when(metaData.getDatabase("foo_db")).thenReturn(null);
+        SQLException expected = new SQLException("Unknown database 'foo_db'", 
"42000", 1049);
+        try (MockedStatic<SQLExceptionTransformEngine> mockedEngine = 
mockStatic(SQLExceptionTransformEngine.class, CALLS_REAL_METHODS)) {
+            mockedEngine.when(() -> SQLExceptionTransformEngine.toSQLException(
+                    argThat(ex -> ex instanceof UnknownDatabaseException && 
"foo_db".equals(((UnknownDatabaseException) ex).getDatabaseName())), 
same(databaseType))).thenReturn(expected);
+            SQLException actual = assertThrows(SQLException.class, () -> new 
ShardingSpherePreparedStatement(connection, "SELECT 1"));
+            assertThat(actual, sameInstance(expected));
+            assertThat(actual.getMessage(), is("Unknown database 'foo_db'"));
+            assertThat(actual.getSQLState(), is("42000"));
+            assertThat(actual.getErrorCode(), is(1049));
+        }
+        verify(connection, never()).registerStatementManager(any());
+    }
+    
+    @Test
+    void assertCreatePreparedStatementWhenDatabaseRemovedDuringParsing() {
+        DatabaseType databaseType = 
TypedSPILoader.getService(DatabaseType.class, "MySQL");
+        ShardingSphereMetaData metaData = createMetaData(databaseType);
+        ShardingSphereConnection connection = 
mock(ShardingSphereConnection.class, RETURNS_DEEP_STUBS);
+        
when(connection.getContextManager().getMetaDataContexts().getMetaData()).thenReturn(metaData);
+        when(connection.getCurrentDatabaseName()).thenReturn("foo_db");
+        
when(metaData.getProtocolType()).thenReturn(TypedSPILoader.getService(DatabaseType.class,
 "PostgreSQL"));
+        SQLParserRule parserRule = mock(SQLParserRule.class, 
RETURNS_DEEP_STUBS);
+        when(metaData.getGlobalRuleMetaData()).thenReturn(new 
RuleMetaData(Collections.singletonList(parserRule)));
+        when(parserRule.getSQLParserEngine(databaseType).parse("foo_distsql", 
true)).thenAnswer(invocation -> {
+            when(metaData.getDatabase("foo_db")).thenReturn(null);
+            return new ParseStatement("SELECT 1");
+        });
+        SQLException expected = new SQLException("Unknown database 'foo_db'", 
"42000", 1049);
+        try (MockedStatic<SQLExceptionTransformEngine> mockedEngine = 
mockStatic(SQLExceptionTransformEngine.class, CALLS_REAL_METHODS)) {
+            mockedEngine.when(() -> SQLExceptionTransformEngine.toSQLException(
+                    argThat(ex -> ex instanceof UnknownDatabaseException && 
"foo_db".equals(((UnknownDatabaseException) ex).getDatabaseName())), 
same(databaseType))).thenReturn(expected);
+            SQLException actual = assertThrows(SQLException.class, () -> new 
ShardingSpherePreparedStatement(connection, "foo_distsql"));
+            assertThat(actual, sameInstance(expected));
+            assertThat(actual.getMessage(), is("Unknown database 'foo_db'"));
+            assertThat(actual.getSQLState(), is("42000"));
+            assertThat(actual.getErrorCode(), is(1049));
+        }
+        verify(connection, never()).registerStatementManager(any());
+    }
+    
     @SuppressWarnings("unchecked")
     @Test
     void assertClearBatchResetsCachedGeneratedKeysResultSet() throws 
SQLException, ReflectiveOperationException {
diff --git 
a/jdbc/src/test/java/org/apache/shardingsphere/driver/jdbc/core/statement/ShardingSphereStatementTest.java
 
b/jdbc/src/test/java/org/apache/shardingsphere/driver/jdbc/core/statement/ShardingSphereStatementTest.java
index f86742f03a3..d22642d117b 100644
--- 
a/jdbc/src/test/java/org/apache/shardingsphere/driver/jdbc/core/statement/ShardingSphereStatementTest.java
+++ 
b/jdbc/src/test/java/org/apache/shardingsphere/driver/jdbc/core/statement/ShardingSphereStatementTest.java
@@ -59,12 +59,16 @@ import java.util.stream.Stream;
 
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.isA;
 import static org.hamcrest.Matchers.sameInstance;
 import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertNull;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.ArgumentMatchers.same;
+import static org.mockito.Mockito.CALLS_REAL_METHODS;
 import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.doThrow;
@@ -76,6 +80,26 @@ import static org.mockito.Mockito.when;
 
 class ShardingSphereStatementTest {
     
+    @Test
+    void assertGetGeneratedKeysBeforeExecutionWithoutDialectColumn() throws 
SQLException {
+        ShardingSphereStatement statement = 
createStatement(TypedSPILoader.getService(DatabaseType.class, "SQL92"));
+        try (ResultSet actual = statement.getGeneratedKeys()) {
+            assertFalse(actual.next());
+            assertNull(actual.getMetaData().getColumnName(1));
+            assertThat(actual.getStatement(), sameInstance(statement));
+        }
+    }
+    
+    @Test
+    void assertGetGeneratedKeysBeforeExecutionWithDialectColumn() throws 
SQLException {
+        ShardingSphereStatement statement = 
createStatement(TypedSPILoader.getService(DatabaseType.class, "MySQL"));
+        try (ResultSet actual = statement.getGeneratedKeys()) {
+            assertFalse(actual.next());
+            assertThat(actual.getMetaData().getColumnName(1), 
is("GENERATED_KEY"));
+            assertThat(actual.getStatement(), sameInstance(statement));
+        }
+    }
+    
     @Test
     void assertGetGeneratedKeysByColumnIndexWhenColumnNameMissing() throws 
SQLException {
         ResultSet generatedKeys = mock(ResultSet.class);
@@ -133,6 +157,73 @@ class ShardingSphereStatementTest {
         assertThat(assertThrows(UnknownDatabaseException.class, 
statement::getGeneratedKeys), sameInstance(expected));
     }
     
+    @Test
+    void assertGetGeneratedKeysBeforeExecutionAfterDatabaseRemoved() {
+        ShardingSphereStatement statement = 
createStatement(TypedSPILoader.getService(DatabaseType.class, "MySQL"));
+        UnknownDatabaseException expected = 
removeDatabase(statement.getConnection());
+        assertThat(assertThrows(UnknownDatabaseException.class, 
statement::getGeneratedKeys), sameInstance(expected));
+    }
+    
+    @Test
+    void assertExecuteQueryAfterDatabaseRemoved() {
+        DatabaseType databaseType = 
TypedSPILoader.getService(DatabaseType.class, "MySQL");
+        ShardingSphereStatement statement = createStatement(databaseType);
+        removeDatabase(statement.getConnection());
+        SQLException expected = new SQLException("Unknown database 'foo_db'", 
"42000", 1049);
+        try (MockedStatic<SQLExceptionTransformEngine> mockedEngine = 
mockStatic(SQLExceptionTransformEngine.class, CALLS_REAL_METHODS)) {
+            mockedEngine.when(() -> SQLExceptionTransformEngine.toSQLException(
+                    argThat(ex -> ex instanceof UnknownDatabaseException && 
"foo_db".equals(((UnknownDatabaseException) ex).getDatabaseName())), 
same(databaseType))).thenReturn(expected);
+            SQLException actual = assertThrows(SQLException.class, () -> 
statement.executeQuery("SELECT 1"));
+            assertThat(actual, sameInstance(expected));
+            assertThat(actual.getMessage(), is("Unknown database 'foo_db'"));
+            assertThat(actual.getSQLState(), is("42000"));
+            assertThat(actual.getErrorCode(), is(1049));
+        }
+    }
+    
+    @Test
+    void assertExecuteQueryAfterDatabaseRemovedWithoutDialectMapper() {
+        ShardingSphereStatement statement = 
createStatement(TypedSPILoader.getService(DatabaseType.class, "SQL92"));
+        removeDatabase(statement.getConnection());
+        SQLException actual = assertThrows(SQLException.class, () -> 
statement.executeQuery("SELECT 1"));
+        assertThat(actual.getCause(), isA(UnknownDatabaseException.class));
+        assertThat(((UnknownDatabaseException) 
actual.getCause()).getDatabaseName(), is("foo_db"));
+    }
+    
+    @Test
+    void assertExecuteUpdateAfterDatabaseRemoved() {
+        DatabaseType databaseType = 
TypedSPILoader.getService(DatabaseType.class, "MySQL");
+        ShardingSphereStatement statement = createStatement(databaseType);
+        removeDatabase(statement.getConnection());
+        SQLException expected = new SQLException("Unknown database 'foo_db'", 
"42000", 1049);
+        try (MockedStatic<SQLExceptionTransformEngine> mockedEngine = 
mockStatic(SQLExceptionTransformEngine.class, CALLS_REAL_METHODS)) {
+            mockedEngine.when(() -> SQLExceptionTransformEngine.toSQLException(
+                    argThat(ex -> ex instanceof UnknownDatabaseException && 
"foo_db".equals(((UnknownDatabaseException) ex).getDatabaseName())), 
same(databaseType))).thenReturn(expected);
+            SQLException actual = assertThrows(SQLException.class, () -> 
statement.executeUpdate("UPDATE foo_table SET id = 1"));
+            assertThat(actual, sameInstance(expected));
+            assertThat(actual.getMessage(), is("Unknown database 'foo_db'"));
+            assertThat(actual.getSQLState(), is("42000"));
+            assertThat(actual.getErrorCode(), is(1049));
+        }
+    }
+    
+    @Test
+    void assertExecuteAfterDatabaseRemoved() {
+        DatabaseType databaseType = 
TypedSPILoader.getService(DatabaseType.class, "MySQL");
+        ShardingSphereStatement statement = createStatement(databaseType);
+        removeDatabase(statement.getConnection());
+        SQLException expected = new SQLException("Unknown database 'foo_db'", 
"42000", 1049);
+        try (MockedStatic<SQLExceptionTransformEngine> mockedEngine = 
mockStatic(SQLExceptionTransformEngine.class, CALLS_REAL_METHODS)) {
+            mockedEngine.when(() -> SQLExceptionTransformEngine.toSQLException(
+                    argThat(ex -> ex instanceof UnknownDatabaseException && 
"foo_db".equals(((UnknownDatabaseException) ex).getDatabaseName())), 
same(databaseType))).thenReturn(expected);
+            SQLException actual = assertThrows(SQLException.class, () -> 
statement.execute("SELECT 1"));
+            assertThat(actual, sameInstance(expected));
+            assertThat(actual.getMessage(), is("Unknown database 'foo_db'"));
+            assertThat(actual.getSQLState(), is("42000"));
+            assertThat(actual.getErrorCode(), is(1049));
+        }
+    }
+    
     @Test
     void assertGetGeneratedKeysWithoutColumnName() throws SQLException, 
ReflectiveOperationException {
         ShardingSphereStatement statement = 
createStatement(TypedSPILoader.getService(DatabaseType.class, "SQL92"));
diff --git 
a/mode/type/cluster/core/src/main/java/org/apache/shardingsphere/mode/manager/cluster/statistics/StatisticsRefreshEngine.java
 
b/mode/type/cluster/core/src/main/java/org/apache/shardingsphere/mode/manager/cluster/statistics/StatisticsRefreshEngine.java
index 0adf384e5ce..80549bc8160 100644
--- 
a/mode/type/cluster/core/src/main/java/org/apache/shardingsphere/mode/manager/cluster/statistics/StatisticsRefreshEngine.java
+++ 
b/mode/type/cluster/core/src/main/java/org/apache/shardingsphere/mode/manager/cluster/statistics/StatisticsRefreshEngine.java
@@ -85,21 +85,22 @@ public final class StatisticsRefreshEngine {
     
     private void refreshForDatabase(final ShardingSphereMetaData metaData, 
final ShardingSphereDatabase database) {
         for (ShardingSphereSchema each : database.getAllSchemas()) {
-            refreshForSchema(metaData, database.getName(), each);
+            refreshForSchema(metaData, database, each);
         }
     }
     
-    private void refreshForSchema(final ShardingSphereMetaData metaData, final 
String databaseName, final ShardingSphereSchema schema) {
+    private void refreshForSchema(final ShardingSphereMetaData metaData, final 
ShardingSphereDatabase database, final ShardingSphereSchema schema) {
         for (ShardingSphereTable each : schema.getAllTables()) {
-            refreshForTable(metaData, databaseName, schema.getName(), each);
+            refreshForTable(metaData, database, schema.getName(), each);
         }
     }
     
-    private void refreshForTable(final ShardingSphereMetaData metaData, final 
String databaseName, final String schemaName, final ShardingSphereTable table) {
+    private void refreshForTable(final ShardingSphereMetaData metaData, final 
ShardingSphereDatabase database, final String schemaName, final 
ShardingSphereTable table) {
+        String databaseName = database.getName();
         try {
             Optional<DialectDatabaseStatisticsCollector> 
dialectStatisticsCollector = "shardingsphere".equalsIgnoreCase(schemaName)
                     ? Optional.of(new ShardingSphereStatisticsCollector())
-                    : 
DatabaseTypedSPILoader.findService(DialectDatabaseStatisticsCollector.class, 
metaData.getDatabase(databaseName).getProtocolType());
+                    : 
DatabaseTypedSPILoader.findService(DialectDatabaseStatisticsCollector.class, 
database.getProtocolType());
             if (dialectStatisticsCollector.isPresent()) {
                 Optional<Collection<Map<String, Object>>> rowColumnValues = 
dialectStatisticsCollector.get().collectRowColumnValues(databaseName, 
schemaName, table.getName(), metaData);
                 rowColumnValues.ifPresent(optional -> new 
StatisticsStorageEngine(contextManager, databaseName, schemaName, 
table.getName(), optional).storage());
diff --git 
a/mode/type/cluster/core/src/test/java/org/apache/shardingsphere/mode/manager/cluster/statistics/StatisticsRefreshEngineTest.java
 
b/mode/type/cluster/core/src/test/java/org/apache/shardingsphere/mode/manager/cluster/statistics/StatisticsRefreshEngineTest.java
new file mode 100644
index 00000000000..7917cc7ae7b
--- /dev/null
+++ 
b/mode/type/cluster/core/src/test/java/org/apache/shardingsphere/mode/manager/cluster/statistics/StatisticsRefreshEngineTest.java
@@ -0,0 +1,115 @@
+/*
+ * 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.mode.manager.cluster.statistics;
+
+import 
org.apache.shardingsphere.database.connector.core.spi.DatabaseTypedSPILoader;
+import org.apache.shardingsphere.database.connector.core.type.DatabaseType;
+import 
org.apache.shardingsphere.infra.config.props.temporary.TemporaryConfigurationProperties;
+import 
org.apache.shardingsphere.infra.config.props.temporary.TemporaryConfigurationPropertyKey;
+import org.apache.shardingsphere.infra.metadata.ShardingSphereMetaData;
+import 
org.apache.shardingsphere.infra.metadata.database.ShardingSphereDatabase;
+import 
org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereSchema;
+import 
org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereTable;
+import 
org.apache.shardingsphere.infra.metadata.statistics.collector.DialectDatabaseStatisticsCollector;
+import org.apache.shardingsphere.infra.util.props.PropertiesBuilder;
+import org.apache.shardingsphere.infra.util.props.PropertiesBuilder.Property;
+import org.apache.shardingsphere.mode.exclusive.ExclusiveOperatorEngine;
+import 
org.apache.shardingsphere.mode.exclusive.callback.ExclusiveOperationVoidCallback;
+import org.apache.shardingsphere.mode.manager.ContextManager;
+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.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Answers;
+import org.mockito.Mock;
+
+import java.sql.SQLException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Optional;
+import java.util.Properties;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+@ExtendWith(AutoMockExtension.class)
+@StaticMockSettings(DatabaseTypedSPILoader.class)
+class StatisticsRefreshEngineTest {
+    
+    @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+    private ContextManager contextManager;
+    
+    @Mock
+    private ShardingSphereMetaData metaData;
+    
+    @Mock
+    private ShardingSphereDatabase database;
+    
+    @Mock
+    private ShardingSphereSchema schema;
+    
+    @Mock
+    private DatabaseType databaseType;
+    
+    @Mock
+    private DialectDatabaseStatisticsCollector collector;
+    
+    @BeforeEach
+    void setUp() throws SQLException {
+        Properties props = PropertiesBuilder.build(new 
Property(TemporaryConfigurationPropertyKey.PROXY_META_DATA_COLLECTOR_ENABLED.getKey(),
 Boolean.TRUE.toString()));
+        when(metaData.getTemporaryProps()).thenReturn(new 
TemporaryConfigurationProperties(props));
+        
when(contextManager.getMetaDataContexts().getMetaData()).thenReturn(metaData);
+        
when(metaData.getAllDatabases()).thenReturn(Collections.singleton(database));
+        when(database.getName()).thenReturn("foo_db");
+        when(database.getProtocolType()).thenReturn(databaseType);
+        
when(database.getAllSchemas()).thenReturn(Collections.singleton(schema));
+        when(schema.getName()).thenReturn("public");
+        
when(DatabaseTypedSPILoader.findService(DialectDatabaseStatisticsCollector.class,
 databaseType)).thenReturn(Optional.of(collector));
+        ExclusiveOperatorEngine exclusiveOperatorEngine = 
contextManager.getExclusiveOperatorEngine();
+        doAnswer(invocation -> {
+            
invocation.<ExclusiveOperationVoidCallback>getArgument(2).execute();
+            return null;
+        
}).when(exclusiveOperatorEngine).operate(any(RefreshStatisticsOperation.class), 
eq(5000L), any(ExclusiveOperationVoidCallback.class));
+    }
+    
+    @Test
+    void assertRefreshWithDatabaseRemovedAfterEnumeration() {
+        ShardingSphereTable table = new ShardingSphereTable("foo_table", 
Collections.emptyList(), Collections.emptyList(), Collections.emptyList());
+        when(schema.getAllTables()).thenReturn(Collections.singleton(table));
+        new StatisticsRefreshEngine(contextManager).refresh();
+        verify(collector).collectRowColumnValues("foo_db", "public", 
"foo_table", metaData);
+        verify(contextManager, never()).getPersistServiceFacade();
+    }
+    
+    @Test
+    void assertRefreshContinuesAfterCollectionFailure() {
+        ShardingSphereTable firstTable = new 
ShardingSphereTable("first_table", Collections.emptyList(), 
Collections.emptyList(), Collections.emptyList());
+        ShardingSphereTable secondTable = new 
ShardingSphereTable("second_table", Collections.emptyList(), 
Collections.emptyList(), Collections.emptyList());
+        when(schema.getAllTables()).thenReturn(Arrays.asList(firstTable, 
secondTable));
+        when(collector.collectRowColumnValues("foo_db", "public", 
"first_table", metaData)).thenThrow(new IllegalStateException("Collection 
failed."));
+        new StatisticsRefreshEngine(contextManager).refresh();
+        verify(collector).collectRowColumnValues("foo_db", "public", 
"first_table", metaData);
+        verify(collector).collectRowColumnValues("foo_db", "public", 
"second_table", metaData);
+        verify(contextManager, never()).getPersistServiceFacade();
+    }
+}
diff --git 
a/proxy/backend/core/src/main/java/org/apache/shardingsphere/proxy/backend/connector/jdbc/executor/ProxyJDBCExecutor.java
 
b/proxy/backend/core/src/main/java/org/apache/shardingsphere/proxy/backend/connector/jdbc/executor/ProxyJDBCExecutor.java
index 2ba716b4ade..6f4042f3c90 100644
--- 
a/proxy/backend/core/src/main/java/org/apache/shardingsphere/proxy/backend/connector/jdbc/executor/ProxyJDBCExecutor.java
+++ 
b/proxy/backend/core/src/main/java/org/apache/shardingsphere/proxy/backend/connector/jdbc/executor/ProxyJDBCExecutor.java
@@ -28,7 +28,6 @@ import 
org.apache.shardingsphere.infra.executor.sql.prepare.driver.jdbc.JDBCDriv
 import org.apache.shardingsphere.infra.executor.sql.process.ProcessEngine;
 import 
org.apache.shardingsphere.infra.metadata.database.ShardingSphereDatabase;
 import org.apache.shardingsphere.infra.session.query.QueryContext;
-import org.apache.shardingsphere.mode.metadata.MetaDataContexts;
 import 
org.apache.shardingsphere.proxy.backend.connector.DatabaseProxyConnector;
 import 
org.apache.shardingsphere.proxy.backend.connector.jdbc.executor.callback.ProxyJDBCExecutorCallbackFactory;
 import org.apache.shardingsphere.proxy.backend.context.ProxyContext;
@@ -66,8 +65,7 @@ public final class ProxyJDBCExecutor {
     public List<ExecuteResult> execute(final QueryContext queryContext, final 
ExecutionGroupContext<JDBCExecutionUnit> executionGroupContext,
                                        final boolean isReturnGeneratedKeys, 
final boolean isExceptionThrown) throws SQLException {
         try {
-            MetaDataContexts metaDataContexts = 
ProxyContext.getInstance().getContextManager().getMetaDataContexts();
-            ShardingSphereDatabase database = 
metaDataContexts.getMetaData().getDatabase(connectionSession.getUsedDatabaseName());
+            ShardingSphereDatabase database = 
ProxyContext.getInstance().getContextManager().getDatabase(connectionSession.getUsedDatabaseName());
             DatabaseType protocolType = database.getProtocolType();
             processEngine.executeSQL(executionGroupContext, queryContext);
             SQLStatementContext context = 
queryContext.getSqlStatementContext();
diff --git 
a/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/connector/jdbc/executor/ProxyJDBCExecutorTest.java
 
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/connector/jdbc/executor/ProxyJDBCExecutorTest.java
index 79e1a2171eb..0873c4f3b76 100644
--- 
a/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/connector/jdbc/executor/ProxyJDBCExecutorTest.java
+++ 
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/connector/jdbc/executor/ProxyJDBCExecutorTest.java
@@ -18,6 +18,7 @@
 package org.apache.shardingsphere.proxy.backend.connector.jdbc.executor;
 
 import org.apache.shardingsphere.database.connector.core.type.DatabaseType;
+import 
org.apache.shardingsphere.database.exception.core.exception.syntax.database.UnknownDatabaseException;
 import 
org.apache.shardingsphere.infra.binder.context.statement.SQLStatementContext;
 import 
org.apache.shardingsphere.infra.executor.kernel.model.ExecutionGroupContext;
 import 
org.apache.shardingsphere.infra.executor.kernel.model.ExecutionGroupReportContext;
@@ -25,6 +26,7 @@ import 
org.apache.shardingsphere.infra.executor.sql.execute.engine.driver.jdbc.J
 import 
org.apache.shardingsphere.infra.executor.sql.execute.engine.driver.jdbc.JDBCExecutor;
 import 
org.apache.shardingsphere.infra.executor.sql.execute.result.ExecuteResult;
 import 
org.apache.shardingsphere.infra.executor.sql.prepare.driver.jdbc.JDBCDriverType;
+import org.apache.shardingsphere.infra.executor.sql.process.ProcessEngine;
 import org.apache.shardingsphere.infra.executor.sql.process.ProcessRegistry;
 import 
org.apache.shardingsphere.infra.metadata.database.resource.ResourceMetaData;
 import org.apache.shardingsphere.infra.session.query.QueryContext;
@@ -45,9 +47,15 @@ import java.util.List;
 
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.sameInstance;
+import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.mockStatic;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoInteractions;
 import static org.mockito.Mockito.when;
 
 class ProxyJDBCExecutorTest {
@@ -75,8 +83,8 @@ class ProxyJDBCExecutorTest {
             ProxyJDBCExecutorCallback secondCallback = 
mock(ProxyJDBCExecutorCallback.class);
             List<ExecuteResult> expected = 
Collections.singletonList(mock(ExecuteResult.class));
             try (MockedStatic<ProxyJDBCExecutorCallbackFactory> mockedStatic = 
mockStatic(ProxyJDBCExecutorCallbackFactory.class)) {
-                ResourceMetaData resourceMetaData = 
contextManager.getMetaDataContexts().getMetaData().getDatabase("logic_db").getResourceMetaData();
-                DatabaseType protocolType = 
contextManager.getMetaDataContexts().getMetaData().getDatabase("logic_db").getProtocolType();
+                ResourceMetaData resourceMetaData = 
contextManager.getDatabase("logic_db").getResourceMetaData();
+                DatabaseType protocolType = 
contextManager.getDatabase("logic_db").getProtocolType();
                 mockedStatic.when(() -> 
ProxyJDBCExecutorCallbackFactory.newInstance(type, protocolType, 
resourceMetaData, sqlStatement, databaseProxyConnector, true, false, true))
                         .thenReturn(firstCallback);
                 mockedStatic.when(() -> 
ProxyJDBCExecutorCallbackFactory.newInstance(type, protocolType, 
resourceMetaData, sqlStatement, databaseProxyConnector, true, false, false))
@@ -92,6 +100,52 @@ class ProxyJDBCExecutorTest {
         }
     }
     
+    @Test
+    void assertExecuteWithUnknownDatabase() throws 
ReflectiveOperationException {
+        Object originalContextManager = 
Plugins.getMemberAccessor().get(ProxyContext.class.getDeclaredField("contextManager"),
 ProxyContext.getInstance());
+        ContextManager contextManager = mock(ContextManager.class);
+        try {
+            ProxyContext.init(contextManager);
+            UnknownDatabaseException expected = new 
UnknownDatabaseException("foo_db");
+            when(contextManager.getDatabase("foo_db")).thenThrow(expected);
+            ConnectionSession connectionSession = 
mock(ConnectionSession.class);
+            when(connectionSession.getUsedDatabaseName()).thenReturn("foo_db");
+            JDBCExecutor jdbcExecutor = mock(JDBCExecutor.class);
+            ProxyJDBCExecutor executor = new 
ProxyJDBCExecutor(JDBCDriverType.STATEMENT, connectionSession, 
mock(DatabaseProxyConnector.class), jdbcExecutor);
+            ProcessEngine processEngine = mock(ProcessEngine.class);
+            
Plugins.getMemberAccessor().set(ProxyJDBCExecutor.class.getDeclaredField("processEngine"),
 executor, processEngine);
+            ExecutionGroupContext<JDBCExecutionUnit> executionGroupContext = 
new ExecutionGroupContext<>(Collections.emptyList(), new 
ExecutionGroupReportContext("foo_pid", "foo_db"));
+            assertThat(assertThrows(UnknownDatabaseException.class, () -> 
executor.execute(mock(QueryContext.class), executionGroupContext, false, 
true)), sameInstance(expected));
+            verify(processEngine).completeSQLExecution("foo_pid");
+            verifyNoInteractions(jdbcExecutor);
+        } finally {
+            
Plugins.getMemberAccessor().set(ProxyContext.class.getDeclaredField("contextManager"),
 ProxyContext.getInstance(), originalContextManager);
+        }
+    }
+    
+    @Test
+    void assertExecuteWithSQLException() throws SQLException, 
ReflectiveOperationException {
+        Object originalContextManager = 
Plugins.getMemberAccessor().get(ProxyContext.class.getDeclaredField("contextManager"),
 ProxyContext.getInstance());
+        ContextManager contextManager = mock(ContextManager.class, 
RETURNS_DEEP_STUBS);
+        try {
+            ProxyContext.init(contextManager);
+            ConnectionSession connectionSession = 
mock(ConnectionSession.class);
+            when(connectionSession.getUsedDatabaseName()).thenReturn("foo_db");
+            JDBCExecutor jdbcExecutor = mock(JDBCExecutor.class);
+            ProxyJDBCExecutor executor = new 
ProxyJDBCExecutor(JDBCDriverType.STATEMENT, connectionSession, 
mock(DatabaseProxyConnector.class), jdbcExecutor);
+            ProcessEngine processEngine = mock(ProcessEngine.class);
+            
Plugins.getMemberAccessor().set(ProxyJDBCExecutor.class.getDeclaredField("processEngine"),
 executor, processEngine);
+            ExecutionGroupContext<JDBCExecutionUnit> executionGroupContext = 
new ExecutionGroupContext<>(Collections.emptyList(), new 
ExecutionGroupReportContext("foo_pid", "foo_db"));
+            SQLException expected = new SQLException("foo execution failure");
+            when(jdbcExecutor.execute(eq(executionGroupContext), any(), 
any())).thenThrow(expected);
+            QueryContext queryContext = 
mockQueryContext(mock(SQLStatement.class));
+            assertThat(assertThrows(SQLException.class, () -> 
executor.execute(queryContext, executionGroupContext, false, true)), 
sameInstance(expected));
+            verify(processEngine).completeSQLExecution("foo_pid");
+        } finally {
+            
Plugins.getMemberAccessor().set(ProxyContext.class.getDeclaredField("contextManager"),
 ProxyContext.getInstance(), originalContextManager);
+        }
+    }
+    
     private QueryContext mockQueryContext(final SQLStatement sqlStatement) {
         QueryContext result = mock(QueryContext.class);
         when(result.getSql()).thenReturn("SELECT 1");
diff --git 
a/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/distsql/DistSQLUpdateProxyBackendHandlerTest.java
 
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/distsql/DistSQLUpdateProxyBackendHandlerTest.java
index c097e70499b..d255b05ffa3 100644
--- 
a/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/distsql/DistSQLUpdateProxyBackendHandlerTest.java
+++ 
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/distsql/DistSQLUpdateProxyBackendHandlerTest.java
@@ -122,7 +122,6 @@ class DistSQLUpdateProxyBackendHandlerTest {
         
when(resourceMetaData.getStorageUnits()).thenReturn(Collections.singletonMap("ds_0",
 mock(StorageUnit.class)));
         ShardingSphereSchema schema = mock(ShardingSphereSchema.class);
         ShardingSphereDatabase database = mock(ShardingSphereDatabase.class);
-        when(database.containsSchema(new 
IdentifierValue("foo_db"))).thenReturn(true);
         when(database.getSchema(new 
IdentifierValue("foo_db"))).thenReturn(schema);
         when(database.getResourceMetaData()).thenReturn(resourceMetaData);
         when(contextManager.getDatabase("foo_db")).thenReturn(database);
@@ -136,7 +135,8 @@ class DistSQLUpdateProxyBackendHandlerTest {
         ResourceMetaData resourceMetaData = mock(ResourceMetaData.class);
         
when(resourceMetaData.getStorageUnits()).thenReturn(Collections.singletonMap("ds_0",
 mock(StorageUnit.class)));
         ShardingSphereDatabase database = mock(ShardingSphereDatabase.class);
-        
when(database.containsSchema(any(IdentifierValue.class))).thenReturn(true);
+        when(database.getDefaultSchemaName()).thenReturn("foo_schema");
+        when(database.getSchema(new 
IdentifierValue("foo_schema"))).thenReturn(mock(ShardingSphereSchema.class));
         when(database.getResourceMetaData()).thenReturn(resourceMetaData);
         when(contextManager.getDatabase("foo_db")).thenReturn(database);
         RefreshTableMetaDataStatement sqlStatement = new 
RefreshTableMetaDataStatement();
diff --git 
a/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/distsql/ral/queryable/export/ExportStorageNodesExecutorTest.java
 
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/distsql/ral/queryable/export/ExportStorageNodesExecutorTest.java
index 995097837fa..b845dd8cee8 100644
--- 
a/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/distsql/ral/queryable/export/ExportStorageNodesExecutorTest.java
+++ 
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/distsql/ral/queryable/export/ExportStorageNodesExecutorTest.java
@@ -108,7 +108,8 @@ class ExportStorageNodesExecutorTest {
     
     @Test
     void assertExecuteWithWrongDatabaseName() {
-        assertThrows(IllegalArgumentException.class, () -> 
executor.getRows(new ExportStorageNodesStatement("foo", null), 
mockEmptyContextManager()));
+        IllegalArgumentException actual = 
assertThrows(IllegalArgumentException.class, () -> executor.getRows(new 
ExportStorageNodesStatement("foo", null), mockEmptyContextManager()));
+        assertThat(actual.getMessage(), is("database foo is not existed"));
     }
     
     @Test
@@ -146,6 +147,16 @@ class ExportStorageNodesExecutorTest {
         assertThat(row.getCell(3), is(loadExpectedRow()));
     }
     
+    @Test
+    void assertExecuteWhenDatabaseDropped() {
+        prepareNormalDatabase();
+        ContextManager contextManager = mock(ContextManager.class, 
RETURNS_DEEP_STUBS);
+        
when(contextManager.getMetaDataContexts().getMetaData().getDatabase("normal_db")).thenReturn(database,
 null);
+        Collection<LocalDataQueryResultRow> actual = executor.getRows(new 
ExportStorageNodesStatement("normal_db", null), contextManager);
+        assertThat(actual.size(), is(1));
+        assertThat(actual.iterator().next().getCell(3), is(loadExpectedRow()));
+    }
+    
     @Test
     void assertExecuteWithFilePath() throws IOException {
         prepareNormalDatabase();
diff --git 
a/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/distsql/ral/updatable/refresh/RefreshTableMetaDataExecutorTest.java
 
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/distsql/ral/updatable/refresh/RefreshTableMetaDataExecutorTest.java
index f823d96c687..d8e062848d5 100644
--- 
a/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/distsql/ral/updatable/refresh/RefreshTableMetaDataExecutorTest.java
+++ 
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/distsql/ral/updatable/refresh/RefreshTableMetaDataExecutorTest.java
@@ -37,7 +37,6 @@ import java.util.Collections;
 
 import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
@@ -96,6 +95,19 @@ class RefreshTableMetaDataExecutorTest {
         verify(contextManager).reloadDatabase(database);
     }
     
+    @Test
+    void assertExecuteUpdateWhenSchemaDropped() {
+        ShardingSphereDatabase database = mockDatabase(true);
+        ShardingSphereSchema schema = mock(ShardingSphereSchema.class);
+        when(schema.getName()).thenReturn("Foo_Schema");
+        when(schema.containsTable(new 
IdentifierValue("foo_table"))).thenReturn(true);
+        when(database.getSchema(new 
IdentifierValue("foo_schema"))).thenReturn(schema, null);
+        ContextManager contextManager = mock(ContextManager.class);
+        executor.setDatabase(database);
+        executor.executeUpdate(new RefreshTableMetaDataStatement(new 
IdentifierValue("foo_table"), null, new IdentifierValue("foo_schema")), 
contextManager);
+        verify(contextManager).reloadTable(database, "Foo_Schema", new 
IdentifierValue("foo_table"));
+    }
+    
     @Test
     void assertExecuteUpdateWithEmptyStorageUnits() {
         ShardingSphereDatabase database = mock(ShardingSphereDatabase.class);
@@ -139,8 +151,7 @@ class RefreshTableMetaDataExecutorTest {
         ShardingSphereDatabase result = mock(ShardingSphereDatabase.class, 
RETURNS_DEEP_STUBS);
         when(result.getName()).thenReturn("logic_db");
         
when(result.getResourceMetaData().getStorageUnits()).thenReturn(Collections.singletonMap("ds_0",
 mock(StorageUnit.class)));
-        when(result.containsSchema(anyString())).thenReturn(schemaExists);
-        
when(result.containsSchema(any(IdentifierValue.class))).thenReturn(schemaExists);
+        
when(result.getSchema(any(IdentifierValue.class))).thenReturn(schemaExists ? 
mock(ShardingSphereSchema.class) : null);
         return result;
     }
 }
diff --git 
a/proxy/frontend/dialect/firebird/src/main/java/org/apache/shardingsphere/proxy/frontend/firebird/command/query/statement/prepare/FirebirdPrepareStatementCommandExecutor.java
 
b/proxy/frontend/dialect/firebird/src/main/java/org/apache/shardingsphere/proxy/frontend/firebird/command/query/statement/prepare/FirebirdPrepareStatementCommandExecutor.java
index 443c9494b02..3468a5dc376 100644
--- 
a/proxy/frontend/dialect/firebird/src/main/java/org/apache/shardingsphere/proxy/frontend/firebird/command/query/statement/prepare/FirebirdPrepareStatementCommandExecutor.java
+++ 
b/proxy/frontend/dialect/firebird/src/main/java/org/apache/shardingsphere/proxy/frontend/firebird/command/query/statement/prepare/FirebirdPrepareStatementCommandExecutor.java
@@ -17,6 +17,7 @@
 
 package 
org.apache.shardingsphere.proxy.frontend.firebird.command.query.statement.prepare;
 
+import com.google.common.base.Suppliers;
 import lombok.RequiredArgsConstructor;
 import org.apache.shardingsphere.database.connector.core.type.DatabaseType;
 import 
org.apache.shardingsphere.database.connector.firebird.metadata.data.FirebirdBlobInfoRegistry;
@@ -48,6 +49,7 @@ import 
org.apache.shardingsphere.infra.binder.context.statement.type.dml.SelectS
 import 
org.apache.shardingsphere.infra.binder.context.statement.type.dml.UpdateStatementContext;
 import org.apache.shardingsphere.infra.binder.engine.SQLBindEngine;
 import org.apache.shardingsphere.infra.exception.ShardingSpherePreconditions;
+import 
org.apache.shardingsphere.infra.exception.kernel.metadata.TableNotFoundException;
 import 
org.apache.shardingsphere.infra.metadata.database.ShardingSphereDatabase;
 import 
org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereColumn;
 import 
org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereSchema;
@@ -100,6 +102,7 @@ import java.util.Locale;
 import java.util.Map;
 import java.util.Optional;
 import java.util.OptionalInt;
+import java.util.function.Supplier;
 
 /**
  * Firebird prepare transaction command executor.
@@ -129,7 +132,7 @@ public final class FirebirdPrepareStatementCommandExecutor 
implements CommandExe
         }
         FirebirdServerPreparedStatement serverPreparedStatement = new 
FirebirdServerPreparedStatement(packet.getSQL(), sqlStatementContext, 
packet.getHintValueContext());
         
connectionSession.getServerPreparedStatementRegistry().addPreparedStatement(statementId,
 serverPreparedStatement);
-        return createResponse(sqlStatementContext, metaDataContexts);
+        return createResponse(sqlStatementContext);
     }
     
     private SQLStatement resolveCurrentDatabase(final SQLStatement 
sqlStatement) {
@@ -145,7 +148,7 @@ public final class FirebirdPrepareStatementCommandExecutor 
implements CommandExe
         return packet.isValidStatementHandle() ? packet.getStatementId() : 
FirebirdStatementIdGenerator.getInstance().getStatementId(connectionSession.getConnectionId());
     }
     
-    private Collection<DatabasePacket> createResponse(final 
SQLStatementContext sqlStatementContext, final MetaDataContexts 
metaDataContexts) {
+    private Collection<DatabasePacket> createResponse(final 
SQLStatementContext sqlStatementContext) {
         FirebirdSQLInfoReturnValue statementType = 
getFirebirdStatementType(sqlStatementContext.getSqlStatement());
         FirebirdPrepareStatementReturnPacket returnPacket = new 
FirebirdPrepareStatementReturnPacket();
         while (packet.nextItem()) {
@@ -155,14 +158,14 @@ public final class 
FirebirdPrepareStatementCommandExecutor implements CommandExe
                     break;
                 case SELECT:
                     if (statementType.isSelectDescribable()) {
-                        processDescribe(sqlStatementContext, metaDataContexts, 
returnPacket.getDescribeSelect(), true);
+                        processDescribe(sqlStatementContext, 
returnPacket.getDescribeSelect(), true);
                     } else {
                         skipDescribe();
                     }
                     break;
                 case BIND:
                     if (statementType.isBindDescribable()) {
-                        processDescribe(sqlStatementContext, metaDataContexts, 
returnPacket.getDescribeBind(), false);
+                        processDescribe(sqlStatementContext, 
returnPacket.getDescribeBind(), false);
                     } else {
                         skipDescribe();
                     }
@@ -223,39 +226,34 @@ public final class 
FirebirdPrepareStatementCommandExecutor implements CommandExe
         }
     }
     
-    private void processDescribe(final SQLStatementContext 
sqlStatementContext, final MetaDataContexts metaDataContexts, final 
Collection<FirebirdReturnColumnPacket> describeColumns,
-                                 final boolean returnAll) {
+    private void processDescribe(final SQLStatementContext 
sqlStatementContext, final Collection<FirebirdReturnColumnPacket> 
describeColumns, final boolean returnAll) {
         // TODO add exception if the first item is not DESCRIBE_VARS
         packet.nextItem();
         Collection<FirebirdSQLInfoPacketType> requestedItems = new 
LinkedList<>();
         while (packet.nextItem()) {
             requestedItems.add(packet.getCurrentItem());
             if (packet.getCurrentItem() == 
FirebirdSQLInfoPacketType.DESCRIBE_END) {
+                Supplier<ShardingSphereDatabase> database = 
Suppliers.memoize(() -> 
ProxyContext.getInstance().getContextManager().getDatabase(connectionSession.getCurrentDatabaseName()));
+                Supplier<Optional<ShardingSphereSchema>> schema = 
Suppliers.memoize(() -> database.get().findDefaultSchema());
                 if (returnAll) {
-                    processReturnValues(sqlStatementContext, metaDataContexts, 
describeColumns, requestedItems);
+                    processReturnValues(sqlStatementContext, database, schema, 
describeColumns, requestedItems);
                 } else {
-                    processParameters(sqlStatementContext, metaDataContexts, 
describeColumns, requestedItems);
+                    processParameters(sqlStatementContext, database, schema, 
describeColumns, requestedItems);
                 }
                 return;
             }
         }
     }
     
-    private void processReturnValues(final SQLStatementContext 
sqlStatementContext, final MetaDataContexts metaDataContexts, final 
Collection<FirebirdReturnColumnPacket> describeColumns,
+    private void processReturnValues(final SQLStatementContext 
sqlStatementContext, final Supplier<ShardingSphereDatabase> database,
+                                     final 
Supplier<Optional<ShardingSphereSchema>> schema, final 
Collection<FirebirdReturnColumnPacket> describeColumns,
                                      final 
Collection<FirebirdSQLInfoPacketType> requestedItems) {
-        String databaseName = connectionSession.getCurrentDatabaseName();
-        ShardingSphereDatabase database = 
metaDataContexts.getMetaData().getDatabase(databaseName);
-        ShardingSphereSchema schema = 
database.findDefaultSchema().orElse(null);
-        Collection<Projection> projections = 
getProjections(sqlStatementContext, schema);
+        Collection<Projection> projections = 
getProjections(sqlStatementContext, database, schema);
         int columnCount = 0;
         for (Projection each : projections) {
             if (each instanceof ColumnProjection) {
                 String tableName = ((ColumnProjection) 
each).getOriginalTable().getValue();
-                ShardingSphereTable table = 
schema.getTable(tableName.isEmpty() ? 
getTableNames(sqlStatementContext).iterator().next() : tableName);
-                if (null == table) {
-                    table = 
metaDataContexts.getMetaData().getDatabase(databaseName).getSchema("system_tables")
-                            .getTable(tableName.isEmpty() ? 
getTableNames(sqlStatementContext).iterator().next() : tableName);
-                }
+                ShardingSphereTable table = getTable(tableName.isEmpty() ? 
getTableNames(sqlStatementContext).iterator().next() : tableName, database, 
schema);
                 ShardingSphereColumn column = 
table.getColumn(((ColumnProjection) each).getOriginalColumn().getValue());
                 processColumn(describeColumns, requestedItems, table, column, 
((ColumnProjection) each).getOwner().orElse(null), 
each.getAlias().orElse(null), ++columnCount);
             } else if (each instanceof ExpressionProjection) {
@@ -270,7 +268,8 @@ public final class FirebirdPrepareStatementCommandExecutor 
implements CommandExe
         }
     }
     
-    private Collection<Projection> getProjections(final SQLStatementContext 
sqlStatementContext, final ShardingSphereSchema schema) {
+    private Collection<Projection> getProjections(final SQLStatementContext 
sqlStatementContext, final Supplier<ShardingSphereDatabase> database,
+                                                  final 
Supplier<Optional<ShardingSphereSchema>> schema) {
         if (sqlStatementContext instanceof SelectStatementContext) {
             SelectStatementContext selectStatement = (SelectStatementContext) 
sqlStatementContext;
             Collection<Projection> expandProjections = 
selectStatement.getProjectionsContext().getExpandProjections();
@@ -298,7 +297,7 @@ public final class FirebirdPrepareStatementCommandExecutor 
implements CommandExe
         for (ProjectionSegment each : projections) {
             Projection projection = 
projectionEngine.createProjection(each).orElse(null);
             if (projection instanceof ShorthandProjection) {
-                result.addAll(processShorthandProjection(sqlStatementContext, 
schema, (ShorthandProjection) projection));
+                result.addAll(processShorthandProjection(sqlStatementContext, 
database, schema, (ShorthandProjection) projection));
             } else if (!(projection instanceof DerivedProjection) && null != 
projection) {
                 result.add(projection);
             }
@@ -306,7 +305,8 @@ public final class FirebirdPrepareStatementCommandExecutor 
implements CommandExe
         return result;
     }
     
-    private Collection<Projection> processShorthandProjection(final 
SQLStatementContext sqlStatementContext, final ShardingSphereSchema schema, 
final ShorthandProjection projection) {
+    private Collection<Projection> processShorthandProjection(final 
SQLStatementContext sqlStatementContext, final Supplier<ShardingSphereDatabase> 
database,
+                                                              final 
Supplier<Optional<ShardingSphereSchema>> schema, final ShorthandProjection 
projection) {
         if (!projection.getActualColumns().isEmpty()) {
             return projection.getActualColumns();
         }
@@ -314,7 +314,7 @@ public final class FirebirdPrepareStatementCommandExecutor 
implements CommandExe
         TablesContext tablesContext = sqlStatementContext.getTablesContext();
         if (null != tablesContext) {
             for (String tableName : tablesContext.getTableNames()) {
-                ShardingSphereTable table = schema.getTable(tableName);
+                ShardingSphereTable table = getTable(tableName, database, 
schema);
                 table.getAllColumns().forEach(each -> {
                     ColumnSegmentBoundInfo info = new 
ColumnSegmentBoundInfo(null, new IdentifierValue(table.getName()), new 
IdentifierValue(each.getName()), TableSourceType.PHYSICAL_TABLE);
                     result.add(new ColumnProjection(null, new 
IdentifierValue(each.getName()), null, 
sqlStatementContext.getSqlStatement().getDatabaseType(), null, null, info));
@@ -324,19 +324,28 @@ public final class 
FirebirdPrepareStatementCommandExecutor implements CommandExe
         return result;
     }
     
-    private void processParameters(final SQLStatementContext 
sqlStatementContext, final MetaDataContexts metaDataContexts, final 
Collection<FirebirdReturnColumnPacket> describeColumns,
+    @HighFrequencyInvocation
+    private ShardingSphereTable getTable(final String tableName, final 
Supplier<ShardingSphereDatabase> database, final 
Supplier<Optional<ShardingSphereSchema>> schema) {
+        ShardingSphereTable result = schema.get().map(optional -> 
optional.getTable(tableName)).orElse(null);
+        if (null == result) {
+            result = 
database.get().getSchema("system_tables").getTable(tableName);
+        }
+        ShardingSpherePreconditions.checkNotNull(result, () -> new 
TableNotFoundException(tableName));
+        return result;
+    }
+    
+    private void processParameters(final SQLStatementContext 
sqlStatementContext, final Supplier<ShardingSphereDatabase> database,
+                                   final 
Supplier<Optional<ShardingSphereSchema>> schema, final 
Collection<FirebirdReturnColumnPacket> describeColumns,
                                    final Collection<FirebirdSQLInfoPacketType> 
requestedItems) {
         if (sqlStatementContext instanceof InsertStatementContext) {
-            processInsertStatement((InsertStatementContext) 
sqlStatementContext, metaDataContexts, describeColumns, requestedItems);
+            processInsertStatement((InsertStatementContext) 
sqlStatementContext, database, schema, describeColumns, requestedItems);
             return;
         }
         Collection<ColumnSegment> affectedColumns = 
findAffectedColumns(sqlStatementContext);
         int parametersCount = 
sqlStatementContext.getSqlStatement().getParameterMarkers().size();
-        String databaseName = connectionSession.getCurrentDatabaseName();
-        ShardingSphereSchema schema = 
metaDataContexts.getMetaData().getDatabase(databaseName).findDefaultSchema().orElse(null);
         int columnCount = 0;
         for (ColumnSegment columnSegment : affectedColumns) {
-            ShardingSphereTable table = 
schema.getTable(columnSegment.getColumnBoundInfo().getOriginalTable().getValue());
+            ShardingSphereTable table = 
getTable(columnSegment.getColumnBoundInfo().getOriginalTable().getValue(), 
database, schema);
             ShardingSphereColumn column = 
table.getColumn(columnSegment.getColumnBoundInfo().getOriginalColumn().getValue());
             processColumn(describeColumns, requestedItems, table, column, 
columnSegment.getOwner().map(OwnerSegment::getIdentifier).orElse(null), 
columnSegment.getIdentifier(), ++columnCount);
         }
@@ -345,18 +354,17 @@ public final class 
FirebirdPrepareStatementCommandExecutor implements CommandExe
         }
     }
     
-    private void processInsertStatement(final InsertStatementContext 
sqlStatementContext, final MetaDataContexts metaDataContexts, final 
Collection<FirebirdReturnColumnPacket> describeColumns,
+    private void processInsertStatement(final InsertStatementContext 
sqlStatementContext, final Supplier<ShardingSphereDatabase> database,
+                                        final 
Supplier<Optional<ShardingSphereSchema>> schema, final 
Collection<FirebirdReturnColumnPacket> describeColumns,
                                         final 
Collection<FirebirdSQLInfoPacketType> requestedItems) {
         Collection<String> tableNames = getTableNames(sqlStatementContext);
         Collection<String> affectedColumns = new LinkedList<>();
         for (InsertValueContext context : 
sqlStatementContext.getInsertValueContexts()) {
             
affectedColumns.addAll(processInsertValueContext(sqlStatementContext, context));
         }
-        String databaseName = connectionSession.getCurrentDatabaseName();
-        ShardingSphereSchema schema = 
metaDataContexts.getMetaData().getDatabase(databaseName).findDefaultSchema().orElse(null);
         int columnCount = 0;
         for (String tableName : tableNames) {
-            ShardingSphereTable table = schema.getTable(tableName);
+            ShardingSphereTable table = getTable(tableName, database, schema);
             for (String columnName : affectedColumns) {
                 ShardingSphereColumn column = table.getColumn(columnName);
                 processColumn(describeColumns, requestedItems, table, column, 
null, null, ++columnCount);
@@ -518,7 +526,7 @@ public final class FirebirdPrepareStatementCommandExecutor 
implements CommandExe
     
     @HighFrequencyInvocation
     private String getActualTableName(final String logicTableName) {
-        ShardingSphereDatabase database = 
ProxyContext.getInstance().getContextManager().getMetaDataContexts().getMetaData().getDatabase(connectionSession.getCurrentDatabaseName());
+        ShardingSphereDatabase database = 
ProxyContext.getInstance().getContextManager().getDatabase(connectionSession.getCurrentDatabaseName());
         for (DataNodeRuleAttribute each : 
database.getRuleMetaData().getAttributes(DataNodeRuleAttribute.class)) {
             Optional<String> actualTableName = 
each.findFirstActualTable(logicTableName);
             if (actualTableName.isPresent()) {
diff --git 
a/proxy/frontend/dialect/firebird/src/test/java/org/apache/shardingsphere/proxy/frontend/firebird/command/query/statement/prepare/FirebirdPrepareStatementCommandExecutorTest.java
 
b/proxy/frontend/dialect/firebird/src/test/java/org/apache/shardingsphere/proxy/frontend/firebird/command/query/statement/prepare/FirebirdPrepareStatementCommandExecutorTest.java
index 8f3249ff0cb..dee52e8336d 100644
--- 
a/proxy/frontend/dialect/firebird/src/test/java/org/apache/shardingsphere/proxy/frontend/firebird/command/query/statement/prepare/FirebirdPrepareStatementCommandExecutorTest.java
+++ 
b/proxy/frontend/dialect/firebird/src/test/java/org/apache/shardingsphere/proxy/frontend/firebird/command/query/statement/prepare/FirebirdPrepareStatementCommandExecutorTest.java
@@ -20,6 +20,7 @@ package 
org.apache.shardingsphere.proxy.frontend.firebird.command.query.statemen
 import org.apache.shardingsphere.database.connector.core.type.DatabaseType;
 import 
org.apache.shardingsphere.database.connector.firebird.metadata.data.FirebirdBlobInfoRegistry;
 import 
org.apache.shardingsphere.database.exception.core.exception.syntax.database.NoDatabaseSelectedException;
+import 
org.apache.shardingsphere.database.exception.core.exception.syntax.database.UnknownDatabaseException;
 import 
org.apache.shardingsphere.database.protocol.firebird.packet.command.query.FirebirdBinaryColumnType;
 import 
org.apache.shardingsphere.database.protocol.firebird.packet.command.query.info.type.sql.FirebirdSQLInfoPacketType;
 import 
org.apache.shardingsphere.database.protocol.firebird.packet.command.query.info.type.sql.FirebirdSQLInfoReturnValue;
@@ -31,6 +32,7 @@ import 
org.apache.shardingsphere.database.protocol.firebird.payload.FirebirdPack
 import org.apache.shardingsphere.database.protocol.packet.DatabasePacket;
 import 
org.apache.shardingsphere.infra.binder.context.statement.type.dml.SelectStatementContext;
 import org.apache.shardingsphere.infra.config.props.ConfigurationProperties;
+import 
org.apache.shardingsphere.infra.exception.kernel.metadata.TableNotFoundException;
 import org.apache.shardingsphere.infra.hint.HintValueContext;
 import org.apache.shardingsphere.infra.metadata.ShardingSphereMetaData;
 import 
org.apache.shardingsphere.infra.metadata.database.ShardingSphereDatabase;
@@ -65,6 +67,9 @@ 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.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
 import org.mockito.Answers;
 import org.mockito.Mock;
 import org.mockito.junit.jupiter.MockitoSettings;
@@ -75,12 +80,15 @@ import java.sql.Types;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.List;
 import java.util.Optional;
 import java.util.Properties;
+import java.util.stream.Stream;
 
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.is;
 import static org.hamcrest.Matchers.isA;
+import static org.hamcrest.Matchers.sameInstance;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
 import static org.mockito.Mockito.doReturn;
@@ -131,6 +139,8 @@ class FirebirdPrepareStatementCommandExecutorTest {
         
when(packet.getCurrentItem()).thenReturn(FirebirdSQLInfoPacketType.STMT_TYPE);
         MetaDataContexts metaDataContexts = createMetaDataContexts();
         
when(ProxyContext.getInstance().getContextManager().getMetaDataContexts()).thenReturn(metaDataContexts);
+        
when(ProxyContext.getInstance().getContextManager().getDatabase("foo_db")).thenReturn(metaDataContexts.getMetaData().getDatabase("foo_db"));
+        
when(ProxyContext.getInstance().getContextManager().getDatabase(null)).thenThrow(NoDatabaseSelectedException.class);
     }
     
     @AfterEach
@@ -339,4 +349,196 @@ class FirebirdPrepareStatementCommandExecutorTest {
         executor.execute();
         
verify(connectionSession).invalidatePreparedStatementCache(FirebirdStatementResourceCleaner.createPreparedStatementCacheKey(1));
     }
+    
+    @Test
+    void assertDescribeLiteralWithoutDatabase() throws Exception {
+        when(connectionSession.getCurrentDatabaseName()).thenReturn(null);
+        mockDescribeRequest(FirebirdSQLInfoPacketType.SELECT);
+        FirebirdPrepareStatementCommandExecutor executor = new 
FirebirdPrepareStatementCommandExecutor(packet, connectionSession);
+        Collection<DatabasePacket> actual = executor.execute();
+        FirebirdPrepareStatementReturnPacket actualReturnPacket = 
(FirebirdPrepareStatementReturnPacket) ((FirebirdGenericResponsePacket) 
actual.iterator().next()).getData();
+        assertThat(actualReturnPacket.getDescribeSelect().size(), is(1));
+        FirebirdPacketPayload payload = mock(FirebirdPacketPayload.class);
+        actualReturnPacket.getDescribeSelect().get(0).write(payload);
+        verify(payload).writeInt4LE(FirebirdBinaryColumnType.LONG.getValue() + 
1);
+    }
+    
+    private void mockDescribeRequest(final FirebirdSQLInfoPacketType 
describeType) {
+        when(packet.nextItem()).thenReturn(true, true, true, true, true, 
false);
+        
when(packet.getCurrentItem()).thenReturn(FirebirdSQLInfoPacketType.STMT_TYPE, 
describeType, FirebirdSQLInfoPacketType.TYPE, FirebirdSQLInfoPacketType.TYPE,
+                FirebirdSQLInfoPacketType.DESCRIBE_END, 
FirebirdSQLInfoPacketType.DESCRIBE_END);
+    }
+    
+    @Test
+    void assertDescribeParameterWithoutDatabase() throws Exception {
+        when(connectionSession.getCurrentDatabaseName()).thenReturn(null);
+        when(packet.getSQL()).thenReturn("SELECT ?");
+        mockDescribeRequest(FirebirdSQLInfoPacketType.BIND);
+        FirebirdPrepareStatementCommandExecutor executor = new 
FirebirdPrepareStatementCommandExecutor(packet, connectionSession);
+        Collection<DatabasePacket> actual = executor.execute();
+        FirebirdPrepareStatementReturnPacket actualReturnPacket = 
(FirebirdPrepareStatementReturnPacket) ((FirebirdGenericResponsePacket) 
actual.iterator().next()).getData();
+        assertThat(actualReturnPacket.getDescribeBind().size(), is(1));
+        FirebirdPacketPayload payload = mock(FirebirdPacketPayload.class);
+        actualReturnPacket.getDescribeBind().get(0).write(payload);
+        
verify(payload).writeInt4LE(FirebirdBinaryColumnType.VARYING.getValue() + 1);
+    }
+    
+    @ParameterizedTest(name = "{0}")
+    @MethodSource("describeTableArguments")
+    void assertDescribeTable(final String name, final String sql, final 
boolean defaultSchemaPresent, final FirebirdBinaryColumnType columnType) throws 
Exception {
+        ShardingSphereDatabase database = 
ProxyContext.getInstance().getContextManager().getDatabase("foo_db");
+        addSystemSchema(database);
+        if (!defaultSchemaPresent) {
+            database.dropSchema("foo_db");
+            doReturn(Optional.empty()).when(database).findDefaultSchema();
+        }
+        when(packet.getSQL()).thenReturn(sql);
+        mockDescribeRequest(FirebirdSQLInfoPacketType.SELECT);
+        FirebirdPrepareStatementCommandExecutor executor = new 
FirebirdPrepareStatementCommandExecutor(packet, connectionSession);
+        Collection<DatabasePacket> actual = executor.execute();
+        FirebirdPrepareStatementReturnPacket actualReturnPacket = 
(FirebirdPrepareStatementReturnPacket) ((FirebirdGenericResponsePacket) 
actual.iterator().next()).getData();
+        assertThat(actualReturnPacket.getDescribeSelect().size(), is(1));
+        FirebirdPacketPayload payload = mock(FirebirdPacketPayload.class);
+        actualReturnPacket.getDescribeSelect().get(0).write(payload);
+        verify(payload).writeInt4LE(columnType.getValue() + 1);
+    }
+    
+    private void addSystemSchema(final ShardingSphereDatabase database) {
+        ShardingSphereColumn column = new 
ShardingSphereColumn("RDB$RELATION_ID", Types.SMALLINT, false, false, false, 
true, false, true);
+        ShardingSphereTable table = new ShardingSphereTable("RDB$DATABASE", 
Collections.singleton(column), Collections.emptyList(), 
Collections.emptyList());
+        database.addSchema(new ShardingSphereSchema("system_tables", 
databaseType, Collections.singleton(table), Collections.emptyList()));
+    }
+    
+    private static Stream<Arguments> describeTableArguments() {
+        return Stream.of(
+                Arguments.of("Default schema table", "SELECT id FROM foo_tbl", 
true, FirebirdBinaryColumnType.LONG),
+                Arguments.of("System table with default schema", "SELECT 
RDB$RELATION_ID FROM RDB$DATABASE", true, FirebirdBinaryColumnType.SHORT),
+                Arguments.of("System table without default schema", "SELECT 
RDB$RELATION_ID FROM RDB$DATABASE", false, FirebirdBinaryColumnType.SHORT));
+    }
+    
+    @Test
+    void assertDescribeSystemTableParameterWithoutDefaultSchema() throws 
Exception {
+        ShardingSphereDatabase database = 
ProxyContext.getInstance().getContextManager().getDatabase("foo_db");
+        addSystemSchema(database);
+        database.dropSchema("foo_db");
+        doReturn(Optional.empty()).when(database).findDefaultSchema();
+        when(packet.getSQL()).thenReturn("SELECT RDB$RELATION_ID FROM 
RDB$DATABASE WHERE RDB$RELATION_ID = ?");
+        mockDescribeRequest(FirebirdSQLInfoPacketType.BIND);
+        FirebirdPrepareStatementCommandExecutor executor = new 
FirebirdPrepareStatementCommandExecutor(packet, connectionSession);
+        Collection<DatabasePacket> actual = executor.execute();
+        FirebirdPrepareStatementReturnPacket actualReturnPacket = 
(FirebirdPrepareStatementReturnPacket) ((FirebirdGenericResponsePacket) 
actual.iterator().next()).getData();
+        assertThat(actualReturnPacket.getDescribeBind().size(), is(1));
+        FirebirdPacketPayload payload = mock(FirebirdPacketPayload.class);
+        actualReturnPacket.getDescribeBind().get(0).write(payload);
+        verify(payload).writeInt4LE(FirebirdBinaryColumnType.SHORT.getValue() 
+ 1);
+    }
+    
+    @Test
+    void assertDescribeInsertParameter() throws Exception {
+        when(packet.getSQL()).thenReturn("INSERT INTO foo_tbl (id) VALUES 
(?)");
+        mockDescribeRequest(FirebirdSQLInfoPacketType.BIND);
+        FirebirdPrepareStatementCommandExecutor executor = new 
FirebirdPrepareStatementCommandExecutor(packet, connectionSession);
+        Collection<DatabasePacket> actual = executor.execute();
+        FirebirdPrepareStatementReturnPacket actualReturnPacket = 
(FirebirdPrepareStatementReturnPacket) ((FirebirdGenericResponsePacket) 
actual.iterator().next()).getData();
+        assertThat(actualReturnPacket.getDescribeBind().size(), is(1));
+        FirebirdPacketPayload payload = mock(FirebirdPacketPayload.class);
+        actualReturnPacket.getDescribeBind().get(0).write(payload);
+        verify(payload).writeInt4LE(FirebirdBinaryColumnType.LONG.getValue() + 
1);
+    }
+    
+    @Test
+    void assertDescribeReturningShorthand() throws Exception {
+        when(packet.getSQL()).thenReturn("INSERT INTO foo_tbl (id) VALUES (1) 
RETURNING *");
+        mockDescribeRequest(FirebirdSQLInfoPacketType.SELECT);
+        FirebirdPrepareStatementCommandExecutor executor = new 
FirebirdPrepareStatementCommandExecutor(packet, connectionSession);
+        Collection<DatabasePacket> actual = executor.execute();
+        FirebirdPrepareStatementReturnPacket actualReturnPacket = 
(FirebirdPrepareStatementReturnPacket) ((FirebirdGenericResponsePacket) 
actual.iterator().next()).getData();
+        assertThat(actualReturnPacket.getDescribeSelect().size(), is(2));
+        FirebirdPacketPayload idPayload = mock(FirebirdPacketPayload.class);
+        actualReturnPacket.getDescribeSelect().get(0).write(idPayload);
+        verify(idPayload).writeInt4LE(FirebirdBinaryColumnType.LONG.getValue() 
+ 1);
+        FirebirdPacketPayload contentPayload = 
mock(FirebirdPacketPayload.class);
+        actualReturnPacket.getDescribeSelect().get(1).write(contentPayload);
+        
verify(contentPayload).writeInt4LE(FirebirdBinaryColumnType.BLOB.getValue() + 
1);
+    }
+    
+    @ParameterizedTest(name = "{0}")
+    @MethodSource("describeWithSchemaReplacementArguments")
+    void assertDescribeWithSchemaReplacement(final String name, final String 
sql, final FirebirdSQLInfoPacketType describeType) throws Exception {
+        ShardingSphereDatabase database = 
ProxyContext.getInstance().getContextManager().getMetaDataContexts().getMetaData().getDatabase("foo_db");
+        ShardingSphereColumn idColumn = new ShardingSphereColumn("id", 
Types.INTEGER, false, false, true, true, false, true);
+        ShardingSphereColumn codeColumn = new ShardingSphereColumn("code", 
Types.BIGINT, false, false, true, true, false, true);
+        ShardingSphereTable originalTable = new ShardingSphereTable("foo_tbl", 
Arrays.asList(idColumn, codeColumn), Collections.emptyList(), 
Collections.emptyList());
+        database.addSchema(new ShardingSphereSchema("foo_db", databaseType, 
Collections.singleton(originalTable), Collections.emptyList()));
+        when(database.findDefaultSchema()).thenCallRealMethod();
+        ShardingSphereTable replacementTable = new 
ShardingSphereTable("foo_tbl", Collections.singleton(idColumn), 
Collections.emptyList(), Collections.emptyList());
+        ShardingSphereSchema replacementSchema = new 
ShardingSphereSchema("foo_db", databaseType, 
Collections.singleton(replacementTable), Collections.emptyList());
+        
when(ProxyContext.getInstance().getContextManager().getDatabase("foo_db")).thenReturn(database).thenAnswer(invocation
 -> {
+            database.addSchema(replacementSchema);
+            return database;
+        }).thenReturn(database);
+        when(packet.getSQL()).thenReturn(sql);
+        when(packet.nextItem()).thenReturn(true, true, true, true, true, true, 
false);
+        
when(packet.getCurrentItem()).thenReturn(FirebirdSQLInfoPacketType.STMT_TYPE, 
describeType, FirebirdSQLInfoPacketType.TYPE, FirebirdSQLInfoPacketType.TYPE,
+                FirebirdSQLInfoPacketType.FIELD, 
FirebirdSQLInfoPacketType.FIELD, FirebirdSQLInfoPacketType.DESCRIBE_END, 
FirebirdSQLInfoPacketType.DESCRIBE_END);
+        FirebirdPrepareStatementCommandExecutor executor = new 
FirebirdPrepareStatementCommandExecutor(packet, connectionSession);
+        Collection<DatabasePacket> actual = executor.execute();
+        FirebirdPrepareStatementReturnPacket actualReturnPacket = 
(FirebirdPrepareStatementReturnPacket) ((FirebirdGenericResponsePacket) 
actual.iterator().next()).getData();
+        List<FirebirdReturnColumnPacket> actualColumns = 
FirebirdSQLInfoPacketType.BIND == describeType ? 
actualReturnPacket.getDescribeBind() : actualReturnPacket.getDescribeSelect();
+        assertThat(actualColumns.size(), is(2));
+        FirebirdPacketPayload idPayload = mock(FirebirdPacketPayload.class);
+        when(idPayload.getCharset()).thenReturn(StandardCharsets.UTF_8);
+        actualColumns.get(0).write(idPayload);
+        verify(idPayload).writeBytes("id".getBytes(StandardCharsets.UTF_8));
+        verify(idPayload).writeInt4LE(FirebirdBinaryColumnType.LONG.getValue() 
+ 1);
+        FirebirdPacketPayload codePayload = mock(FirebirdPacketPayload.class);
+        when(codePayload.getCharset()).thenReturn(StandardCharsets.UTF_8);
+        actualColumns.get(1).write(codePayload);
+        
verify(codePayload).writeBytes("code".getBytes(StandardCharsets.UTF_8));
+        
verify(codePayload).writeInt4LE(FirebirdBinaryColumnType.INT64.getValue() + 1);
+    }
+    
+    private static Stream<Arguments> describeWithSchemaReplacementArguments() {
+        return Stream.of(
+                Arguments.of("Select columns", "SELECT id, code FROM foo_tbl", 
FirebirdSQLInfoPacketType.SELECT),
+                Arguments.of("Bind parameters", "SELECT id, code FROM foo_tbl 
WHERE id = ? AND code = ?", FirebirdSQLInfoPacketType.BIND),
+                Arguments.of("Returning shorthand", "INSERT INTO foo_tbl (id, 
code) VALUES (1, 2) RETURNING *", FirebirdSQLInfoPacketType.SELECT));
+    }
+    
+    @Test
+    void assertDescribeWithDatabaseRemoved() {
+        when(packet.getSQL()).thenReturn("SELECT id FROM foo_tbl");
+        mockDescribeRequest(FirebirdSQLInfoPacketType.SELECT);
+        UnknownDatabaseException expected = new 
UnknownDatabaseException("foo_db");
+        
when(ProxyContext.getInstance().getContextManager().getDatabase("foo_db")).thenThrow(expected);
+        FirebirdPrepareStatementCommandExecutor executor = new 
FirebirdPrepareStatementCommandExecutor(packet, connectionSession);
+        assertThat(assertThrows(UnknownDatabaseException.class, 
executor::execute), sameInstance(expected));
+    }
+    
+    @Test
+    void assertDescribeBlobWithDatabaseRemoved() {
+        ShardingSphereDatabase database = 
ProxyContext.getInstance().getContextManager().getDatabase("foo_db");
+        when(packet.getSQL()).thenReturn("SELECT content FROM foo_tbl");
+        mockDescribeRequest(FirebirdSQLInfoPacketType.SELECT);
+        UnknownDatabaseException expected = new 
UnknownDatabaseException("foo_db");
+        
when(ProxyContext.getInstance().getContextManager().getDatabase("foo_db")).thenReturn(database).thenThrow(expected);
+        FirebirdPrepareStatementCommandExecutor executor = new 
FirebirdPrepareStatementCommandExecutor(packet, connectionSession);
+        assertThat(assertThrows(UnknownDatabaseException.class, 
executor::execute), sameInstance(expected));
+    }
+    
+    @Test
+    void assertDescribeWithTableRemoved() {
+        ShardingSphereDatabase database = 
ProxyContext.getInstance().getContextManager().getDatabase("foo_db");
+        addSystemSchema(database);
+        when(packet.getSQL()).thenReturn("SELECT id FROM foo_tbl");
+        mockDescribeRequest(FirebirdSQLInfoPacketType.SELECT);
+        
when(ProxyContext.getInstance().getContextManager().getDatabase("foo_db")).thenAnswer(invocation
 -> {
+            database.getSchema("foo_db").removeTable("foo_tbl");
+            return database;
+        });
+        FirebirdPrepareStatementCommandExecutor executor = new 
FirebirdPrepareStatementCommandExecutor(packet, connectionSession);
+        TableNotFoundException actual = 
assertThrows(TableNotFoundException.class, executor::execute);
+        assertThat(actual.getMessage(), is("Table or view 'foo_tbl' does not 
exist."));
+    }
+    
 }

Reply via email to