You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@shardingsphere.apache.org by pa...@apache.org on 2021/08/03 09:50:03 UTC

[shardingsphere] branch master updated: Add unit test for the optimizer. (#11130)

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

panjuan 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 37b7fd2  Add unit test for the optimizer. (#11130)
37b7fd2 is described below

commit 37b7fd2357a955c1742d055968fe6be9a80a447c
Author: coco <co...@gmail.com>
AuthorDate: Tue Aug 3 17:49:39 2021 +0800

    Add unit test for the optimizer. (#11130)
    
    * test: add test for optimizer.
    
    * test: add local schema and table for unit test in optimize package.
    
    * fix: bugs in join table sql node converter.
    
    * style: modify code style.
    
    * style: modify code style.
    
    * style: add license in .csv file.
    
    * fix: remove the final \n in the result of the explain.
    
    * fix: remove .gz and .json file type.
    
    * fix: bugs in unit test. When execute explain() in windows env, the result doesn't contain '\n'.
    
    * fix: bugs in unit test. When execute explain() in windows env, the result doesn't contain '\n'.
    
    * test: add unit test for optimization.
    
    * fix: bugs in initializing table meta data.
    
    * chore: delete useless dependency.
    
    * fix: bugs in initializing table meta data.
    
    * test: remove useless class.
    
    * test: remove unneccessory classes.
    
    * test: modify the way of initializing database sources.
    
    * test: modify the scope of parser.
    
    * test: modify the scope of parser.
    
    * test: remove useless sentence in sql.
---
 .../shardingsphere-infra-executor/pom.xml          |  11 ++
 .../sql/federate/FederateJDBCExecutorTest.java     | 192 +++++++++++++++++++++
 ...ere.sql.parser.spi.DatabaseTypedSQLParserFacade |  18 ++
 .../src/test/resources/sql/federate_data.sql       |  27 +++
 .../converter/impl/JoinTableSqlNodeConverter.java  |   4 +-
 5 files changed, 250 insertions(+), 2 deletions(-)

diff --git a/shardingsphere-infra/shardingsphere-infra-executor/pom.xml b/shardingsphere-infra/shardingsphere-infra-executor/pom.xml
index 21f6560..1185097 100644
--- a/shardingsphere-infra/shardingsphere-infra-executor/pom.xml
+++ b/shardingsphere-infra/shardingsphere-infra-executor/pom.xml
@@ -48,5 +48,16 @@
             <groupId>org.apache.calcite</groupId>
             <artifactId>calcite-core</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.apache.shardingsphere</groupId>
+            <artifactId>shardingsphere-sql-parser-mysql</artifactId>
+            <version>${project.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.h2database</groupId>
+            <artifactId>h2</artifactId>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 </project>
diff --git a/shardingsphere-infra/shardingsphere-infra-executor/src/test/java/org/apache/shardingsphere/infra/executor/sql/federate/FederateJDBCExecutorTest.java b/shardingsphere-infra/shardingsphere-infra-executor/src/test/java/org/apache/shardingsphere/infra/executor/sql/federate/FederateJDBCExecutorTest.java
new file mode 100644
index 0000000..e141b51
--- /dev/null
+++ b/shardingsphere-infra/shardingsphere-infra-executor/src/test/java/org/apache/shardingsphere/infra/executor/sql/federate/FederateJDBCExecutorTest.java
@@ -0,0 +1,192 @@
+/*
+ * 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.infra.executor.sql.federate;
+
+import org.apache.calcite.rel.RelNode;
+import org.apache.commons.dbcp2.BasicDataSource;
+import org.apache.shardingsphere.infra.config.DatabaseAccessConfiguration;
+import org.apache.shardingsphere.infra.config.RuleConfiguration;
+import org.apache.shardingsphere.infra.database.type.dialect.H2DatabaseType;
+import org.apache.shardingsphere.infra.database.type.dialect.MySQLDatabaseType;
+import org.apache.shardingsphere.infra.executor.sql.federate.schema.FederateLogicSchema;
+import org.apache.shardingsphere.infra.metadata.ShardingSphereMetaData;
+import org.apache.shardingsphere.infra.metadata.resource.DataSourcesMetaData;
+import org.apache.shardingsphere.infra.metadata.resource.ShardingSphereResource;
+import org.apache.shardingsphere.infra.metadata.rule.ShardingSphereRuleMetaData;
+import org.apache.shardingsphere.infra.metadata.schema.ShardingSphereSchema;
+import org.apache.shardingsphere.infra.metadata.schema.builder.loader.dialect.H2TableMetaDataLoader;
+import org.apache.shardingsphere.infra.metadata.schema.model.ColumnMetaData;
+import org.apache.shardingsphere.infra.metadata.schema.model.IndexMetaData;
+import org.apache.shardingsphere.infra.metadata.schema.model.TableMetaData;
+import org.apache.shardingsphere.infra.optimize.ShardingSphereOptimizer;
+import org.apache.shardingsphere.infra.optimize.context.OptimizeContext;
+import org.apache.shardingsphere.infra.optimize.context.OptimizeContextFactory;
+import org.apache.shardingsphere.infra.optimize.core.metadata.FederateSchemaMetadata;
+import org.apache.shardingsphere.infra.rule.ShardingSphereRule;
+import org.apache.shardingsphere.infra.rule.builder.ShardingSphereRulesBuilder;
+
+import javax.sql.DataSource;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.junit.Assert.assertEquals;
+
+@RunWith(MockitoJUnitRunner.class)
+public final class FederateJDBCExecutorTest {
+    
+    private static final String SELECT_SQL_BY_ID_ACROSS_SINGLE_AND_SHARDING_TABLES =
+        "SELECT t_order_federate.order_id, t_order_federate.user_id, t_user_info.information "
+            + "FROM t_order_federate , t_user_info "
+            + "WHERE t_order_federate.user_id = t_user_info.user_id";
+    
+    private ShardingSphereOptimizer optimizer;
+    
+    @Mock
+    private RuleConfiguration testRuleConfiguration;
+    
+    @Before
+    public void init() throws Exception {
+        String schemaName = "federate_jdbc";
+        Map<String, List<String>> columnMap = initializeColumnMap();
+        Map<String, List<String>> tableMap = initializeTableMap();
+        Map<String, DataSource> actualDataSourceMap = initializeDataSourceMap(schemaName);
+        OptimizeContextFactory optimizeContextFactory = initializeOptimizeContextFactory(schemaName, tableMap, actualDataSourceMap);
+        FederateLogicSchema calciteSchema = initializeCalciteSchema(schemaName, columnMap, tableMap);
+        OptimizeContext context = optimizeContextFactory.create(schemaName, calciteSchema);
+        optimizer = new ShardingSphereOptimizer(context);
+    }
+    
+    @Test
+    public void testSimpleSelect() {
+        RelNode relNode = optimizer.optimize(SELECT_SQL_BY_ID_ACROSS_SINGLE_AND_SHARDING_TABLES);
+        String temp = "EnumerableCalc(expr#0..4=[{inputs}],proj#0..1=[{exprs}],information=[$t4])"
+            + "  EnumerableCalc(expr#0..4=[{inputs}],expr#5=[=($t1,$t3)],proj#0..4=[{exprs}],$condition=[$t5])"
+            + "    EnumerableNestedLoopJoin(condition=[true],joinType=[inner])"
+            + "      EnumerableTableScan(table=[[federate_jdbc,t_order_federate]])"
+            + "      EnumerableTableScan(table=[[federate_jdbc,t_user_info]])";
+        String expected = temp.replaceAll("\\s*", "");
+        String actual = relNode.explain().replaceAll("\\s*", "");
+        assertEquals(expected, actual);
+    }
+    
+    private Map<String, List<String>> initializeTableMap() {
+        Map<String, List<String>> result = new HashMap<>();
+        List<String> tableList = new ArrayList<>();
+        tableList.add("t_order_federate");
+        tableList.add("t_user_info");
+        result.put("federate_jdbc", tableList);
+        return result;
+    }
+    
+    private Map<String, List<String>> initializeColumnMap() {
+        final Map<String, List<String>> result = new HashMap<>();
+        List<String> columnList = new ArrayList<>();
+        columnList.add("order_id");
+        columnList.add("user_id");
+        columnList.add("status");
+        result.put("t_order_federate", columnList);
+        List<String> columnList2 = new ArrayList<>();
+        columnList2.add("user_id");
+        columnList2.add("information");
+        result.put("t_user_info", columnList2);
+        return result;
+    }
+    
+    private Map<String, DataSource> initializeDataSourceMap(final String schemaName) {
+        Map<String, DataSource> result = new HashMap<>();
+        result.put(schemaName, buildDataSource(schemaName));
+        return result;
+    }
+    
+    private static DataSource buildDataSource(final String dataSourceName) {
+        BasicDataSource result = new BasicDataSource();
+        result.setDriverClassName("org.h2.Driver");
+        result.setUrl(String.format("jdbc:h2:mem:%s;DATABASE_TO_UPPER=false;MODE=MySQL", dataSourceName));
+        result.setUsername("sa");
+        result.setPassword("");
+        result.setMaxTotal(50);
+        return result;
+    }
+    
+    private FederateLogicSchema initializeCalciteSchema(final String schemaName, final Map<String, List<String>> columnMap, final Map<String, List<String>> tableMap) {
+        FederateSchemaMetadata federateSchemaMetadata = buildSchemaMetaData(schemaName, tableMap.get(schemaName), columnMap);
+        return new FederateLogicSchema(federateSchemaMetadata, null);
+    }
+    
+    private FederateSchemaMetadata buildSchemaMetaData(final String schemaName, final List<String> tableNames, final Map<String, List<String>> tableColumns) {
+        Map<String, TableMetaData> tableMetaDatas = new HashMap<>();
+        for (String table: tableNames) {
+            List<ColumnMetaData> columnMetaDatas = new ArrayList<>();
+            List<IndexMetaData> indexMetaDatas = new ArrayList<>();
+            for (String colunmn: tableColumns.get(table)) {
+                columnMetaDatas.add(new ColumnMetaData(colunmn, 1, false, false, false));
+                indexMetaDatas.add(new IndexMetaData("index"));
+            }
+            TableMetaData tableMetaData = new TableMetaData(table, columnMetaDatas, indexMetaDatas);
+            tableMetaDatas.put(table, tableMetaData);
+        }
+        return new FederateSchemaMetadata(schemaName, tableMetaDatas);
+    }
+    
+    private OptimizeContextFactory initializeOptimizeContextFactory(final String schemaName, final Map<String, List<String>> tableMap, 
+        final Map<String, DataSource> actualDataSourceMap) throws SQLException {
+        DataSource dataSource = actualDataSourceMap.get(schemaName);
+        H2TableMetaDataLoader loader = new H2TableMetaDataLoader();
+        Map<String, TableMetaData> tableMetaDatas = loader.load(dataSource, tableMap.get(schemaName));
+        Collection<RuleConfiguration> ruleConfigurations = Collections.singletonList(testRuleConfiguration);
+        Map<String, String> accessConfiguration = initializeAccessConfiguration();
+        Map<String, ShardingSphereMetaData> shardingSphereMetaDataMap = createMetaDataMap(tableMetaDatas, ruleConfigurations, schemaName, accessConfiguration, actualDataSourceMap);
+        return new OptimizeContextFactory(shardingSphereMetaDataMap);
+    }
+    
+    private Map<String, String> initializeAccessConfiguration() {
+        Map<String, String> result = new HashMap<>();
+        result.put("jdbcUrl", "jdbc:h2:mem:federate_jdbc;DB_CLOSE_DELAY=-1;DATABASE_TO_UPPER=false;MODE=MYSQL");
+        result.put("username", "sa");
+        return result;
+    }
+    
+    private Map<String, ShardingSphereMetaData> createMetaDataMap(final Map<String, TableMetaData> tableMetaDatas, final Collection<RuleConfiguration> ruleConfigurations, 
+        final String schemaName, final Map<String, String> accessConfiguration, final Map<String, DataSource> actualDataSourceMap) {
+        DataSourcesMetaData dataSourcesMetaData = getInstance(schemaName, accessConfiguration);
+        ShardingSphereResource resource = new ShardingSphereResource(actualDataSourceMap, dataSourcesMetaData, null, new MySQLDatabaseType());
+        ShardingSphereSchema schema = new ShardingSphereSchema(tableMetaDatas);
+        Collection<ShardingSphereRule> shardingSphereRules = ShardingSphereRulesBuilder.buildSchemaRules(schemaName, ruleConfigurations, new MySQLDatabaseType(), actualDataSourceMap);
+        ShardingSphereRuleMetaData shardingSphereRuleMetaData = new ShardingSphereRuleMetaData(ruleConfigurations, shardingSphereRules);
+        ShardingSphereMetaData shardingSphereMetaData = new ShardingSphereMetaData(schemaName, resource, shardingSphereRuleMetaData, schema);
+        return Collections.singletonMap("testSchema", shardingSphereMetaData);
+    }
+    
+    private DataSourcesMetaData getInstance(final String schemaName, final Map<String, String> configurationMap) {
+        DatabaseAccessConfiguration configuration = new DatabaseAccessConfiguration(configurationMap.get("jdbcUrl"), configurationMap.get("username"));
+        Map<String, DatabaseAccessConfiguration> accessConfigurationMap = new HashMap<>();
+        accessConfigurationMap.put(schemaName, configuration);
+        return new DataSourcesMetaData(new H2DatabaseType(), accessConfigurationMap);
+    }
+}
diff --git a/shardingsphere-infra/shardingsphere-infra-executor/src/test/resources/META-INF/services/org.apache.shardingsphere.sql.parser.spi.DatabaseTypedSQLParserFacade b/shardingsphere-infra/shardingsphere-infra-executor/src/test/resources/META-INF/services/org.apache.shardingsphere.sql.parser.spi.DatabaseTypedSQLParserFacade
new file mode 100644
index 0000000..4b31740
--- /dev/null
+++ b/shardingsphere-infra/shardingsphere-infra-executor/src/test/resources/META-INF/services/org.apache.shardingsphere.sql.parser.spi.DatabaseTypedSQLParserFacade
@@ -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.sql.parser.mysql.parser.MySQLParserFacade
diff --git a/shardingsphere-infra/shardingsphere-infra-executor/src/test/resources/sql/federate_data.sql b/shardingsphere-infra/shardingsphere-infra-executor/src/test/resources/sql/federate_data.sql
new file mode 100644
index 0000000..716e48a
--- /dev/null
+++ b/shardingsphere-infra/shardingsphere-infra-executor/src/test/resources/sql/federate_data.sql
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+
+DELETE FROM t_order_federate;
+DELETE FROM t_user_info;
+
+INSERT INTO t_order_federate VALUES(1000, 0, 'init');
+INSERT INTO t_order_federate VALUES(1001, 1, 'init');
+
+INSERT INTO t_user_info VALUES(0, 'description0');
+INSERT INTO t_user_info VALUES(1, 'description1');
+INSERT INTO t_user_info VALUES(2, 'description2');
+INSERT INTO t_user_info VALUES(3, 'description3');
diff --git a/shardingsphere-infra/shardingsphere-infra-optimize/src/main/java/org/apache/shardingsphere/infra/optimize/core/convert/converter/impl/JoinTableSqlNodeConverter.java b/shardingsphere-infra/shardingsphere-infra-optimize/src/main/java/org/apache/shardingsphere/infra/optimize/core/convert/converter/impl/JoinTableSqlNodeConverter.java
index 57c7687..3d3077f 100644
--- a/shardingsphere-infra/shardingsphere-infra-optimize/src/main/java/org/apache/shardingsphere/infra/optimize/core/convert/converter/impl/JoinTableSqlNodeConverter.java
+++ b/shardingsphere-infra/shardingsphere-infra-optimize/src/main/java/org/apache/shardingsphere/infra/optimize/core/convert/converter/impl/JoinTableSqlNodeConverter.java
@@ -48,8 +48,8 @@ public final class JoinTableSqlNodeConverter implements SqlNodeConverter<JoinTab
         SqlNode right = new TableSqlNodeConverter().convert(join.getRight()).get();
         ExpressionSegment expressionSegment = join.getCondition();
         Optional<SqlNode> condition = new ExpressionSqlNodeConverter().convert(expressionSegment);
-        SqlLiteral conditionType = condition.isPresent() ? JoinConditionType.NONE.symbol(SqlParserPos.ZERO)
-                : JoinConditionType.ON.symbol(SqlParserPos.ZERO);
+        SqlLiteral conditionType = condition.isPresent() ? JoinConditionType.ON.symbol(SqlParserPos.ZERO)
+                : JoinConditionType.NONE.symbol(SqlParserPos.ZERO);
         SqlLiteral joinTypeSqlNode = convertJoinType(join.getJoinType());
         SqlNode sqlNode = new SqlJoin(SqlParserPos.ZERO, left,
                 SqlLiteral.createBoolean(false, SqlParserPos.ZERO),