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 43c3a34a8dc Refactor table identifier lookup for heterogeneous 
databases with LOGICAL_TABLE scope fallback (#38672)
43c3a34a8dc is described below

commit 43c3a34a8dc6ee9e220bea077d1e1dfd0f818a00
Author: Haoran Meng <[email protected]>
AuthorDate: Wed May 6 18:22:42 2026 +0800

    Refactor table identifier lookup for heterogeneous databases with 
LOGICAL_TABLE scope fallback (#38672)
    
    * Refactor table identifier lookup for heterogeneous databases with 
LOGICAL_TABLE scope fallback
    
    * Fix table lookup priority and heterogeneous fallback tests
    
    * Fix checkstyle
    
    * Fix heterogeneous lookup detection for mixed storage types
---
 .../core/metadata/identifier/IdentifierScope.java  |  2 +
 .../schema/model/ShardingSphereSchema.java         | 33 ++++++++++-
 .../identifier/DatabaseIdentifierContext.java      | 20 +++++++
 .../DatabaseIdentifierContextFactory.java          | 42 ++++++++++----
 .../model/ShardingSphereSchemaIdentifierTest.java  | 30 ++++++++++
 .../DatabaseIdentifierContextFactoryTest.java      | 64 ++++++++++++++++++++++
 6 files changed, 177 insertions(+), 14 deletions(-)

diff --git 
a/database/connector/core/src/main/java/org/apache/shardingsphere/database/connector/core/metadata/identifier/IdentifierScope.java
 
b/database/connector/core/src/main/java/org/apache/shardingsphere/database/connector/core/metadata/identifier/IdentifierScope.java
index b0b45a6d37d..61ebfae59b9 100644
--- 
a/database/connector/core/src/main/java/org/apache/shardingsphere/database/connector/core/metadata/identifier/IdentifierScope.java
+++ 
b/database/connector/core/src/main/java/org/apache/shardingsphere/database/connector/core/metadata/identifier/IdentifierScope.java
@@ -28,6 +28,8 @@ public enum IdentifierScope {
     
     TABLE,
     
+    LOGICAL_TABLE,
+    
     VIEW,
     
     COLUMN,
diff --git 
a/infra/common/src/main/java/org/apache/shardingsphere/infra/metadata/database/schema/model/ShardingSphereSchema.java
 
b/infra/common/src/main/java/org/apache/shardingsphere/infra/metadata/database/schema/model/ShardingSphereSchema.java
index bc248becea6..8f816764499 100644
--- 
a/infra/common/src/main/java/org/apache/shardingsphere/infra/metadata/database/schema/model/ShardingSphereSchema.java
+++ 
b/infra/common/src/main/java/org/apache/shardingsphere/infra/metadata/database/schema/model/ShardingSphereSchema.java
@@ -53,6 +53,9 @@ public final class ShardingSphereSchema {
     @Getter(AccessLevel.NONE)
     private IdentifierIndex<ShardingSphereTable> tableIndex;
     
+    @Getter(AccessLevel.NONE)
+    private IdentifierIndex<ShardingSphereTable> logicalTableIndex;
+    
     @Getter(AccessLevel.NONE)
     private IdentifierIndex<ShardingSphereView> viewIndex;
     
@@ -69,6 +72,7 @@ public final class ShardingSphereSchema {
         this.protocolType = protocolType;
         identifierContext = DatabaseIdentifierContextFactory.createDefault();
         tableIndex = new IdentifierIndex<>(identifierContext, 
IdentifierScope.TABLE);
+        logicalTableIndex = null;
         viewIndex = new IdentifierIndex<>(identifierContext, 
IdentifierScope.VIEW);
         tableIndex.rebuild(Collections.emptyMap());
         viewIndex.rebuild(Collections.emptyMap());
@@ -109,7 +113,14 @@ public final class ShardingSphereSchema {
      * @return table
      */
     private Optional<ShardingSphereTable> findTable(final IdentifierValue 
tableName) {
-        return tableIndex.find(tableName);
+        Optional<ShardingSphereTable> physicalMatchedTable = 
tableIndex.find(tableName);
+        if (physicalMatchedTable.isPresent()) {
+            return physicalMatchedTable;
+        }
+        if (null == logicalTableIndex) {
+            return Optional.empty();
+        }
+        return logicalTableIndex.find(tableName);
     }
     
     /**
@@ -160,6 +171,9 @@ public final class ShardingSphereSchema {
     public void putTable(final ShardingSphereTable table) {
         refreshTableIdentifierContext(table);
         tableIndex.put(table.getName(), table);
+        if (null != logicalTableIndex) {
+            logicalTableIndex.put(table.getName(), table);
+        }
     }
     
     /**
@@ -173,6 +187,9 @@ public final class ShardingSphereSchema {
             return;
         }
         tableIndex.remove(table.getName());
+        if (null != logicalTableIndex) {
+            logicalTableIndex.remove(table.getName());
+        }
     }
     
     /**
@@ -266,9 +283,14 @@ public final class ShardingSphereSchema {
         final Collection<ShardingSphereView> views = new 
LinkedList<>(viewIndex.getAll());
         this.identifierContext = identifierContext;
         tableIndex = new IdentifierIndex<>(identifierContext, 
IdentifierScope.TABLE);
+        logicalTableIndex = createLogicalTableIndex(identifierContext);
         viewIndex = new IdentifierIndex<>(identifierContext, 
IdentifierScope.VIEW);
         tables.forEach(this::refreshTableIdentifierContext);
-        tableIndex.rebuild(createTableMap(tables));
+        Map<String, ShardingSphereTable> tableMap = createTableMap(tables);
+        tableIndex.rebuild(tableMap);
+        if (null != logicalTableIndex) {
+            logicalTableIndex.rebuild(tableMap);
+        }
         viewIndex.rebuild(createViewMap(views));
     }
     
@@ -345,4 +367,11 @@ public final class ShardingSphereSchema {
         return 
views.stream().collect(Collectors.toMap(ShardingSphereView::getName, each -> 
each, (oldValue, currentValue) -> currentValue,
                 () -> new LinkedHashMap<>(views.size(), 1F)));
     }
+    
+    private IdentifierIndex<ShardingSphereTable> createLogicalTableIndex(final 
DatabaseIdentifierContext context) {
+        if (!context.isHeterogeneousTableLookupEnabled()) {
+            return null;
+        }
+        return new IdentifierIndex<>(context, IdentifierScope.LOGICAL_TABLE);
+    }
 }
diff --git 
a/infra/common/src/main/java/org/apache/shardingsphere/infra/metadata/identifier/DatabaseIdentifierContext.java
 
b/infra/common/src/main/java/org/apache/shardingsphere/infra/metadata/identifier/DatabaseIdentifierContext.java
index fbd9768d5da..84463a88499 100644
--- 
a/infra/common/src/main/java/org/apache/shardingsphere/infra/metadata/identifier/DatabaseIdentifierContext.java
+++ 
b/infra/common/src/main/java/org/apache/shardingsphere/infra/metadata/identifier/DatabaseIdentifierContext.java
@@ -17,6 +17,7 @@
 
 package org.apache.shardingsphere.infra.metadata.identifier;
 
+import lombok.Getter;
 import 
org.apache.shardingsphere.database.connector.core.metadata.identifier.IdentifierCaseRule;
 import 
org.apache.shardingsphere.database.connector.core.metadata.identifier.IdentifierCaseRuleSet;
 import 
org.apache.shardingsphere.database.connector.core.metadata.identifier.IdentifierScope;
@@ -30,8 +31,16 @@ public final class DatabaseIdentifierContext {
     
     private volatile IdentifierCaseRuleSet ruleSet;
     
+    @Getter
+    private volatile boolean heterogeneousTableLookupEnabled;
+    
     public DatabaseIdentifierContext(final IdentifierCaseRuleSet ruleSet) {
+        this(ruleSet, false);
+    }
+    
+    public DatabaseIdentifierContext(final IdentifierCaseRuleSet ruleSet, 
final boolean heterogeneousTableLookupEnabled) {
         this.ruleSet = Objects.requireNonNull(ruleSet, "ruleSet cannot be 
null.");
+        this.heterogeneousTableLookupEnabled = heterogeneousTableLookupEnabled;
     }
     
     /**
@@ -52,4 +61,15 @@ public final class DatabaseIdentifierContext {
     public synchronized void refresh(final IdentifierCaseRuleSet ruleSet) {
         this.ruleSet = Objects.requireNonNull(ruleSet, "ruleSet cannot be 
null.");
     }
+    
+    /**
+     * Refresh identifier context.
+     *
+     * @param ruleSet identifier case rule set
+     * @param heterogeneousTableLookupEnabled heterogeneous table lookup 
enabled or not
+     */
+    public synchronized void refresh(final IdentifierCaseRuleSet ruleSet, 
final boolean heterogeneousTableLookupEnabled) {
+        this.ruleSet = Objects.requireNonNull(ruleSet, "ruleSet cannot be 
null.");
+        this.heterogeneousTableLookupEnabled = heterogeneousTableLookupEnabled;
+    }
 }
diff --git 
a/infra/common/src/main/java/org/apache/shardingsphere/infra/metadata/identifier/DatabaseIdentifierContextFactory.java
 
b/infra/common/src/main/java/org/apache/shardingsphere/infra/metadata/identifier/DatabaseIdentifierContextFactory.java
index 2b94f029d37..81650674773 100644
--- 
a/infra/common/src/main/java/org/apache/shardingsphere/infra/metadata/identifier/DatabaseIdentifierContextFactory.java
+++ 
b/infra/common/src/main/java/org/apache/shardingsphere/infra/metadata/identifier/DatabaseIdentifierContextFactory.java
@@ -30,6 +30,7 @@ import 
org.apache.shardingsphere.infra.metadata.database.resource.unit.StorageUn
 
 import javax.sql.DataSource;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.EnumMap;
 import java.util.LinkedHashSet;
 import java.util.Map;
@@ -62,7 +63,8 @@ public final class DatabaseIdentifierContextFactory {
         ConfigurationProperties actualProps = getProps(props);
         IdentifierCaseRuleResolver resolver = new IdentifierCaseRuleResolver();
         IdentifierCaseRuleSet protocolRuleSet = resolver.resolve(protocolType, 
actualProps, null);
-        return new 
DatabaseIdentifierContext(createScopeAwareRuleSet(protocolRuleSet, 
protocolRuleSet));
+        IdentifierCaseRuleSet scopeAwareRuleSet = 
createScopeAwareRuleSet(protocolRuleSet, protocolRuleSet);
+        return new DatabaseIdentifierContext(scopeAwareRuleSet, false);
     }
     
     /**
@@ -74,7 +76,13 @@ public final class DatabaseIdentifierContextFactory {
      * @return identifier context
      */
     public static DatabaseIdentifierContext create(final DatabaseType 
protocolType, final ResourceMetaData resourceMetaData, final 
ConfigurationProperties props) {
-        return new DatabaseIdentifierContext(createRuleSet(protocolType, 
resourceMetaData, getProps(props)));
+        ConfigurationProperties actualProps = getProps(props);
+        IdentifierCaseRuleResolver resolver = new IdentifierCaseRuleResolver();
+        IdentifierCaseRuleSet protocolRuleSet = resolver.resolve(protocolType, 
actualProps, null);
+        Optional<DatabaseType> storageDatabaseType = 
getIdentifierRuleDatabaseType(resourceMetaData);
+        IdentifierCaseRuleSet storageRuleSet = 
resolver.resolve(storageDatabaseType.orElse(protocolType), actualProps, 
getFirstDataSource(resourceMetaData));
+        IdentifierCaseRuleSet scopeAwareRuleSet = 
createScopeAwareRuleSet(protocolRuleSet, storageRuleSet);
+        return new DatabaseIdentifierContext(scopeAwareRuleSet, 
isHeterogeneous(protocolType, getStorageDatabaseTypes(resourceMetaData)));
     }
     
     /**
@@ -88,7 +96,7 @@ public final class DatabaseIdentifierContextFactory {
         ConfigurationProperties actualProps = getProps(props);
         IdentifierCaseRuleResolver resolver = new IdentifierCaseRuleResolver();
         IdentifierCaseRuleSet protocolRuleSet = resolver.resolve(protocolType, 
actualProps, null);
-        identifierContext.refresh(createScopeAwareRuleSet(protocolRuleSet, 
protocolRuleSet));
+        identifierContext.refresh(createScopeAwareRuleSet(protocolRuleSet, 
protocolRuleSet), false);
     }
     
     /**
@@ -100,7 +108,12 @@ public final class DatabaseIdentifierContextFactory {
      * @param props configuration properties
      */
     public static void refresh(final DatabaseIdentifierContext 
identifierContext, final DatabaseType protocolType, final ResourceMetaData 
resourceMetaData, final ConfigurationProperties props) {
-        identifierContext.refresh(createRuleSet(protocolType, 
resourceMetaData, getProps(props)));
+        ConfigurationProperties actualProps = getProps(props);
+        IdentifierCaseRuleResolver resolver = new IdentifierCaseRuleResolver();
+        IdentifierCaseRuleSet protocolRuleSet = resolver.resolve(protocolType, 
actualProps, null);
+        Optional<DatabaseType> storageDatabaseType = 
getIdentifierRuleDatabaseType(resourceMetaData);
+        IdentifierCaseRuleSet storageRuleSet = 
resolver.resolve(storageDatabaseType.orElse(protocolType), actualProps, 
getFirstDataSource(resourceMetaData));
+        identifierContext.refresh(createScopeAwareRuleSet(protocolRuleSet, 
storageRuleSet), isHeterogeneous(protocolType, 
getStorageDatabaseTypes(resourceMetaData)));
     }
     
     private static ConfigurationProperties getProps(final 
ConfigurationProperties props) {
@@ -114,12 +127,6 @@ public final class DatabaseIdentifierContextFactory {
         return 
resourceMetaData.getStorageUnits().values().iterator().next().getDataSource();
     }
     
-    private static IdentifierCaseRuleSet createRuleSet(final DatabaseType 
protocolType, final ResourceMetaData resourceMetaData, final 
ConfigurationProperties props) {
-        IdentifierCaseRuleResolver resolver = new IdentifierCaseRuleResolver();
-        DatabaseType resolvedDatabaseType = 
getIdentifierRuleDatabaseType(resourceMetaData).orElse(protocolType);
-        return createScopeAwareRuleSet(resolver.resolve(protocolType, props, 
null), resolver.resolve(resolvedDatabaseType, props, 
getFirstDataSource(resourceMetaData)));
-    }
-    
     private static IdentifierCaseRuleSet createScopeAwareRuleSet(final 
IdentifierCaseRuleSet protocolRuleSet, final IdentifierCaseRuleSet 
storageRuleSet) {
         IdentifierCaseRuleSet databaseRuleSet = 
IdentifierCaseRuleSets.newInsensitiveRuleSet();
         Map<IdentifierScope, IdentifierCaseRule> scopedRules = new 
EnumMap<>(IdentifierScope.class);
@@ -130,17 +137,28 @@ public final class DatabaseIdentifierContextFactory {
             }
             scopedRules.put(each, IdentifierScope.SCHEMA == each ? 
protocolRuleSet.getRule(each) : storageRuleSet.getRule(each));
         }
+        scopedRules.put(IdentifierScope.LOGICAL_TABLE, 
protocolRuleSet.getRule(IdentifierScope.TABLE));
         return new 
IdentifierCaseRuleSet(storageRuleSet.getRule(IdentifierScope.TABLE), 
scopedRules);
     }
     
     private static Optional<DatabaseType> getIdentifierRuleDatabaseType(final 
ResourceMetaData resourceMetaData) {
+        Collection<DatabaseType> storageDatabaseTypes = 
getStorageDatabaseTypes(resourceMetaData);
+        return storageDatabaseTypes.stream().findFirst();
+    }
+    
+    private static Collection<DatabaseType> getStorageDatabaseTypes(final 
ResourceMetaData resourceMetaData) {
         if (null == resourceMetaData || null == 
resourceMetaData.getStorageUnits() || 
resourceMetaData.getStorageUnits().isEmpty()) {
-            return Optional.empty();
+            return Collections.emptyList();
         }
         Collection<DatabaseType> storageDatabaseTypes = new 
LinkedHashSet<>(resourceMetaData.getStorageUnits().size(), 1F);
         for (StorageUnit each : resourceMetaData.getStorageUnits().values()) {
             storageDatabaseTypes.add(each.getStorageType());
         }
-        return storageDatabaseTypes.stream().findFirst();
+        return storageDatabaseTypes;
+    }
+    
+    private static boolean isHeterogeneous(final DatabaseType protocolType, 
final Collection<DatabaseType> storageDatabaseTypes) {
+        return null != protocolType && null != protocolType.getType() && 
storageDatabaseTypes.stream()
+                .anyMatch(each -> null != each && null != each.getType() && 
!protocolType.getType().equalsIgnoreCase(each.getType()));
     }
 }
diff --git 
a/infra/common/src/test/java/org/apache/shardingsphere/infra/metadata/database/schema/model/ShardingSphereSchemaIdentifierTest.java
 
b/infra/common/src/test/java/org/apache/shardingsphere/infra/metadata/database/schema/model/ShardingSphereSchemaIdentifierTest.java
index 81ddd57e2fc..af10eaff98e 100644
--- 
a/infra/common/src/test/java/org/apache/shardingsphere/infra/metadata/database/schema/model/ShardingSphereSchemaIdentifierTest.java
+++ 
b/infra/common/src/test/java/org/apache/shardingsphere/infra/metadata/database/schema/model/ShardingSphereSchemaIdentifierTest.java
@@ -18,12 +18,18 @@
 package org.apache.shardingsphere.infra.metadata.database.schema.model;
 
 import 
org.apache.shardingsphere.database.connector.core.metadata.identifier.IdentifierCaseRuleSets;
+import 
org.apache.shardingsphere.database.connector.core.metadata.identifier.IdentifierCaseRuleSet;
+import 
org.apache.shardingsphere.database.connector.core.metadata.identifier.IdentifierCaseRule;
+import 
org.apache.shardingsphere.database.connector.core.metadata.identifier.IdentifierScope;
 import org.apache.shardingsphere.database.connector.core.type.DatabaseType;
 import 
org.apache.shardingsphere.infra.metadata.identifier.DatabaseIdentifierContext;
 import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;
 import org.junit.jupiter.api.Test;
 
 import java.util.Collections;
+import java.util.EnumMap;
+import java.util.Arrays;
+import java.util.Map;
 
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.is;
@@ -101,4 +107,28 @@ class ShardingSphereSchemaIdentifierTest {
         schema.refreshIdentifierContext(new 
DatabaseIdentifierContext(IdentifierCaseRuleSets.newLowerCaseRuleSet()));
         assertFalse(schema.getTable("foo_tbl").containsColumn("FOO_COL"));
     }
+    
+    @Test
+    void 
assertContainsTableByLogicalTableIndexWhenHeterogeneousLookupEnabled() {
+        ShardingSphereTable table = new ShardingSphereTable("foo_tbl", 
Collections.emptyList(), Collections.emptyList(), Collections.emptyList());
+        ShardingSphereSchema schema = new ShardingSphereSchema("foo_schema", 
postgreSQLDatabaseType, Collections.singleton(table), Collections.emptyList());
+        Map<IdentifierScope, IdentifierCaseRule> scopedRules = new 
EnumMap<>(IdentifierScope.class);
+        scopedRules.put(IdentifierScope.LOGICAL_TABLE, 
IdentifierCaseRuleSets.newLowerCaseRuleSet().getRule(IdentifierScope.TABLE));
+        DatabaseIdentifierContext context = new DatabaseIdentifierContext(new 
IdentifierCaseRuleSet(IdentifierCaseRuleSets.newUpperCaseRuleSet().getRule(IdentifierScope.TABLE),
 scopedRules), true);
+        schema.refreshIdentifierContext(context);
+        assertTrue(schema.containsTable("FOO_TBL"));
+        assertThat(schema.getTable("FOO_TBL"), is(table));
+    }
+    
+    @Test
+    void assertGetTablePrioritizesPhysicalTableIndexWhenBothIndexesCanMatch() {
+        ShardingSphereTable lowerCaseTable = new 
ShardingSphereTable("foo_tbl", Collections.emptyList(), 
Collections.emptyList(), Collections.emptyList());
+        ShardingSphereTable upperCaseTable = new 
ShardingSphereTable("FOO_TBL", Collections.emptyList(), 
Collections.emptyList(), Collections.emptyList());
+        ShardingSphereSchema schema = new ShardingSphereSchema("foo_schema", 
postgreSQLDatabaseType, Arrays.asList(lowerCaseTable, upperCaseTable), 
Collections.emptyList());
+        Map<IdentifierScope, IdentifierCaseRule> scopedRules = new 
EnumMap<>(IdentifierScope.class);
+        scopedRules.put(IdentifierScope.LOGICAL_TABLE, 
IdentifierCaseRuleSets.newLowerCaseRuleSet().getRule(IdentifierScope.TABLE));
+        DatabaseIdentifierContext context = new DatabaseIdentifierContext(new 
IdentifierCaseRuleSet(IdentifierCaseRuleSets.newUpperCaseRuleSet().getRule(IdentifierScope.TABLE),
 scopedRules), true);
+        schema.refreshIdentifierContext(context);
+        assertThat(schema.getTable("FOO_TBL"), is(upperCaseTable));
+    }
 }
diff --git 
a/infra/common/src/test/java/org/apache/shardingsphere/infra/metadata/identifier/DatabaseIdentifierContextFactoryTest.java
 
b/infra/common/src/test/java/org/apache/shardingsphere/infra/metadata/identifier/DatabaseIdentifierContextFactoryTest.java
index 012e2276784..7cc724c5670 100644
--- 
a/infra/common/src/test/java/org/apache/shardingsphere/infra/metadata/identifier/DatabaseIdentifierContextFactoryTest.java
+++ 
b/infra/common/src/test/java/org/apache/shardingsphere/infra/metadata/identifier/DatabaseIdentifierContextFactoryTest.java
@@ -57,6 +57,7 @@ import java.util.logging.Logger;
 
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.is;
+import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
 class DatabaseIdentifierContextFactoryTest {
@@ -81,6 +82,12 @@ class DatabaseIdentifierContextFactoryTest {
     
     private static final ResourceMetaData ORACLE_RESOURCE_META_DATA = 
createResourceMetaDataWithStorageUrls("jdbc:oracle:thin:@localhost:1521:xe");
     
+    private static final ResourceMetaData 
MYSQL_ORACLE_MIXED_RESOURCE_META_DATA = createResourceMetaDataWithStorageUrls(
+            "jdbc:mysql://localhost:3306/foo_db", 
"jdbc:oracle:thin:@localhost:1521:xe");
+    
+    private static final ResourceMetaData 
ORACLE_MYSQL_MIXED_RESOURCE_META_DATA = createResourceMetaDataWithStorageUrls(
+            "jdbc:oracle:thin:@localhost:1521:xe", 
"jdbc:mysql://localhost:3306/foo_db");
+    
     @Test
     void assertCreateDefault() {
         DatabaseIdentifierContext actual = 
DatabaseIdentifierContextFactory.createDefault();
@@ -152,6 +159,63 @@ class DatabaseIdentifierContextFactoryTest {
         assertTrue(actualTableRule.matches("T_ORDER", "t_order", 
QuoteCharacter.NONE));
     }
     
+    @Test
+    void 
assertCreateUsesProtocolRuleForLogicalTableAndEnablesHeterogeneousLookup() {
+        DatabaseIdentifierContext actual = 
DatabaseIdentifierContextFactory.create(MYSQL_DATABASE_TYPE, 
ORACLE_RESOURCE_META_DATA, new ConfigurationProperties(new Properties()));
+        IdentifierCaseRule actualLogicalTableRule = 
actual.getRule(IdentifierScope.LOGICAL_TABLE);
+        IdentifierCaseRule actualTableRule = 
actual.getRule(IdentifierScope.TABLE);
+        assertTrue(actual.isHeterogeneousTableLookupEnabled());
+        assertTrue(actualLogicalTableRule.matches("t_order", "T_ORDER", 
QuoteCharacter.NONE));
+        assertTrue(actualTableRule.matches("T_ORDER", "t_order", 
QuoteCharacter.NONE));
+    }
+    
+    @Test
+    void 
assertRefreshUsesProtocolRuleForLogicalTableAndEnablesHeterogeneousLookup() {
+        DatabaseIdentifierContext actual = 
DatabaseIdentifierContextFactory.createDefault();
+        DatabaseIdentifierContextFactory.refresh(actual, MYSQL_DATABASE_TYPE, 
ORACLE_RESOURCE_META_DATA, new ConfigurationProperties(new Properties()));
+        IdentifierCaseRule actualLogicalTableRule = 
actual.getRule(IdentifierScope.LOGICAL_TABLE);
+        IdentifierCaseRule actualTableRule = 
actual.getRule(IdentifierScope.TABLE);
+        assertTrue(actual.isHeterogeneousTableLookupEnabled());
+        assertTrue(actualLogicalTableRule.matches("t_order", "T_ORDER", 
QuoteCharacter.NONE));
+        assertTrue(actualTableRule.matches("T_ORDER", "t_order", 
QuoteCharacter.NONE));
+    }
+    
+    @Test
+    void 
assertCreateDisablesHeterogeneousLookupWhenProtocolAndStorageAreHomogeneous() {
+        DatabaseIdentifierContext actual = 
DatabaseIdentifierContextFactory.create(MYSQL_DATABASE_TYPE, 
MYSQL_INSENSITIVE_RESOURCE_META_DATA, new ConfigurationProperties(new 
Properties()));
+        assertFalse(actual.isHeterogeneousTableLookupEnabled());
+    }
+    
+    @Test
+    void 
assertRefreshDisablesHeterogeneousLookupWhenProtocolAndStorageAreHomogeneous() {
+        DatabaseIdentifierContext actual = 
DatabaseIdentifierContextFactory.createDefault();
+        DatabaseIdentifierContextFactory.refresh(actual, MYSQL_DATABASE_TYPE, 
MYSQL_INSENSITIVE_RESOURCE_META_DATA, new ConfigurationProperties(new 
Properties()));
+        assertFalse(actual.isHeterogeneousTableLookupEnabled());
+    }
+    
+    @Test
+    void 
assertCreateEnablesHeterogeneousLookupWhenAnyStorageTypeDiffersFromProtocolEvenIfFirstMatches()
 {
+        DatabaseIdentifierContext actual = 
DatabaseIdentifierContextFactory.create(MYSQL_DATABASE_TYPE, 
MYSQL_ORACLE_MIXED_RESOURCE_META_DATA, new ConfigurationProperties(new 
Properties()));
+        assertTrue(actual.isHeterogeneousTableLookupEnabled());
+    }
+    
+    @Test
+    void 
assertRefreshEnablesHeterogeneousLookupWhenAnyStorageTypeDiffersFromProtocolEvenIfFirstMatches()
 {
+        DatabaseIdentifierContext actual = 
DatabaseIdentifierContextFactory.createDefault();
+        DatabaseIdentifierContextFactory.refresh(actual, MYSQL_DATABASE_TYPE, 
MYSQL_ORACLE_MIXED_RESOURCE_META_DATA, new ConfigurationProperties(new 
Properties()));
+        assertTrue(actual.isHeterogeneousTableLookupEnabled());
+    }
+    
+    @Test
+    void 
assertCreateEnablesHeterogeneousLookupRegardlessOfStorageUnitIterationOrder() {
+        DatabaseIdentifierContext mysqlFirstActual = 
DatabaseIdentifierContextFactory.create(
+                MYSQL_DATABASE_TYPE, MYSQL_ORACLE_MIXED_RESOURCE_META_DATA, 
new ConfigurationProperties(new Properties()));
+        DatabaseIdentifierContext oracleFirstActual = 
DatabaseIdentifierContextFactory.create(
+                MYSQL_DATABASE_TYPE, ORACLE_MYSQL_MIXED_RESOURCE_META_DATA, 
new ConfigurationProperties(new Properties()));
+        assertTrue(mysqlFirstActual.isHeterogeneousTableLookupEnabled());
+        assertTrue(oracleFirstActual.isHeterogeneousTableLookupEnabled());
+    }
+    
     @Test
     void assertCreateUsesInsensitiveRuleForDatabaseScope() {
         DatabaseIdentifierContext actual = 
DatabaseIdentifierContextFactory.create(ORACLE_DATABASE_TYPE,

Reply via email to