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

menghaoranss 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 dad38461489 Unify identifier normalization with policy-based engine 
(#39168)
dad38461489 is described below

commit dad38461489d1def0d4ff5183e5f37b2a9b6c6b2
Author: Haoran Meng <[email protected]>
AuthorDate: Fri Jul 17 17:44:22 2026 +0800

    Unify identifier normalization with policy-based engine (#39168)
    
    * Unify identifier normalization with policy-based engine
    
    * Add Firebird identifier case policy provider
    
    * Add Apache license header to IdentifierCasePolicyProvider file
---
 .../core/metadata/data/loader/MetaDataLoader.java  |  2 +-
 .../data/loader/MetaDataLoaderMaterial.java        | 19 ++++++
 .../data/loader/type/TableMetaDataLoader.java      | 21 ++++++-
 .../identifier/IdentifierNormalizeEngine.java      | 67 ++++++++++++++++++++++
 .../metadata/data/loader/MetaDataLoaderTest.java   |  9 +++
 .../identifier/IdentifierNormalizeEngineTest.java  | 55 ++++++++++++++++++
 .../data/loader/FirebirdBlobColumnLoader.java      |  5 +-
 .../data/loader/FirebirdMetaDataLoader.java        |  2 +-
 .../FirebirdNonFixedLengthColumnSizeLoader.java    |  5 +-
 .../FirebirdIdentifierCasePolicyProvider.java      | 46 +++++++++++++++
 ...etadata.identifier.IdentifierCasePolicyProvider | 18 ++++++
 .../data/loader/FirebirdMetaDataLoaderTest.java    |  5 +-
 .../FirebirdIdentifierCasePolicyProviderTest.java  | 58 +++++++++++++++++++
 .../metadata/data/loader/HiveMetaDataLoader.java   |  2 +-
 .../data/loader/HiveMetaDataLoaderTest.java        |  7 ++-
 15 files changed, 307 insertions(+), 14 deletions(-)

diff --git 
a/database/connector/core/src/main/java/org/apache/shardingsphere/database/connector/core/metadata/data/loader/MetaDataLoader.java
 
b/database/connector/core/src/main/java/org/apache/shardingsphere/database/connector/core/metadata/data/loader/MetaDataLoader.java
index 89a06490ebe..fe62e92816e 100644
--- 
a/database/connector/core/src/main/java/org/apache/shardingsphere/database/connector/core/metadata/data/loader/MetaDataLoader.java
+++ 
b/database/connector/core/src/main/java/org/apache/shardingsphere/database/connector/core/metadata/data/loader/MetaDataLoader.java
@@ -95,7 +95,7 @@ public final class MetaDataLoader {
     private static Collection<SchemaMetaData> loadByDefault(final 
MetaDataLoaderMaterial material) throws SQLException {
         Collection<TableMetaData> tableMetaData = new LinkedList<>();
         for (String each : material.getActualTableNames()) {
-            TableMetaDataLoader.load(material.getDataSource(), each, 
material.getStorageType()).ifPresent(tableMetaData::add);
+            TableMetaDataLoader.load(material.getDataSource(), each, 
material.getStorageType(), 
material.getTableIdentifierPolicy()).ifPresent(tableMetaData::add);
         }
         return Collections.singleton(new 
SchemaMetaData(material.getDefaultSchemaName(), tableMetaData));
     }
diff --git 
a/database/connector/core/src/main/java/org/apache/shardingsphere/database/connector/core/metadata/data/loader/MetaDataLoaderMaterial.java
 
b/database/connector/core/src/main/java/org/apache/shardingsphere/database/connector/core/metadata/data/loader/MetaDataLoaderMaterial.java
index 8cfefafdc49..3f03dbcb37e 100644
--- 
a/database/connector/core/src/main/java/org/apache/shardingsphere/database/connector/core/metadata/data/loader/MetaDataLoaderMaterial.java
+++ 
b/database/connector/core/src/main/java/org/apache/shardingsphere/database/connector/core/metadata/data/loader/MetaDataLoaderMaterial.java
@@ -17,8 +17,12 @@
 
 package org.apache.shardingsphere.database.connector.core.metadata.data.loader;
 
+import lombok.AccessLevel;
 import lombok.Getter;
 import lombok.RequiredArgsConstructor;
+import 
org.apache.shardingsphere.database.connector.core.metadata.identifier.IdentifierCasePolicy;
+import 
org.apache.shardingsphere.database.connector.core.metadata.identifier.IdentifierNormalizeEngine;
+import 
org.apache.shardingsphere.database.connector.core.metadata.identifier.IdentifierScope;
 import org.apache.shardingsphere.database.connector.core.type.DatabaseType;
 
 import javax.sql.DataSource;
@@ -40,4 +44,19 @@ public final class MetaDataLoaderMaterial {
     private final DatabaseType storageType;
     
     private final String defaultSchemaName;
+    
+    @Getter(AccessLevel.NONE)
+    private volatile IdentifierCasePolicy tableIdentifierPolicy;
+    
+    /**
+     * Get table identifier case policy.
+     *
+     * @return table identifier case policy
+     */
+    public synchronized IdentifierCasePolicy getTableIdentifierPolicy() {
+        if (null == tableIdentifierPolicy) {
+            tableIdentifierPolicy = 
IdentifierNormalizeEngine.resolvePolicy(storageType, dataSource, 
IdentifierScope.TABLE);
+        }
+        return tableIdentifierPolicy;
+    }
 }
diff --git 
a/database/connector/core/src/main/java/org/apache/shardingsphere/database/connector/core/metadata/data/loader/type/TableMetaDataLoader.java
 
b/database/connector/core/src/main/java/org/apache/shardingsphere/database/connector/core/metadata/data/loader/type/TableMetaDataLoader.java
index ba15eaaf5f2..872ee837070 100644
--- 
a/database/connector/core/src/main/java/org/apache/shardingsphere/database/connector/core/metadata/data/loader/type/TableMetaDataLoader.java
+++ 
b/database/connector/core/src/main/java/org/apache/shardingsphere/database/connector/core/metadata/data/loader/type/TableMetaDataLoader.java
@@ -21,8 +21,10 @@ import lombok.AccessLevel;
 import lombok.NoArgsConstructor;
 import 
org.apache.shardingsphere.database.connector.core.metadata.data.loader.MetaDataLoaderConnection;
 import 
org.apache.shardingsphere.database.connector.core.metadata.data.model.TableMetaData;
+import 
org.apache.shardingsphere.database.connector.core.metadata.identifier.IdentifierCasePolicy;
+import 
org.apache.shardingsphere.database.connector.core.metadata.identifier.IdentifierNormalizeEngine;
+import 
org.apache.shardingsphere.database.connector.core.metadata.identifier.IdentifierScope;
 import org.apache.shardingsphere.database.connector.core.type.DatabaseType;
-import 
org.apache.shardingsphere.database.connector.core.type.DatabaseTypeRegistry;
 
 import javax.sql.DataSource;
 import java.sql.Connection;
@@ -47,8 +49,23 @@ public final class TableMetaDataLoader {
      * @throws SQLException SQL exception
      */
     public static Optional<TableMetaData> load(final DataSource dataSource, 
final String tableNamePattern, final DatabaseType databaseType) throws 
SQLException {
+        return load(dataSource, tableNamePattern, databaseType, 
IdentifierNormalizeEngine.resolvePolicy(databaseType, dataSource, 
IdentifierScope.TABLE));
+    }
+    
+    /**
+     * Load table meta data.
+     *
+     * @param dataSource data source
+     * @param tableNamePattern table name pattern
+     * @param databaseType database type
+     * @param tableIdentifierPolicy table identifier case policy
+     * @return table meta data
+     * @throws SQLException SQL exception
+     */
+    public static Optional<TableMetaData> load(final DataSource dataSource, 
final String tableNamePattern, final DatabaseType databaseType,
+                                               final IdentifierCasePolicy 
tableIdentifierPolicy) throws SQLException {
         try (MetaDataLoaderConnection connection = new 
MetaDataLoaderConnection(databaseType, dataSource.getConnection())) {
-            String formattedTableNamePattern = new 
DatabaseTypeRegistry(databaseType).formatIdentifierPattern(tableNamePattern);
+            String formattedTableNamePattern = 
IdentifierNormalizeEngine.normalize(tableIdentifierPolicy, tableNamePattern);
             return isTableExist(connection, formattedTableNamePattern)
                     ? Optional.of(new TableMetaData(tableNamePattern, 
ColumnMetaDataLoader.load(
                             connection, formattedTableNamePattern, 
databaseType), IndexMetaDataLoader.load(connection, formattedTableNamePattern), 
Collections.emptyList()))
diff --git 
a/database/connector/core/src/main/java/org/apache/shardingsphere/database/connector/core/metadata/identifier/IdentifierNormalizeEngine.java
 
b/database/connector/core/src/main/java/org/apache/shardingsphere/database/connector/core/metadata/identifier/IdentifierNormalizeEngine.java
new file mode 100644
index 00000000000..c14c3ab2c78
--- /dev/null
+++ 
b/database/connector/core/src/main/java/org/apache/shardingsphere/database/connector/core/metadata/identifier/IdentifierNormalizeEngine.java
@@ -0,0 +1,67 @@
+/*
+ * 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.database.connector.core.metadata.identifier;
+
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import 
org.apache.shardingsphere.database.connector.core.metadata.database.enums.QuoteCharacter;
+import 
org.apache.shardingsphere.database.connector.core.spi.DatabaseTypedSPILoader;
+import org.apache.shardingsphere.database.connector.core.type.DatabaseType;
+
+import javax.sql.DataSource;
+
+/**
+ * Identifier normalize engine.
+ */
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public final class IdentifierNormalizeEngine {
+    
+    /**
+     * Resolve identifier case policy.
+     *
+     * @param databaseType database type
+     * @param dataSource data source
+     * @param identifierScope identifier scope
+     * @return identifier case policy
+     */
+    public static IdentifierCasePolicy resolvePolicy(final DatabaseType 
databaseType, final DataSource dataSource, final IdentifierScope 
identifierScope) {
+        return 
DatabaseTypedSPILoader.findService(IdentifierCasePolicyProvider.class, 
databaseType)
+                .map(each -> each.provide(new 
IdentifierCasePolicyProviderContext(databaseType, dataSource)))
+                
.orElseGet(IdentifierCasePolicyFactory::newInsensitivePolicySet)
+                .getPolicy(identifierScope);
+    }
+    
+    /**
+     * Normalize identifier.
+     *
+     * @param policy identifier case policy
+     * @param identifier identifier
+     * @return normalized identifier
+     */
+    public static String normalize(final IdentifierCasePolicy policy, final 
String identifier) {
+        if (null == identifier) {
+            return null;
+        }
+        QuoteCharacter quoteCharacter = 
QuoteCharacter.getQuoteCharacter(identifier);
+        String unwrappedIdentifier = quoteCharacter.unwrap(identifier);
+        if (QuoteCharacter.NONE != quoteCharacter) {
+            return unwrappedIdentifier;
+        }
+        return LookupMode.NORMALIZED == 
policy.getLookupMode(QuoteCharacter.NONE) ? 
policy.normalize(unwrappedIdentifier) : unwrappedIdentifier;
+    }
+}
diff --git 
a/database/connector/core/src/test/java/org/apache/shardingsphere/database/connector/core/metadata/data/loader/MetaDataLoaderTest.java
 
b/database/connector/core/src/test/java/org/apache/shardingsphere/database/connector/core/metadata/data/loader/MetaDataLoaderTest.java
index f0e60a19844..93ba7c6acd6 100644
--- 
a/database/connector/core/src/test/java/org/apache/shardingsphere/database/connector/core/metadata/data/loader/MetaDataLoaderTest.java
+++ 
b/database/connector/core/src/test/java/org/apache/shardingsphere/database/connector/core/metadata/data/loader/MetaDataLoaderTest.java
@@ -20,6 +20,7 @@ package 
org.apache.shardingsphere.database.connector.core.metadata.data.loader;
 import lombok.SneakyThrows;
 import 
org.apache.shardingsphere.database.connector.core.metadata.data.model.SchemaMetaData;
 import 
org.apache.shardingsphere.database.connector.core.metadata.data.model.TableMetaData;
+import 
org.apache.shardingsphere.database.connector.core.metadata.identifier.IdentifierCasePolicy;
 import org.apache.shardingsphere.database.connector.core.type.DatabaseType;
 import org.apache.shardingsphere.infra.spi.ShardingSphereServiceLoader;
 import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;
@@ -41,6 +42,7 @@ import java.util.concurrent.TimeUnit;
 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.assertNull;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -96,6 +98,13 @@ class MetaDataLoaderTest {
         assertTrue(actual.get("foo_db").getTables().isEmpty());
     }
     
+    @Test
+    void assertGetTableIdentifierPolicyCachesResolvedPolicy() {
+        MetaDataLoaderMaterial material = new 
MetaDataLoaderMaterial(Collections.emptyList(), "foo_ds", 
mock(DataSource.class), databaseType, "foo_db");
+        IdentifierCasePolicy actual = material.getTableIdentifierPolicy();
+        assertThat(material.getTableIdentifierPolicy(), sameInstance(actual));
+    }
+    
     @Test
     void assertLoadWhenInterrupted() throws Exception {
         MetaDataLoaderMaterial material = new 
MetaDataLoaderMaterial(Collections.emptyList(), "foo_ds", 
mock(DataSource.class, RETURNS_DEEP_STUBS), databaseType, "foo_db");
diff --git 
a/database/connector/core/src/test/java/org/apache/shardingsphere/database/connector/core/metadata/identifier/IdentifierNormalizeEngineTest.java
 
b/database/connector/core/src/test/java/org/apache/shardingsphere/database/connector/core/metadata/identifier/IdentifierNormalizeEngineTest.java
new file mode 100644
index 00000000000..a3f50b9a7ea
--- /dev/null
+++ 
b/database/connector/core/src/test/java/org/apache/shardingsphere/database/connector/core/metadata/identifier/IdentifierNormalizeEngineTest.java
@@ -0,0 +1,55 @@
+/*
+ * 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.database.connector.core.metadata.identifier;
+
+import org.apache.shardingsphere.database.connector.core.type.DatabaseType;
+import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;
+import org.junit.jupiter.api.Test;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+class IdentifierNormalizeEngineTest {
+    
+    private final DatabaseType databaseType = 
TypedSPILoader.getService(DatabaseType.class, "TRUNK");
+    
+    @Test
+    void assertNormalizeQuotedIdentifier() {
+        IdentifierCasePolicy policy = 
IdentifierNormalizeEngine.resolvePolicy(databaseType, null, 
IdentifierScope.TABLE);
+        assertThat(IdentifierNormalizeEngine.normalize(policy, "\"Foo_Tbl\""), 
is("Foo_Tbl"));
+    }
+    
+    @Test
+    void assertNormalizeWithResolvedPolicy() {
+        IdentifierCasePolicy policy = 
IdentifierNormalizeEngine.resolvePolicy(databaseType, null, 
IdentifierScope.TABLE);
+        assertThat(IdentifierNormalizeEngine.normalize(policy, "Foo_Tbl"), 
is("foo_tbl"));
+    }
+    
+    @Test
+    void assertNormalizeExactPolicy() {
+        IdentifierCasePolicy policy = 
IdentifierCasePolicyFactory.newSensitivePolicySet().getPolicy(IdentifierScope.TABLE);
+        assertThat(IdentifierNormalizeEngine.normalize(policy, "Foo_Tbl"), 
is("Foo_Tbl"));
+    }
+    
+    @Test
+    void assertNormalizeNullIdentifier() {
+        IdentifierCasePolicy policy = 
IdentifierNormalizeEngine.resolvePolicy(databaseType, null, 
IdentifierScope.TABLE);
+        assertNull(IdentifierNormalizeEngine.normalize(policy, null));
+    }
+}
diff --git 
a/database/connector/dialect/firebird/src/main/java/org/apache/shardingsphere/database/connector/firebird/metadata/data/loader/FirebirdBlobColumnLoader.java
 
b/database/connector/dialect/firebird/src/main/java/org/apache/shardingsphere/database/connector/firebird/metadata/data/loader/FirebirdBlobColumnLoader.java
index 653613d0558..da091a3f3d0 100644
--- 
a/database/connector/dialect/firebird/src/main/java/org/apache/shardingsphere/database/connector/firebird/metadata/data/loader/FirebirdBlobColumnLoader.java
+++ 
b/database/connector/dialect/firebird/src/main/java/org/apache/shardingsphere/database/connector/firebird/metadata/data/loader/FirebirdBlobColumnLoader.java
@@ -20,7 +20,7 @@ package 
org.apache.shardingsphere.database.connector.firebird.metadata.data.load
 import lombok.RequiredArgsConstructor;
 import 
org.apache.shardingsphere.database.connector.core.metadata.data.loader.MetaDataLoaderConnection;
 import 
org.apache.shardingsphere.database.connector.core.metadata.data.loader.MetaDataLoaderMaterial;
-import 
org.apache.shardingsphere.database.connector.core.type.DatabaseTypeRegistry;
+import 
org.apache.shardingsphere.database.connector.core.metadata.identifier.IdentifierNormalizeEngine;
 
 import java.sql.PreparedStatement;
 import java.sql.ResultSet;
@@ -50,12 +50,11 @@ final class FirebirdBlobColumnLoader {
             return Collections.emptyMap();
         }
         Map<String, Map<String, Integer>> result = new 
HashMap<>(material.getActualTableNames().size(), 1F);
-        DatabaseTypeRegistry databaseTypeRegistry = new 
DatabaseTypeRegistry(material.getStorageType());
         try (
                 MetaDataLoaderConnection connection = new 
MetaDataLoaderConnection(
                         material.getStorageType(), 
material.getDataSource().getConnection())) {
             for (String each : material.getActualTableNames()) {
-                String formattedTableName = 
databaseTypeRegistry.formatIdentifierPattern(each);
+                String formattedTableName = 
IdentifierNormalizeEngine.normalize(material.getTableIdentifierPolicy(), each);
                 Map<String, Integer> blobColumns = 
loadTableBlobColumns(connection, formattedTableName);
                 result.put(each, blobColumns);
             }
diff --git 
a/database/connector/dialect/firebird/src/main/java/org/apache/shardingsphere/database/connector/firebird/metadata/data/loader/FirebirdMetaDataLoader.java
 
b/database/connector/dialect/firebird/src/main/java/org/apache/shardingsphere/database/connector/firebird/metadata/data/loader/FirebirdMetaDataLoader.java
index ddff5308a28..9ac3b39d549 100644
--- 
a/database/connector/dialect/firebird/src/main/java/org/apache/shardingsphere/database/connector/firebird/metadata/data/loader/FirebirdMetaDataLoader.java
+++ 
b/database/connector/dialect/firebird/src/main/java/org/apache/shardingsphere/database/connector/firebird/metadata/data/loader/FirebirdMetaDataLoader.java
@@ -40,7 +40,7 @@ public final class FirebirdMetaDataLoader implements 
DialectMetaDataLoader {
     public Collection<SchemaMetaData> load(final MetaDataLoaderMaterial 
material) throws SQLException {
         Collection<TableMetaData> tableMetaData = new LinkedList<>();
         for (String each : material.getActualTableNames()) {
-            TableMetaDataLoader.load(material.getDataSource(), each, 
material.getStorageType()).ifPresent(tableMetaData::add);
+            TableMetaDataLoader.load(material.getDataSource(), each, 
material.getStorageType(), 
material.getTableIdentifierPolicy()).ifPresent(tableMetaData::add);
         }
         loadBlobColumns(material);
         loadNonFixedLengthColumnSizes(material);
diff --git 
a/database/connector/dialect/firebird/src/main/java/org/apache/shardingsphere/database/connector/firebird/metadata/data/loader/FirebirdNonFixedLengthColumnSizeLoader.java
 
b/database/connector/dialect/firebird/src/main/java/org/apache/shardingsphere/database/connector/firebird/metadata/data/loader/FirebirdNonFixedLengthColumnSizeLoader.java
index 7fb2157c863..2acc8a4c671 100644
--- 
a/database/connector/dialect/firebird/src/main/java/org/apache/shardingsphere/database/connector/firebird/metadata/data/loader/FirebirdNonFixedLengthColumnSizeLoader.java
+++ 
b/database/connector/dialect/firebird/src/main/java/org/apache/shardingsphere/database/connector/firebird/metadata/data/loader/FirebirdNonFixedLengthColumnSizeLoader.java
@@ -20,7 +20,7 @@ package 
org.apache.shardingsphere.database.connector.firebird.metadata.data.load
 import lombok.RequiredArgsConstructor;
 import 
org.apache.shardingsphere.database.connector.core.metadata.data.loader.MetaDataLoaderConnection;
 import 
org.apache.shardingsphere.database.connector.core.metadata.data.loader.MetaDataLoaderMaterial;
-import 
org.apache.shardingsphere.database.connector.core.type.DatabaseTypeRegistry;
+import 
org.apache.shardingsphere.database.connector.core.metadata.identifier.IdentifierNormalizeEngine;
 
 import java.sql.ResultSet;
 import java.sql.SQLException;
@@ -44,10 +44,9 @@ final class FirebirdNonFixedLengthColumnSizeLoader {
             return Collections.emptyMap();
         }
         Map<String, Map<String, Integer>> result = new 
HashMap<>(material.getActualTableNames().size(), 1F);
-        DatabaseTypeRegistry databaseTypeRegistry = new 
DatabaseTypeRegistry(material.getStorageType());
         try (MetaDataLoaderConnection connection = new 
MetaDataLoaderConnection(material.getStorageType(), 
material.getDataSource().getConnection())) {
             for (String each : material.getActualTableNames()) {
-                String formattedTableName = 
databaseTypeRegistry.formatIdentifierPattern(each);
+                String formattedTableName = 
IdentifierNormalizeEngine.normalize(material.getTableIdentifierPolicy(), each);
                 Map<String, Integer> columnSizes = 
loadTableColumnSizes(connection, formattedTableName);
                 result.put(each, columnSizes);
             }
diff --git 
a/database/connector/dialect/firebird/src/main/java/org/apache/shardingsphere/database/connector/firebird/metadata/identifier/FirebirdIdentifierCasePolicyProvider.java
 
b/database/connector/dialect/firebird/src/main/java/org/apache/shardingsphere/database/connector/firebird/metadata/identifier/FirebirdIdentifierCasePolicyProvider.java
new file mode 100644
index 00000000000..9bf8291d9f9
--- /dev/null
+++ 
b/database/connector/dialect/firebird/src/main/java/org/apache/shardingsphere/database/connector/firebird/metadata/identifier/FirebirdIdentifierCasePolicyProvider.java
@@ -0,0 +1,46 @@
+/*
+ * 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.database.connector.firebird.metadata.identifier;
+
+import 
org.apache.shardingsphere.database.connector.core.metadata.identifier.IdentifierCasePolicyProvider;
+import 
org.apache.shardingsphere.database.connector.core.metadata.identifier.IdentifierCasePolicyProviderContext;
+import 
org.apache.shardingsphere.database.connector.core.metadata.identifier.IdentifierCasePolicySet;
+import 
org.apache.shardingsphere.database.connector.core.metadata.identifier.LookupMode;
+import 
org.apache.shardingsphere.database.connector.core.metadata.identifier.StandardIdentifierCasePolicy;
+
+import java.util.Locale;
+
+/**
+ * Firebird provider of identifier case rules.
+ */
+public final class FirebirdIdentifierCasePolicyProvider implements 
IdentifierCasePolicyProvider {
+    
+    @Override
+    public IdentifierCasePolicySet provide(final 
IdentifierCasePolicyProviderContext context) {
+        return new IdentifierCasePolicySet(new 
StandardIdentifierCasePolicy(LookupMode.EXACT, LookupMode.NORMALIZED, 
FirebirdIdentifierCasePolicyProvider::toUpperCase, each -> true));
+    }
+    
+    @Override
+    public String getDatabaseType() {
+        return "Firebird";
+    }
+    
+    private static String toUpperCase(final String value) {
+        return value.toUpperCase(Locale.ENGLISH);
+    }
+}
diff --git 
a/database/connector/dialect/firebird/src/main/resources/META-INF/services/org.apache.shardingsphere.database.connector.core.metadata.identifier.IdentifierCasePolicyProvider
 
b/database/connector/dialect/firebird/src/main/resources/META-INF/services/org.apache.shardingsphere.database.connector.core.metadata.identifier.IdentifierCasePolicyProvider
new file mode 100644
index 00000000000..e6c59302cb9
--- /dev/null
+++ 
b/database/connector/dialect/firebird/src/main/resources/META-INF/services/org.apache.shardingsphere.database.connector.core.metadata.identifier.IdentifierCasePolicyProvider
@@ -0,0 +1,18 @@
+#
+# 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.
+#
+
+org.apache.shardingsphere.database.connector.firebird.metadata.identifier.FirebirdIdentifierCasePolicyProvider
diff --git 
a/database/connector/dialect/firebird/src/test/java/org/apache/shardingsphere/database/connector/firebird/metadata/data/loader/FirebirdMetaDataLoaderTest.java
 
b/database/connector/dialect/firebird/src/test/java/org/apache/shardingsphere/database/connector/firebird/metadata/data/loader/FirebirdMetaDataLoaderTest.java
index 75bf3e1afc1..01e3b61876b 100644
--- 
a/database/connector/dialect/firebird/src/test/java/org/apache/shardingsphere/database/connector/firebird/metadata/data/loader/FirebirdMetaDataLoaderTest.java
+++ 
b/database/connector/dialect/firebird/src/test/java/org/apache/shardingsphere/database/connector/firebird/metadata/data/loader/FirebirdMetaDataLoaderTest.java
@@ -22,6 +22,7 @@ import 
org.apache.shardingsphere.database.connector.core.metadata.data.loader.Me
 import 
org.apache.shardingsphere.database.connector.core.metadata.data.loader.type.TableMetaDataLoader;
 import 
org.apache.shardingsphere.database.connector.core.metadata.data.model.SchemaMetaData;
 import 
org.apache.shardingsphere.database.connector.core.metadata.data.model.TableMetaData;
+import 
org.apache.shardingsphere.database.connector.core.metadata.identifier.IdentifierCasePolicy;
 import 
org.apache.shardingsphere.database.connector.core.spi.DatabaseTypedSPILoader;
 import org.apache.shardingsphere.database.connector.core.type.DatabaseType;
 import 
org.apache.shardingsphere.database.connector.firebird.metadata.data.FirebirdBlobInfoRegistry;
@@ -42,6 +43,8 @@ import static org.hamcrest.Matchers.is;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.contains;
 import static org.hamcrest.Matchers.hasSize;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.mockConstruction;
 import static org.mockito.Mockito.mockStatic;
@@ -71,7 +74,7 @@ class FirebirdMetaDataLoaderTest {
                         
mockConstruction(FirebirdNonFixedLengthColumnSizeLoader.class, (mock, context) 
-> when(mock.load()).thenReturn(allSizes));
                 MockedConstruction<FirebirdBlobColumnLoader> 
blobColumnLoaderMocked =
                         mockConstruction(FirebirdBlobColumnLoader.class, 
(mock, context) -> when(mock.load()).thenReturn(allBlobColumns))) {
-            tableLoaderMocked.when(() -> TableMetaDataLoader.load(dataSource, 
"test_table", databaseType)).thenReturn(Optional.of(tableMetaData));
+            tableLoaderMocked.when(() -> 
TableMetaDataLoader.load(eq(dataSource), eq("test_table"), eq(databaseType), 
any(IdentifierCasePolicy.class))).thenReturn(Optional.of(tableMetaData));
             Collection<SchemaMetaData> actual = 
dialectMetaDataLoader.load(material);
             assertThat(actual, hasSize(1));
             SchemaMetaData schema = actual.iterator().next();
diff --git 
a/database/connector/dialect/firebird/src/test/java/org/apache/shardingsphere/database/connector/firebird/metadata/identifier/FirebirdIdentifierCasePolicyProviderTest.java
 
b/database/connector/dialect/firebird/src/test/java/org/apache/shardingsphere/database/connector/firebird/metadata/identifier/FirebirdIdentifierCasePolicyProviderTest.java
new file mode 100644
index 00000000000..011a1711d41
--- /dev/null
+++ 
b/database/connector/dialect/firebird/src/test/java/org/apache/shardingsphere/database/connector/firebird/metadata/identifier/FirebirdIdentifierCasePolicyProviderTest.java
@@ -0,0 +1,58 @@
+/*
+ * 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.database.connector.firebird.metadata.identifier;
+
+import 
org.apache.shardingsphere.database.connector.core.metadata.database.enums.QuoteCharacter;
+import 
org.apache.shardingsphere.database.connector.core.metadata.identifier.IdentifierCasePolicy;
+import 
org.apache.shardingsphere.database.connector.core.metadata.identifier.IdentifierCasePolicyProvider;
+import 
org.apache.shardingsphere.database.connector.core.metadata.identifier.IdentifierCasePolicyProviderContext;
+import 
org.apache.shardingsphere.database.connector.core.metadata.identifier.IdentifierScope;
+import 
org.apache.shardingsphere.database.connector.core.metadata.identifier.LookupMode;
+import 
org.apache.shardingsphere.database.connector.core.spi.DatabaseTypedSPILoader;
+import org.apache.shardingsphere.database.connector.core.type.DatabaseType;
+import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;
+import org.junit.jupiter.api.Test;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.isA;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+class FirebirdIdentifierCasePolicyProviderTest {
+    
+    private final DatabaseType databaseType = 
TypedSPILoader.getService(DatabaseType.class, "Firebird");
+    
+    private final IdentifierCasePolicyProvider provider = 
DatabaseTypedSPILoader.getService(IdentifierCasePolicyProvider.class, 
databaseType);
+    
+    @Test
+    void assertGetDatabaseType() {
+        assertThat(provider, isA(FirebirdIdentifierCasePolicyProvider.class));
+        assertThat(provider.getDatabaseType(), is("Firebird"));
+    }
+    
+    @Test
+    void assertProvide() {
+        IdentifierCasePolicy actual = provider.provide(new 
IdentifierCasePolicyProviderContext(databaseType, 
null)).getPolicy(IdentifierScope.TABLE);
+        assertThat(actual.getLookupMode(QuoteCharacter.NONE), 
is(LookupMode.NORMALIZED));
+        assertThat(actual.normalize("Foo"), is("FOO"));
+        assertTrue(actual.matches("FOO", "foo", QuoteCharacter.NONE));
+        assertTrue(actual.matches("Foo", "foo", QuoteCharacter.NONE));
+        assertFalse(actual.matches("Foo", "foo", QuoteCharacter.QUOTE));
+    }
+}
diff --git 
a/database/connector/dialect/hive/src/main/java/org/apache/shardingsphere/database/connector/hive/metadata/data/loader/HiveMetaDataLoader.java
 
b/database/connector/dialect/hive/src/main/java/org/apache/shardingsphere/database/connector/hive/metadata/data/loader/HiveMetaDataLoader.java
index aacc80c7d25..b5386fc3992 100644
--- 
a/database/connector/dialect/hive/src/main/java/org/apache/shardingsphere/database/connector/hive/metadata/data/loader/HiveMetaDataLoader.java
+++ 
b/database/connector/dialect/hive/src/main/java/org/apache/shardingsphere/database/connector/hive/metadata/data/loader/HiveMetaDataLoader.java
@@ -60,7 +60,7 @@ public final class HiveMetaDataLoader implements 
DialectMetaDataLoader {
             return Collections.singleton(new 
SchemaMetaData(material.getDefaultSchemaName(), tableMetaData));
         }
         for (String each : material.getActualTableNames()) {
-            TableMetaDataLoader.load(material.getDataSource(), each, 
material.getStorageType()).ifPresent(tableMetaData::add);
+            TableMetaDataLoader.load(material.getDataSource(), each, 
material.getStorageType(), 
material.getTableIdentifierPolicy()).ifPresent(tableMetaData::add);
         }
         return Collections.singleton(new 
SchemaMetaData(material.getDefaultSchemaName(), tableMetaData));
     }
diff --git 
a/database/connector/dialect/hive/src/test/java/org/apache/shardingsphere/database/connector/hive/metadata/data/loader/HiveMetaDataLoaderTest.java
 
b/database/connector/dialect/hive/src/test/java/org/apache/shardingsphere/database/connector/hive/metadata/data/loader/HiveMetaDataLoaderTest.java
index f8ddc4a6b10..f2fefbf1d36 100644
--- 
a/database/connector/dialect/hive/src/test/java/org/apache/shardingsphere/database/connector/hive/metadata/data/loader/HiveMetaDataLoaderTest.java
+++ 
b/database/connector/dialect/hive/src/test/java/org/apache/shardingsphere/database/connector/hive/metadata/data/loader/HiveMetaDataLoaderTest.java
@@ -26,6 +26,7 @@ import 
org.apache.shardingsphere.database.connector.core.metadata.data.model.Col
 import 
org.apache.shardingsphere.database.connector.core.metadata.data.model.SchemaMetaData;
 import 
org.apache.shardingsphere.database.connector.core.metadata.data.model.TableMetaData;
 import 
org.apache.shardingsphere.database.connector.core.metadata.database.datatype.DataTypeRegistry;
+import 
org.apache.shardingsphere.database.connector.core.metadata.identifier.IdentifierCasePolicy;
 import 
org.apache.shardingsphere.database.connector.core.spi.DatabaseTypedSPILoader;
 import org.apache.shardingsphere.database.connector.core.type.DatabaseType;
 import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;
@@ -55,6 +56,8 @@ import static org.hamcrest.Matchers.is;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
@@ -116,8 +119,8 @@ class HiveMetaDataLoaderTest {
     void assertLoadWithoutInformationSchemaFallbackToDefaultLoader() throws 
SQLException {
         DataSource dataSource = 
mockDataSource(mockInformationSchemaConnection(false));
         TableMetaData tableMetaData = new TableMetaData("present_table", 
Collections.emptyList(), Collections.emptyList(), Collections.emptyList());
-        when(TableMetaDataLoader.load(dataSource, "missing_table", 
databaseType)).thenReturn(Optional.empty());
-        when(TableMetaDataLoader.load(dataSource, "present_table", 
databaseType)).thenReturn(Optional.of(tableMetaData));
+        when(TableMetaDataLoader.load(eq(dataSource), eq("missing_table"), 
eq(databaseType), 
any(IdentifierCasePolicy.class))).thenReturn(Optional.empty());
+        when(TableMetaDataLoader.load(eq(dataSource), eq("present_table"), 
eq(databaseType), 
any(IdentifierCasePolicy.class))).thenReturn(Optional.of(tableMetaData));
         Collection<SchemaMetaData> fallbackSchemas = loader.load(new 
MetaDataLoaderMaterial(Arrays.asList("missing_table", "present_table"), "ds_2", 
dataSource, databaseType, "fallback_schema"));
         TableMetaData defaultLoadedTable = 
fallbackSchemas.iterator().next().getTables().iterator().next();
         assertThat(defaultLoadedTable.getName(), is("present_table"));


Reply via email to