From 940540af1d0332012863fec2b02cd6d462d411ee Mon Sep 17 00:00:00 2001 From: Liang Zhang Date: Mon, 18 Nov 2024 20:16:43 +0800 Subject: [PATCH] Add more test cases on ShardingSQLFederationDecider (#33712) --- .../decider/ShardingSQLFederationDecider.java | 11 +- .../sharding/rule/ShardingRule.java | 1 + .../ShardingSQLFederationDeciderTest.java | 200 ++++++++++-------- 3 files changed, 119 insertions(+), 93 deletions(-) diff --git a/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/decider/ShardingSQLFederationDecider.java b/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/decider/ShardingSQLFederationDecider.java index 436be74666280..9f7e6ad61268f 100644 --- a/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/decider/ShardingSQLFederationDecider.java +++ b/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/decider/ShardingSQLFederationDecider.java @@ -44,7 +44,7 @@ public boolean decide(final SelectStatementContext selectStatementContext, final if (tableNames.isEmpty()) { return false; } - includedDataNodes.addAll(getTableDataNodes(rule, tableNames, database)); + includedDataNodes.addAll(getTableDataNodes(rule, database, tableNames)); if (selectStatementContext.isContainsSubquery() || selectStatementContext.isContainsHaving() || selectStatementContext.isContainsCombine() || selectStatementContext.isContainsPartialDistinctAggregation()) { return true; @@ -52,13 +52,18 @@ public boolean decide(final SelectStatementContext selectStatementContext, final if (!selectStatementContext.isContainsJoinQuery() || rule.isAllTablesInSameDataSource(tableNames)) { return false; } - if (1 == tableNames.size() && selectStatementContext.isContainsJoinQuery() && !rule.isAllBindingTables(database, selectStatementContext, tableNames)) { + if (isSelfJoinWithoutShardingColumn(selectStatementContext, rule, database, tableNames)) { return true; } return tableNames.size() > 1 && !rule.isAllBindingTables(database, selectStatementContext, tableNames); } - private Collection getTableDataNodes(final ShardingRule rule, final Collection tableNames, final ShardingSphereDatabase database) { + private boolean isSelfJoinWithoutShardingColumn(final SelectStatementContext selectStatementContext, + final ShardingRule rule, final ShardingSphereDatabase database, final Collection tableNames) { + return 1 == tableNames.size() && selectStatementContext.isContainsJoinQuery() && !rule.isAllBindingTables(database, selectStatementContext, tableNames); + } + + private Collection getTableDataNodes(final ShardingRule rule, final ShardingSphereDatabase database, final Collection tableNames) { Collection result = new HashSet<>(); for (String each : tableNames) { rule.findShardingTable(each).ifPresent(optional -> result.addAll(new DataNodes(database.getRuleMetaData().getRules()).getDataNodes(each))); diff --git a/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/rule/ShardingRule.java b/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/rule/ShardingRule.java index ffeb6588265a1..bc2160bd4c507 100644 --- a/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/rule/ShardingRule.java +++ b/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/rule/ShardingRule.java @@ -338,6 +338,7 @@ public boolean isAllBindingTables(final Collection logicTableNames) { * @param logicTableNames logic table names * @return whether logic table is all binding tables */ + // TODO rename the method name, add sharding condition judgement in method name @duanzhengqiang public boolean isAllBindingTables(final ShardingSphereDatabase database, final SQLStatementContext sqlStatementContext, final Collection logicTableNames) { if (!(sqlStatementContext instanceof SelectStatementContext && ((SelectStatementContext) sqlStatementContext).isContainsJoinQuery())) { return isAllBindingTables(logicTableNames); diff --git a/features/sharding/core/src/test/java/org/apache/shardingsphere/sharding/decider/ShardingSQLFederationDeciderTest.java b/features/sharding/core/src/test/java/org/apache/shardingsphere/sharding/decider/ShardingSQLFederationDeciderTest.java index 81b63babb01c7..2cd9d471b2faf 100644 --- a/features/sharding/core/src/test/java/org/apache/shardingsphere/sharding/decider/ShardingSQLFederationDeciderTest.java +++ b/features/sharding/core/src/test/java/org/apache/shardingsphere/sharding/decider/ShardingSQLFederationDeciderTest.java @@ -18,16 +18,19 @@ package org.apache.shardingsphere.sharding.decider; import org.apache.shardingsphere.infra.binder.context.statement.dml.SelectStatementContext; -import org.apache.shardingsphere.infra.database.core.DefaultDatabase; import org.apache.shardingsphere.infra.database.core.type.DatabaseType; import org.apache.shardingsphere.infra.datanode.DataNode; import org.apache.shardingsphere.infra.metadata.database.ShardingSphereDatabase; import org.apache.shardingsphere.infra.metadata.database.rule.RuleMetaData; +import org.apache.shardingsphere.infra.rule.attribute.RuleAttributes; import org.apache.shardingsphere.infra.rule.attribute.datanode.DataNodeRuleAttribute; +import org.apache.shardingsphere.infra.spi.type.ordered.OrderedSPILoader; import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader; import org.apache.shardingsphere.sharding.rule.BindingTableRule; import org.apache.shardingsphere.sharding.rule.ShardingRule; import org.apache.shardingsphere.sharding.rule.ShardingTable; +import org.apache.shardingsphere.sqlfederation.spi.SQLFederationDecider; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import java.util.Arrays; @@ -46,158 +49,175 @@ class ShardingSQLFederationDeciderTest { + private ShardingSQLFederationDecider decider; + + @BeforeEach + void setUp() { + decider = (ShardingSQLFederationDecider) OrderedSPILoader.getServicesByClass(SQLFederationDecider.class, Collections.singleton(ShardingRule.class)).get(ShardingRule.class); + } + @Test - void assertDecideWhenNotContainsShardingTable() { + void assertDecideWithoutShardingTable() { ShardingRule rule = mock(ShardingRule.class); - when(rule.getShardingLogicTableNames(Arrays.asList("t_order", "t_order_item"))).thenReturn(Collections.emptyList()); - when(rule.findShardingTable("t_order")).thenReturn(Optional.of(mock(ShardingTable.class))); - when(rule.findShardingTable("t_order_item")).thenReturn(Optional.of(mock(ShardingTable.class))); + when(rule.getShardingLogicTableNames(Arrays.asList("foo_tbl", "bar_tbl"))).thenReturn(Collections.emptyList()); + when(rule.findShardingTable("foo_tbl")).thenReturn(Optional.of(mock(ShardingTable.class))); + when(rule.findShardingTable("bar_tbl")).thenReturn(Optional.of(mock(ShardingTable.class))); Collection includedDataNodes = new HashSet<>(); - assertFalse(new ShardingSQLFederationDecider().decide( - createStatementContext(), Collections.emptyList(), mock(RuleMetaData.class), mock(ShardingSphereDatabase.class), rule, includedDataNodes)); + assertFalse(decider.decide(createSQLStatementContext(), Collections.emptyList(), mock(RuleMetaData.class), mock(ShardingSphereDatabase.class), rule, includedDataNodes)); assertTrue(includedDataNodes.isEmpty()); } @Test - void assertDecideWhenContainsSameShardingCondition() { - SelectStatementContext select = createStatementContext(); - when(select.isContainsSubquery()).thenReturn(true); + void assertDecideWithSubquery() { + SelectStatementContext sqlStatementContext = createSQLStatementContext(); + when(sqlStatementContext.isContainsSubquery()).thenReturn(true); Collection includedDataNodes = new HashSet<>(); - ShardingRule shardingRule = createShardingRule(); - assertTrue(new ShardingSQLFederationDecider().decide(select, Collections.emptyList(), mock(RuleMetaData.class), createDatabase(shardingRule), shardingRule, includedDataNodes)); + ShardingRule rule = createShardingRule(); + assertTrue(decider.decide(sqlStatementContext, Collections.emptyList(), mock(RuleMetaData.class), createDatabase(rule), rule, includedDataNodes)); assertThat(includedDataNodes.size(), is(4)); } @Test - void assertDecideWhenContainsSubquery() { - SelectStatementContext select = createStatementContext(); - when(select.isContainsSubquery()).thenReturn(true); + void assertDecideWithHaving() { + SelectStatementContext sqlStatementContext = createSQLStatementContext(); + when(sqlStatementContext.isContainsHaving()).thenReturn(true); Collection includedDataNodes = new HashSet<>(); - ShardingRule shardingRule = createShardingRule(); - assertTrue(new ShardingSQLFederationDecider().decide(select, Collections.emptyList(), mock(RuleMetaData.class), createDatabase(shardingRule), shardingRule, includedDataNodes)); + ShardingRule rule = createShardingRule(); + assertTrue(decider.decide(sqlStatementContext, Collections.emptyList(), mock(RuleMetaData.class), createDatabase(rule), rule, includedDataNodes)); assertThat(includedDataNodes.size(), is(4)); } @Test - void assertDecideWhenContainsHaving() { - SelectStatementContext select = createStatementContext(); - when(select.isContainsHaving()).thenReturn(true); + void assertDecideWithCombine() { + SelectStatementContext sqlStatementContext = createSQLStatementContext(); + when(sqlStatementContext.isContainsCombine()).thenReturn(true); Collection includedDataNodes = new HashSet<>(); - ShardingRule shardingRule = createShardingRule(); - assertTrue(new ShardingSQLFederationDecider().decide(select, Collections.emptyList(), mock(RuleMetaData.class), createDatabase(shardingRule), shardingRule, includedDataNodes)); + ShardingRule rule = createShardingRule(); + assertTrue(decider.decide(sqlStatementContext, Collections.emptyList(), mock(RuleMetaData.class), createDatabase(rule), rule, includedDataNodes)); assertThat(includedDataNodes.size(), is(4)); } @Test - void assertDecideWhenContainsCombine() { - SelectStatementContext select = createStatementContext(); - when(select.isContainsCombine()).thenReturn(true); + void assertDecideWithPartialDistinctAggregation() { + SelectStatementContext sqlStatementContext = createSQLStatementContext(); + when(sqlStatementContext.isContainsPartialDistinctAggregation()).thenReturn(true); Collection includedDataNodes = new HashSet<>(); - ShardingRule shardingRule = createShardingRule(); - assertTrue(new ShardingSQLFederationDecider().decide(select, Collections.emptyList(), mock(RuleMetaData.class), createDatabase(shardingRule), shardingRule, includedDataNodes)); + ShardingRule rule = createShardingRule(); + assertTrue(decider.decide(sqlStatementContext, Collections.emptyList(), mock(RuleMetaData.class), createDatabase(rule), rule, includedDataNodes)); assertThat(includedDataNodes.size(), is(4)); } @Test - void assertDecideWhenContainsPartialDistinctAggregation() { - SelectStatementContext select = createStatementContext(); - when(select.isContainsPartialDistinctAggregation()).thenReturn(true); + void assertDecideWithoutJoinQuery() { + SelectStatementContext sqlStatementContext = createSQLStatementContext(); + ShardingRule rule = createShardingRule(); Collection includedDataNodes = new HashSet<>(); - ShardingRule shardingRule = createShardingRule(); - assertTrue(new ShardingSQLFederationDecider().decide(select, Collections.emptyList(), mock(RuleMetaData.class), createDatabase(shardingRule), shardingRule, includedDataNodes)); + assertFalse(decider.decide(sqlStatementContext, Collections.emptyList(), mock(RuleMetaData.class), createDatabase(rule), rule, includedDataNodes)); assertThat(includedDataNodes.size(), is(4)); } @Test - void assertDecideWhenAllTablesInSameDataSource() { - SelectStatementContext select = createStatementContext(); - when(select.isContainsJoinQuery()).thenReturn(true); - ShardingRule shardingRule = createShardingRule(); - when(shardingRule.isAllTablesInSameDataSource(Arrays.asList("t_order", "t_order_item"))).thenReturn(true); + void assertDecideWithAllTablesInSameDataSource() { + SelectStatementContext sqlStatementContext = createSQLStatementContext(); + when(sqlStatementContext.isContainsJoinQuery()).thenReturn(true); + ShardingRule rule = createShardingRule(); + ShardingSphereDatabase database = createDatabase(rule); + when(rule.isAllTablesInSameDataSource(Arrays.asList("foo_tbl", "bar_tbl"))).thenReturn(true); Collection includedDataNodes = new HashSet<>(); - assertFalse(new ShardingSQLFederationDecider().decide(select, Collections.emptyList(), mock(RuleMetaData.class), createDatabase(shardingRule), shardingRule, includedDataNodes)); + assertFalse(decider.decide(sqlStatementContext, Collections.emptyList(), mock(RuleMetaData.class), database, rule, includedDataNodes)); assertThat(includedDataNodes.size(), is(4)); } @Test - void assertDecideWhenAllTablesIsBindingTables() { - SelectStatementContext select = createStatementContext(); - when(select.isContainsJoinQuery()).thenReturn(true); - ShardingRule shardingRule = createShardingRule(); - ShardingSphereDatabase database = createDatabase(shardingRule); - when(shardingRule.isAllBindingTables(database, select, Arrays.asList("t_order", "t_order_item"))).thenReturn(true); + void assertDecideWithSelfJoinWithoutShardingColumn() { + SelectStatementContext sqlStatementContext = createSQLStatementContext(); + when(sqlStatementContext.getTablesContext().getTableNames()).thenReturn(Collections.singleton("foo_tbl")); + when(sqlStatementContext.isContainsJoinQuery()).thenReturn(true); + ShardingRule rule = createShardingRule(); + when(rule.getShardingLogicTableNames(Collections.singleton("foo_tbl"))).thenReturn(Collections.singleton("foo_tbl")); + ShardingSphereDatabase database = createDatabase(rule); Collection includedDataNodes = new HashSet<>(); - assertFalse(new ShardingSQLFederationDecider().decide(select, Collections.emptyList(), mock(RuleMetaData.class), database, shardingRule, includedDataNodes)); - assertThat(includedDataNodes.size(), is(4)); + assertTrue(decider.decide(sqlStatementContext, Collections.emptyList(), mock(RuleMetaData.class), database, rule, includedDataNodes)); + assertThat(includedDataNodes.size(), is(2)); } @Test - void assertDecideWhenAllTablesIsNotBindingTables() { - SelectStatementContext select = createStatementContext(); - when(select.isContainsJoinQuery()).thenReturn(true); - ShardingRule shardingRule = createShardingRule(); - ShardingSphereDatabase database = createDatabase(shardingRule); - when(shardingRule.isAllBindingTables(database, select, Arrays.asList("t_order", "t_order_item"))).thenReturn(false); + void assertDecideWithNotSelfJoin() { + SelectStatementContext sqlStatementContext = createSQLStatementContext(); + when(sqlStatementContext.getTablesContext().getTableNames()).thenReturn(Collections.singleton("foo_tbl")); + ShardingRule rule = createShardingRule(); + when(rule.getShardingLogicTableNames(Collections.singleton("foo_tbl"))).thenReturn(Collections.singleton("foo_tbl")); + ShardingSphereDatabase database = createDatabase(rule); Collection includedDataNodes = new HashSet<>(); - assertTrue(new ShardingSQLFederationDecider().decide(select, Collections.emptyList(), mock(RuleMetaData.class), database, shardingRule, includedDataNodes)); - assertThat(includedDataNodes.size(), is(4)); + assertFalse(decider.decide(sqlStatementContext, Collections.emptyList(), mock(RuleMetaData.class), database, rule, includedDataNodes)); + assertThat(includedDataNodes.size(), is(2)); } @Test - void assertDecideWhenContainsOnlyOneTable() { - SelectStatementContext select = createStatementContext(); - when(select.getTablesContext().getTableNames()).thenReturn(Collections.singletonList("t_order")); - when(select.isContainsJoinQuery()).thenReturn(true); - ShardingRule shardingRule = createShardingRule(); - when(shardingRule.getShardingLogicTableNames(Collections.singletonList("t_order"))).thenReturn(Collections.singletonList("t_order")); - ShardingSphereDatabase database = createDatabase(shardingRule); - when(shardingRule.isAllBindingTables(database, select, Collections.singletonList("t_order"))).thenReturn(false); + void assertDecideWithSelfJoinAndShardingColumn() { + SelectStatementContext sqlStatementContext = createSQLStatementContext(); + when(sqlStatementContext.getTablesContext().getTableNames()).thenReturn(Collections.singleton("foo_tbl")); + when(sqlStatementContext.isContainsJoinQuery()).thenReturn(true); + ShardingRule rule = createShardingRule(); + when(rule.getShardingLogicTableNames(Collections.singleton("foo_tbl"))).thenReturn(Collections.singleton("foo_tbl")); + ShardingSphereDatabase database = createDatabase(rule); + when(rule.isAllBindingTables(database, sqlStatementContext, Collections.singleton("foo_tbl"))).thenReturn(true); Collection includedDataNodes = new HashSet<>(); - assertTrue(new ShardingSQLFederationDecider().decide(select, Collections.emptyList(), mock(RuleMetaData.class), database, shardingRule, includedDataNodes)); + assertFalse(decider.decide(sqlStatementContext, Collections.emptyList(), mock(RuleMetaData.class), database, rule, includedDataNodes)); assertThat(includedDataNodes.size(), is(2)); } @Test - void assertDecideWhenAllTablesIsNotBindingTablesAndContainsPagination() { - SelectStatementContext select = createStatementContext(); - when(select.isContainsJoinQuery()).thenReturn(true); - when(select.getPaginationContext().isHasPagination()).thenReturn(true); - ShardingRule shardingRule = createShardingRule(); - ShardingSphereDatabase database = createDatabase(shardingRule); - when(shardingRule.isAllBindingTables(database, select, Arrays.asList("t_order", "t_order_item"))).thenReturn(false); + void assertDecideWithAllBindingTables() { + SelectStatementContext sqlStatementContext = createSQLStatementContext(); + when(sqlStatementContext.isContainsJoinQuery()).thenReturn(true); + ShardingRule rule = createShardingRule(); + ShardingSphereDatabase database = createDatabase(rule); + when(rule.isAllBindingTables(database, sqlStatementContext, Arrays.asList("foo_tbl", "bar_tbl"))).thenReturn(true); Collection includedDataNodes = new HashSet<>(); - assertTrue(new ShardingSQLFederationDecider().decide(select, Collections.emptyList(), mock(RuleMetaData.class), database, shardingRule, includedDataNodes)); + assertFalse(decider.decide(sqlStatementContext, Collections.emptyList(), mock(RuleMetaData.class), database, rule, includedDataNodes)); assertThat(includedDataNodes.size(), is(4)); } - private SelectStatementContext createStatementContext() { - SelectStatementContext result = mock(SelectStatementContext.class, RETURNS_DEEP_STUBS); - when(result.getTablesContext().getTableNames()).thenReturn(Arrays.asList("t_order", "t_order_item")); - when(result.getDatabaseType()).thenReturn(TypedSPILoader.getService(DatabaseType.class, "FIXTURE")); - return result; + @Test + void assertDecideWithNotAllBindingTables() { + SelectStatementContext sqlStatementContext = createSQLStatementContext(); + when(sqlStatementContext.isContainsJoinQuery()).thenReturn(true); + ShardingRule rule = createShardingRule(); + ShardingSphereDatabase database = createDatabase(rule); + Collection includedDataNodes = new HashSet<>(); + assertTrue(decider.decide(sqlStatementContext, Collections.emptyList(), mock(RuleMetaData.class), database, rule, includedDataNodes)); + assertThat(includedDataNodes.size(), is(4)); } - private ShardingSphereDatabase createDatabase(final ShardingRule shardingRule) { - ShardingSphereDatabase result = mock(ShardingSphereDatabase.class, RETURNS_DEEP_STUBS); - when(result.getName()).thenReturn(DefaultDatabase.LOGIC_NAME); - when(result.getRuleMetaData().getRules()).thenReturn(Collections.singletonList(shardingRule)); + private SelectStatementContext createSQLStatementContext() { + SelectStatementContext result = mock(SelectStatementContext.class, RETURNS_DEEP_STUBS); + when(result.getTablesContext().getTableNames()).thenReturn(Arrays.asList("foo_tbl", "bar_tbl")); + when(result.getDatabaseType()).thenReturn(TypedSPILoader.getService(DatabaseType.class, "FIXTURE")); return result; } private ShardingRule createShardingRule() { ShardingRule result = mock(ShardingRule.class, RETURNS_DEEP_STUBS); - when(result.getShardingLogicTableNames(Arrays.asList("t_order", "t_order_item"))).thenReturn(Arrays.asList("t_order", "t_order_item")); + when(result.getShardingLogicTableNames(Arrays.asList("foo_tbl", "bar_tbl"))).thenReturn(Arrays.asList("foo_tbl", "bar_tbl")); DataNodeRuleAttribute dataNodeRuleAttribute = mock(DataNodeRuleAttribute.class); - when(result.getAttributes().findAttribute(DataNodeRuleAttribute.class)).thenReturn(Optional.of(dataNodeRuleAttribute)); - when(dataNodeRuleAttribute.getDataNodesByTableName("t_order")).thenReturn(Arrays.asList(new DataNode("ds_0", "t_order"), new DataNode("ds_1", "t_order"))); - when(dataNodeRuleAttribute.getDataNodesByTableName("t_order_item")).thenReturn(Arrays.asList(new DataNode("ds_0", "t_order_item"), new DataNode("ds_1", "t_order_item"))); - when(result.findShardingTable("t_order")).thenReturn(Optional.of(mock(ShardingTable.class))); - when(result.findShardingTable("t_order_item")).thenReturn(Optional.of(mock(ShardingTable.class))); + when(dataNodeRuleAttribute.getDataNodesByTableName("foo_tbl")).thenReturn(Arrays.asList(new DataNode("ds_0", "foo_tbl"), new DataNode("ds_1", "foo_tbl"))); + when(dataNodeRuleAttribute.getDataNodesByTableName("bar_tbl")).thenReturn(Arrays.asList(new DataNode("ds_0", "bar_tbl"), new DataNode("ds_1", "bar_tbl"))); + when(result.getAttributes()).thenReturn(new RuleAttributes(dataNodeRuleAttribute)); + when(result.findShardingTable("foo_tbl")).thenReturn(Optional.of(mock(ShardingTable.class))); + when(result.findShardingTable("bar_tbl")).thenReturn(Optional.of(mock(ShardingTable.class))); BindingTableRule bindingTableRule = mock(BindingTableRule.class); - when(bindingTableRule.hasLogicTable("t_order")).thenReturn(true); - when(bindingTableRule.hasLogicTable("t_order_item")).thenReturn(true); - when(result.findBindingTableRule("t_order")).thenReturn(Optional.of(bindingTableRule)); - when(result.findBindingTableRule("t_order_item")).thenReturn(Optional.of(bindingTableRule)); + when(bindingTableRule.hasLogicTable("foo_tbl")).thenReturn(true); + when(bindingTableRule.hasLogicTable("bar_tbl")).thenReturn(true); + when(result.findBindingTableRule("foo_tbl")).thenReturn(Optional.of(bindingTableRule)); + when(result.findBindingTableRule("bar_tbl")).thenReturn(Optional.of(bindingTableRule)); + return result; + } + + private ShardingSphereDatabase createDatabase(final ShardingRule rule) { + ShardingSphereDatabase result = mock(ShardingSphereDatabase.class, RETURNS_DEEP_STUBS); + when(result.getName()).thenReturn("foo_db"); + when(result.getRuleMetaData()).thenReturn(new RuleMetaData(Collections.singleton(rule))); return result; } }