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 2020/12/25 12:28:54 UTC

[shardingsphere] branch master updated: Use sane query result engine for different databases dialect compatibility (#8783)

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 d7c7341  Use sane query result engine for different databases dialect compatibility  (#8783)
d7c7341 is described below

commit d7c7341e2f3e96812189d9d60d88c234de9a66f8
Author: Liang Zhang <te...@163.com>
AuthorDate: Fri Dec 25 20:28:38 2020 +0800

    Use sane query result engine for different databases dialect compatibility  (#8783)
    
    * Refactor ProxyJDBCExecutorCallback
    
    * Refactor JDBCExecutorCallback.getSaneResult
    
    * Add JDBCSaneQueryResultEngine
    
    * Refactor ExecuteQueryCallback
    
    * Add MySQLSaneQueryResultEngine
    
    * Refactor MySQLSaneQueryResultEngine
    
    * Refactor MySQLSaneQueryResultEngine
    
    * Add MySQLDefaultVariable
    
    * Update MySQLDefaultVariable
---
 .../engine/driver/jdbc/JDBCExecutorCallback.java   | 11 ++-
 .../jdbc/sane/DefaultSaneQueryResultEngine.java    | 46 +++++++++++++
 .../jdbc/sane/JDBCSaneQueryResultEngine.java       | 32 +++++----
 .../sane/JDBCSaneQueryResultEngineFactory.java     | 47 +++++++++++++
 .../jdbc/sane/mysql/MySQLDefaultVariable.java      | 76 +++++++++++++++++++++
 .../sane/mysql/MySQLSaneQueryResultEngine.java     | 79 ++++++++++++++++++++++
 ...gine.driver.jdbc.sane.JDBCSaneQueryResultEngine | 18 +++++
 .../engine/jdbc/JDBCExecutorCallbackTest.java      |  7 +-
 .../batch/BatchPreparedStatementExecutor.java      |  6 +-
 .../executor/callback/ExecuteQueryCallback.java    | 25 +++----
 .../PreparedStatementExecuteQueryCallback.java     |  4 +-
 .../impl/StatementExecuteQueryCallback.java        |  4 +-
 .../statement/ShardingSpherePreparedStatement.java | 10 +--
 .../core/statement/ShardingSphereStatement.java    | 15 ++--
 .../callback/ProxyJDBCExecutorCallback.java        | 32 +++------
 15 files changed, 338 insertions(+), 74 deletions(-)

diff --git a/shardingsphere-infra/shardingsphere-infra-executor/src/main/java/org/apache/shardingsphere/infra/executor/sql/execute/engine/driver/jdbc/JDBCExecutorCallback.java b/shardingsphere-infra/shardingsphere-infra-executor/src/main/java/org/apache/shardingsphere/infra/executor/sql/execute/engine/driver/jdbc/JDBCExecutorCallback.java
index defa353..6ed1b14 100644
--- a/shardingsphere-infra/shardingsphere-infra-executor/src/main/java/org/apache/shardingsphere/infra/executor/sql/execute/engine/driver/jdbc/JDBCExecutorCallback.java
+++ b/shardingsphere-infra/shardingsphere-infra-executor/src/main/java/org/apache/shardingsphere/infra/executor/sql/execute/engine/driver/jdbc/JDBCExecutorCallback.java
@@ -17,6 +17,7 @@
 
 package org.apache.shardingsphere.infra.executor.sql.execute.engine.driver.jdbc;
 
+import lombok.Getter;
 import lombok.RequiredArgsConstructor;
 import org.apache.shardingsphere.infra.database.metadata.DataSourceMetaData;
 import org.apache.shardingsphere.infra.database.type.DatabaseType;
@@ -26,6 +27,7 @@ import org.apache.shardingsphere.infra.executor.sql.execute.engine.ConnectionMod
 import org.apache.shardingsphere.infra.executor.sql.execute.engine.SQLExecutorExceptionHandler;
 import org.apache.shardingsphere.infra.executor.sql.hook.SPISQLExecutionHook;
 import org.apache.shardingsphere.infra.executor.sql.hook.SQLExecutionHook;
+import org.apache.shardingsphere.sql.parser.sql.common.statement.SQLStatement;
 
 import java.sql.DatabaseMetaData;
 import java.sql.SQLException;
@@ -45,8 +47,11 @@ public abstract class JDBCExecutorCallback<T> implements ExecutorCallback<JDBCEx
     
     private static final Map<String, DataSourceMetaData> CACHED_DATASOURCE_METADATA = new ConcurrentHashMap<>();
     
+    @Getter
     private final DatabaseType databaseType;
-
+    
+    private final SQLStatement sqlStatement;
+    
     private final boolean isExceptionThrown;
     
     @Override
@@ -80,7 +85,7 @@ public abstract class JDBCExecutorCallback<T> implements ExecutorCallback<JDBCEx
         } catch (final SQLException ex) {
             sqlExecutionHook.finishFailure(ex);
             SQLExecutorExceptionHandler.handleException(ex);
-            return isTrunkThread ? getSaneResult(jdbcExecutionUnit) : null;
+            return isTrunkThread ? getSaneResult(sqlStatement, jdbcExecutionUnit) : null;
         }
     }
     
@@ -96,5 +101,5 @@ public abstract class JDBCExecutorCallback<T> implements ExecutorCallback<JDBCEx
     
     protected abstract T executeSQL(String sql, Statement statement, ConnectionMode connectionMode) throws SQLException;
     
-    protected abstract T getSaneResult(JDBCExecutionUnit jdbcExecutionUnit) throws SQLException;
+    protected abstract T getSaneResult(SQLStatement sqlStatement, JDBCExecutionUnit jdbcExecutionUnit) throws SQLException;
 }
diff --git a/shardingsphere-infra/shardingsphere-infra-executor/src/main/java/org/apache/shardingsphere/infra/executor/sql/execute/engine/driver/jdbc/sane/DefaultSaneQueryResultEngine.java b/shardingsphere-infra/shardingsphere-infra-executor/src/main/java/org/apache/shardingsphere/infra/executor/sql/execute/engine/driver/jdbc/sane/DefaultSaneQueryResultEngine.java
new file mode 100644
index 0000000..1f7eb0e
--- /dev/null
+++ b/shardingsphere-infra/shardingsphere-infra-executor/src/main/java/org/apache/shardingsphere/infra/executor/sql/execute/engine/driver/jdbc/sane/DefaultSaneQueryResultEngine.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.infra.executor.sql.execute.engine.driver.jdbc.sane;
+
+import org.apache.shardingsphere.infra.database.type.DatabaseType;
+import org.apache.shardingsphere.infra.executor.sql.execute.engine.driver.jdbc.JDBCExecutionUnit;
+import org.apache.shardingsphere.infra.executor.sql.execute.result.query.QueryResult;
+import org.apache.shardingsphere.infra.executor.sql.execute.result.query.impl.driver.jdbc.type.memory.JDBCMemoryQueryResult;
+import org.apache.shardingsphere.sql.parser.sql.common.statement.SQLStatement;
+import org.apache.shardingsphere.sql.parser.sql.common.statement.dml.SelectStatement;
+import org.apache.shardingsphere.sql.parser.sql.dialect.statement.mysql.dal.MySQLShowOtherStatement;
+
+import java.sql.SQLException;
+import java.util.Optional;
+
+/**
+ * Default Sane query result engine.
+ */
+public final class DefaultSaneQueryResultEngine implements JDBCSaneQueryResultEngine {
+    
+    @Override
+    public Optional<QueryResult> getSaneQueryResult(final SQLStatement sqlStatement, final JDBCExecutionUnit jdbcExecutionUnit, final DatabaseType targetDatabaseType) throws SQLException {
+        return sqlStatement instanceof SelectStatement || sqlStatement instanceof MySQLShowOtherStatement
+                ? Optional.of(new JDBCMemoryQueryResult(jdbcExecutionUnit.getStorageResource().executeQuery("SELECT 1"))) : Optional.empty();
+    }
+    
+    @Override
+    public String getType() {
+        return "";
+    }
+}
diff --git a/shardingsphere-jdbc/shardingsphere-jdbc-core/src/main/java/org/apache/shardingsphere/driver/executor/callback/impl/PreparedStatementExecuteQueryCallback.java b/shardingsphere-infra/shardingsphere-infra-executor/src/main/java/org/apache/shardingsphere/infra/executor/sql/execute/engine/driver/jdbc/sane/JDBCSaneQueryResultEngine.java
similarity index 52%
copy from shardingsphere-jdbc/shardingsphere-jdbc-core/src/main/java/org/apache/shardingsphere/driver/executor/callback/impl/PreparedStatementExecuteQueryCallback.java
copy to shardingsphere-infra/shardingsphere-infra-executor/src/main/java/org/apache/shardingsphere/infra/executor/sql/execute/engine/driver/jdbc/sane/JDBCSaneQueryResultEngine.java
index 9e0cc51..783b518 100644
--- a/shardingsphere-jdbc/shardingsphere-jdbc-core/src/main/java/org/apache/shardingsphere/driver/executor/callback/impl/PreparedStatementExecuteQueryCallback.java
+++ b/shardingsphere-infra/shardingsphere-infra-executor/src/main/java/org/apache/shardingsphere/infra/executor/sql/execute/engine/driver/jdbc/sane/JDBCSaneQueryResultEngine.java
@@ -15,28 +15,30 @@
  * limitations under the License.
  */
 
-package org.apache.shardingsphere.driver.executor.callback.impl;
+package org.apache.shardingsphere.infra.executor.sql.execute.engine.driver.jdbc.sane;
 
-import org.apache.shardingsphere.driver.executor.callback.ExecuteQueryCallback;
 import org.apache.shardingsphere.infra.database.type.DatabaseType;
+import org.apache.shardingsphere.infra.executor.sql.execute.engine.driver.jdbc.JDBCExecutionUnit;
+import org.apache.shardingsphere.infra.executor.sql.execute.result.query.QueryResult;
+import org.apache.shardingsphere.infra.spi.typed.TypedSPI;
 import org.apache.shardingsphere.sql.parser.sql.common.statement.SQLStatement;
 
-import java.sql.PreparedStatement;
-import java.sql.ResultSet;
 import java.sql.SQLException;
-import java.sql.Statement;
+import java.util.Optional;
 
 /**
- * Prepared statement execute query callback.
+ * JDBC sane query result engine.
  */
-public final class PreparedStatementExecuteQueryCallback extends ExecuteQueryCallback {
+public interface JDBCSaneQueryResultEngine extends TypedSPI {
     
-    public PreparedStatementExecuteQueryCallback(final DatabaseType databaseType, final boolean isExceptionThrown, final SQLStatement sqlStatement) {
-        super(databaseType, isExceptionThrown, sqlStatement);
-    }
-    
-    @Override
-    protected ResultSet executeQuery(final String sql, final Statement statement) throws SQLException {
-        return ((PreparedStatement) statement).executeQuery();
-    }
+    /**
+     * Get sane query result.
+     * 
+     * @param sqlStatement SQL statement
+     * @param jdbcExecutionUnit JDBC execution unit
+     * @param targetDatabaseType target database type
+     * @return sane query result
+     * @throws SQLException SQL exception
+     */
+    Optional<QueryResult> getSaneQueryResult(SQLStatement sqlStatement, JDBCExecutionUnit jdbcExecutionUnit, DatabaseType targetDatabaseType) throws SQLException;
 }
diff --git a/shardingsphere-infra/shardingsphere-infra-executor/src/main/java/org/apache/shardingsphere/infra/executor/sql/execute/engine/driver/jdbc/sane/JDBCSaneQueryResultEngineFactory.java b/shardingsphere-infra/shardingsphere-infra-executor/src/main/java/org/apache/shardingsphere/infra/executor/sql/execute/engine/driver/jdbc/sane/JDBCSaneQueryResultEngineFactory.java
new file mode 100644
index 0000000..f3b8e39
--- /dev/null
+++ b/shardingsphere-infra/shardingsphere-infra-executor/src/main/java/org/apache/shardingsphere/infra/executor/sql/execute/engine/driver/jdbc/sane/JDBCSaneQueryResultEngineFactory.java
@@ -0,0 +1,47 @@
+/*
+ * 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.execute.engine.driver.jdbc.sane;
+
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import org.apache.shardingsphere.infra.database.type.DatabaseType;
+import org.apache.shardingsphere.infra.spi.ShardingSphereServiceLoader;
+import org.apache.shardingsphere.infra.spi.typed.TypedSPIRegistry;
+
+import java.util.Properties;
+
+/**
+ * JDBC sane query result engine factory.
+ */
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public final class JDBCSaneQueryResultEngineFactory {
+    
+    static {
+        ShardingSphereServiceLoader.register(JDBCSaneQueryResultEngine.class);
+    }
+    
+    /**
+     * Get new instance of JDBC sane query result engine.
+     * 
+     * @param databaseType database type
+     * @return new instance of JDBC sane query result engine
+     */
+    public static JDBCSaneQueryResultEngine newInstance(final DatabaseType databaseType) {
+        return TypedSPIRegistry.findRegisteredService(JDBCSaneQueryResultEngine.class, databaseType.getName(), new Properties()).orElse(new DefaultSaneQueryResultEngine());
+    }
+}
diff --git a/shardingsphere-infra/shardingsphere-infra-executor/src/main/java/org/apache/shardingsphere/infra/executor/sql/execute/engine/driver/jdbc/sane/mysql/MySQLDefaultVariable.java b/shardingsphere-infra/shardingsphere-infra-executor/src/main/java/org/apache/shardingsphere/infra/executor/sql/execute/engine/driver/jdbc/sane/mysql/MySQLDefaultVariable.java
new file mode 100644
index 0000000..9476136
--- /dev/null
+++ b/shardingsphere-infra/shardingsphere-infra-executor/src/main/java/org/apache/shardingsphere/infra/executor/sql/execute/engine/driver/jdbc/sane/mysql/MySQLDefaultVariable.java
@@ -0,0 +1,76 @@
+/*
+ * 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.execute.engine.driver.jdbc.sane.mysql;
+
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * MySQL default variable.
+ */
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public final class MySQLDefaultVariable {
+    
+    private static final Map<String, String> VARIABLES = new HashMap<>();
+    
+    static {
+        VARIABLES.put("auto_increment_increment", "1");
+        VARIABLES.put("character_set_client", "utf8");
+        VARIABLES.put("character_set_connection", "utf8");
+        VARIABLES.put("character_set_results", "utf8");
+        VARIABLES.put("character_set_server", "utf8");
+        VARIABLES.put("collation_server", "utf8_general_ci");
+        VARIABLES.put("collation_connection", "utf8_general_ci");
+        VARIABLES.put("init_connect", "");
+        VARIABLES.put("interactive_timeout", "28800");
+        VARIABLES.put("license", "GPL");
+        VARIABLES.put("lower_case_table_names", "2");
+        VARIABLES.put("max_allowed_packet", "4194304");
+        VARIABLES.put("net_buffer_length", "16384");
+        VARIABLES.put("net_write_timeout", "60");
+        VARIABLES.put("sql_mode", "STRICT_TRANS_TABLES");
+        VARIABLES.put("system_time_zone", "CST");
+        VARIABLES.put("time_zone", "SYSTEM");
+        VARIABLES.put("transaction_isolation", "REPEATABLE-READ");
+        VARIABLES.put("wait_timeout", "28800");
+        VARIABLES.put("@@session.transaction_read_only", "0");
+    }
+    
+    /**
+     * Judge whether contains variable.
+     * 
+     * @param variableName variable name
+     * @return contains variable or not
+     */
+    public static boolean containsVariable(final String variableName) {
+        return VARIABLES.containsKey(variableName);
+    }
+    
+    /**
+     * Get variable value.
+     *
+     * @param variableName variable name
+     * @return variable value
+     */
+    public static String getVariable(final String variableName) {
+        return VARIABLES.get(variableName);
+    }
+}
diff --git a/shardingsphere-infra/shardingsphere-infra-executor/src/main/java/org/apache/shardingsphere/infra/executor/sql/execute/engine/driver/jdbc/sane/mysql/MySQLSaneQueryResultEngine.java b/shardingsphere-infra/shardingsphere-infra-executor/src/main/java/org/apache/shardingsphere/infra/executor/sql/execute/engine/driver/jdbc/sane/mysql/MySQLSaneQueryResultEngine.java
new file mode 100644
index 0000000..fc2ac03
--- /dev/null
+++ b/shardingsphere-infra/shardingsphere-infra-executor/src/main/java/org/apache/shardingsphere/infra/executor/sql/execute/engine/driver/jdbc/sane/mysql/MySQLSaneQueryResultEngine.java
@@ -0,0 +1,79 @@
+/*
+ * 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.execute.engine.driver.jdbc.sane.mysql;
+
+import org.apache.shardingsphere.infra.database.type.DatabaseType;
+import org.apache.shardingsphere.infra.executor.sql.execute.engine.driver.jdbc.JDBCExecutionUnit;
+import org.apache.shardingsphere.infra.executor.sql.execute.engine.driver.jdbc.sane.JDBCSaneQueryResultEngine;
+import org.apache.shardingsphere.infra.executor.sql.execute.result.query.QueryResult;
+import org.apache.shardingsphere.infra.executor.sql.execute.result.query.impl.driver.jdbc.type.memory.JDBCMemoryQueryResult;
+import org.apache.shardingsphere.infra.metadata.schema.builder.loader.dialect.DatabaseMetaDataDialectHandler;
+import org.apache.shardingsphere.infra.metadata.schema.builder.loader.dialect.DatabaseMetaDataDialectHandlerFactory;
+import org.apache.shardingsphere.sql.parser.sql.common.constant.QuoteCharacter;
+import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.item.ExpressionProjectionSegment;
+import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.item.ProjectionSegment;
+import org.apache.shardingsphere.sql.parser.sql.common.statement.SQLStatement;
+import org.apache.shardingsphere.sql.parser.sql.common.statement.dml.SelectStatement;
+import org.apache.shardingsphere.sql.parser.sql.dialect.statement.mysql.dal.MySQLShowOtherStatement;
+
+import java.sql.SQLException;
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.Optional;
+
+/**
+ * Sane query result engine for MySQL.
+ */
+public final class MySQLSaneQueryResultEngine implements JDBCSaneQueryResultEngine {
+    
+    @Override
+    public Optional<QueryResult> getSaneQueryResult(final SQLStatement sqlStatement, final JDBCExecutionUnit jdbcExecutionUnit, final DatabaseType targetDatabaseType) throws SQLException {
+        Optional<String> saneSQL = getSaneSQL(sqlStatement, getDialectQuoteCharacter(targetDatabaseType));
+        return saneSQL.isPresent() ? Optional.of(new JDBCMemoryQueryResult(jdbcExecutionUnit.getStorageResource().executeQuery(saneSQL.get()))) : Optional.empty();
+    }
+    
+    private QuoteCharacter getDialectQuoteCharacter(final DatabaseType targetDatabaseType) {
+        Optional<DatabaseMetaDataDialectHandler> databaseMetaDataDialectHandler = DatabaseMetaDataDialectHandlerFactory.findHandler(targetDatabaseType);
+        return databaseMetaDataDialectHandler.isPresent() ? databaseMetaDataDialectHandler.get().getQuoteCharacter() : QuoteCharacter.NONE;
+    }
+    
+    private Optional<String> getSaneSQL(final SQLStatement sqlStatement, final QuoteCharacter quoteCharacter) {
+        if (sqlStatement instanceof SelectStatement) {
+            return Optional.of(getSaneSQL((SelectStatement) sqlStatement, quoteCharacter));
+        } else if (sqlStatement instanceof MySQLShowOtherStatement) {
+            return Optional.of("SELECT 1");
+        }
+        return Optional.empty();
+    }
+    
+    private String getSaneSQL(final SelectStatement selectStatement, final QuoteCharacter quoteCharacter) {
+        Collection<String> saneProjections = new LinkedList<>();
+        for (ProjectionSegment each : selectStatement.getProjections().getProjections()) {
+            if (each instanceof ExpressionProjectionSegment) {
+                String alias = ((ExpressionProjectionSegment) each).getAlias().orElse(((ExpressionProjectionSegment) each).getText());
+                saneProjections.add(String.format("'%s' AS %s", MySQLDefaultVariable.containsVariable(alias) ? MySQLDefaultVariable.getVariable(alias) : "1", quoteCharacter.wrap(alias)));
+            }
+        }
+        return String.format("SELECT %s", String.join(", ", saneProjections));
+    }
+    
+    @Override
+    public String getType() {
+        return "MySQL";
+    }
+}
diff --git a/shardingsphere-infra/shardingsphere-infra-executor/src/main/resources/META-INF/services/org.apache.shardingsphere.infra.executor.sql.execute.engine.driver.jdbc.sane.JDBCSaneQueryResultEngine b/shardingsphere-infra/shardingsphere-infra-executor/src/main/resources/META-INF/services/org.apache.shardingsphere.infra.executor.sql.execute.engine.driver.jdbc.sane.JDBCSaneQueryResultEngine
new file mode 100644
index 0000000..d98090e
--- /dev/null
+++ b/shardingsphere-infra/shardingsphere-infra-executor/src/main/resources/META-INF/services/org.apache.shardingsphere.infra.executor.sql.execute.engine.driver.jdbc.sane.JDBCSaneQueryResultEngine
@@ -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.infra.executor.sql.execute.engine.driver.jdbc.sane.mysql.MySQLSaneQueryResultEngine
diff --git a/shardingsphere-infra/shardingsphere-infra-executor/src/test/java/org/apache/shardingsphere/infra/executor/sql/execute/engine/jdbc/JDBCExecutorCallbackTest.java b/shardingsphere-infra/shardingsphere-infra-executor/src/test/java/org/apache/shardingsphere/infra/executor/sql/execute/engine/jdbc/JDBCExecutorCallbackTest.java
index 178c7ec..0fedb42 100644
--- a/shardingsphere-infra/shardingsphere-infra-executor/src/test/java/org/apache/shardingsphere/infra/executor/sql/execute/engine/jdbc/JDBCExecutorCallbackTest.java
+++ b/shardingsphere-infra/shardingsphere-infra-executor/src/test/java/org/apache/shardingsphere/infra/executor/sql/execute/engine/jdbc/JDBCExecutorCallbackTest.java
@@ -24,6 +24,8 @@ import org.apache.shardingsphere.infra.executor.sql.context.SQLUnit;
 import org.apache.shardingsphere.infra.executor.sql.execute.engine.ConnectionMode;
 import org.apache.shardingsphere.infra.executor.sql.execute.engine.driver.jdbc.JDBCExecutionUnit;
 import org.apache.shardingsphere.infra.executor.sql.execute.engine.driver.jdbc.JDBCExecutorCallback;
+import org.apache.shardingsphere.sql.parser.sql.common.statement.SQLStatement;
+import org.apache.shardingsphere.sql.parser.sql.common.statement.dml.SelectStatement;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -42,6 +44,7 @@ import java.util.Map;
 
 import static org.hamcrest.CoreMatchers.is;
 import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
 @RunWith(MockitoJUnitRunner.class)
@@ -70,7 +73,7 @@ public final class JDBCExecutorCallbackTest {
     @SuppressWarnings("unchecked")
     @Test
     public void assertExecute() throws SQLException, NoSuchFieldException, IllegalAccessException {
-        JDBCExecutorCallback<?> jdbcExecutorCallback = new JDBCExecutorCallback<Integer>(DatabaseTypeRegistry.getActualDatabaseType("MySQL"), true) {
+        JDBCExecutorCallback<?> jdbcExecutorCallback = new JDBCExecutorCallback<Integer>(DatabaseTypeRegistry.getActualDatabaseType("MySQL"), mock(SelectStatement.class), true) {
             
             @Override
             protected Integer executeSQL(final String sql, final Statement statement, final ConnectionMode connectionMode) throws SQLException {
@@ -78,7 +81,7 @@ public final class JDBCExecutorCallbackTest {
             }
             
             @Override
-            protected Integer getSaneResult(final JDBCExecutionUnit jdbcExecutionUnit) {
+            protected Integer getSaneResult(final SQLStatement sqlStatement, final JDBCExecutionUnit jdbcExecutionUnit) {
                 return 0;
             }
         };
diff --git a/shardingsphere-jdbc/shardingsphere-jdbc-core/src/main/java/org/apache/shardingsphere/driver/executor/batch/BatchPreparedStatementExecutor.java b/shardingsphere-jdbc/shardingsphere-jdbc-core/src/main/java/org/apache/shardingsphere/driver/executor/batch/BatchPreparedStatementExecutor.java
index 477aff4..a5c8ad6 100644
--- a/shardingsphere-jdbc/shardingsphere-jdbc-core/src/main/java/org/apache/shardingsphere/driver/executor/batch/BatchPreparedStatementExecutor.java
+++ b/shardingsphere-jdbc/shardingsphere-jdbc-core/src/main/java/org/apache/shardingsphere/driver/executor/batch/BatchPreparedStatementExecutor.java
@@ -30,6 +30,7 @@ import org.apache.shardingsphere.infra.executor.sql.execute.engine.driver.jdbc.J
 import org.apache.shardingsphere.infra.executor.sql.execute.engine.driver.jdbc.JDBCExecutorCallback;
 import org.apache.shardingsphere.infra.rule.ShardingSphereRule;
 import org.apache.shardingsphere.infra.rule.type.DataNodeContainedRule;
+import org.apache.shardingsphere.sql.parser.sql.common.statement.SQLStatement;
 
 import java.sql.SQLException;
 import java.sql.Statement;
@@ -118,7 +119,8 @@ public final class BatchPreparedStatementExecutor {
      */
     public int[] executeBatch(final SQLStatementContext sqlStatementContext) throws SQLException {
         boolean isExceptionThrown = SQLExecutorExceptionHandler.isExceptionThrown();
-        JDBCExecutorCallback<int[]> callback = new JDBCExecutorCallback<int[]>(metaDataContexts.getDefaultMetaData().getResource().getDatabaseType(), isExceptionThrown) {
+        JDBCExecutorCallback<int[]> callback = new JDBCExecutorCallback<int[]>(
+                metaDataContexts.getDefaultMetaData().getResource().getDatabaseType(), sqlStatementContext.getSqlStatement(), isExceptionThrown) {
             
             @Override
             protected int[] executeSQL(final String sql, final Statement statement, final ConnectionMode connectionMode) throws SQLException {
@@ -126,7 +128,7 @@ public final class BatchPreparedStatementExecutor {
             }
             
             @Override
-            protected int[] getSaneResult(final JDBCExecutionUnit jdbcExecutionUnit) {
+            protected int[] getSaneResult(final SQLStatement sqlStatement, final JDBCExecutionUnit jdbcExecutionUnit) {
                 return new int[batchCount];
             }
         };
diff --git a/shardingsphere-jdbc/shardingsphere-jdbc-core/src/main/java/org/apache/shardingsphere/driver/executor/callback/ExecuteQueryCallback.java b/shardingsphere-jdbc/shardingsphere-jdbc-core/src/main/java/org/apache/shardingsphere/driver/executor/callback/ExecuteQueryCallback.java
index c1110a5..21329db 100644
--- a/shardingsphere-jdbc/shardingsphere-jdbc-core/src/main/java/org/apache/shardingsphere/driver/executor/callback/ExecuteQueryCallback.java
+++ b/shardingsphere-jdbc/shardingsphere-jdbc-core/src/main/java/org/apache/shardingsphere/driver/executor/callback/ExecuteQueryCallback.java
@@ -17,31 +17,29 @@
 
 package org.apache.shardingsphere.driver.executor.callback;
 
+import com.google.common.base.Preconditions;
 import org.apache.shardingsphere.infra.database.type.DatabaseType;
 import org.apache.shardingsphere.infra.executor.sql.execute.engine.ConnectionMode;
 import org.apache.shardingsphere.infra.executor.sql.execute.engine.driver.jdbc.JDBCExecutionUnit;
 import org.apache.shardingsphere.infra.executor.sql.execute.engine.driver.jdbc.JDBCExecutorCallback;
+import org.apache.shardingsphere.infra.executor.sql.execute.engine.driver.jdbc.sane.JDBCSaneQueryResultEngineFactory;
 import org.apache.shardingsphere.infra.executor.sql.execute.result.query.QueryResult;
 import org.apache.shardingsphere.infra.executor.sql.execute.result.query.impl.driver.jdbc.type.memory.JDBCMemoryQueryResult;
 import org.apache.shardingsphere.infra.executor.sql.execute.result.query.impl.driver.jdbc.type.stream.JDBCStreamQueryResult;
 import org.apache.shardingsphere.sql.parser.sql.common.statement.SQLStatement;
-import org.apache.shardingsphere.sql.parser.sql.common.statement.dml.SelectStatement;
 
 import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.sql.Statement;
-import java.util.Collections;
+import java.util.Optional;
 
 /**
  * Execute query callback.
  */
 public abstract class ExecuteQueryCallback extends JDBCExecutorCallback<QueryResult> {
     
-    private final SQLStatement sqlStatement;
-    
-    protected ExecuteQueryCallback(final DatabaseType databaseType, final boolean isExceptionThrown, final SQLStatement sqlStatement) {
-        super(databaseType, isExceptionThrown);
-        this.sqlStatement = sqlStatement;
+    protected ExecuteQueryCallback(final DatabaseType databaseType, final SQLStatement sqlStatement, final boolean isExceptionThrown) {
+        super(databaseType, sqlStatement, isExceptionThrown);
     }
     
     @Override
@@ -51,14 +49,11 @@ public abstract class ExecuteQueryCallback extends JDBCExecutorCallback<QueryRes
     }
     
     @Override
-    protected final QueryResult getSaneResult(final JDBCExecutionUnit jdbcExecutionUnit) throws SQLException {
-        return new JDBCMemoryQueryResult(jdbcExecutionUnit.getStorageResource().executeQuery(getSaneSQL()));
-    }
-    
-    private String getSaneSQL() {
-        int size = sqlStatement instanceof SelectStatement ? ((SelectStatement) sqlStatement).getProjections().getProjections().size() : 1;
-        String saneProjections = String.join(", ", Collections.nCopies(size, "1"));
-        return String.format("SELECT %s", saneProjections);
+    protected final QueryResult getSaneResult(final SQLStatement sqlStatement, final JDBCExecutionUnit jdbcExecutionUnit) throws SQLException {
+        // TODO useless, JDBC cannot support database gateway now
+        Optional<QueryResult> queryResult = JDBCSaneQueryResultEngineFactory.newInstance(getDatabaseType()).getSaneQueryResult(sqlStatement, jdbcExecutionUnit, getDatabaseType());
+        Preconditions.checkState(queryResult.isPresent());
+        return queryResult.get();
     }
     
     protected abstract ResultSet executeQuery(String sql, Statement statement) throws SQLException;
diff --git a/shardingsphere-jdbc/shardingsphere-jdbc-core/src/main/java/org/apache/shardingsphere/driver/executor/callback/impl/PreparedStatementExecuteQueryCallback.java b/shardingsphere-jdbc/shardingsphere-jdbc-core/src/main/java/org/apache/shardingsphere/driver/executor/callback/impl/PreparedStatementExecuteQueryCallback.java
index 9e0cc51..90f69dc 100644
--- a/shardingsphere-jdbc/shardingsphere-jdbc-core/src/main/java/org/apache/shardingsphere/driver/executor/callback/impl/PreparedStatementExecuteQueryCallback.java
+++ b/shardingsphere-jdbc/shardingsphere-jdbc-core/src/main/java/org/apache/shardingsphere/driver/executor/callback/impl/PreparedStatementExecuteQueryCallback.java
@@ -31,8 +31,8 @@ import java.sql.Statement;
  */
 public final class PreparedStatementExecuteQueryCallback extends ExecuteQueryCallback {
     
-    public PreparedStatementExecuteQueryCallback(final DatabaseType databaseType, final boolean isExceptionThrown, final SQLStatement sqlStatement) {
-        super(databaseType, isExceptionThrown, sqlStatement);
+    public PreparedStatementExecuteQueryCallback(final DatabaseType databaseType, final SQLStatement sqlStatement, final boolean isExceptionThrown) {
+        super(databaseType, sqlStatement, isExceptionThrown);
     }
     
     @Override
diff --git a/shardingsphere-jdbc/shardingsphere-jdbc-core/src/main/java/org/apache/shardingsphere/driver/executor/callback/impl/StatementExecuteQueryCallback.java b/shardingsphere-jdbc/shardingsphere-jdbc-core/src/main/java/org/apache/shardingsphere/driver/executor/callback/impl/StatementExecuteQueryCallback.java
index 2984472..81f1a8b 100644
--- a/shardingsphere-jdbc/shardingsphere-jdbc-core/src/main/java/org/apache/shardingsphere/driver/executor/callback/impl/StatementExecuteQueryCallback.java
+++ b/shardingsphere-jdbc/shardingsphere-jdbc-core/src/main/java/org/apache/shardingsphere/driver/executor/callback/impl/StatementExecuteQueryCallback.java
@@ -30,8 +30,8 @@ import java.sql.Statement;
  */
 public final class StatementExecuteQueryCallback extends ExecuteQueryCallback {
     
-    public StatementExecuteQueryCallback(final DatabaseType databaseType, final boolean isExceptionThrown, final SQLStatement sqlStatement) {
-        super(databaseType, isExceptionThrown, sqlStatement);
+    public StatementExecuteQueryCallback(final DatabaseType databaseType, final SQLStatement sqlStatement, final boolean isExceptionThrown) {
+        super(databaseType, sqlStatement, isExceptionThrown);
     }
     
     @Override
diff --git a/shardingsphere-jdbc/shardingsphere-jdbc-core/src/main/java/org/apache/shardingsphere/driver/jdbc/core/statement/ShardingSpherePreparedStatement.java b/shardingsphere-jdbc/shardingsphere-jdbc-core/src/main/java/org/apache/shardingsphere/driver/jdbc/core/statement/ShardingSpherePreparedStatement.java
index 20d2075..a5e96c8 100644
--- a/shardingsphere-jdbc/shardingsphere-jdbc-core/src/main/java/org/apache/shardingsphere/driver/jdbc/core/statement/ShardingSpherePreparedStatement.java
+++ b/shardingsphere-jdbc/shardingsphere-jdbc-core/src/main/java/org/apache/shardingsphere/driver/jdbc/core/statement/ShardingSpherePreparedStatement.java
@@ -181,7 +181,7 @@ public final class ShardingSpherePreparedStatement extends AbstractPreparedState
         Collection<ExecutionGroup<JDBCExecutionUnit>> executionGroups = createExecutionGroups();
         cacheStatements(executionGroups);
         return driverJDBCExecutor.executeQuery(executionGroups, 
-                new PreparedStatementExecuteQueryCallback(metaDataContexts.getDefaultMetaData().getResource().getDatabaseType(), SQLExecutorExceptionHandler.isExceptionThrown(), sqlStatement));
+                new PreparedStatementExecuteQueryCallback(metaDataContexts.getDefaultMetaData().getResource().getDatabaseType(), sqlStatement, SQLExecutorExceptionHandler.isExceptionThrown()));
     }
     
     @Override
@@ -212,7 +212,7 @@ public final class ShardingSpherePreparedStatement extends AbstractPreparedState
     
     private JDBCExecutorCallback<Integer> createExecuteUpdateCallback() {
         boolean isExceptionThrown = SQLExecutorExceptionHandler.isExceptionThrown();
-        return new JDBCExecutorCallback<Integer>(metaDataContexts.getDefaultMetaData().getResource().getDatabaseType(), isExceptionThrown) {
+        return new JDBCExecutorCallback<Integer>(metaDataContexts.getDefaultMetaData().getResource().getDatabaseType(), sqlStatement, isExceptionThrown) {
             
             @Override
             protected Integer executeSQL(final String sql, final Statement statement, final ConnectionMode connectionMode) throws SQLException {
@@ -220,7 +220,7 @@ public final class ShardingSpherePreparedStatement extends AbstractPreparedState
             }
             
             @Override
-            protected Integer getSaneResult(final JDBCExecutionUnit jdbcExecutionUnit) {
+            protected Integer getSaneResult(final SQLStatement sqlStatement, final JDBCExecutionUnit jdbcExecutionUnit) {
                 return 0;
             }
         };
@@ -260,7 +260,7 @@ public final class ShardingSpherePreparedStatement extends AbstractPreparedState
     
     private JDBCExecutorCallback<Boolean> createExecuteCallback() {
         boolean isExceptionThrown = SQLExecutorExceptionHandler.isExceptionThrown();
-        return new JDBCExecutorCallback<Boolean>(metaDataContexts.getDefaultMetaData().getResource().getDatabaseType(), isExceptionThrown) {
+        return new JDBCExecutorCallback<Boolean>(metaDataContexts.getDefaultMetaData().getResource().getDatabaseType(), sqlStatement, isExceptionThrown) {
             
             @Override
             protected Boolean executeSQL(final String sql, final Statement statement, final ConnectionMode connectionMode) throws SQLException {
@@ -268,7 +268,7 @@ public final class ShardingSpherePreparedStatement extends AbstractPreparedState
             }
             
             @Override
-            protected Boolean getSaneResult(final JDBCExecutionUnit jdbcExecutionUnit) {
+            protected Boolean getSaneResult(final SQLStatement sqlStatement, final JDBCExecutionUnit jdbcExecutionUnit) {
                 return sqlStatement instanceof SelectStatement;
             }
         };
diff --git a/shardingsphere-jdbc/shardingsphere-jdbc-core/src/main/java/org/apache/shardingsphere/driver/jdbc/core/statement/ShardingSphereStatement.java b/shardingsphere-jdbc/shardingsphere-jdbc-core/src/main/java/org/apache/shardingsphere/driver/jdbc/core/statement/ShardingSphereStatement.java
index d2838ba..a1da5ab 100644
--- a/shardingsphere-jdbc/shardingsphere-jdbc-core/src/main/java/org/apache/shardingsphere/driver/jdbc/core/statement/ShardingSphereStatement.java
+++ b/shardingsphere-jdbc/shardingsphere-jdbc-core/src/main/java/org/apache/shardingsphere/driver/jdbc/core/statement/ShardingSphereStatement.java
@@ -151,8 +151,8 @@ public final class ShardingSphereStatement extends AbstractStatementAdapter {
         }
         Collection<ExecutionGroup<JDBCExecutionUnit>> executionGroups = createExecutionGroups();
         cacheStatements(executionGroups);
-        StatementExecuteQueryCallback callback = new StatementExecuteQueryCallback(metaDataContexts.getDefaultMetaData().getResource().getDatabaseType(), 
-                SQLExecutorExceptionHandler.isExceptionThrown(), executionContext.getSqlStatementContext().getSqlStatement());
+        StatementExecuteQueryCallback callback = new StatementExecuteQueryCallback(metaDataContexts.getDefaultMetaData().getResource().getDatabaseType(),
+                executionContext.getSqlStatementContext().getSqlStatement(), SQLExecutorExceptionHandler.isExceptionThrown());
         return driverJDBCExecutor.executeQuery(executionGroups, callback);
     }
     
@@ -229,7 +229,7 @@ public final class ShardingSphereStatement extends AbstractStatementAdapter {
                               final SQLStatementContext<?> sqlStatementContext, final Collection<RouteUnit> routeUnits) throws SQLException {
         boolean isExceptionThrown = SQLExecutorExceptionHandler.isExceptionThrown();
         JDBCExecutorCallback<Integer> callback = new JDBCExecutorCallback<Integer>(
-                metaDataContexts.getDefaultMetaData().getResource().getDatabaseType(), isExceptionThrown) {
+                metaDataContexts.getDefaultMetaData().getResource().getDatabaseType(), sqlStatementContext.getSqlStatement(), isExceptionThrown) {
             
             @Override
             protected Integer executeSQL(final String sql, final Statement statement, final ConnectionMode connectionMode) throws SQLException {
@@ -237,7 +237,7 @@ public final class ShardingSphereStatement extends AbstractStatementAdapter {
             }
             
             @Override
-            protected Integer getSaneResult(final JDBCExecutionUnit jdbcExecutionUnit) {
+            protected Integer getSaneResult(final SQLStatement sqlStatement, final JDBCExecutionUnit jdbcExecutionUnit) {
                 return 0;
             }
         };
@@ -332,15 +332,16 @@ public final class ShardingSphereStatement extends AbstractStatementAdapter {
     private boolean execute(final Collection<ExecutionGroup<JDBCExecutionUnit>> executionGroups, final ExecuteCallback executor,
                             final SQLStatement sqlStatement, final Collection<RouteUnit> routeUnits) throws SQLException {
         boolean isExceptionThrown = SQLExecutorExceptionHandler.isExceptionThrown();
-        JDBCExecutorCallback<Boolean> jdbcExecutorCallback = new JDBCExecutorCallback<Boolean>(metaDataContexts.getDefaultMetaData().getResource().getDatabaseType(), isExceptionThrown) {
+        JDBCExecutorCallback<Boolean> jdbcExecutorCallback = new JDBCExecutorCallback<Boolean>(
+                metaDataContexts.getDefaultMetaData().getResource().getDatabaseType(), sqlStatement, isExceptionThrown) {
             
             @Override
             protected Boolean executeSQL(final String sql, final Statement statement, final ConnectionMode connectionMode) throws SQLException {
                 return executor.execute(sql, statement);
             }
-
+            
             @Override
-            protected Boolean getSaneResult(final JDBCExecutionUnit jdbcExecutionUnit) {
+            protected Boolean getSaneResult(final SQLStatement sqlStatement, final JDBCExecutionUnit jdbcExecutionUnit) {
                 return sqlStatement instanceof SelectStatement;
             }
         };
diff --git a/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/communication/jdbc/executor/callback/ProxyJDBCExecutorCallback.java b/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/communication/jdbc/executor/callback/ProxyJDBCExecutorCallback.java
index 9a44c21..951d65f 100644
--- a/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/communication/jdbc/executor/callback/ProxyJDBCExecutorCallback.java
+++ b/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/communication/jdbc/executor/callback/ProxyJDBCExecutorCallback.java
@@ -17,32 +17,32 @@
 
 package org.apache.shardingsphere.proxy.backend.communication.jdbc.executor.callback;
 
+import org.apache.shardingsphere.infra.config.properties.ConfigurationPropertyKey;
 import org.apache.shardingsphere.infra.database.type.DatabaseType;
+import org.apache.shardingsphere.infra.database.type.DatabaseTypeRegistry;
 import org.apache.shardingsphere.infra.executor.sql.execute.engine.ConnectionMode;
 import org.apache.shardingsphere.infra.executor.sql.execute.engine.driver.jdbc.JDBCExecutionUnit;
 import org.apache.shardingsphere.infra.executor.sql.execute.engine.driver.jdbc.JDBCExecutorCallback;
+import org.apache.shardingsphere.infra.executor.sql.execute.engine.driver.jdbc.sane.JDBCSaneQueryResultEngineFactory;
 import org.apache.shardingsphere.infra.executor.sql.execute.result.ExecuteResult;
 import org.apache.shardingsphere.infra.executor.sql.execute.result.query.QueryResult;
 import org.apache.shardingsphere.infra.executor.sql.execute.result.query.impl.driver.jdbc.type.memory.JDBCMemoryQueryResult;
 import org.apache.shardingsphere.infra.executor.sql.execute.result.query.impl.driver.jdbc.type.stream.JDBCStreamQueryResult;
 import org.apache.shardingsphere.infra.executor.sql.execute.result.update.UpdateResult;
 import org.apache.shardingsphere.proxy.backend.communication.jdbc.connection.BackendConnection;
+import org.apache.shardingsphere.proxy.backend.context.ProxyContext;
 import org.apache.shardingsphere.sql.parser.sql.common.statement.SQLStatement;
-import org.apache.shardingsphere.sql.parser.sql.common.statement.dml.SelectStatement;
-import org.apache.shardingsphere.sql.parser.sql.dialect.statement.mysql.dal.MySQLShowOtherStatement;
 
 import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.sql.Statement;
-import java.util.Collections;
+import java.util.Optional;
 
 /**
  * JDBC executor callback for proxy.
  */
 public abstract class ProxyJDBCExecutorCallback extends JDBCExecutorCallback<ExecuteResult> {
     
-    private final SQLStatement sqlStatement;
-    
     private final BackendConnection backendConnection;
     
     private final boolean isReturnGeneratedKeys;
@@ -53,8 +53,7 @@ public abstract class ProxyJDBCExecutorCallback extends JDBCExecutorCallback<Exe
     
     public ProxyJDBCExecutorCallback(final DatabaseType databaseType, final SQLStatement sqlStatement, final BackendConnection backendConnection,
                                      final boolean isExceptionThrown, final boolean isReturnGeneratedKeys, final boolean fetchMetaData) {
-        super(databaseType, isExceptionThrown);
-        this.sqlStatement = sqlStatement;
+        super(databaseType, sqlStatement, isExceptionThrown);
         this.backendConnection = backendConnection;
         this.isReturnGeneratedKeys = isReturnGeneratedKeys;
         this.fetchMetaData = fetchMetaData;
@@ -91,19 +90,10 @@ public abstract class ProxyJDBCExecutorCallback extends JDBCExecutorCallback<Exe
     }
     
     @Override
-    protected ExecuteResult getSaneResult(final JDBCExecutionUnit jdbcExecutionUnit) throws SQLException {
-        if (sqlStatement instanceof SelectStatement) {
-            return new JDBCMemoryQueryResult(jdbcExecutionUnit.getStorageResource().executeQuery(getSaneSQL((SelectStatement) sqlStatement)));
-        }
-        // TODO abstract with show statement
-        if (sqlStatement instanceof MySQLShowOtherStatement) {
-            return new JDBCMemoryQueryResult(jdbcExecutionUnit.getStorageResource().executeQuery("SELECT 1"));
-        }
-        return new UpdateResult(0, 0);
-    }
-    
-    private String getSaneSQL(final SelectStatement selectStatement) {
-        String saneProjections = String.join(", ", Collections.nCopies(selectStatement.getProjections().getProjections().size(), "1"));
-        return String.format("SELECT %s", saneProjections);
+    protected final ExecuteResult getSaneResult(final SQLStatement sqlStatement, final JDBCExecutionUnit jdbcExecutionUnit) throws SQLException {
+        String configuredDatabaseType = ProxyContext.getInstance().getMetaDataContexts().getProps().getValue(ConfigurationPropertyKey.PROXY_FRONTEND_DATABASE_PROTOCOL_TYPE);
+        Optional<QueryResult> queryResult = JDBCSaneQueryResultEngineFactory.newInstance(
+                DatabaseTypeRegistry.getTrunkDatabaseType(configuredDatabaseType)).getSaneQueryResult(sqlStatement, jdbcExecutionUnit, getDatabaseType());
+        return queryResult.isPresent() ? queryResult.get() : new UpdateResult(0, 0);
     }
 }