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 2022/09/19 05:44:06 UTC

[shardingsphere] branch master updated: Use calcite jdbc ordinal to replace ShardingSphere column metadata in SQLFederationResultSetMetaData (#21042)

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 2be65f55629 Use calcite jdbc ordinal to replace ShardingSphere column metadata in SQLFederationResultSetMetaData (#21042)
2be65f55629 is described below

commit 2be65f556290945b250d2ea3608f8c1568d3ec99
Author: Zhengqiang Duan <du...@apache.org>
AuthorDate: Mon Sep 19 13:43:58 2022 +0800

    Use calcite jdbc ordinal to replace ShardingSphere column metadata in SQLFederationResultSetMetaData (#21042)
    
    * Use calcite jdbc ordinal to replace ShardingSphere column metadata in SQLFederationResultSetMetaData
    
    * refactor logic
    
    * refactor logic
---
 .../advanced/AdvancedSQLFederationExecutor.java    | 29 +++----
 .../advanced/resultset/SQLFederationResultSet.java | 20 ++---
 .../resultset/SQLFederationResultSetMetaData.java  | 11 +--
 ...etTest.java => SQLFederationResultSetTest.java} | 97 +++++++++++-----------
 .../executor/FilterableTableScanExecutor.java      |  7 +-
 .../executor/TranslatableTableScanExecutor.java    |  9 +-
 .../optimizer/SQLOptimizeContext.java              | 35 ++++++++
 ...SphereOptimizer.java => SQLOptimizeEngine.java} | 15 ++--
 .../planner/OptimizerPlannerContextFactory.java    | 89 +-------------------
 .../SQLFederationPlannerUtil.java}                 | 93 ++++++++++++++++++++-
 ...timizerTest.java => SQLOptimizeEngineTest.java} | 61 +++++++-------
 .../cases/dql/dql-integration-test-cases.xml       | 20 ++---
 12 files changed, 257 insertions(+), 229 deletions(-)

diff --git a/shardingsphere-kernel/shardingsphere-sql-federation/shardingsphere-sql-federation-executor/shardingsphere-sql-federation-executor-advanced/src/main/java/org/apache/shardingsphere/sqlfederation/advanced/AdvancedSQLFederationExecutor.java b/shardingsphere-kernel/shardingsphere-sql-federation/shardingsphere-sql-federation-executor/shardingsphere-sql-federation-executor-advanced/src/main/java/org/apache/shardingsphere/sqlfederation/advanced/AdvancedSQLFederationExecutor.java
index 0093f0871aa..7f347fe5f73 100644
--- a/shardingsphere-kernel/shardingsphere-sql-federation/shardingsphere-sql-federation-executor/shardingsphere-sql-federation-executor-advanced/src/main/java/org/apache/shardingsphere/sqlfederation/advanced/AdvancedSQLFederationExecutor.java
+++ b/shardingsphere-kernel/shardingsphere-sql-federation/shardingsphere-sql-federation-executor/shardingsphere-sql-federation-executor-advanced/src/main/java/org/apache/shardingsphere/sqlfederation/advanced/AdvancedSQLFederationExecutor.java
@@ -23,10 +23,8 @@ import org.apache.calcite.adapter.enumerable.EnumerableRel;
 import org.apache.calcite.config.CalciteConnectionConfig;
 import org.apache.calcite.config.CalciteConnectionConfigImpl;
 import org.apache.calcite.jdbc.JavaTypeFactoryImpl;
-import org.apache.calcite.linq4j.Enumerable;
 import org.apache.calcite.linq4j.Enumerator;
 import org.apache.calcite.prepare.CalciteCatalogReader;
-import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.type.RelDataTypeFactory;
 import org.apache.calcite.runtime.Bindable;
 import org.apache.calcite.schema.impl.AbstractSchema;
@@ -44,19 +42,18 @@ import org.apache.shardingsphere.infra.metadata.ShardingSphereMetaData;
 import org.apache.shardingsphere.infra.metadata.database.rule.ShardingSphereRuleMetaData;
 import org.apache.shardingsphere.infra.metadata.database.schema.decorator.model.ShardingSphereSchema;
 import org.apache.shardingsphere.infra.util.eventbus.EventBusContext;
-import org.apache.shardingsphere.sql.parser.sql.common.statement.SQLStatement;
 import org.apache.shardingsphere.sqlfederation.SQLFederationDataContext;
 import org.apache.shardingsphere.sqlfederation.advanced.resultset.SQLFederationResultSet;
 import org.apache.shardingsphere.sqlfederation.executor.FilterableTableScanExecutor;
 import org.apache.shardingsphere.sqlfederation.executor.TableScanExecutorContext;
-import org.apache.shardingsphere.sqlfederation.optimizer.ShardingSphereOptimizer;
+import org.apache.shardingsphere.sqlfederation.optimizer.SQLOptimizeContext;
+import org.apache.shardingsphere.sqlfederation.optimizer.SQLOptimizeEngine;
 import org.apache.shardingsphere.sqlfederation.optimizer.context.OptimizerContext;
 import org.apache.shardingsphere.sqlfederation.optimizer.context.OptimizerContextFactory;
 import org.apache.shardingsphere.sqlfederation.optimizer.context.parser.OptimizerParserContext;
-import org.apache.shardingsphere.sqlfederation.optimizer.context.planner.OptimizerPlannerContextFactory;
 import org.apache.shardingsphere.sqlfederation.optimizer.executor.TableScanExecutor;
 import org.apache.shardingsphere.sqlfederation.optimizer.metadata.filter.FilterableSchema;
-import org.apache.shardingsphere.sqlfederation.optimizer.planner.QueryOptimizePlannerFactory;
+import org.apache.shardingsphere.sqlfederation.optimizer.util.SQLFederationPlannerUtil;
 import org.apache.shardingsphere.sqlfederation.spi.SQLFederationExecutor;
 import org.apache.shardingsphere.sqlfederation.spi.SQLFederationExecutorContext;
 
@@ -108,8 +105,7 @@ public final class AdvancedSQLFederationExecutor implements SQLFederationExecuto
         ShardingSphereSchema schema = federationContext.getDatabases().get(databaseName.toLowerCase()).getSchema(schemaName);
         AbstractSchema sqlFederationSchema = createSQLFederationSchema(prepareEngine, schema, callback, federationContext);
         Map<String, Object> parameters = createParameters(federationContext.getQueryContext().getParameters());
-        Enumerator<Object> enumerator = execute(sqlStatementContext.getSqlStatement(), sqlFederationSchema, parameters).enumerator();
-        resultSet = new SQLFederationResultSet(enumerator, schema, sqlFederationSchema, sqlStatementContext);
+        resultSet = execute((SelectStatementContext) sqlStatementContext, schema, sqlFederationSchema, parameters);
         return resultSet;
     }
     
@@ -132,17 +128,18 @@ public final class AdvancedSQLFederationExecutor implements SQLFederationExecuto
     }
     
     @SuppressWarnings("unchecked")
-    private Enumerable<Object> execute(final SQLStatement sqlStatement, final AbstractSchema sqlFederationSchema, final Map<String, Object> parameters) {
+    private ResultSet execute(final SelectStatementContext selectStatementContext, final ShardingSphereSchema schema, final AbstractSchema sqlFederationSchema, final Map<String, Object> parameters) {
         OptimizerParserContext parserContext = optimizerContext.getParserContexts().get(databaseName);
         CalciteConnectionConfig connectionConfig = new CalciteConnectionConfigImpl(parserContext.getDialectProps());
         RelDataTypeFactory relDataTypeFactory = new JavaTypeFactoryImpl();
-        CalciteCatalogReader catalogReader = OptimizerPlannerContextFactory.createCatalogReader(schemaName, sqlFederationSchema, relDataTypeFactory, connectionConfig);
-        SqlValidator validator = OptimizerPlannerContextFactory.createValidator(catalogReader, relDataTypeFactory, parserContext.getDatabaseType(), connectionConfig);
-        SqlToRelConverter converter = OptimizerPlannerContextFactory.createConverter(catalogReader, validator, relDataTypeFactory);
-        RelNode bestPlan =
-                new ShardingSphereOptimizer(converter, QueryOptimizePlannerFactory.createHepPlanner()).optimize(sqlStatement);
-        Bindable<Object> executablePlan = EnumerableInterpretable.toBindable(Collections.emptyMap(), null, (EnumerableRel) bestPlan, EnumerableRel.Prefer.ARRAY);
-        return executablePlan.bind(new SQLFederationDataContext(validator, converter, parameters));
+        CalciteCatalogReader catalogReader = SQLFederationPlannerUtil.createCatalogReader(schemaName, sqlFederationSchema, relDataTypeFactory, connectionConfig);
+        SqlValidator validator = SQLFederationPlannerUtil.createSqlValidator(catalogReader, relDataTypeFactory, parserContext.getDatabaseType(), connectionConfig);
+        SqlToRelConverter converter = SQLFederationPlannerUtil.createSqlToRelConverter(catalogReader, validator, relDataTypeFactory);
+        SQLOptimizeContext optimizeContext =
+                new SQLOptimizeEngine(converter, SQLFederationPlannerUtil.createHepPlanner()).optimize(selectStatementContext.getSqlStatement());
+        Bindable<Object> executablePlan = EnumerableInterpretable.toBindable(Collections.emptyMap(), null, (EnumerableRel) optimizeContext.getBestPlan(), EnumerableRel.Prefer.ARRAY);
+        Enumerator<Object> enumerator = executablePlan.bind(new SQLFederationDataContext(validator, converter, parameters)).enumerator();
+        return new SQLFederationResultSet(enumerator, schema, sqlFederationSchema, selectStatementContext, optimizeContext.getValidatedNodeType());
     }
     
     @Override
diff --git a/shardingsphere-kernel/shardingsphere-sql-federation/shardingsphere-sql-federation-executor/shardingsphere-sql-federation-executor-advanced/src/main/java/org/apache/shardingsphere/sqlfederation/advanced/resultset/SQLFederationResultSet.java b/shardingsphere-kernel/shardingsphere-sql-federation/shardingsphere-sql-federation-executor/shardingsphere-sql-federation-executor-advanced/src/main/java/org/apache/shardingsphere/sqlfederation/advanced/resultset/SQLFederationResultSet.java
index 88acbac0637..134fb8a7e09 100644
--- a/shardingsphere-kernel/shardingsphere-sql-federation/shardingsphere-sql-federation-executor/shardingsphere-sql-federation-executor-advanced/src/main/java/org/apache/shardingsphere/sqlfederation/advanced/resultset/SQLFederationResultSet.java
+++ b/shardingsphere-kernel/shardingsphere-sql-federation/shardingsphere-sql-federation-executor/shardingsphere-sql-federation-executor-advanced/src/main/java/org/apache/shardingsphere/sqlfederation/advanced/resultset/SQLFederationResultSet.java
@@ -19,9 +19,9 @@ package org.apache.shardingsphere.sqlfederation.advanced.resultset;
 
 import org.apache.calcite.jdbc.JavaTypeFactoryImpl;
 import org.apache.calcite.linq4j.Enumerator;
+import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.schema.impl.AbstractSchema;
 import org.apache.shardingsphere.infra.binder.segment.select.projection.Projection;
-import org.apache.shardingsphere.infra.binder.statement.SQLStatementContext;
 import org.apache.shardingsphere.infra.binder.statement.dml.SelectStatementContext;
 import org.apache.shardingsphere.infra.executor.sql.execute.result.query.impl.driver.jdbc.type.util.ResultSetUtil;
 import org.apache.shardingsphere.infra.metadata.database.schema.decorator.model.ShardingSphereSchema;
@@ -72,14 +72,14 @@ public final class SQLFederationResultSet extends AbstractUnsupportedOperationRe
     
     private boolean closed;
     
-    public SQLFederationResultSet(final Enumerator<Object> enumerator, final ShardingSphereSchema schema, final AbstractSchema filterableSchema, final SQLStatementContext<?> sqlStatementContext) {
+    public SQLFederationResultSet(final Enumerator<Object> enumerator, final ShardingSphereSchema schema, final AbstractSchema filterableSchema,
+                                  final SelectStatementContext selectStatementContext, final RelDataType validatedNodeType) {
         this.enumerator = enumerator;
-        columnLabelAndIndexMap = createColumnLabelAndIndexMap(sqlStatementContext);
-        resultSetMetaData = new SQLFederationResultSetMetaData(schema, filterableSchema, new JavaTypeFactoryImpl(), (SelectStatementContext) sqlStatementContext);
+        columnLabelAndIndexMap = createColumnLabelAndIndexMap(selectStatementContext);
+        resultSetMetaData = new SQLFederationResultSetMetaData(schema, filterableSchema, new JavaTypeFactoryImpl(), selectStatementContext, validatedNodeType);
     }
     
-    private Map<String, Integer> createColumnLabelAndIndexMap(final SQLStatementContext<?> sqlStatementContext) {
-        SelectStatementContext selectStatementContext = (SelectStatementContext) sqlStatementContext;
+    private Map<String, Integer> createColumnLabelAndIndexMap(final SelectStatementContext selectStatementContext) {
         List<Projection> projections = selectStatementContext.getProjectionsContext().getExpandProjections();
         Map<String, Integer> result = new HashMap<>(projections.size(), 1);
         for (int columnIndex = 1; columnIndex <= projections.size(); columnIndex++) {
@@ -229,7 +229,7 @@ public final class SQLFederationResultSet extends AbstractUnsupportedOperationRe
     
     @Override
     public Date getDate(final int columnIndex, final Calendar cal) throws SQLException {
-        return (Date) ResultSetUtil.convertValue(getCalendarValue(columnIndex, Date.class, cal), Date.class);
+        return (Date) ResultSetUtil.convertValue(getCalendarValue(columnIndex), Date.class);
     }
     
     @Override
@@ -249,7 +249,7 @@ public final class SQLFederationResultSet extends AbstractUnsupportedOperationRe
     
     @Override
     public Time getTime(final int columnIndex, final Calendar cal) throws SQLException {
-        return (Time) ResultSetUtil.convertValue(getCalendarValue(columnIndex, Time.class, cal), Time.class);
+        return (Time) ResultSetUtil.convertValue(getCalendarValue(columnIndex), Time.class);
     }
     
     @Override
@@ -269,7 +269,7 @@ public final class SQLFederationResultSet extends AbstractUnsupportedOperationRe
     
     @Override
     public Timestamp getTimestamp(final int columnIndex, final Calendar cal) throws SQLException {
-        return (Timestamp) ResultSetUtil.convertValue(getCalendarValue(columnIndex, Timestamp.class, cal), Timestamp.class);
+        return (Timestamp) ResultSetUtil.convertValue(getCalendarValue(columnIndex), Timestamp.class);
     }
     
     @Override
@@ -459,7 +459,7 @@ public final class SQLFederationResultSet extends AbstractUnsupportedOperationRe
         return result;
     }
     
-    private Object getCalendarValue(final int columnIndex, final Class<?> type, final Calendar calendar) {
+    private Object getCalendarValue(final int columnIndex) {
         // TODO implement with calendar
         Object result = currentRows[columnIndex - 1];
         wasNull = null == result;
diff --git a/shardingsphere-kernel/shardingsphere-sql-federation/shardingsphere-sql-federation-executor/shardingsphere-sql-federation-executor-advanced/src/main/java/org/apache/shardingsphere/sqlfederation/advanced/resultset/SQLFederationResultSetMetaData.java b/shardingsphere-kernel/shardingsphere-sql-federation/shardingsphere-sql-federation-executor/shardingsphere-sql-federation-executor-advanced/src/main/java/org/apache/shardingsphere/sqlfederation/advanced/resultset/SQLFederationResul [...]
index cb0fdec0bb8..faa5151cb4d 100644
--- a/shardingsphere-kernel/shardingsphere-sql-federation/shardingsphere-sql-federation-executor/shardingsphere-sql-federation-executor-advanced/src/main/java/org/apache/shardingsphere/sqlfederation/advanced/resultset/SQLFederationResultSetMetaData.java
+++ b/shardingsphere-kernel/shardingsphere-sql-federation/shardingsphere-sql-federation-executor/shardingsphere-sql-federation-executor-advanced/src/main/java/org/apache/shardingsphere/sqlfederation/advanced/resultset/SQLFederationResultSetMetaData.java
@@ -27,9 +27,7 @@ import org.apache.shardingsphere.infra.binder.segment.select.projection.Projecti
 import org.apache.shardingsphere.infra.binder.segment.select.projection.impl.ColumnProjection;
 import org.apache.shardingsphere.infra.binder.statement.dml.SelectStatementContext;
 import org.apache.shardingsphere.infra.database.DefaultDatabase;
-import org.apache.shardingsphere.infra.metadata.database.schema.decorator.model.ShardingSphereColumn;
 import org.apache.shardingsphere.infra.metadata.database.schema.decorator.model.ShardingSphereSchema;
-import org.apache.shardingsphere.infra.metadata.database.schema.decorator.model.ShardingSphereTable;
 
 import java.sql.ResultSetMetaData;
 import java.util.Collections;
@@ -50,6 +48,8 @@ public final class SQLFederationResultSetMetaData extends WrapperAdapter impleme
     
     private final SelectStatementContext selectStatementContext;
     
+    private final RelDataType validatedNodeType;
+    
     @Override
     public int getColumnCount() {
         return selectStatementContext.getProjectionsContext().getExpandProjections().size();
@@ -135,12 +135,7 @@ public final class SQLFederationResultSetMetaData extends WrapperAdapter impleme
     
     @Override
     public int getColumnType(final int column) {
-        Projection projection = selectStatementContext.getProjectionsContext().getExpandProjections().get(column - 1);
-        if (projection instanceof ColumnProjection) {
-            Optional<ShardingSphereTable> table = findTableName(column).flatMap(optional -> Optional.ofNullable(schema.getTable(optional)));
-            return table.flatMap(optional -> Optional.ofNullable(optional.getColumns().get(((ColumnProjection) projection).getName()))).map(ShardingSphereColumn::getDataType).orElse(0);
-        }
-        return 0;
+        return validatedNodeType.getFieldList().get(column - 1).getType().getSqlTypeName().getJdbcOrdinal();
     }
     
     @Override
diff --git a/shardingsphere-kernel/shardingsphere-sql-federation/shardingsphere-sql-federation-executor/shardingsphere-sql-federation-executor-advanced/src/test/java/org/apache/shardingsphere/sqlfederation/advanced/result/FederationResultSetTest.java b/shardingsphere-kernel/shardingsphere-sql-federation/shardingsphere-sql-federation-executor/shardingsphere-sql-federation-executor-advanced/src/test/java/org/apache/shardingsphere/sqlfederation/advanced/result/SQLFederationResultSetTest.java
similarity index 79%
rename from shardingsphere-kernel/shardingsphere-sql-federation/shardingsphere-sql-federation-executor/shardingsphere-sql-federation-executor-advanced/src/test/java/org/apache/shardingsphere/sqlfederation/advanced/result/FederationResultSetTest.java
rename to shardingsphere-kernel/shardingsphere-sql-federation/shardingsphere-sql-federation-executor/shardingsphere-sql-federation-executor-advanced/src/test/java/org/apache/shardingsphere/sqlfederation/advanced/result/SQLFederationResultSetTest.java
index 4b14c3cc8f7..2fe85e9a3a5 100644
--- a/shardingsphere-kernel/shardingsphere-sql-federation/shardingsphere-sql-federation-executor/shardingsphere-sql-federation-executor-advanced/src/test/java/org/apache/shardingsphere/sqlfederation/advanced/result/FederationResultSetTest.java
+++ b/shardingsphere-kernel/shardingsphere-sql-federation/shardingsphere-sql-federation-executor/shardingsphere-sql-federation-executor-advanced/src/test/java/org/apache/shardingsphere/sqlfederation/advanced/result/SQLFederationResultSetTest.java
@@ -18,6 +18,7 @@
 package org.apache.shardingsphere.sqlfederation.advanced.result;
 
 import org.apache.calcite.linq4j.Enumerator;
+import org.apache.calcite.rel.type.RelDataType;
 import org.apache.shardingsphere.infra.binder.segment.select.projection.Projection;
 import org.apache.shardingsphere.infra.binder.segment.select.projection.impl.ColumnProjection;
 import org.apache.shardingsphere.infra.binder.segment.table.TablesContext;
@@ -25,6 +26,7 @@ import org.apache.shardingsphere.infra.binder.statement.dml.SelectStatementConte
 import org.apache.shardingsphere.infra.metadata.database.schema.decorator.model.ShardingSphereSchema;
 import org.apache.shardingsphere.sqlfederation.advanced.resultset.SQLFederationResultSet;
 import org.apache.shardingsphere.sqlfederation.optimizer.metadata.filter.FilterableSchema;
+import org.hamcrest.MatcherAssert;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -51,13 +53,12 @@ import java.util.List;
 import static org.hamcrest.CoreMatchers.instanceOf;
 import static org.hamcrest.CoreMatchers.is;
 import static org.junit.Assert.assertFalse;
-import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
-public final class FederationResultSetTest {
+public final class SQLFederationResultSetTest {
     
     private Enumerator<Object> enumerator;
     
@@ -66,7 +67,7 @@ public final class FederationResultSetTest {
     @Before
     public void setUp() {
         enumerator = createEnumerator();
-        federationResultSet = new SQLFederationResultSet(enumerator, mock(ShardingSphereSchema.class), mock(FilterableSchema.class), createSelectStatementContext());
+        federationResultSet = new SQLFederationResultSet(enumerator, mock(ShardingSphereSchema.class), mock(FilterableSchema.class), createSelectStatementContext(), mock(RelDataType.class));
     }
     
     private static SelectStatementContext createSelectStatementContext() {
@@ -89,7 +90,7 @@ public final class FederationResultSetTest {
     }
     
     @Test
-    public void assertNext() throws SQLException {
+    public void assertNext() {
         assertTrue(federationResultSet.next());
     }
     
@@ -123,280 +124,280 @@ public final class FederationResultSetTest {
     public void assertGetByteWithColumnIndex() throws SQLException {
         when(enumerator.current()).thenReturn(new Object[]{(byte) 1, 1, true, 1});
         federationResultSet.next();
-        assertThat(federationResultSet.getByte(1), is((byte) 1));
+        MatcherAssert.assertThat(federationResultSet.getByte(1), is((byte) 1));
     }
     
     @Test
     public void assertGetByteWithColumnLabel() throws SQLException {
         when(enumerator.current()).thenReturn(new Object[]{(byte) 1, 1, true, 1});
         federationResultSet.next();
-        assertThat(federationResultSet.getByte("order_id"), is((byte) 1));
+        MatcherAssert.assertThat(federationResultSet.getByte("order_id"), is((byte) 1));
     }
     
     @Test
     public void assertGetShortWithColumnIndex() throws SQLException {
         when(enumerator.current()).thenReturn(new Object[]{(short) 1, 1, true, 1});
         federationResultSet.next();
-        assertThat(federationResultSet.getShort(1), is((short) 1));
+        MatcherAssert.assertThat(federationResultSet.getShort(1), is((short) 1));
     }
     
     @Test
     public void assertGetShortWithColumnLabel() throws SQLException {
         when(enumerator.current()).thenReturn(new Object[]{(short) 1, 1, true, 1});
         federationResultSet.next();
-        assertThat(federationResultSet.getShort("order_id"), is((short) 1));
+        MatcherAssert.assertThat(federationResultSet.getShort("order_id"), is((short) 1));
     }
     
     @Test
     public void assertGetIntWithColumnIndex() throws SQLException {
         when(enumerator.current()).thenReturn(new Object[]{1, 1, true, 1});
         federationResultSet.next();
-        assertThat(federationResultSet.getInt(1), is(1));
+        MatcherAssert.assertThat(federationResultSet.getInt(1), is(1));
     }
     
     @Test
     public void assertGetIntWithColumnLabel() throws SQLException {
         when(enumerator.current()).thenReturn(new Object[]{1, 1, true, 1});
         federationResultSet.next();
-        assertThat(federationResultSet.getInt("order_id"), is(1));
+        MatcherAssert.assertThat(federationResultSet.getInt("order_id"), is(1));
     }
     
     @Test
     public void assertGetLongWithColumnIndex() throws SQLException {
         when(enumerator.current()).thenReturn(new Object[]{1L, 1, true, 1});
         federationResultSet.next();
-        assertThat(federationResultSet.getLong(1), is(1L));
+        MatcherAssert.assertThat(federationResultSet.getLong(1), is(1L));
     }
     
     @Test
     public void assertGetLongWithColumnLabel() throws SQLException {
         when(enumerator.current()).thenReturn(new Object[]{1L, 1, true, 1});
         federationResultSet.next();
-        assertThat(federationResultSet.getLong("order_id"), is(1L));
+        MatcherAssert.assertThat(federationResultSet.getLong("order_id"), is(1L));
     }
     
     @Test
     public void assertGetFloatWithColumnIndex() throws SQLException {
         when(enumerator.current()).thenReturn(new Object[]{1.0F, 1, true, 1});
         federationResultSet.next();
-        assertThat(federationResultSet.getFloat(1), is(1.0F));
+        MatcherAssert.assertThat(federationResultSet.getFloat(1), is(1.0F));
     }
     
     @Test
     public void assertGetFloatWithColumnLabel() throws SQLException {
         when(enumerator.current()).thenReturn(new Object[]{1.0F, 1, true, 1});
         federationResultSet.next();
-        assertThat(federationResultSet.getFloat("order_id"), is(1.0F));
+        MatcherAssert.assertThat(federationResultSet.getFloat("order_id"), is(1.0F));
     }
     
     @Test
     public void assertGetDoubleWithColumnIndex() throws SQLException {
         when(enumerator.current()).thenReturn(new Object[]{1.0D, 1, true, 1});
         federationResultSet.next();
-        assertThat(federationResultSet.getDouble(1), is(1.0D));
+        MatcherAssert.assertThat(federationResultSet.getDouble(1), is(1.0D));
     }
     
     @Test
     public void assertGetDoubleWithColumnLabel() throws SQLException {
         when(enumerator.current()).thenReturn(new Object[]{1.0D, 1, true, 1});
         federationResultSet.next();
-        assertThat(federationResultSet.getDouble("order_id"), is(1.0D));
+        MatcherAssert.assertThat(federationResultSet.getDouble("order_id"), is(1.0D));
     }
     
     @Test
     public void assertGetStringWithColumnIndex() throws SQLException {
         when(enumerator.current()).thenReturn(new Object[]{1, 1, "OK", 1});
         federationResultSet.next();
-        assertThat(federationResultSet.getString(3), is("OK"));
+        MatcherAssert.assertThat(federationResultSet.getString(3), is("OK"));
     }
     
     @Test
     public void assertGetStringWithColumnLabel() throws SQLException {
         when(enumerator.current()).thenReturn(new Object[]{1, 1, "OK", 1});
         federationResultSet.next();
-        assertThat(federationResultSet.getString("status"), is("OK"));
+        MatcherAssert.assertThat(federationResultSet.getString("status"), is("OK"));
     }
     
     @Test
     public void assertGetNStringWithColumnIndex() throws SQLException {
         when(enumerator.current()).thenReturn(new Object[]{1, 1, "OK", 1});
         federationResultSet.next();
-        assertThat(federationResultSet.getNString(3), is("OK"));
+        MatcherAssert.assertThat(federationResultSet.getNString(3), is("OK"));
     }
     
     @Test
     public void assertGetNStringWithColumnLabel() throws SQLException {
         when(enumerator.current()).thenReturn(new Object[]{1, 1, "OK", 1});
         federationResultSet.next();
-        assertThat(federationResultSet.getNString("status"), is("OK"));
+        MatcherAssert.assertThat(federationResultSet.getNString("status"), is("OK"));
     }
     
     @Test
     public void assertGetBigDecimalWithColumnIndex() throws SQLException {
         when(enumerator.current()).thenReturn(new Object[]{new BigDecimal("1"), 1, "OK", 1});
         federationResultSet.next();
-        assertThat(federationResultSet.getBigDecimal(1), is(new BigDecimal("1")));
+        MatcherAssert.assertThat(federationResultSet.getBigDecimal(1), is(new BigDecimal("1")));
     }
     
     @Test
     public void assertGetBigDecimalWithColumnLabel() throws SQLException {
         when(enumerator.current()).thenReturn(new Object[]{new BigDecimal("1"), 1, "OK", 1});
         federationResultSet.next();
-        assertThat(federationResultSet.getBigDecimal("order_id"), is(new BigDecimal("1")));
+        MatcherAssert.assertThat(federationResultSet.getBigDecimal("order_id"), is(new BigDecimal("1")));
     }
     
     @Test
     public void assertGetBigDecimalAndScaleWithColumnIndex() throws SQLException {
         when(enumerator.current()).thenReturn(new Object[]{new BigDecimal("1"), 1, "OK", 1});
         federationResultSet.next();
-        assertThat(federationResultSet.getBigDecimal(1, 10), is(new BigDecimal("1")));
+        MatcherAssert.assertThat(federationResultSet.getBigDecimal(1, 10), is(new BigDecimal("1")));
     }
     
     @Test
     public void assertGetBigDecimalAndScaleWithColumnLabel() throws SQLException {
         when(enumerator.current()).thenReturn(new Object[]{new BigDecimal("1"), 1, "OK", 1});
         federationResultSet.next();
-        assertThat(federationResultSet.getBigDecimal("order_id", 10), is(new BigDecimal("1")));
+        MatcherAssert.assertThat(federationResultSet.getBigDecimal("order_id", 10), is(new BigDecimal("1")));
     }
     
     @Test
     public void assertGetBytesWithColumnIndex() throws SQLException {
         when(enumerator.current()).thenReturn(new Object[]{new byte[]{(byte) 1}, 1, "OK", 1});
         federationResultSet.next();
-        assertThat(federationResultSet.getBytes(1), is(new byte[]{(byte) 1}));
+        MatcherAssert.assertThat(federationResultSet.getBytes(1), is(new byte[]{(byte) 1}));
     }
     
     @Test
     public void assertGetBytesWithColumnLabel() throws SQLException {
         when(enumerator.current()).thenReturn(new Object[]{new byte[]{(byte) 1}, 1, "OK", 1});
         federationResultSet.next();
-        assertThat(federationResultSet.getBytes("order_id"), is(new byte[]{(byte) 1}));
+        MatcherAssert.assertThat(federationResultSet.getBytes("order_id"), is(new byte[]{(byte) 1}));
     }
     
     @Test
     public void assertGetDateWithColumnIndex() throws SQLException {
         when(enumerator.current()).thenReturn(new Object[]{new Date(0L), 1, "OK", 1});
         federationResultSet.next();
-        assertThat(federationResultSet.getDate(1), is(new Date(0L)));
+        MatcherAssert.assertThat(federationResultSet.getDate(1), is(new Date(0L)));
     }
     
     @Test
     public void assertGetDateWithColumnLabel() throws SQLException {
         when(enumerator.current()).thenReturn(new Object[]{new Date(0L), 1, "OK", 1});
         federationResultSet.next();
-        assertThat(federationResultSet.getDate("order_id"), is(new Date(0L)));
+        MatcherAssert.assertThat(federationResultSet.getDate("order_id"), is(new Date(0L)));
     }
     
     @Test
     public void assertGetDateAndCalendarWithColumnIndex() throws SQLException {
         when(enumerator.current()).thenReturn(new Object[]{new Date(0L), 1, "OK", 1});
         federationResultSet.next();
-        assertThat(federationResultSet.getDate(1, Calendar.getInstance()), is(new Date(0L)));
+        MatcherAssert.assertThat(federationResultSet.getDate(1, Calendar.getInstance()), is(new Date(0L)));
     }
     
     @Test
     public void assertGetDateAndCalendarWithColumnLabel() throws SQLException {
         when(enumerator.current()).thenReturn(new Object[]{new Date(0L), 1, "OK", 1});
         federationResultSet.next();
-        assertThat(federationResultSet.getDate("order_id", Calendar.getInstance()), is(new Date(0L)));
+        MatcherAssert.assertThat(federationResultSet.getDate("order_id", Calendar.getInstance()), is(new Date(0L)));
     }
     
     @Test
     public void assertGetTimeWithColumnIndex() throws SQLException {
         when(enumerator.current()).thenReturn(new Object[]{new Time(0L), 1, "OK", 1});
         federationResultSet.next();
-        assertThat(federationResultSet.getTime(1), is(new Time(0L)));
+        MatcherAssert.assertThat(federationResultSet.getTime(1), is(new Time(0L)));
     }
     
     @Test
     public void assertGetTimeWithColumnLabel() throws SQLException {
         when(enumerator.current()).thenReturn(new Object[]{new Time(0L), 1, "OK", 1});
         federationResultSet.next();
-        assertThat(federationResultSet.getTime("order_id"), is(new Time(0L)));
+        MatcherAssert.assertThat(federationResultSet.getTime("order_id"), is(new Time(0L)));
     }
     
     @Test
     public void assertGetTimeAndCalendarWithColumnIndex() throws SQLException {
         when(enumerator.current()).thenReturn(new Object[]{new Time(0L), 1, "OK", 1});
         federationResultSet.next();
-        assertThat(federationResultSet.getTime(1, Calendar.getInstance()), is(new Time(0L)));
+        MatcherAssert.assertThat(federationResultSet.getTime(1, Calendar.getInstance()), is(new Time(0L)));
     }
     
     @Test
     public void assertGetTimeAndCalendarWithColumnLabel() throws SQLException {
         when(enumerator.current()).thenReturn(new Object[]{new Time(0L), 1, "OK", 1});
         federationResultSet.next();
-        assertThat(federationResultSet.getTime("order_id", Calendar.getInstance()), is(new Time(0L)));
+        MatcherAssert.assertThat(federationResultSet.getTime("order_id", Calendar.getInstance()), is(new Time(0L)));
     }
     
     @Test
     public void assertGetTimestampWithColumnIndex() throws SQLException {
         when(enumerator.current()).thenReturn(new Object[]{new Timestamp(0L), 1, "OK", 1});
         federationResultSet.next();
-        assertThat(federationResultSet.getTimestamp(1), is(new Timestamp(0L)));
+        MatcherAssert.assertThat(federationResultSet.getTimestamp(1), is(new Timestamp(0L)));
     }
     
     @Test
     public void assertGetTimestampWithColumnLabel() throws SQLException {
         when(enumerator.current()).thenReturn(new Object[]{new Timestamp(0L), 1, "OK", 1});
         federationResultSet.next();
-        assertThat(federationResultSet.getTimestamp("order_id"), is(new Timestamp(0L)));
+        MatcherAssert.assertThat(federationResultSet.getTimestamp("order_id"), is(new Timestamp(0L)));
     }
     
     @Test
     public void assertGetTimestampAndCalendarWithColumnIndex() throws SQLException {
         when(enumerator.current()).thenReturn(new Object[]{new Timestamp(0L), 1, "OK", 1});
         federationResultSet.next();
-        assertThat(federationResultSet.getTimestamp(1, Calendar.getInstance()), is(new Timestamp(0L)));
+        MatcherAssert.assertThat(federationResultSet.getTimestamp(1, Calendar.getInstance()), is(new Timestamp(0L)));
     }
     
     @Test
     public void assertGetTimestampAndCalendarWithColumnLabel() throws SQLException {
         when(enumerator.current()).thenReturn(new Object[]{new Timestamp(0L), 1, "OK", 1});
         federationResultSet.next();
-        assertThat(federationResultSet.getTimestamp("order_id", Calendar.getInstance()), is(new Timestamp(0L)));
+        MatcherAssert.assertThat(federationResultSet.getTimestamp("order_id", Calendar.getInstance()), is(new Timestamp(0L)));
     }
     
     @Test(expected = SQLFeatureNotSupportedException.class)
     public void assertGetAsciiStreamWithColumnIndex() throws SQLException {
         when(enumerator.current()).thenReturn(new Object[]{mock(InputStream.class), 1, "OK", 1});
         federationResultSet.next();
-        assertThat(federationResultSet.getAsciiStream(1), instanceOf(InputStream.class));
+        MatcherAssert.assertThat(federationResultSet.getAsciiStream(1), instanceOf(InputStream.class));
     }
     
     @Test(expected = SQLFeatureNotSupportedException.class)
     public void assertGetAsciiStreamWithColumnLabel() throws SQLException {
         when(enumerator.current()).thenReturn(new Object[]{mock(InputStream.class), 1, "OK", 1});
         federationResultSet.next();
-        assertThat(federationResultSet.getAsciiStream("order_id"), instanceOf(InputStream.class));
+        MatcherAssert.assertThat(federationResultSet.getAsciiStream("order_id"), instanceOf(InputStream.class));
     }
     
     @Test(expected = SQLFeatureNotSupportedException.class)
     public void assertGetUnicodeStreamWithColumnIndex() throws SQLException {
         when(enumerator.current()).thenReturn(new Object[]{mock(InputStream.class), 1, "OK", 1});
         federationResultSet.next();
-        assertThat(federationResultSet.getUnicodeStream(1), instanceOf(InputStream.class));
+        MatcherAssert.assertThat(federationResultSet.getUnicodeStream(1), instanceOf(InputStream.class));
     }
     
     @Test(expected = SQLFeatureNotSupportedException.class)
     public void assertGetUnicodeStreamWithColumnLabel() throws SQLException {
         when(enumerator.current()).thenReturn(new Object[]{mock(InputStream.class), 1, "OK", 1});
         federationResultSet.next();
-        assertThat(federationResultSet.getUnicodeStream("order_id"), instanceOf(InputStream.class));
+        MatcherAssert.assertThat(federationResultSet.getUnicodeStream("order_id"), instanceOf(InputStream.class));
     }
     
     @Test(expected = SQLFeatureNotSupportedException.class)
     public void assertGetBinaryStreamWithColumnIndex() throws SQLException {
         when(enumerator.current()).thenReturn(new Object[]{mock(InputStream.class), 1, "OK", 1});
         federationResultSet.next();
-        assertThat(federationResultSet.getBinaryStream(1), instanceOf(InputStream.class));
+        MatcherAssert.assertThat(federationResultSet.getBinaryStream(1), instanceOf(InputStream.class));
     }
     
     @Test(expected = SQLFeatureNotSupportedException.class)
     public void assertGetBinaryStreamWithColumnLabel() throws SQLException {
         when(enumerator.current()).thenReturn(new Object[]{mock(InputStream.class), 1, "OK", 1});
         federationResultSet.next();
-        assertThat(federationResultSet.getBinaryStream("order_id"), instanceOf(InputStream.class));
+        MatcherAssert.assertThat(federationResultSet.getBinaryStream("order_id"), instanceOf(InputStream.class));
     }
     
     @Test(expected = SQLFeatureNotSupportedException.class)
@@ -445,28 +446,28 @@ public final class FederationResultSetTest {
     public void assertGetArrayWithColumnIndex() throws SQLException {
         when(enumerator.current()).thenReturn(new Object[]{mock(Array.class), 1, "OK", 1});
         federationResultSet.next();
-        assertThat(federationResultSet.getArray(1), instanceOf(Array.class));
+        MatcherAssert.assertThat(federationResultSet.getArray(1), instanceOf(Array.class));
     }
     
     @Test
     public void assertGetArrayWithColumnLabel() throws SQLException {
         when(enumerator.current()).thenReturn(new Object[]{mock(Array.class), 1, "OK", 1});
         federationResultSet.next();
-        assertThat(federationResultSet.getArray("order_id"), instanceOf(Array.class));
+        MatcherAssert.assertThat(federationResultSet.getArray("order_id"), instanceOf(Array.class));
     }
     
     @Test
     public void assertGetURLWithColumnIndex() throws SQLException, MalformedURLException {
         when(enumerator.current()).thenReturn(new Object[]{new URL("http://xxx.xxx"), 1, "OK", 1});
         federationResultSet.next();
-        assertThat(federationResultSet.getURL(1), is(new URL("http://xxx.xxx")));
+        MatcherAssert.assertThat(federationResultSet.getURL(1), is(new URL("http://xxx.xxx")));
     }
     
     @Test
     public void assertGetURLWithColumnLabel() throws SQLException, MalformedURLException {
         when(enumerator.current()).thenReturn(new Object[]{new URL("http://xxx.xxx"), 1, "OK", 1});
         federationResultSet.next();
-        assertThat(federationResultSet.getURL("order_id"), is(new URL("http://xxx.xxx")));
+        MatcherAssert.assertThat(federationResultSet.getURL("order_id"), is(new URL("http://xxx.xxx")));
     }
     
     @Test(expected = SQLFeatureNotSupportedException.class)
diff --git a/shardingsphere-kernel/shardingsphere-sql-federation/shardingsphere-sql-federation-executor/shardingsphere-sql-federation-executor-core/src/main/java/org/apache/shardingsphere/sqlfederation/executor/FilterableTableScanExecutor.java b/shardingsphere-kernel/shardingsphere-sql-federation/shardingsphere-sql-federation-executor/shardingsphere-sql-federation-executor-core/src/main/java/org/apache/shardingsphere/sqlfederation/executor/FilterableTableScanExecutor.java
index b530209eff8..15f6aee51bc 100644
--- a/shardingsphere-kernel/shardingsphere-sql-federation/shardingsphere-sql-federation-executor/shardingsphere-sql-federation-executor-core/src/main/java/org/apache/shardingsphere/sqlfederation/executor/FilterableTableScanExecutor.java
+++ b/shardingsphere-kernel/shardingsphere-sql-federation/shardingsphere-sql-federation-executor/shardingsphere-sql-federation-executor-core/src/main/java/org/apache/shardingsphere/sqlfederation/executor/FilterableTableScanExecutor.java
@@ -67,12 +67,11 @@ import org.apache.shardingsphere.infra.util.exception.external.sql.type.wrapper.
 import org.apache.shardingsphere.sql.parser.sql.common.statement.SQLStatement;
 import org.apache.shardingsphere.sqlfederation.SQLDialectFactory;
 import org.apache.shardingsphere.sqlfederation.optimizer.context.OptimizerContext;
-import org.apache.shardingsphere.sqlfederation.optimizer.context.planner.OptimizerPlannerContextFactory;
 import org.apache.shardingsphere.sqlfederation.optimizer.executor.FilterableScanNodeExecutorContext;
 import org.apache.shardingsphere.sqlfederation.optimizer.executor.ScanNodeExecutorContext;
 import org.apache.shardingsphere.sqlfederation.optimizer.executor.TableScanExecutor;
 import org.apache.shardingsphere.sqlfederation.optimizer.metadata.filter.FilterableSchema;
-import org.apache.shardingsphere.sqlfederation.optimizer.planner.QueryOptimizePlannerFactory;
+import org.apache.shardingsphere.sqlfederation.optimizer.util.SQLFederationPlannerUtil;
 import org.apache.shardingsphere.sqlfederation.row.EmptyRowEnumerator;
 import org.apache.shardingsphere.sqlfederation.row.SQLFederationRowEnumerator;
 import org.apache.shardingsphere.sqlfederation.spi.SQLFederationExecutorContext;
@@ -196,9 +195,9 @@ public final class FilterableTableScanExecutor implements TableScanExecutor {
         String schemaName = executorContext.getSchemaName();
         CalciteConnectionConfig connectionConfig = new CalciteConnectionConfigImpl(optimizerContext.getParserContexts().get(databaseName).getDialectProps());
         ShardingSphereSchema schema = executorContext.getFederationContext().getDatabases().get(databaseName).getSchema(schemaName);
-        CalciteCatalogReader catalogReader = OptimizerPlannerContextFactory.createCatalogReader(schemaName,
+        CalciteCatalogReader catalogReader = SQLFederationPlannerUtil.createCatalogReader(schemaName,
                 new FilterableSchema(schemaName, schema, null), new JavaTypeFactoryImpl(), connectionConfig);
-        RelOptCluster relOptCluster = RelOptCluster.create(QueryOptimizePlannerFactory.createVolcanoPlanner(), new RexBuilder(new JavaTypeFactoryImpl()));
+        RelOptCluster relOptCluster = RelOptCluster.create(SQLFederationPlannerUtil.createVolcanoPlanner(), new RexBuilder(new JavaTypeFactoryImpl()));
         RelBuilder builder = RelFactories.LOGICAL_BUILDER.create(relOptCluster, catalogReader).scan(table.getName()).filter(scanContext.getFilterValues());
         if (null != scanContext.getProjects()) {
             builder.project(createProjections(scanContext.getProjects(), builder, table.getColumnNames()));
diff --git a/shardingsphere-kernel/shardingsphere-sql-federation/shardingsphere-sql-federation-executor/shardingsphere-sql-federation-executor-core/src/main/java/org/apache/shardingsphere/sqlfederation/executor/TranslatableTableScanExecutor.java b/shardingsphere-kernel/shardingsphere-sql-federation/shardingsphere-sql-federation-executor/shardingsphere-sql-federation-executor-core/src/main/java/org/apache/shardingsphere/sqlfederation/executor/TranslatableTableScanExecutor.java
index 66643232c5f..a819e5ad500 100644
--- a/shardingsphere-kernel/shardingsphere-sql-federation/shardingsphere-sql-federation-executor/shardingsphere-sql-federation-executor-core/src/main/java/org/apache/shardingsphere/sqlfederation/executor/TranslatableTableScanExecutor.java
+++ b/shardingsphere-kernel/shardingsphere-sql-federation/shardingsphere-sql-federation-executor/shardingsphere-sql-federation-executor-core/src/main/java/org/apache/shardingsphere/sqlfederation/executor/TranslatableTableScanExecutor.java
@@ -70,13 +70,12 @@ import org.apache.shardingsphere.infra.util.exception.external.sql.type.wrapper.
 import org.apache.shardingsphere.sql.parser.sql.common.statement.SQLStatement;
 import org.apache.shardingsphere.sqlfederation.SQLDialectFactory;
 import org.apache.shardingsphere.sqlfederation.optimizer.context.OptimizerContext;
-import org.apache.shardingsphere.sqlfederation.optimizer.context.planner.OptimizerPlannerContextFactory;
 import org.apache.shardingsphere.sqlfederation.optimizer.executor.ScanNodeExecutorContext;
 import org.apache.shardingsphere.sqlfederation.optimizer.executor.TableScanExecutor;
 import org.apache.shardingsphere.sqlfederation.optimizer.executor.TranslatableScanNodeExecutorContext;
 import org.apache.shardingsphere.sqlfederation.optimizer.metadata.filter.FilterableSchema;
 import org.apache.shardingsphere.sqlfederation.optimizer.metadata.translatable.StringToRexNodeUtil;
-import org.apache.shardingsphere.sqlfederation.optimizer.planner.QueryOptimizePlannerFactory;
+import org.apache.shardingsphere.sqlfederation.optimizer.util.SQLFederationPlannerUtil;
 import org.apache.shardingsphere.sqlfederation.row.EmptyRowEnumerator;
 import org.apache.shardingsphere.sqlfederation.row.SQLFederationRowEnumerator;
 import org.apache.shardingsphere.sqlfederation.spi.SQLFederationExecutorContext;
@@ -200,9 +199,9 @@ public final class TranslatableTableScanExecutor implements TableScanExecutor {
         String schemaName = executorContext.getSchemaName();
         CalciteConnectionConfig connectionConfig = new CalciteConnectionConfigImpl(optimizerContext.getParserContexts().get(databaseName).getDialectProps());
         ShardingSphereSchema schema = executorContext.getFederationContext().getDatabases().get(databaseName).getSchema(schemaName);
-        CalciteCatalogReader catalogReader = OptimizerPlannerContextFactory.createCatalogReader(schemaName,
+        CalciteCatalogReader catalogReader = SQLFederationPlannerUtil.createCatalogReader(schemaName,
                 new FilterableSchema(schemaName, schema, null), new JavaTypeFactoryImpl(), connectionConfig);
-        RelOptCluster relOptCluster = RelOptCluster.create(QueryOptimizePlannerFactory.createVolcanoPlanner(), new RexBuilder(new JavaTypeFactoryImpl()));
+        RelOptCluster relOptCluster = RelOptCluster.create(SQLFederationPlannerUtil.createVolcanoPlanner(), new RexBuilder(new JavaTypeFactoryImpl()));
         RelBuilder builder = RelFactories.LOGICAL_BUILDER.create(relOptCluster, catalogReader).scan(table.getName());
         if (null != scanContext.getFilterValues()) {
             builder.filter(createFilters(scanContext.getFilterValues()));
@@ -221,7 +220,7 @@ public final class TranslatableTableScanExecutor implements TableScanExecutor {
             if (Strings.isNullOrEmpty(each)) {
                 continue;
             }
-            RexNode filterCondition = null;
+            RexNode filterCondition;
             try {
                 filterCondition = StringToRexNodeUtil.buildRexNode(each, rexBuilder);
             } catch (IOException ignored) {
diff --git a/shardingsphere-kernel/shardingsphere-sql-federation/shardingsphere-sql-federation-optimizer/src/main/java/org/apache/shardingsphere/sqlfederation/optimizer/SQLOptimizeContext.java b/shardingsphere-kernel/shardingsphere-sql-federation/shardingsphere-sql-federation-optimizer/src/main/java/org/apache/shardingsphere/sqlfederation/optimizer/SQLOptimizeContext.java
new file mode 100644
index 00000000000..113845c5b20
--- /dev/null
+++ b/shardingsphere-kernel/shardingsphere-sql-federation/shardingsphere-sql-federation-optimizer/src/main/java/org/apache/shardingsphere/sqlfederation/optimizer/SQLOptimizeContext.java
@@ -0,0 +1,35 @@
+/*
+ * 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.sqlfederation.optimizer;
+
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.rel.type.RelDataType;
+
+/**
+ * SQL optimize context.
+ */
+@RequiredArgsConstructor
+@Getter
+public final class SQLOptimizeContext {
+    
+    private final RelNode bestPlan;
+    
+    private final RelDataType validatedNodeType;
+}
diff --git a/shardingsphere-kernel/shardingsphere-sql-federation/shardingsphere-sql-federation-optimizer/src/main/java/org/apache/shardingsphere/sqlfederation/optimizer/ShardingSphereOptimizer.java b/shardingsphere-kernel/shardingsphere-sql-federation/shardingsphere-sql-federation-optimizer/src/main/java/org/apache/shardingsphere/sqlfederation/optimizer/SQLOptimizeEngine.java
similarity index 84%
rename from shardingsphere-kernel/shardingsphere-sql-federation/shardingsphere-sql-federation-optimizer/src/main/java/org/apache/shardingsphere/sqlfederation/optimizer/ShardingSphereOptimizer.java
rename to shardingsphere-kernel/shardingsphere-sql-federation/shardingsphere-sql-federation-optimizer/src/main/java/org/apache/shardingsphere/sqlfederation/optimizer/SQLOptimizeEngine.java
index 454e9b7bf60..a59b374e2c9 100644
--- a/shardingsphere-kernel/shardingsphere-sql-federation/shardingsphere-sql-federation-optimizer/src/main/java/org/apache/shardingsphere/sqlfederation/optimizer/ShardingSphereOptimizer.java
+++ b/shardingsphere-kernel/shardingsphere-sql-federation/shardingsphere-sql-federation-optimizer/src/main/java/org/apache/shardingsphere/sqlfederation/optimizer/SQLOptimizeEngine.java
@@ -21,16 +21,19 @@ import lombok.RequiredArgsConstructor;
 import org.apache.calcite.adapter.enumerable.EnumerableConvention;
 import org.apache.calcite.plan.RelOptPlanner;
 import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.sql.SqlNode;
 import org.apache.calcite.sql2rel.SqlToRelConverter;
 import org.apache.shardingsphere.sql.parser.sql.common.statement.SQLStatement;
 import org.apache.shardingsphere.sqlfederation.optimizer.converter.SQLNodeConverterEngine;
 
+import java.util.Objects;
+
 /**
- * ShardingSphere optimizer.
+ * SQL optimize engine.
  */
 @RequiredArgsConstructor
-public final class ShardingSphereOptimizer {
+public final class SQLOptimizeEngine {
     
     private final SqlToRelConverter converter;
     
@@ -38,15 +41,17 @@ public final class ShardingSphereOptimizer {
     
     /**
      * Optimize query execution plan.
-     * 
+     *
      * @param sqlStatement SQL statement
      * @return optimized relational node
      */
-    public RelNode optimize(final SQLStatement sqlStatement) {
+    public SQLOptimizeContext optimize(final SQLStatement sqlStatement) {
         SqlNode sqlNode = SQLNodeConverterEngine.convert(sqlStatement);
         RelNode logicPlan = converter.convertQuery(sqlNode, true, true).rel;
+        RelDataType validatedNodeType = Objects.requireNonNull(converter.validator).getValidatedNodeType(sqlNode);
         RelNode ruleBasedPlan = optimizeWithRBO(logicPlan, hepPlanner);
-        return optimizeWithCBO(ruleBasedPlan, converter);
+        RelNode bestPlan = optimizeWithCBO(ruleBasedPlan, converter);
+        return new SQLOptimizeContext(bestPlan, validatedNodeType);
     }
     
     private static RelNode optimizeWithRBO(final RelNode logicPlan, final RelOptPlanner hepPlanner) {
diff --git a/shardingsphere-kernel/shardingsphere-sql-federation/shardingsphere-sql-federation-optimizer/src/main/java/org/apache/shardingsphere/sqlfederation/optimizer/context/planner/OptimizerPlannerContextFactory.java b/shardingsphere-kernel/shardingsphere-sql-federation/shardingsphere-sql-federation-optimizer/src/main/java/org/apache/shardingsphere/sqlfederation/optimizer/context/planner/OptimizerPlannerContextFactory.java
index 193c6639624..603851375d3 100644
--- a/shardingsphere-kernel/shardingsphere-sql-federation/shardingsphere-sql-federation-optimizer/src/main/java/org/apache/shardingsphere/sqlfederation/optimizer/context/planner/OptimizerPlannerContextFactory.java
+++ b/shardingsphere-kernel/shardingsphere-sql-federation/shardingsphere-sql-federation-optimizer/src/main/java/org/apache/shardingsphere/sqlfederation/optimizer/context/planner/OptimizerPlannerContextFactory.java
@@ -19,30 +19,9 @@ package org.apache.shardingsphere.sqlfederation.optimizer.context.planner;
 
 import lombok.AccessLevel;
 import lombok.NoArgsConstructor;
-import org.apache.calcite.config.CalciteConnectionConfig;
-import org.apache.calcite.jdbc.CalciteSchema;
-import org.apache.calcite.plan.RelOptCluster;
-import org.apache.calcite.plan.RelOptTable.ViewExpander;
-import org.apache.calcite.prepare.CalciteCatalogReader;
-import org.apache.calcite.rel.type.RelDataTypeFactory;
-import org.apache.calcite.rex.RexBuilder;
-import org.apache.calcite.schema.Schema;
-import org.apache.calcite.sql.SqlOperatorTable;
-import org.apache.calcite.sql.fun.SqlLibrary;
-import org.apache.calcite.sql.fun.SqlLibraryOperatorTableFactory;
-import org.apache.calcite.sql.util.SqlOperatorTables;
-import org.apache.calcite.sql.validate.SqlValidator;
-import org.apache.calcite.sql.validate.SqlValidatorUtil;
-import org.apache.calcite.sql2rel.SqlToRelConverter;
-import org.apache.calcite.sql2rel.SqlToRelConverter.Config;
-import org.apache.calcite.sql2rel.StandardConvertletTable;
-import org.apache.shardingsphere.infra.database.type.DatabaseType;
 import org.apache.shardingsphere.infra.metadata.database.ShardingSphereDatabase;
-import org.apache.shardingsphere.sqlfederation.optimizer.planner.QueryOptimizePlannerFactory;
+import org.apache.shardingsphere.sqlfederation.optimizer.util.SQLFederationPlannerUtil;
 
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.concurrent.ConcurrentHashMap;
@@ -53,15 +32,6 @@ import java.util.concurrent.ConcurrentHashMap;
 @NoArgsConstructor(access = AccessLevel.PRIVATE)
 public final class OptimizerPlannerContextFactory {
     
-    private static final Map<String, SqlLibrary> DATABASE_TYPE_SQL_LIBRARIES = new HashMap<>();
-    
-    static {
-        DATABASE_TYPE_SQL_LIBRARIES.put(SqlLibrary.MYSQL.name().toLowerCase(), SqlLibrary.MYSQL);
-        DATABASE_TYPE_SQL_LIBRARIES.put(SqlLibrary.POSTGRESQL.name().toLowerCase(), SqlLibrary.POSTGRESQL);
-        DATABASE_TYPE_SQL_LIBRARIES.put(SqlLibrary.ORACLE.name(), SqlLibrary.ORACLE);
-        DATABASE_TYPE_SQL_LIBRARIES.put("openGauss", SqlLibrary.POSTGRESQL);
-    }
-    
     /**
      * Create optimizer planner context map.
      *
@@ -71,63 +41,8 @@ public final class OptimizerPlannerContextFactory {
     public static Map<String, OptimizerPlannerContext> create(final Map<String, ShardingSphereDatabase> databases) {
         Map<String, OptimizerPlannerContext> result = new ConcurrentHashMap<>(databases.size(), 1);
         for (Entry<String, ShardingSphereDatabase> entry : databases.entrySet()) {
-            result.put(entry.getKey(), new OptimizerPlannerContext(QueryOptimizePlannerFactory.createHepPlanner()));
+            result.put(entry.getKey(), new OptimizerPlannerContext(SQLFederationPlannerUtil.createHepPlanner()));
         }
         return result;
     }
-    
-    /**
-     * Create catalog reader.
-     * 
-     * @param schemaName schema name
-     * @param schema schema
-     * @param relDataTypeFactory rel data type factory
-     * @param connectionConfig connection config
-     * @return calcite catalog reader
-     */
-    public static CalciteCatalogReader createCatalogReader(final String schemaName, final Schema schema, final RelDataTypeFactory relDataTypeFactory, final CalciteConnectionConfig connectionConfig) {
-        CalciteSchema rootSchema = CalciteSchema.createRootSchema(true);
-        rootSchema.add(schemaName, schema);
-        return new CalciteCatalogReader(rootSchema, Collections.singletonList(schemaName), relDataTypeFactory, connectionConfig);
-    }
-    
-    /**
-     * Create validator.
-     *
-     * @param catalogReader catalog reader
-     * @param relDataTypeFactory rel data type factory
-     * @param databaseType database type
-     * @param connectionConfig connection config
-     * @return sql validator
-     */
-    public static SqlValidator createValidator(final CalciteCatalogReader catalogReader, final RelDataTypeFactory relDataTypeFactory,
-                                               final DatabaseType databaseType, final CalciteConnectionConfig connectionConfig) {
-        SqlValidator.Config validatorConfig = SqlValidator.Config.DEFAULT
-                .withLenientOperatorLookup(connectionConfig.lenientOperatorLookup())
-                .withConformance(connectionConfig.conformance())
-                .withDefaultNullCollation(connectionConfig.defaultNullCollation())
-                .withIdentifierExpansion(true);
-        SqlOperatorTable sqlOperatorTable = getSQLOperatorTable(catalogReader, databaseType);
-        return SqlValidatorUtil.newValidator(sqlOperatorTable, catalogReader, relDataTypeFactory, validatorConfig);
-    }
-    
-    private static SqlOperatorTable getSQLOperatorTable(final CalciteCatalogReader catalogReader, final DatabaseType databaseType) {
-        return SqlOperatorTables.chain(Arrays.asList(SqlLibraryOperatorTableFactory.INSTANCE.getOperatorTable(
-                Arrays.asList(SqlLibrary.STANDARD, DATABASE_TYPE_SQL_LIBRARIES.getOrDefault(databaseType.getType(), SqlLibrary.MYSQL))), catalogReader));
-    }
-    
-    /**
-     * Create Converter.
-     * 
-     * @param catalogReader catalog reader
-     * @param validator validator
-     * @param relDataTypeFactory rel data type factory
-     * @return sql to rel converter
-     */
-    public static SqlToRelConverter createConverter(final CalciteCatalogReader catalogReader, final SqlValidator validator, final RelDataTypeFactory relDataTypeFactory) {
-        ViewExpander expander = (rowType, queryString, schemaPath, viewPath) -> null;
-        Config converterConfig = SqlToRelConverter.config().withTrimUnusedFields(true);
-        RelOptCluster cluster = RelOptCluster.create(QueryOptimizePlannerFactory.createVolcanoPlanner(), new RexBuilder(relDataTypeFactory));
-        return new SqlToRelConverter(expander, validator, catalogReader, cluster, StandardConvertletTable.INSTANCE, converterConfig);
-    }
 }
diff --git a/shardingsphere-kernel/shardingsphere-sql-federation/shardingsphere-sql-federation-optimizer/src/main/java/org/apache/shardingsphere/sqlfederation/optimizer/planner/QueryOptimizePlannerFactory.java b/shardingsphere-kernel/shardingsphere-sql-federation/shardingsphere-sql-federation-optimizer/src/main/java/org/apache/shardingsphere/sqlfederation/optimizer/util/SQLFederationPlannerUtil.java
similarity index 55%
rename from shardingsphere-kernel/shardingsphere-sql-federation/shardingsphere-sql-federation-optimizer/src/main/java/org/apache/shardingsphere/sqlfederation/optimizer/planner/QueryOptimizePlannerFactory.java
rename to shardingsphere-kernel/shardingsphere-sql-federation/shardingsphere-sql-federation-optimizer/src/main/java/org/apache/shardingsphere/sqlfederation/optimizer/util/SQLFederationPlannerUtil.java
index ff03cd52a00..1146a8e5ab9 100644
--- a/shardingsphere-kernel/shardingsphere-sql-federation/shardingsphere-sql-federation-optimizer/src/main/java/org/apache/shardingsphere/sqlfederation/optimizer/planner/QueryOptimizePlannerFactory.java
+++ b/shardingsphere-kernel/shardingsphere-sql-federation/shardingsphere-sql-federation-optimizer/src/main/java/org/apache/shardingsphere/sqlfederation/optimizer/util/SQLFederationPlannerUtil.java
@@ -15,37 +15,68 @@
  * limitations under the License.
  */
 
-package org.apache.shardingsphere.sqlfederation.optimizer.planner;
+package org.apache.shardingsphere.sqlfederation.optimizer.util;
 
 import lombok.AccessLevel;
 import lombok.NoArgsConstructor;
 import org.apache.calcite.adapter.enumerable.EnumerableRules;
+import org.apache.calcite.config.CalciteConnectionConfig;
+import org.apache.calcite.jdbc.CalciteSchema;
 import org.apache.calcite.plan.ConventionTraitDef;
+import org.apache.calcite.plan.RelOptCluster;
 import org.apache.calcite.plan.RelOptPlanner;
 import org.apache.calcite.plan.RelOptRule;
+import org.apache.calcite.plan.RelOptTable.ViewExpander;
 import org.apache.calcite.plan.hep.HepMatchOrder;
 import org.apache.calcite.plan.hep.HepPlanner;
 import org.apache.calcite.plan.hep.HepProgramBuilder;
 import org.apache.calcite.plan.volcano.VolcanoPlanner;
+import org.apache.calcite.prepare.CalciteCatalogReader;
 import org.apache.calcite.rel.RelCollationTraitDef;
 import org.apache.calcite.rel.rules.AggregateExpandDistinctAggregatesRule;
 import org.apache.calcite.rel.rules.CoreRules;
 import org.apache.calcite.rel.rules.ProjectRemoveRule;
+import org.apache.calcite.rel.type.RelDataTypeFactory;
+import org.apache.calcite.rex.RexBuilder;
+import org.apache.calcite.schema.Schema;
+import org.apache.calcite.sql.SqlOperatorTable;
+import org.apache.calcite.sql.fun.SqlLibrary;
+import org.apache.calcite.sql.fun.SqlLibraryOperatorTableFactory;
+import org.apache.calcite.sql.util.SqlOperatorTables;
+import org.apache.calcite.sql.validate.SqlValidator;
+import org.apache.calcite.sql.validate.SqlValidatorUtil;
+import org.apache.calcite.sql2rel.SqlToRelConverter;
+import org.apache.calcite.sql2rel.SqlToRelConverter.Config;
+import org.apache.calcite.sql2rel.StandardConvertletTable;
+import org.apache.shardingsphere.infra.database.type.DatabaseType;
 import org.apache.shardingsphere.sqlfederation.optimizer.metadata.translatable.TranslatableFilterRule;
 import org.apache.shardingsphere.sqlfederation.optimizer.metadata.translatable.TranslatableProjectFilterRule;
 import org.apache.shardingsphere.sqlfederation.optimizer.metadata.translatable.TranslatableProjectRule;
 
+import java.util.Arrays;
 import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
 import java.util.LinkedList;
+import java.util.Map;
 
 /**
- * Query optimize planner factory.
+ * SQL federation planner util.
  */
 @NoArgsConstructor(access = AccessLevel.PRIVATE)
-public final class QueryOptimizePlannerFactory {
+public final class SQLFederationPlannerUtil {
     
     private static final int DEFAULT_MATCH_LIMIT = 1024;
     
+    private static final Map<String, SqlLibrary> DATABASE_TYPE_SQL_LIBRARIES = new HashMap<>();
+    
+    static {
+        DATABASE_TYPE_SQL_LIBRARIES.put(SqlLibrary.MYSQL.name().toLowerCase(), SqlLibrary.MYSQL);
+        DATABASE_TYPE_SQL_LIBRARIES.put(SqlLibrary.POSTGRESQL.name().toLowerCase(), SqlLibrary.POSTGRESQL);
+        DATABASE_TYPE_SQL_LIBRARIES.put(SqlLibrary.ORACLE.name(), SqlLibrary.ORACLE);
+        DATABASE_TYPE_SQL_LIBRARIES.put("openGauss", SqlLibrary.POSTGRESQL);
+    }
+    
     /**
      * Create new instance of volcano planner.
      *
@@ -67,6 +98,7 @@ public final class QueryOptimizePlannerFactory {
         builder.addGroupBegin().addRuleCollection(getFilterRules()).addGroupEnd().addMatchOrder(HepMatchOrder.BOTTOM_UP);
         builder.addGroupBegin().addRuleCollection(getProjectRules()).addGroupEnd().addMatchOrder(HepMatchOrder.BOTTOM_UP);
         builder.addGroupBegin().addRuleCollection(getCalcRules()).addGroupEnd().addMatchOrder(HepMatchOrder.BOTTOM_UP);
+        builder.addGroupBegin().addRuleCollection(getSubQueryRules()).addGroupEnd().addMatchOrder(HepMatchOrder.BOTTOM_UP);
         builder.addMatchLimit(DEFAULT_MATCH_LIMIT);
         return new HepPlanner(builder.build());
     }
@@ -136,4 +168,59 @@ public final class QueryOptimizePlannerFactory {
         result.add(TranslatableProjectFilterRule.INSTANCE);
         return result;
     }
+    
+    /**
+     * Create catalog reader.
+     *
+     * @param schemaName schema name
+     * @param schema schema
+     * @param relDataTypeFactory rel data type factory
+     * @param connectionConfig connection config
+     * @return calcite catalog reader
+     */
+    public static CalciteCatalogReader createCatalogReader(final String schemaName, final Schema schema, final RelDataTypeFactory relDataTypeFactory, final CalciteConnectionConfig connectionConfig) {
+        CalciteSchema rootSchema = CalciteSchema.createRootSchema(true);
+        rootSchema.add(schemaName, schema);
+        return new CalciteCatalogReader(rootSchema, Collections.singletonList(schemaName), relDataTypeFactory, connectionConfig);
+    }
+    
+    /**
+     * Create sql validator.
+     *
+     * @param catalogReader catalog reader
+     * @param relDataTypeFactory rel data type factory
+     * @param databaseType database type
+     * @param connectionConfig connection config
+     * @return sql validator
+     */
+    public static SqlValidator createSqlValidator(final CalciteCatalogReader catalogReader, final RelDataTypeFactory relDataTypeFactory,
+                                                  final DatabaseType databaseType, final CalciteConnectionConfig connectionConfig) {
+        SqlValidator.Config validatorConfig = SqlValidator.Config.DEFAULT
+                .withLenientOperatorLookup(connectionConfig.lenientOperatorLookup())
+                .withConformance(connectionConfig.conformance())
+                .withDefaultNullCollation(connectionConfig.defaultNullCollation())
+                .withIdentifierExpansion(true);
+        SqlOperatorTable sqlOperatorTable = getSQLOperatorTable(catalogReader, databaseType);
+        return SqlValidatorUtil.newValidator(sqlOperatorTable, catalogReader, relDataTypeFactory, validatorConfig);
+    }
+    
+    private static SqlOperatorTable getSQLOperatorTable(final CalciteCatalogReader catalogReader, final DatabaseType databaseType) {
+        return SqlOperatorTables.chain(Arrays.asList(SqlLibraryOperatorTableFactory.INSTANCE.getOperatorTable(
+                Arrays.asList(SqlLibrary.STANDARD, DATABASE_TYPE_SQL_LIBRARIES.getOrDefault(databaseType.getType(), SqlLibrary.MYSQL))), catalogReader));
+    }
+    
+    /**
+     * Create sql to rel converter.
+     *
+     * @param catalogReader catalog reader
+     * @param validator validator
+     * @param relDataTypeFactory rel data type factory
+     * @return sql to rel converter
+     */
+    public static SqlToRelConverter createSqlToRelConverter(final CalciteCatalogReader catalogReader, final SqlValidator validator, final RelDataTypeFactory relDataTypeFactory) {
+        ViewExpander expander = (rowType, queryString, schemaPath, viewPath) -> null;
+        Config converterConfig = SqlToRelConverter.config().withTrimUnusedFields(true);
+        RelOptCluster cluster = RelOptCluster.create(SQLFederationPlannerUtil.createVolcanoPlanner(), new RexBuilder(relDataTypeFactory));
+        return new SqlToRelConverter(expander, validator, catalogReader, cluster, StandardConvertletTable.INSTANCE, converterConfig);
+    }
 }
diff --git a/shardingsphere-kernel/shardingsphere-sql-federation/shardingsphere-sql-federation-optimizer/src/test/java/org/apache/shardingsphere/sqlfederation/optimizer/ShardingSphereOptimizerTest.java b/shardingsphere-kernel/shardingsphere-sql-federation/shardingsphere-sql-federation-optimizer/src/test/java/org/apache/shardingsphere/sqlfederation/optimizer/SQLOptimizeEngineTest.java
similarity index 87%
rename from shardingsphere-kernel/shardingsphere-sql-federation/shardingsphere-sql-federation-optimizer/src/test/java/org/apache/shardingsphere/sqlfederation/optimizer/ShardingSphereOptimizerTest.java
rename to shardingsphere-kernel/shardingsphere-sql-federation/shardingsphere-sql-federation-optimizer/src/test/java/org/apache/shardingsphere/sqlfederation/optimizer/SQLOptimizeEngineTest.java
index 634770941a6..8b34c557ee9 100644
--- a/shardingsphere-kernel/shardingsphere-sql-federation/shardingsphere-sql-federation-optimizer/src/test/java/org/apache/shardingsphere/sqlfederation/optimizer/ShardingSphereOptimizerTest.java
+++ b/shardingsphere-kernel/shardingsphere-sql-federation/shardingsphere-sql-federation-optimizer/src/test/java/org/apache/shardingsphere/sqlfederation/optimizer/SQLOptimizeEngineTest.java
@@ -33,9 +33,9 @@ import org.apache.shardingsphere.infra.parser.ShardingSphereSQLParserEngine;
 import org.apache.shardingsphere.parser.rule.SQLParserRule;
 import org.apache.shardingsphere.parser.rule.builder.DefaultSQLParserRuleConfigurationBuilder;
 import org.apache.shardingsphere.sql.parser.sql.common.statement.SQLStatement;
-import org.apache.shardingsphere.sqlfederation.optimizer.context.planner.OptimizerPlannerContextFactory;
 import org.apache.shardingsphere.sqlfederation.optimizer.metadata.translatable.TranslatableSchema;
-import org.apache.shardingsphere.sqlfederation.optimizer.planner.QueryOptimizePlannerFactory;
+import org.apache.shardingsphere.sqlfederation.optimizer.util.SQLFederationPlannerUtil;
+import org.hamcrest.MatcherAssert;
 import org.junit.Before;
 import org.junit.Test;
 
@@ -47,9 +47,8 @@ import java.util.Map;
 import java.util.Properties;
 
 import static org.hamcrest.CoreMatchers.is;
-import static org.hamcrest.MatcherAssert.assertThat;
 
-public final class ShardingSphereOptimizerTest {
+public final class SQLOptimizeEngineTest {
     
     private static final String LINE_SEPARATOR = System.lineSeparator();
     
@@ -92,7 +91,7 @@ public final class ShardingSphereOptimizerTest {
     
     private final SQLParserRule sqlParserRule = new SQLParserRule(new DefaultSQLParserRuleConfigurationBuilder().build());
     
-    private ShardingSphereOptimizer optimizer;
+    private SQLOptimizeEngine optimizeEngine;
     
     @Before
     public void init() {
@@ -101,7 +100,7 @@ public final class ShardingSphereOptimizerTest {
         tables.put("t_user_info", createUserInfoTableMetaData());
         ShardingSphereSchema schema = new ShardingSphereSchema(tables, Collections.emptyMap());
         SqlToRelConverter converter = createSqlToRelConverter(schema);
-        optimizer = new ShardingSphereOptimizer(converter, QueryOptimizePlannerFactory.createHepPlanner());
+        optimizeEngine = new SQLOptimizeEngine(converter, SQLFederationPlannerUtil.createHepPlanner());
     }
     
     private ShardingSphereTable createOrderTableMetaData() {
@@ -121,126 +120,126 @@ public final class ShardingSphereOptimizerTest {
         CalciteConnectionConfig connectionConfig = new CalciteConnectionConfigImpl(new Properties());
         RelDataTypeFactory relDataTypeFactory = new JavaTypeFactoryImpl();
         TranslatableSchema federationSchema = new TranslatableSchema(SCHEMA_NAME, schema, null);
-        CalciteCatalogReader catalogReader = OptimizerPlannerContextFactory.createCatalogReader(SCHEMA_NAME, federationSchema, relDataTypeFactory, connectionConfig);
-        SqlValidator validator = OptimizerPlannerContextFactory.createValidator(catalogReader, relDataTypeFactory, new H2DatabaseType(), connectionConfig);
-        return OptimizerPlannerContextFactory.createConverter(catalogReader, validator, relDataTypeFactory);
+        CalciteCatalogReader catalogReader = SQLFederationPlannerUtil.createCatalogReader(SCHEMA_NAME, federationSchema, relDataTypeFactory, connectionConfig);
+        SqlValidator validator = SQLFederationPlannerUtil.createSqlValidator(catalogReader, relDataTypeFactory, new H2DatabaseType(), connectionConfig);
+        return SQLFederationPlannerUtil.createSqlToRelConverter(catalogReader, validator, relDataTypeFactory);
     }
     
     @Test
     public void assertSelectCrossJoinCondition() {
         ShardingSphereSQLParserEngine sqlParserEngine = sqlParserRule.getSQLParserEngine(DatabaseTypeEngine.getTrunkDatabaseTypeName(new H2DatabaseType()));
         SQLStatement sqlStatement = sqlParserEngine.parse(SELECT_CROSS_JOIN_CONDITION, false);
-        String actual = optimizer.optimize(sqlStatement).explain();
+        String actual = optimizeEngine.optimize(sqlStatement).getBestPlan().explain();
         String expected = "EnumerableCalc(expr#0..4=[{inputs}], proj#0..1=[{exprs}], user_id0=[$t3])" + LINE_SEPARATOR
                 + "  EnumerableHashJoin(condition=[=($2, $4)], joinType=[inner])" + LINE_SEPARATOR
                 + "    EnumerableCalc(expr#0..1=[{inputs}], expr#2=[CAST($t1):VARCHAR], proj#0..2=[{exprs}])" + LINE_SEPARATOR
                 + "      TranslatableTableScan(table=[[federate_jdbc, t_order_federate]], fields=[[0, 1]])" + LINE_SEPARATOR
                 + "    EnumerableCalc(expr#0=[{inputs}], expr#1=[CAST($t0):VARCHAR], proj#0..1=[{exprs}])" + LINE_SEPARATOR
                 + "      TranslatableTableScan(table=[[federate_jdbc, t_user_info]], fields=[[0]], filters=[[=(CAST($0):INTEGER, 13), null]])" + LINE_SEPARATOR;
-        assertThat(actual, is(expected));
+        MatcherAssert.assertThat(actual, is(expected));
     }
     
     @Test
     public void assertSelectWhereAllFields() {
         ShardingSphereSQLParserEngine sqlParserEngine = sqlParserRule.getSQLParserEngine(DatabaseTypeEngine.getTrunkDatabaseTypeName(new H2DatabaseType()));
         SQLStatement sqlStatement = sqlParserEngine.parse(SELECT_WHERE_ALL_FIELDS, false);
-        String actual = optimizer.optimize(sqlStatement).explain();
+        String actual = optimizeEngine.optimize(sqlStatement).getBestPlan().explain();
         String expected = "TranslatableTableScan(table=[[federate_jdbc, t_user_info]], fields=[[0, 1]], filters=[[=(CAST($0):INTEGER, 12), null]])" + LINE_SEPARATOR;
-        assertThat(actual, is(expected));
+        MatcherAssert.assertThat(actual, is(expected));
     }
     
     @Test
     public void assertSelectWhereSingleField() {
         ShardingSphereSQLParserEngine sqlParserEngine = sqlParserRule.getSQLParserEngine(DatabaseTypeEngine.getTrunkDatabaseTypeName(new H2DatabaseType()));
         SQLStatement sqlStatement = sqlParserEngine.parse(SELECT_WHERE_SINGLE_FIELD, false);
-        String actual = optimizer.optimize(sqlStatement).explain();
+        String actual = optimizeEngine.optimize(sqlStatement).getBestPlan().explain();
         String expected = "TranslatableTableScan(table=[[federate_jdbc, t_user_info]], fields=[[0]], filters=[[=(CAST($0):INTEGER, 12)]])" + LINE_SEPARATOR;
-        assertThat(actual, is(expected));
+        MatcherAssert.assertThat(actual, is(expected));
     }
     
     @Test
     public void assertSelectCrossWhere() {
         ShardingSphereSQLParserEngine sqlParserEngine = sqlParserRule.getSQLParserEngine(DatabaseTypeEngine.getTrunkDatabaseTypeName(new H2DatabaseType()));
         SQLStatement sqlStatement = sqlParserEngine.parse(SELECT_CROSS_WHERE, false);
-        String actual = optimizer.optimize(sqlStatement).explain();
+        String actual = optimizeEngine.optimize(sqlStatement).getBestPlan().explain();
         String expected = "EnumerableCalc(expr#0..4=[{inputs}], proj#0..1=[{exprs}], user_id0=[$t3])" + LINE_SEPARATOR
                 + "  EnumerableHashJoin(condition=[=($2, $4)], joinType=[inner])" + LINE_SEPARATOR
                 + "    EnumerableCalc(expr#0..1=[{inputs}], expr#2=[CAST($t1):VARCHAR], proj#0..2=[{exprs}])" + LINE_SEPARATOR
                 + "      TranslatableTableScan(table=[[federate_jdbc, t_order_federate]], fields=[[0, 1]])" + LINE_SEPARATOR
                 + "    EnumerableCalc(expr#0=[{inputs}], expr#1=[CAST($t0):VARCHAR], proj#0..1=[{exprs}])" + LINE_SEPARATOR
                 + "      TranslatableTableScan(table=[[federate_jdbc, t_user_info]], fields=[[0]])" + LINE_SEPARATOR;
-        assertThat(actual, is(expected));
+        MatcherAssert.assertThat(actual, is(expected));
     }
     
     @Test
     public void assertSelectCrossJoin() {
         ShardingSphereSQLParserEngine sqlParserEngine = sqlParserRule.getSQLParserEngine(DatabaseTypeEngine.getTrunkDatabaseTypeName(new H2DatabaseType()));
         SQLStatement sqlStatement = sqlParserEngine.parse(SELECT_CROSS_JOIN, false);
-        String actual = optimizer.optimize(sqlStatement).explain();
+        String actual = optimizeEngine.optimize(sqlStatement).getBestPlan().explain();
         String expected = "EnumerableCalc(expr#0..4=[{inputs}], proj#0..1=[{exprs}], user_id0=[$t3])" + LINE_SEPARATOR
                 + "  EnumerableHashJoin(condition=[=($2, $4)], joinType=[inner])" + LINE_SEPARATOR
                 + "    EnumerableCalc(expr#0..1=[{inputs}], expr#2=[CAST($t1):VARCHAR], proj#0..2=[{exprs}])" + LINE_SEPARATOR
                 + "      TranslatableTableScan(table=[[federate_jdbc, t_order_federate]], fields=[[0, 1]])" + LINE_SEPARATOR
                 + "    EnumerableCalc(expr#0=[{inputs}], expr#1=[CAST($t0):VARCHAR], proj#0..1=[{exprs}])" + LINE_SEPARATOR
                 + "      TranslatableTableScan(table=[[federate_jdbc, t_user_info]], fields=[[0]])" + LINE_SEPARATOR;
-        assertThat(actual, is(expected));
+        MatcherAssert.assertThat(actual, is(expected));
     }
     
     @Test
     public void assertSelectJoinWhere() {
         ShardingSphereSQLParserEngine sqlParserEngine = sqlParserRule.getSQLParserEngine(DatabaseTypeEngine.getTrunkDatabaseTypeName(new H2DatabaseType()));
         SQLStatement sqlStatement = sqlParserEngine.parse(SELECT_CROSS_WHERE_CONDITION, false);
-        String actual = optimizer.optimize(sqlStatement).explain();
+        String actual = optimizeEngine.optimize(sqlStatement).getBestPlan().explain();
         String expected = "EnumerableCalc(expr#0..4=[{inputs}], proj#0..1=[{exprs}], user_id0=[$t3])" + LINE_SEPARATOR
                 + "  EnumerableHashJoin(condition=[=($2, $4)], joinType=[inner])" + LINE_SEPARATOR
                 + "    EnumerableCalc(expr#0..1=[{inputs}], expr#2=[CAST($t1):VARCHAR], proj#0..2=[{exprs}])" + LINE_SEPARATOR
                 + "      TranslatableTableScan(table=[[federate_jdbc, t_order_federate]], fields=[[0, 1]])" + LINE_SEPARATOR
                 + "    EnumerableCalc(expr#0=[{inputs}], expr#1=[CAST($t0):VARCHAR], proj#0..1=[{exprs}])" + LINE_SEPARATOR
                 + "      TranslatableTableScan(table=[[federate_jdbc, t_user_info]], fields=[[0]], filters=[[=(CAST($0):INTEGER, 13), null]])" + LINE_SEPARATOR;
-        assertThat(actual, is(expected));
+        MatcherAssert.assertThat(actual, is(expected));
     }
     
     @Test
     public void assertSelectSubQueryFrom() {
         ShardingSphereSQLParserEngine sqlParserEngine = sqlParserRule.getSQLParserEngine(DatabaseTypeEngine.getTrunkDatabaseTypeName(new H2DatabaseType()));
         SQLStatement sqlStatement = sqlParserEngine.parse(SELECT_SUBQUERY_FROM, false);
-        String actual = optimizer.optimize(sqlStatement).explain();
+        String actual = optimizeEngine.optimize(sqlStatement).getBestPlan().explain();
         String expected = "TranslatableTableScan(table=[[federate_jdbc, t_user_info]], fields=[[0, 1]], filters=[[>(CAST($0):INTEGER, 1), null]])" + LINE_SEPARATOR;
-        assertThat(actual, is(expected));
+        MatcherAssert.assertThat(actual, is(expected));
     }
     
     @Test
     public void assertSelectSubQueryWhereExist() {
         ShardingSphereSQLParserEngine sqlParserEngine = sqlParserRule.getSQLParserEngine(DatabaseTypeEngine.getTrunkDatabaseTypeName(new H2DatabaseType()));
         SQLStatement sqlStatement = sqlParserEngine.parse(SELECT_SUBQUERY_WHERE_EXIST, false);
-        String actual = optimizer.optimize(sqlStatement).explain();
+        String actual = optimizeEngine.optimize(sqlStatement).getBestPlan().explain();
         String expected = "EnumerableCalc(expr#0..3=[{inputs}], expr#4=[IS NOT NULL($t3)], proj#0..1=[{exprs}], $condition=[$t4])" + LINE_SEPARATOR
                 + "  EnumerableCorrelate(correlation=[$cor0], joinType=[left], requiredColumns=[{1}])" + LINE_SEPARATOR
                 + "    TranslatableTableScan(table=[[federate_jdbc, t_order_federate]], fields=[[0, 1, 2]])" + LINE_SEPARATOR
                 + "    EnumerableAggregate(group=[{}], agg#0=[MIN($0)])" + LINE_SEPARATOR
                 + "      EnumerableCalc(expr#0..1=[{inputs}], expr#2=[true], $f0=[$t2])" + LINE_SEPARATOR
                 + "        TranslatableTableScan(table=[[federate_jdbc, t_user_info]], fields=[[0, 1]], filters=[[=(CAST($cor0.user_id):VARCHAR, CAST($0):VARCHAR), null]])" + LINE_SEPARATOR;
-        assertThat(actual, is(expected));
+        MatcherAssert.assertThat(actual, is(expected));
     }
     
     @Test
     public void assertSelectSubQueryWhereIn() {
         ShardingSphereSQLParserEngine sqlParserEngine = sqlParserRule.getSQLParserEngine(DatabaseTypeEngine.getTrunkDatabaseTypeName(new H2DatabaseType()));
         SQLStatement sqlStatement = sqlParserEngine.parse(SELECT_SUBQUERY_WHERE_IN, false);
-        String actual = optimizer.optimize(sqlStatement).explain();
+        String actual = optimizeEngine.optimize(sqlStatement).getBestPlan().explain();
         String expected = "EnumerableCalc(expr#0..2=[{inputs}], proj#0..1=[{exprs}])" + LINE_SEPARATOR
                 + "  EnumerableHashJoin(condition=[=($1, $2)], joinType=[inner])" + LINE_SEPARATOR
                 + "    TranslatableTableScan(table=[[federate_jdbc, t_order_federate]], fields=[[0, 1]])" + LINE_SEPARATOR
                 + "    EnumerableAggregate(group=[{0}])" + LINE_SEPARATOR
                 + "      TranslatableTableScan(table=[[federate_jdbc, t_user_info]], fields=[[0]])" + LINE_SEPARATOR;
-        assertThat(actual, is(expected));
+        MatcherAssert.assertThat(actual, is(expected));
     }
     
     @Test
     public void assertSelectSubQueryWhereBetween() {
         ShardingSphereSQLParserEngine sqlParserEngine = sqlParserRule.getSQLParserEngine(DatabaseTypeEngine.getTrunkDatabaseTypeName(new H2DatabaseType()));
         SQLStatement sqlStatement = sqlParserEngine.parse(SELECT_SUBQUERY_WHERE_BETWEEN, false);
-        String actual = optimizer.optimize(sqlStatement).explain();
+        String actual = optimizeEngine.optimize(sqlStatement).getBestPlan().explain();
         String expected = "EnumerableCalc(expr#0..2=[{inputs}], proj#0..1=[{exprs}])" + LINE_SEPARATOR
                 + "  EnumerableNestedLoopJoin(condition=[<=($1, $2)], joinType=[inner])" + LINE_SEPARATOR
                 + "    EnumerableCalc(expr#0..2=[{inputs}], proj#0..1=[{exprs}])" + LINE_SEPARATOR
@@ -250,18 +249,18 @@ public final class ShardingSphereOptimizerTest {
                 + "          TranslatableTableScan(table=[[federate_jdbc, t_user_info]], fields=[[0]], filters=[[=(CAST($0):INTEGER, 1)]])" + LINE_SEPARATOR
                 + "    EnumerableAggregate(group=[{}], agg#0=[SINGLE_VALUE($0)])" + LINE_SEPARATOR
                 + "      TranslatableTableScan(table=[[federate_jdbc, t_user_info]], fields=[[0]], filters=[[=(CAST($0):INTEGER, 3)]])" + LINE_SEPARATOR;
-        assertThat(actual, is(expected));
+        MatcherAssert.assertThat(actual, is(expected));
     }
     
     @Test
     public void assertSelectUnion() {
         ShardingSphereSQLParserEngine sqlParserEngine = sqlParserRule.getSQLParserEngine(DatabaseTypeEngine.getTrunkDatabaseTypeName(new H2DatabaseType()));
         SQLStatement sqlStatement = sqlParserEngine.parse(SELECT_UNION, false);
-        String actual = optimizer.optimize(sqlStatement).explain();
+        String actual = optimizeEngine.optimize(sqlStatement).getBestPlan().explain();
         String expected = "EnumerableUnion(all=[false])" + LINE_SEPARATOR
                 + "  TranslatableTableScan(table=[[federate_jdbc, t_order_federate]], fields=[[0, 1]])" + LINE_SEPARATOR
                 + "  EnumerableCalc(expr#0=[{inputs}], expr#1=['1':VARCHAR], EXPR$0=[$t1], user_id=[$t0])" + LINE_SEPARATOR
                 + "    TranslatableTableScan(table=[[federate_jdbc, t_user_info]], fields=[[0]], filters=[[=(CAST($1):VARCHAR, 'before'), null]])" + LINE_SEPARATOR;
-        assertThat(actual, is(expected));
+        MatcherAssert.assertThat(actual, is(expected));
     }
 }
diff --git a/shardingsphere-test/shardingsphere-integration-test/shardingsphere-integration-test-suite/src/test/resources/cases/dql/dql-integration-test-cases.xml b/shardingsphere-test/shardingsphere-integration-test/shardingsphere-integration-test-suite/src/test/resources/cases/dql/dql-integration-test-cases.xml
index d6d6f986d71..eff886f2d45 100644
--- a/shardingsphere-test/shardingsphere-integration-test/shardingsphere-integration-test-suite/src/test/resources/cases/dql/dql-integration-test-cases.xml
+++ b/shardingsphere-test/shardingsphere-integration-test/shardingsphere-integration-test-suite/src/test/resources/cases/dql/dql-integration-test-cases.xml
@@ -531,15 +531,13 @@
         <assertion parameters="1000:int, 100000:int" expected-data-source-name="read_dataset" />
     </test-case>
 
-    <!-- FIXME No match found for function signature CONCAT(<CHARACTER>, <CHARACTER>) -->
-    <!--<test-case sql="SELECT user_id, CONCAT('SUM:', total, '.') AS content FROM (SELECT user_id, SUM(order_id_sharding) AS total FROM t_order_federate_sharding GROUP BY user_id HAVING SUM(order_id_sharding) > ?) AS temp ORDER BY temp.user_id" db-types="MySQL,PostgreSQL" scenario-types="tbl">
+    <test-case sql="SELECT user_id, CONCAT('SUM:', total, '.') AS content FROM (SELECT user_id, SUM(order_id_sharding) AS total FROM t_order_federate_sharding GROUP BY user_id HAVING SUM(order_id_sharding) > ?) AS temp ORDER BY temp.user_id" db-types="MySQL,PostgreSQL" scenario-types="tbl">
         <assertion parameters="1000:int" />
-    </test-case>-->
+    </test-case>
     
-    <!-- FIXME Unknown exception: org.apache.calcite.runtime.FlatLists$ComparableEmptyList cannot be cast to [Ljava.lang.Object; -->
-    <!--<test-case sql="SELECT GROUP_CONCAT(i.item_id SEPARATOR ';') AS item_ids FROM t_order_federate o INNER JOIN t_order_item_federate_sharding i ON o.order_id = i.item_id WHERE i.order_id >= ?" db-types="MySQL" scenario-types="dbtbl_with_readwrite_splitting,dbtbl_with_readwrite_splitting_and_encrypt,sharding_and_encrypt,encrypt_and_readwrite_splitting">
+    <test-case sql="SELECT GROUP_CONCAT(i.item_id SEPARATOR ';') AS item_ids FROM t_order_federate o INNER JOIN t_order_item_federate_sharding i ON o.order_id = i.item_id WHERE i.order_id >= ?" db-types="MySQL" scenario-types="dbtbl_with_readwrite_splitting,dbtbl_with_readwrite_splitting_and_encrypt,sharding_and_encrypt,encrypt_and_readwrite_splitting">
         <assertion parameters="10000:int" expected-data-source-name="read_dataset" />
-    </test-case>-->
+    </test-case>
     
     <test-case sql="select t_order_federate.*, t_order_item_federate_sharding.* from t_order_federate,t_order_item_federate_sharding where t_order_federate.order_id = t_order_item_federate_sharding.item_id" scenario-types="dbtbl_with_readwrite_splitting,dbtbl_with_readwrite_splitting_and_encrypt,sharding_and_encrypt,encrypt_and_readwrite_splitting">
         <assertion expected-data-source-name="read_dataset" />
@@ -554,15 +552,13 @@
         <assertion parameters="1000:int" />
     </test-case>-->
     
-    <!-- FIXME Cannot find JDBC type '0' in PostgreSQL column type -->
-    <!--<test-case sql="SELECT (SELECT MAX(user_id) FROM t_order_federate_sharding) max_user_id, order_id_sharding, status FROM t_order_federate_sharding WHERE order_id_sharding > ?" db-types="MySQL,PostgreSQL" scenario-types="tbl">
+    <test-case sql="SELECT (SELECT MAX(user_id) FROM t_order_federate_sharding) max_user_id, order_id_sharding, status FROM t_order_federate_sharding WHERE order_id_sharding > ?" db-types="MySQL,PostgreSQL" scenario-types="tbl">
         <assertion parameters="1100:int" />
-    </test-case>-->
+    </test-case>
     
-    <!-- FIXME Cannot find JDBC type '0' in PostgreSQL column type -->
-    <!--<test-case sql="SELECT user_id, SUM(order_id_sharding) FROM t_order_federate_sharding GROUP BY user_id HAVING SUM(order_id_sharding) > ? ORDER BY user_id" db-types="MySQL,PostgreSQL" scenario-types="tbl">
+    <test-case sql="SELECT user_id, SUM(order_id_sharding) FROM t_order_federate_sharding GROUP BY user_id HAVING SUM(order_id_sharding) > ? ORDER BY user_id" db-types="MySQL,PostgreSQL" scenario-types="tbl">
         <assertion parameters="1000:int" />
-    </test-case>-->
+    </test-case>
     
     <test-case sql="SELECT COUNT(1) FROM t_order WHERE order_id &lt; ?" db-types="PostgreSQL" scenario-types="db,tbl">
         <assertion parameters="2000:int" />