You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@shardingsphere.apache.org by zh...@apache.org on 2022/07/12 09:19:50 UTC

[shardingsphere] branch master updated: Use SPI to handle MySQL SET statement behaviour (#19060)

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

zhangliang 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 127b59af6bd Use SPI to handle MySQL SET statement behaviour (#19060)
127b59af6bd is described below

commit 127b59af6bd4f7f0f7408413872c4fd29a343808
Author: 吴伟杰 <wu...@apache.org>
AuthorDate: Tue Jul 12 17:19:44 2022 +0800

    Use SPI to handle MySQL SET statement behaviour (#19060)
    
    * Use SPI to handle MySQL SET variable behaviour
    
    * Add test for MySQLSetVariableAdminExecutor
    
    * Add MySQLSessionVariableHandlerFactoryTest
    
    * Fix checkstyle in MySQLSessionVariableHandlerFactoryTest
    
    * Complete TextProtocolBackendHandlerFactoryTest
---
 ...ava => DefaultMySQLSessionVariableHandler.java} | 24 +++---
 .../admin/mysql/MySQLAdminExecutorCreator.java     | 16 +---
 ...cutor.java => MySQLSessionVariableHandler.java} | 25 ++----
 .../mysql/MySQLSessionVariableHandlerFactory.java  | 48 +++++++++++
 .../admin/mysql/MySQLSetVariableAdminExecutor.java | 92 ++++++++++++++++++++++
 .../mysql/executor/MySQLSetCharsetExecutor.java    | 40 +++++++---
 .../text/data/DatabaseBackendHandlerFactory.java   |  1 -
 ...nd.text.admin.mysql.MySQLSessionVariableHandler | 18 +++++
 .../TextProtocolBackendHandlerFactoryTest.java     | 12 ---
 .../MySQLSessionVariableHandlerFactoryTest.java}   | 33 ++++----
 .../mysql/MySQLSetVariableAdminExecutorTest.java   | 80 +++++++++++++++++++
 .../mysql/TestFixtureSessionVariableHandler.java}  | 25 +++---
 ...nd.text.admin.mysql.MySQLSessionVariableHandler | 18 +++++
 13 files changed, 330 insertions(+), 102 deletions(-)

diff --git a/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/admin/mysql/executor/NoResourceSetExecutor.java b/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/admin/mysql/DefaultMySQLSessionVariableHandler.java
similarity index 61%
copy from shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/admin/mysql/executor/NoResourceSetExecutor.java
copy to shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/admin/mysql/DefaultMySQLSessionVariableHandler.java
index 847ac040492..ac076292710 100644
--- a/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/admin/mysql/executor/NoResourceSetExecutor.java
+++ b/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/admin/mysql/DefaultMySQLSessionVariableHandler.java
@@ -15,27 +15,25 @@
  * limitations under the License.
  */
 
-package org.apache.shardingsphere.proxy.backend.text.admin.mysql.executor;
+package org.apache.shardingsphere.proxy.backend.text.admin.mysql;
 
-import lombok.Getter;
-import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
 import org.apache.shardingsphere.proxy.backend.session.ConnectionSession;
-import org.apache.shardingsphere.proxy.backend.text.admin.executor.DatabaseAdminExecutor;
 import org.apache.shardingsphere.sql.parser.sql.common.statement.dal.SetStatement;
 
-import java.sql.SQLException;
+import java.util.stream.Collectors;
 
 /**
- * No Resource set executor.
+ * Default session variable handler for MySQL.
  */
-@Getter
-@RequiredArgsConstructor
-public final class NoResourceSetExecutor implements DatabaseAdminExecutor {
-    
-    private final SetStatement sqlStatement;
+@Slf4j
+public final class DefaultMySQLSessionVariableHandler implements MySQLSessionVariableHandler {
     
     @Override
-    public void execute(final ConnectionSession connectionSession) throws SQLException {
-        return;
+    public void handle(final ConnectionSession connectionSession, final SetStatement setStatement) {
+        if (log.isDebugEnabled()) {
+            log.debug("Set statement {} was discarded.", setStatement.getVariableAssigns().stream()
+                    .map(segment -> String.format("%s %s = %s", segment.getVariable().getScope(), segment.getVariable().getVariable(), segment.getAssignValue())).collect(Collectors.joining(", ")));
+        }
     }
 }
diff --git a/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/admin/mysql/MySQLAdminExecutorCreator.java b/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/admin/mysql/MySQLAdminExecutorCreator.java
index 829b24e061f..c835a7dbfdf 100644
--- a/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/admin/mysql/MySQLAdminExecutorCreator.java
+++ b/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/admin/mysql/MySQLAdminExecutorCreator.java
@@ -22,8 +22,6 @@ import org.apache.shardingsphere.infra.config.props.ConfigurationPropertyKey;
 import org.apache.shardingsphere.proxy.backend.context.ProxyContext;
 import org.apache.shardingsphere.proxy.backend.text.admin.executor.DatabaseAdminExecutor;
 import org.apache.shardingsphere.proxy.backend.text.admin.executor.DatabaseAdminExecutorCreator;
-import org.apache.shardingsphere.proxy.backend.text.admin.mysql.executor.MySQLSetCharsetExecutor;
-import org.apache.shardingsphere.proxy.backend.text.admin.mysql.executor.NoResourceSetExecutor;
 import org.apache.shardingsphere.proxy.backend.text.admin.mysql.executor.NoResourceShowExecutor;
 import org.apache.shardingsphere.proxy.backend.text.admin.mysql.executor.ShowConnectionIdExecutor;
 import org.apache.shardingsphere.proxy.backend.text.admin.mysql.executor.ShowCreateDatabaseExecutor;
@@ -38,7 +36,6 @@ import org.apache.shardingsphere.proxy.backend.text.admin.mysql.executor.ShowTra
 import org.apache.shardingsphere.proxy.backend.text.admin.mysql.executor.ShowVersionExecutor;
 import org.apache.shardingsphere.proxy.backend.text.admin.mysql.executor.UnicastResourceShowExecutor;
 import org.apache.shardingsphere.proxy.backend.text.admin.mysql.executor.UseDatabaseExecutor;
-import org.apache.shardingsphere.sql.parser.sql.common.segment.dal.VariableAssignSegment;
 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.segment.generic.table.SimpleTableSegment;
@@ -54,7 +51,6 @@ import org.apache.shardingsphere.sql.parser.sql.dialect.statement.mysql.dal.MySQ
 import org.apache.shardingsphere.sql.parser.sql.dialect.statement.mysql.dal.MySQLShowProcessListStatement;
 import org.apache.shardingsphere.sql.parser.sql.dialect.statement.mysql.dal.MySQLShowTablesStatement;
 
-import java.util.Iterator;
 import java.util.Optional;
 
 /**
@@ -97,12 +93,7 @@ public final class MySQLAdminExecutorCreator implements DatabaseAdminExecutorCre
             return Optional.of(new ShowCreateDatabaseExecutor((MySQLShowCreateDatabaseStatement) sqlStatement));
         }
         if (sqlStatement instanceof SetStatement) {
-            if (!hasDatabases() || !hasResources()) {
-                return Optional.of(new NoResourceSetExecutor((SetStatement) sqlStatement));
-            }
-            if (isSetClientEncoding((SetStatement) sqlStatement)) {
-                return Optional.of(new MySQLSetCharsetExecutor((SetStatement) sqlStatement));
-            }
+            return Optional.of(new MySQLSetVariableAdminExecutor((SetStatement) sqlStatement));
         }
         if (sqlStatement instanceof SelectStatement) {
             if (isShowSpecialFunction((SelectStatement) sqlStatement, ShowConnectionIdExecutor.FUNCTION_NAME)) {
@@ -177,11 +168,6 @@ public final class MySQLAdminExecutorCreator implements DatabaseAdminExecutorCre
         return ProxyContext.getInstance().getAllDatabaseNames().stream().anyMatch(each -> ProxyContext.getInstance().getDatabase(each).containsDataSource());
     }
     
-    private boolean isSetClientEncoding(final SetStatement setStatement) {
-        Iterator<VariableAssignSegment> iterator = setStatement.getVariableAssigns().iterator();
-        return iterator.hasNext() && "charset".equalsIgnoreCase(iterator.next().getVariable().getVariable());
-    }
-    
     @Override
     public String getType() {
         return "MySQL";
diff --git a/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/admin/mysql/executor/NoResourceSetExecutor.java b/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/admin/mysql/MySQLSessionVariableHandler.java
similarity index 60%
copy from shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/admin/mysql/executor/NoResourceSetExecutor.java
copy to shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/admin/mysql/MySQLSessionVariableHandler.java
index 847ac040492..edfcb182370 100644
--- a/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/admin/mysql/executor/NoResourceSetExecutor.java
+++ b/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/admin/mysql/MySQLSessionVariableHandler.java
@@ -15,27 +15,14 @@
  * limitations under the License.
  */
 
-package org.apache.shardingsphere.proxy.backend.text.admin.mysql.executor;
+package org.apache.shardingsphere.proxy.backend.text.admin.mysql;
 
-import lombok.Getter;
-import lombok.RequiredArgsConstructor;
-import org.apache.shardingsphere.proxy.backend.session.ConnectionSession;
-import org.apache.shardingsphere.proxy.backend.text.admin.executor.DatabaseAdminExecutor;
-import org.apache.shardingsphere.sql.parser.sql.common.statement.dal.SetStatement;
-
-import java.sql.SQLException;
+import org.apache.shardingsphere.proxy.backend.text.admin.executor.SessionVariableHandler;
+import org.apache.shardingsphere.spi.annotation.SingletonSPI;
 
 /**
- * No Resource set executor.
+ * Session variable handler for MySQL.
  */
-@Getter
-@RequiredArgsConstructor
-public final class NoResourceSetExecutor implements DatabaseAdminExecutor {
-    
-    private final SetStatement sqlStatement;
-    
-    @Override
-    public void execute(final ConnectionSession connectionSession) throws SQLException {
-        return;
-    }
+@SingletonSPI
+public interface MySQLSessionVariableHandler extends SessionVariableHandler {
 }
diff --git a/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/admin/mysql/MySQLSessionVariableHandlerFactory.java b/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/admin/mysql/MySQLSessionVariableHandlerFactory.java
new file mode 100644
index 00000000000..dadcdc0a80c
--- /dev/null
+++ b/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/admin/mysql/MySQLSessionVariableHandlerFactory.java
@@ -0,0 +1,48 @@
+/*
+ * 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.proxy.backend.text.admin.mysql;
+
+import org.apache.shardingsphere.spi.ShardingSphereServiceLoader;
+import org.apache.shardingsphere.spi.type.typed.TypedSPIRegistry;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Factory for {@link MySQLSessionVariableHandler}.
+ */
+public final class MySQLSessionVariableHandlerFactory {
+    
+    static {
+        ShardingSphereServiceLoader.register(MySQLSessionVariableHandler.class);
+    }
+    
+    /**
+     * Get list of {@link MySQLSessionVariableHandler} for variables.
+     *
+     * @param variableNames variable names
+     * @return {@link MySQLSessionVariableHandler} for variables
+     */
+    public static List<MySQLSessionVariableHandler> getHandlers(final List<String> variableNames) {
+        List<MySQLSessionVariableHandler> result = new ArrayList<>(variableNames.size());
+        for (String each : variableNames) {
+            result.add(TypedSPIRegistry.findRegisteredService(MySQLSessionVariableHandler.class, each).orElseGet(DefaultMySQLSessionVariableHandler::new));
+        }
+        return result;
+    }
+}
diff --git a/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/admin/mysql/MySQLSetVariableAdminExecutor.java b/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/admin/mysql/MySQLSetVariableAdminExecutor.java
new file mode 100644
index 00000000000..f290bbc2cf6
--- /dev/null
+++ b/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/admin/mysql/MySQLSetVariableAdminExecutor.java
@@ -0,0 +1,92 @@
+/*
+ * 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.proxy.backend.text.admin.mysql;
+
+import lombok.RequiredArgsConstructor;
+import org.apache.shardingsphere.infra.binder.SQLStatementContextFactory;
+import org.apache.shardingsphere.infra.binder.statement.SQLStatementContext;
+import org.apache.shardingsphere.infra.database.type.DatabaseTypeFactory;
+import org.apache.shardingsphere.mode.metadata.MetaDataContexts;
+import org.apache.shardingsphere.parser.rule.SQLParserRule;
+import org.apache.shardingsphere.proxy.backend.context.ProxyContext;
+import org.apache.shardingsphere.proxy.backend.session.ConnectionSession;
+import org.apache.shardingsphere.proxy.backend.text.admin.executor.DatabaseAdminExecutor;
+import org.apache.shardingsphere.proxy.backend.text.data.DatabaseBackendHandler;
+import org.apache.shardingsphere.proxy.backend.text.data.impl.SchemaAssignedDatabaseBackendHandler;
+import org.apache.shardingsphere.sql.parser.sql.common.segment.dal.VariableAssignSegment;
+import org.apache.shardingsphere.sql.parser.sql.common.statement.SQLStatement;
+import org.apache.shardingsphere.sql.parser.sql.common.statement.dal.SetStatement;
+
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * Set variable admin executor for MySQL.
+ */
+@RequiredArgsConstructor
+public final class MySQLSetVariableAdminExecutor implements DatabaseAdminExecutor {
+    
+    private final SetStatement setStatement;
+    
+    @Override
+    public void execute(final ConnectionSession connectionSession) throws SQLException {
+        Map<String, String> sessionVariables = extractSessionVariables();
+        List<MySQLSessionVariableHandler> handlers = MySQLSessionVariableHandlerFactory.getHandlers(new ArrayList<>(sessionVariables.keySet()));
+        for (MySQLSessionVariableHandler each : handlers) {
+            each.handle(connectionSession, setStatement);
+        }
+        executeSetGlobalVariablesIfPresent(connectionSession);
+    }
+    
+    private Map<String, String> extractSessionVariables() {
+        return setStatement.getVariableAssigns().stream().filter(each -> !"global".equalsIgnoreCase(each.getVariable().getScope()))
+                .collect(Collectors.toMap(each -> each.getVariable().getVariable(), VariableAssignSegment::getAssignValue));
+    }
+    
+    private Map<String, String> extractGlobalVariables() {
+        return setStatement.getVariableAssigns().stream().filter(each -> "global".equalsIgnoreCase(each.getVariable().getScope()))
+                .collect(Collectors.toMap(each -> each.getVariable().getVariable(), VariableAssignSegment::getAssignValue, (oldValue, newValue) -> newValue, LinkedHashMap::new));
+    }
+    
+    private void executeSetGlobalVariablesIfPresent(final ConnectionSession connectionSession) throws SQLException {
+        if (null == connectionSession.getDatabaseName()) {
+            return;
+        }
+        String concatenatedGlobalVariables = extractGlobalVariables().entrySet().stream().map(entry -> String.format("@@GLOBAL.%s = %s", entry.getKey(), entry.getValue()))
+                .collect(Collectors.joining(", "));
+        if (concatenatedGlobalVariables.isEmpty()) {
+            return;
+        }
+        String sql = "SET " + concatenatedGlobalVariables;
+        MetaDataContexts metaDataContexts = ProxyContext.getInstance().getContextManager().getMetaDataContexts();
+        SQLParserRule sqlParserRule = metaDataContexts.getMetaData().getGlobalRuleMetaData().getSingleRule(SQLParserRule.class);
+        SQLStatement sqlStatement = sqlParserRule.getSQLParserEngine(DatabaseTypeFactory.getInstance("MySQL").getType()).parse(sql, false);
+        SQLStatementContext<?> sqlStatementContext = SQLStatementContextFactory.newInstance(ProxyContext.getInstance().getContextManager().getMetaDataContexts().getMetaData().getDatabases(),
+                sqlStatement, connectionSession.getDefaultDatabaseName());
+        DatabaseBackendHandler databaseBackendHandler = new SchemaAssignedDatabaseBackendHandler(sqlStatementContext, sql, connectionSession);
+        try {
+            databaseBackendHandler.execute();
+        } finally {
+            databaseBackendHandler.close();
+        }
+    }
+}
diff --git a/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/admin/mysql/executor/MySQLSetCharsetExecutor.java b/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/admin/mysql/executor/MySQLSetCharsetExecutor.java
index 9144cd4fd4e..f48a08076f7 100644
--- a/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/admin/mysql/executor/MySQLSetCharsetExecutor.java
+++ b/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/admin/mysql/executor/MySQLSetCharsetExecutor.java
@@ -17,35 +17,47 @@
 
 package org.apache.shardingsphere.proxy.backend.text.admin.mysql.executor;
 
-import lombok.RequiredArgsConstructor;
 import org.apache.shardingsphere.db.protocol.CommonConstants;
 import org.apache.shardingsphere.db.protocol.mysql.constant.MySQLServerInfo;
 import org.apache.shardingsphere.proxy.backend.session.ConnectionSession;
-import org.apache.shardingsphere.proxy.backend.text.admin.executor.DatabaseAdminExecutor;
+import org.apache.shardingsphere.proxy.backend.text.admin.mysql.MySQLSessionVariableHandler;
 import org.apache.shardingsphere.sql.parser.sql.common.segment.dal.VariableAssignSegment;
 import org.apache.shardingsphere.sql.parser.sql.common.statement.dal.SetStatement;
 
 import java.nio.charset.Charset;
 import java.nio.charset.StandardCharsets;
 import java.nio.charset.UnsupportedCharsetException;
-import java.sql.SQLException;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashSet;
 import java.util.Locale;
+import java.util.Set;
+import java.util.TreeSet;
 
 /**
  * Set charset executor of MySQL.
  */
-@RequiredArgsConstructor
-public final class MySQLSetCharsetExecutor implements DatabaseAdminExecutor {
+public final class MySQLSetCharsetExecutor implements MySQLSessionVariableHandler {
     
-    private final SetStatement setStatement;
+    private static final Set<String> TYPE_ALIASES = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
+    
+    private static final Set<String> CHARSET_VARIABLE_NAMES = new HashSet<>(Arrays.asList("charset", "character_set_client"));
+    
+    static {
+        TYPE_ALIASES.add("character_set_client");
+    }
     
     @Override
-    public void execute(final ConnectionSession connectionSession) throws SQLException {
-        VariableAssignSegment segment = setStatement.getVariableAssigns().iterator().next();
-        String value = formatValue(segment.getAssignValue().trim());
+    public void handle(final ConnectionSession connectionSession, final SetStatement setStatement) {
+        String value = formatValue(getCharacterSetValue(setStatement));
         connectionSession.getAttributeMap().attr(CommonConstants.CHARSET_ATTRIBUTE_KEY).set(parseCharset(value));
     }
     
+    private String getCharacterSetValue(final SetStatement setStatement) {
+        return setStatement.getVariableAssigns().stream().filter(each -> CHARSET_VARIABLE_NAMES.contains(each.getVariable().getVariable().toLowerCase(Locale.ROOT)))
+                .map(VariableAssignSegment::getAssignValue).findFirst().orElse("");
+    }
+    
     private String formatValue(final String value) {
         return value.startsWith("'") && value.endsWith("'") || value.startsWith("\"") && value.endsWith("\"") ? value.substring(1, value.length() - 1) : value.trim();
     }
@@ -66,4 +78,14 @@ public final class MySQLSetCharsetExecutor implements DatabaseAdminExecutor {
                 }
         }
     }
+    
+    @Override
+    public String getType() {
+        return "charset";
+    }
+    
+    @Override
+    public Collection<String> getTypeAliases() {
+        return TYPE_ALIASES;
+    }
 }
diff --git a/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/data/DatabaseBackendHandlerFactory.java b/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/data/DatabaseBackendHandlerFactory.java
index 5e4348f8469..c00436ec3e8 100644
--- a/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/data/DatabaseBackendHandlerFactory.java
+++ b/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/data/DatabaseBackendHandlerFactory.java
@@ -52,7 +52,6 @@ public final class DatabaseBackendHandlerFactory {
             return new UnicastDatabaseBackendHandler(sqlStatementContext, sql, connectionSession);
         }
         if (sqlStatement instanceof SetStatement && null == connectionSession.getDatabaseName()) {
-            // TODO Handle SET GLOBAL and SET SESSION differently
             return new DatabaseBackendHandler() {
                 
                 @Override
diff --git a/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/resources/META-INF/services/org.apache.shardingsphere.proxy.backend.text.admin.mysql.MySQLSessionVariableHandler b/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/resources/META-INF/services/org.apache.shardingsphere.proxy.backend.text.admin.mysql.MySQLSessionVariableHandler
new file mode 100644
index 00000000000..be3c5ce6224
--- /dev/null
+++ b/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/resources/META-INF/services/org.apache.shardingsphere.proxy.backend.text.admin.mysql.MySQLSessionVariableHandler
@@ -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.proxy.backend.text.admin.mysql.executor.MySQLSetCharsetExecutor
diff --git a/shardingsphere-proxy/shardingsphere-proxy-backend/src/test/java/org/apache/shardingsphere/proxy/backend/text/TextProtocolBackendHandlerFactoryTest.java b/shardingsphere-proxy/shardingsphere-proxy-backend/src/test/java/org/apache/shardingsphere/proxy/backend/text/TextProtocolBackendHandlerFactoryTest.java
index d2a11166c9d..c8cae084581 100644
--- a/shardingsphere-proxy/shardingsphere-proxy-backend/src/test/java/org/apache/shardingsphere/proxy/backend/text/TextProtocolBackendHandlerFactoryTest.java
+++ b/shardingsphere-proxy/shardingsphere-proxy-backend/src/test/java/org/apache/shardingsphere/proxy/backend/text/TextProtocolBackendHandlerFactoryTest.java
@@ -32,7 +32,6 @@ import org.apache.shardingsphere.proxy.backend.context.ProxyContext;
 import org.apache.shardingsphere.proxy.backend.session.ConnectionSession;
 import org.apache.shardingsphere.proxy.backend.text.admin.DatabaseAdminQueryBackendHandler;
 import org.apache.shardingsphere.proxy.backend.text.admin.DatabaseAdminUpdateBackendHandler;
-import org.apache.shardingsphere.proxy.backend.text.data.DatabaseBackendHandler;
 import org.apache.shardingsphere.proxy.backend.text.data.impl.SchemaAssignedDatabaseBackendHandler;
 import org.apache.shardingsphere.proxy.backend.text.data.impl.UnicastDatabaseBackendHandler;
 import org.apache.shardingsphere.proxy.backend.text.distsql.ral.QueryableRALBackendHandler;
@@ -185,17 +184,6 @@ public final class TextProtocolBackendHandlerFactoryTest extends ProxyContextRes
     
     @Test
     public void assertNewInstanceWithSet() throws SQLException {
-        String sql = "set @num=1";
-        ProxyContext proxyContext = ProxyContext.getInstance();
-        when(proxyContext.getAllDatabaseNames()).thenReturn(new HashSet<>(Collections.singletonList("schema")));
-        when(proxyContext.getContextManager().getMetaDataContexts().getMetaData().getDatabases().containsKey("schema")).thenReturn(true);
-        when(proxyContext.getDatabase("schema").containsDataSource()).thenReturn(true);
-        TextProtocolBackendHandler actual = TextProtocolBackendHandlerFactory.newInstance(databaseType, sql, Optional::empty, connectionSession);
-        assertThat(actual, instanceOf(DatabaseBackendHandler.class));
-    }
-    
-    @Test
-    public void assertNewInstanceWithSetNoResource() throws SQLException {
         String sql = "set @num=1";
         TextProtocolBackendHandler actual = TextProtocolBackendHandlerFactory.newInstance(databaseType, sql, Optional::empty, connectionSession);
         assertThat(actual, instanceOf(DatabaseAdminUpdateBackendHandler.class));
diff --git a/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/admin/mysql/executor/NoResourceSetExecutor.java b/shardingsphere-proxy/shardingsphere-proxy-backend/src/test/java/org/apache/shardingsphere/proxy/backend/text/admin/mysql/MySQLSessionVariableHandlerFactoryTest.java
similarity index 56%
copy from shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/admin/mysql/executor/NoResourceSetExecutor.java
copy to shardingsphere-proxy/shardingsphere-proxy-backend/src/test/java/org/apache/shardingsphere/proxy/backend/text/admin/mysql/MySQLSessionVariableHandlerFactoryTest.java
index 847ac040492..20683955878 100644
--- a/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/admin/mysql/executor/NoResourceSetExecutor.java
+++ b/shardingsphere-proxy/shardingsphere-proxy-backend/src/test/java/org/apache/shardingsphere/proxy/backend/text/admin/mysql/MySQLSessionVariableHandlerFactoryTest.java
@@ -15,27 +15,24 @@
  * limitations under the License.
  */
 
-package org.apache.shardingsphere.proxy.backend.text.admin.mysql.executor;
+package org.apache.shardingsphere.proxy.backend.text.admin.mysql;
 
-import lombok.Getter;
-import lombok.RequiredArgsConstructor;
-import org.apache.shardingsphere.proxy.backend.session.ConnectionSession;
-import org.apache.shardingsphere.proxy.backend.text.admin.executor.DatabaseAdminExecutor;
-import org.apache.shardingsphere.sql.parser.sql.common.statement.dal.SetStatement;
+import org.junit.Test;
 
-import java.sql.SQLException;
+import java.util.Arrays;
+import java.util.List;
 
-/**
- * No Resource set executor.
- */
-@Getter
-@RequiredArgsConstructor
-public final class NoResourceSetExecutor implements DatabaseAdminExecutor {
-    
-    private final SetStatement sqlStatement;
+import static org.hamcrest.CoreMatchers.instanceOf;
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+
+public final class MySQLSessionVariableHandlerFactoryTest {
     
-    @Override
-    public void execute(final ConnectionSession connectionSession) throws SQLException {
-        return;
+    @Test
+    public void assertGetHandlers() {
+        List<MySQLSessionVariableHandler> actual = MySQLSessionVariableHandlerFactory.getHandlers(Arrays.asList("test_fixture", "test_fixture"));
+        assertThat(actual.size(), is(2));
+        assertThat(actual.get(0), instanceOf(TestFixtureSessionVariableHandler.class));
+        assertThat(actual.get(1), instanceOf(TestFixtureSessionVariableHandler.class));
     }
 }
diff --git a/shardingsphere-proxy/shardingsphere-proxy-backend/src/test/java/org/apache/shardingsphere/proxy/backend/text/admin/mysql/MySQLSetVariableAdminExecutorTest.java b/shardingsphere-proxy/shardingsphere-proxy-backend/src/test/java/org/apache/shardingsphere/proxy/backend/text/admin/mysql/MySQLSetVariableAdminExecutorTest.java
new file mode 100644
index 00000000000..db7da356a9a
--- /dev/null
+++ b/shardingsphere-proxy/shardingsphere-proxy-backend/src/test/java/org/apache/shardingsphere/proxy/backend/text/admin/mysql/MySQLSetVariableAdminExecutorTest.java
@@ -0,0 +1,80 @@
+/*
+ * 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.proxy.backend.text.admin.mysql;
+
+import org.apache.shardingsphere.infra.metadata.database.rule.ShardingSphereRuleMetaData;
+import org.apache.shardingsphere.mode.manager.ContextManager;
+import org.apache.shardingsphere.parser.config.SQLParserRuleConfiguration;
+import org.apache.shardingsphere.parser.rule.SQLParserRule;
+import org.apache.shardingsphere.proxy.backend.context.ProxyContext;
+import org.apache.shardingsphere.proxy.backend.session.ConnectionSession;
+import org.apache.shardingsphere.proxy.backend.text.data.impl.SchemaAssignedDatabaseBackendHandler;
+import org.apache.shardingsphere.proxy.backend.util.ProxyContextRestorer;
+import org.apache.shardingsphere.sql.parser.api.CacheOption;
+import org.apache.shardingsphere.sql.parser.sql.common.segment.dal.VariableAssignSegment;
+import org.apache.shardingsphere.sql.parser.sql.common.segment.dal.VariableSegment;
+import org.apache.shardingsphere.sql.parser.sql.common.statement.dal.SetStatement;
+import org.apache.shardingsphere.sql.parser.sql.dialect.statement.mysql.dal.MySQLSetStatement;
+import org.junit.Test;
+import org.mockito.MockedConstruction;
+
+import java.sql.SQLException;
+import java.util.Collections;
+
+import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.mockConstruction;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+public final class MySQLSetVariableAdminExecutorTest extends ProxyContextRestorer {
+    
+    @Test
+    public void assertExecute() throws SQLException {
+        SetStatement setStatement = prepareSetStatement();
+        MySQLSetVariableAdminExecutor executor = new MySQLSetVariableAdminExecutor(setStatement);
+        ConnectionSession connectionSession = mock(ConnectionSession.class);
+        when(connectionSession.getDatabaseName()).thenReturn("db");
+        ProxyContext.init(mock(ContextManager.class, RETURNS_DEEP_STUBS));
+        when(ProxyContext.getInstance().getContextManager().getMetaDataContexts().getMetaData().getGlobalRuleMetaData())
+                .thenReturn(new ShardingSphereRuleMetaData(Collections.singletonList(new SQLParserRule(new SQLParserRuleConfiguration(false, new CacheOption(1, 1), new CacheOption(1, 1))))));
+        try (MockedConstruction<SchemaAssignedDatabaseBackendHandler> mockConstruction = mockConstruction(SchemaAssignedDatabaseBackendHandler.class)) {
+            executor.execute(connectionSession);
+            verify(mockConstruction.constructed().get(0)).execute();
+        }
+        verify(connectionSession).setCurrentDatabase("'value'");
+    }
+    
+    private SetStatement prepareSetStatement() {
+        VariableAssignSegment setGlobalMaxConnectionAssignSegment = new VariableAssignSegment();
+        VariableSegment maxConnectionVariableSegment = new VariableSegment();
+        maxConnectionVariableSegment.setScope("global");
+        maxConnectionVariableSegment.setVariable("max_connections");
+        setGlobalMaxConnectionAssignSegment.setVariable(maxConnectionVariableSegment);
+        setGlobalMaxConnectionAssignSegment.setAssignValue("151");
+        VariableAssignSegment setTestFixtureAssignSegment = new VariableAssignSegment();
+        VariableSegment testFixtureSegment = new VariableSegment();
+        testFixtureSegment.setVariable("test_fixture");
+        setTestFixtureAssignSegment.setVariable(testFixtureSegment);
+        setTestFixtureAssignSegment.setAssignValue("'value'");
+        SetStatement result = new MySQLSetStatement();
+        result.getVariableAssigns().add(setGlobalMaxConnectionAssignSegment);
+        result.getVariableAssigns().add(setTestFixtureAssignSegment);
+        return result;
+    }
+}
diff --git a/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/admin/mysql/executor/NoResourceSetExecutor.java b/shardingsphere-proxy/shardingsphere-proxy-backend/src/test/java/org/apache/shardingsphere/proxy/backend/text/admin/mysql/TestFixtureSessionVariableHandler.java
similarity index 62%
rename from shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/admin/mysql/executor/NoResourceSetExecutor.java
rename to shardingsphere-proxy/shardingsphere-proxy-backend/src/test/java/org/apache/shardingsphere/proxy/backend/text/admin/mysql/TestFixtureSessionVariableHandler.java
index 847ac040492..9930c89863f 100644
--- a/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/admin/mysql/executor/NoResourceSetExecutor.java
+++ b/shardingsphere-proxy/shardingsphere-proxy-backend/src/test/java/org/apache/shardingsphere/proxy/backend/text/admin/mysql/TestFixtureSessionVariableHandler.java
@@ -15,27 +15,22 @@
  * limitations under the License.
  */
 
-package org.apache.shardingsphere.proxy.backend.text.admin.mysql.executor;
+package org.apache.shardingsphere.proxy.backend.text.admin.mysql;
 
-import lombok.Getter;
-import lombok.RequiredArgsConstructor;
 import org.apache.shardingsphere.proxy.backend.session.ConnectionSession;
-import org.apache.shardingsphere.proxy.backend.text.admin.executor.DatabaseAdminExecutor;
+import org.apache.shardingsphere.sql.parser.sql.common.segment.dal.VariableAssignSegment;
 import org.apache.shardingsphere.sql.parser.sql.common.statement.dal.SetStatement;
 
-import java.sql.SQLException;
-
-/**
- * No Resource set executor.
- */
-@Getter
-@RequiredArgsConstructor
-public final class NoResourceSetExecutor implements DatabaseAdminExecutor {
+public final class TestFixtureSessionVariableHandler implements MySQLSessionVariableHandler {
     
-    private final SetStatement sqlStatement;
+    @Override
+    public void handle(final ConnectionSession connectionSession, final SetStatement setStatement) {
+        connectionSession.setCurrentDatabase(setStatement.getVariableAssigns().stream()
+                .filter(each -> getType().equals(each.getVariable().getVariable())).map(VariableAssignSegment::getAssignValue).findFirst().orElseThrow(IllegalArgumentException::new));
+    }
     
     @Override
-    public void execute(final ConnectionSession connectionSession) throws SQLException {
-        return;
+    public String getType() {
+        return "test_fixture";
     }
 }
diff --git a/shardingsphere-proxy/shardingsphere-proxy-backend/src/test/resources/META-INF/services/org.apache.shardingsphere.proxy.backend.text.admin.mysql.MySQLSessionVariableHandler b/shardingsphere-proxy/shardingsphere-proxy-backend/src/test/resources/META-INF/services/org.apache.shardingsphere.proxy.backend.text.admin.mysql.MySQLSessionVariableHandler
new file mode 100644
index 00000000000..b3b01dbfcd1
--- /dev/null
+++ b/shardingsphere-proxy/shardingsphere-proxy-backend/src/test/resources/META-INF/services/org.apache.shardingsphere.proxy.backend.text.admin.mysql.MySQLSessionVariableHandler
@@ -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.proxy.backend.text.admin.mysql.TestFixtureSessionVariableHandler