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 ab2c5361f5a Supports replaying session variables on database 
connections (#19826)
ab2c5361f5a is described below

commit ab2c5361f5aae091e8c637e3951eefbedab0e398
Author: 吴伟杰 <[email protected]>
AuthorDate: Wed Aug 3 14:09:40 2022 +0800

    Supports replaying session variables on database connections (#19826)
    
    * Add logic of replaying set session on connections
    
    * Add ReplayRequiredSessionVariables SPI
    
    * Handling PostgreSQL RESET statement
    
    * Add ReplayRequiredSessionVariablesLoaderTest
    
    * Add PostgreSQLResetVariableAdminExecutorTest
    
    * Add RequiredSessionVariableRecorderTest
    
    * Add TODO in RequiredSessionVariableRecorder
    
    * Complete JDBCBackendConnectionTest
    
    * Revise variables and conditions
    
    * Complete PostgreSQLAdminExecutorCreatorTest
    
    * Complete tests for DefaultSessionVariableHandler
---
 .../jdbc/connection/JDBCBackendConnection.java     |  57 +++++++++
 .../ReplayRequiredSessionVariables.java}           |  24 ++--
 .../ReplayRequiredSessionVariablesLoader.java      |  44 +++++++
 .../mysql/DefaultMySQLSessionVariableHandler.java  |  11 +-
 .../DefaultPostgreSQLSessionVariableHandler.java   |  11 +-
 .../postgresql/PostgreSQLAdminExecutorCreator.java |   9 +-
 ...a => PostgreSQLResetVariableAdminExecutor.java} |  21 +++-
 .../proxy/backend/session/ConnectionSession.java   |   2 +
 .../session/RequiredSessionVariableRecorder.java   | 129 +++++++++++++++++++++
 .../jdbc/connection/JDBCBackendConnectionTest.java |  77 ++++++++++++
 .../ReplayRequiredSessionVariablesLoaderTest.java} |  23 ++--
 .../FixtureReplayRequiredSessionVariables.java}    |  23 ++--
 .../DefaultMySQLSessionVariableHandlerTest.java    |  53 +++++++++
 ...efaultPostgreSQLSessionVariableHandlerTest.java |  21 +++-
 .../PostgreSQLAdminExecutorCreatorTest.java        |   9 ++
 .../PostgreSQLResetVariableAdminExecutorTest.java  |  42 +++++++
 .../RequiredSessionVariableRecorderTest.java       |  75 ++++++++++++
 ...r.admin.executor.ReplayRequiredSessionVariables |  18 +++
 18 files changed, 610 insertions(+), 39 deletions(-)

diff --git 
a/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/communication/jdbc/connection/JDBCBackendConnection.java
 
b/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/communication/jdbc/connection/JDBCBackendConnection.java
index 1d24788bd59..19cb274b5ae 100644
--- 
a/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/communication/jdbc/connection/JDBCBackendConnection.java
+++ 
b/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/communication/jdbc/connection/JDBCBackendConnection.java
@@ -35,6 +35,7 @@ import 
org.apache.shardingsphere.transaction.core.TransactionType;
 
 import java.sql.Connection;
 import java.sql.SQLException;
+import java.sql.Statement;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -93,6 +94,7 @@ public final class JDBCBackendConnection implements 
BackendConnection<Void>, Exe
     private List<Connection> createNewConnections(final String dataSourceName, 
final int connectionSize, final ConnectionMode connectionMode) throws 
SQLException {
         Preconditions.checkNotNull(connectionSession.getDatabaseName(), 
"Current schema is null.");
         List<Connection> result = 
ProxyContext.getInstance().getBackendDataSource().getConnections(connectionSession.getDatabaseName(),
 dataSourceName, connectionSize, connectionMode);
+        setSessionVariablesIfNecessary(result);
         for (Connection each : result) {
             replayTransactionOption(each);
         }
@@ -104,6 +106,36 @@ public final class JDBCBackendConnection implements 
BackendConnection<Void>, Exe
         return result;
     }
     
+    private void setSessionVariablesIfNecessary(final List<Connection> 
connections) throws SQLException {
+        if (connectionSession.getRequiredSessionVariableRecorder().isEmpty() 
|| connections.isEmpty()) {
+            return;
+        }
+        String databaseType = 
connections.iterator().next().getMetaData().getDatabaseProductName();
+        List<String> setSQLs = 
connectionSession.getRequiredSessionVariableRecorder().toSetSQLs(databaseType);
+        SQLException sqlException = null;
+        for (Connection each : connections) {
+            try (Statement statement = each.createStatement()) {
+                for (String eachSetSQL : setSQLs) {
+                    statement.execute(eachSetSQL);
+                }
+            } catch (final SQLException ex) {
+                sqlException = ex;
+                break;
+            }
+        }
+        if (null == sqlException) {
+            return;
+        }
+        for (Connection each : connections) {
+            try {
+                each.close();
+            } catch (final SQLException ex) {
+                sqlException.setNextException(ex);
+            }
+        }
+        throw sqlException;
+    }
+    
     private void replayMethodsInvocation(final Connection target) {
         for (ConnectionPostProcessor<Connection> each : 
connectionPostProcessors) {
             each.process(target);
@@ -245,6 +277,7 @@ public final class JDBCBackendConnection implements 
BackendConnection<Void>, Exe
     public Collection<SQLException> closeConnections(final boolean 
forceRollback) {
         Collection<SQLException> result = new LinkedList<>();
         synchronized (cachedConnections) {
+            resetSessionVariablesIfNecessary(cachedConnections.values(), 
result);
             for (Connection each : cachedConnections.values()) {
                 try {
                     if (forceRollback && 
connectionSession.getTransactionStatus().isInTransaction()) {
@@ -262,4 +295,28 @@ public final class JDBCBackendConnection implements 
BackendConnection<Void>, Exe
         }
         return result;
     }
+    
+    private void resetSessionVariablesIfNecessary(final Collection<Connection> 
values, final Collection<SQLException> exceptions) {
+        if (connectionSession.getRequiredSessionVariableRecorder().isEmpty() 
|| values.isEmpty()) {
+            return;
+        }
+        String databaseType;
+        try {
+            databaseType = 
values.iterator().next().getMetaData().getDatabaseProductName();
+        } catch (final SQLException ex) {
+            exceptions.add(ex);
+            return;
+        }
+        List<String> resetSQLs = 
connectionSession.getRequiredSessionVariableRecorder().toResetSQLs(databaseType);
+        for (Connection each : values) {
+            try (Statement statement = each.createStatement()) {
+                for (String eachResetSQL : resetSQLs) {
+                    statement.execute(eachResetSQL);
+                }
+            } catch (final SQLException ex) {
+                exceptions.add(ex);
+            }
+        }
+        
connectionSession.getRequiredSessionVariableRecorder().removeVariablesWithDefaultValue();
+    }
 }
diff --git 
a/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/handler/admin/mysql/DefaultMySQLSessionVariableHandler.java
 
b/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/handler/admin/executor/ReplayRequiredSessionVariables.java
similarity index 59%
copy from 
shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/handler/admin/mysql/DefaultMySQLSessionVariableHandler.java
copy to 
shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/handler/admin/executor/ReplayRequiredSessionVariables.java
index 21bd448ac35..9a138565511 100644
--- 
a/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/handler/admin/mysql/DefaultMySQLSessionVariableHandler.java
+++ 
b/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/handler/admin/executor/ReplayRequiredSessionVariables.java
@@ -15,19 +15,23 @@
  * limitations under the License.
  */
 
-package org.apache.shardingsphere.proxy.backend.handler.admin.mysql;
+package org.apache.shardingsphere.proxy.backend.handler.admin.executor;
 
-import lombok.extern.slf4j.Slf4j;
-import org.apache.shardingsphere.proxy.backend.session.ConnectionSession;
+import org.apache.shardingsphere.spi.annotation.SingletonSPI;
+import org.apache.shardingsphere.spi.type.typed.TypedSPI;
+
+import java.util.Collection;
 
 /**
- * Default session variable handler for MySQL.
+ * Declaring variables need to be replayed on connections.
  */
-@Slf4j
-public final class DefaultMySQLSessionVariableHandler implements 
MySQLSessionVariableHandler {
+@SingletonSPI
+public interface ReplayRequiredSessionVariables extends TypedSPI {
     
-    @Override
-    public void handle(final ConnectionSession connectionSession, final String 
variableName, final String assignValue) {
-        log.debug("Set statement {} = {} was discarded.", variableName, 
assignValue);
-    }
+    /**
+     * Get variables need to be replayed on connections.
+     *
+     * @return variables need to be replayed on connections
+     */
+    Collection<String> getReplayRequiredVariables();
 }
diff --git 
a/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/handler/admin/executor/ReplayRequiredSessionVariablesLoader.java
 
b/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/handler/admin/executor/ReplayRequiredSessionVariablesLoader.java
new file mode 100644
index 00000000000..dbbde7ebfd3
--- /dev/null
+++ 
b/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/handler/admin/executor/ReplayRequiredSessionVariablesLoader.java
@@ -0,0 +1,44 @@
+/*
+ * 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.handler.admin.executor;
+
+import org.apache.shardingsphere.spi.ShardingSphereServiceLoader;
+import org.apache.shardingsphere.spi.type.typed.TypedSPIRegistry;
+
+import java.util.Collection;
+import java.util.Collections;
+
+/**
+ * Loader for session variables need to be replayed.
+ */
+public final class ReplayRequiredSessionVariablesLoader {
+    
+    static {
+        
ShardingSphereServiceLoader.register(ReplayRequiredSessionVariables.class);
+    }
+    
+    /**
+     * Get session variables need to be replayed on connections.
+     *
+     * @param databaseType database type
+     * @return session variables need to be replayed on connections
+     */
+    public static Collection<String> getVariables(final String databaseType) {
+        return 
TypedSPIRegistry.findRegisteredService(ReplayRequiredSessionVariables.class, 
databaseType).orElseGet(() -> 
Collections::emptySet).getReplayRequiredVariables();
+    }
+}
diff --git 
a/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/handler/admin/mysql/DefaultMySQLSessionVariableHandler.java
 
b/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/handler/admin/mysql/DefaultMySQLSessionVariableHandler.java
index 21bd448ac35..399549b9189 100644
--- 
a/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/handler/admin/mysql/DefaultMySQLSessionVariableHandler.java
+++ 
b/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/handler/admin/mysql/DefaultMySQLSessionVariableHandler.java
@@ -18,16 +18,25 @@
 package org.apache.shardingsphere.proxy.backend.handler.admin.mysql;
 
 import lombok.extern.slf4j.Slf4j;
+import 
org.apache.shardingsphere.proxy.backend.handler.admin.executor.ReplayRequiredSessionVariablesLoader;
 import org.apache.shardingsphere.proxy.backend.session.ConnectionSession;
 
+import java.util.Collection;
+
 /**
  * Default session variable handler for MySQL.
  */
 @Slf4j
 public final class DefaultMySQLSessionVariableHandler implements 
MySQLSessionVariableHandler {
     
+    private final Collection<String> replayRequiredSessionVariables = 
ReplayRequiredSessionVariablesLoader.getVariables("MySQL");
+    
     @Override
     public void handle(final ConnectionSession connectionSession, final String 
variableName, final String assignValue) {
-        log.debug("Set statement {} = {} was discarded.", variableName, 
assignValue);
+        if (!replayRequiredSessionVariables.contains(variableName)) {
+            log.debug("Set statement {} = {} was discarded.", variableName, 
assignValue);
+        } else {
+            
connectionSession.getRequiredSessionVariableRecorder().setVariable(variableName,
 assignValue);
+        }
     }
 }
diff --git 
a/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/handler/admin/postgresql/DefaultPostgreSQLSessionVariableHandler.java
 
b/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/handler/admin/postgresql/DefaultPostgreSQLSessionVariableHandler.java
index 8a7fda73950..c3bf4b062d3 100644
--- 
a/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/handler/admin/postgresql/DefaultPostgreSQLSessionVariableHandler.java
+++ 
b/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/handler/admin/postgresql/DefaultPostgreSQLSessionVariableHandler.java
@@ -18,16 +18,25 @@
 package org.apache.shardingsphere.proxy.backend.handler.admin.postgresql;
 
 import lombok.extern.slf4j.Slf4j;
+import 
org.apache.shardingsphere.proxy.backend.handler.admin.executor.ReplayRequiredSessionVariablesLoader;
 import org.apache.shardingsphere.proxy.backend.session.ConnectionSession;
 
+import java.util.Collection;
+
 /**
  * Default session variable handler for PostgreSQL.
  */
 @Slf4j
 public final class DefaultPostgreSQLSessionVariableHandler implements 
PostgreSQLSessionVariableHandler {
     
+    private final Collection<String> replayRequiredSessionVariables = 
ReplayRequiredSessionVariablesLoader.getVariables("PostgreSQL");
+    
     @Override
     public void handle(final ConnectionSession connectionSession, final String 
variableName, final String assignValue) {
-        log.debug("Set statement {} = {} was discarded.", variableName, 
assignValue);
+        if (!replayRequiredSessionVariables.contains(variableName)) {
+            log.debug("Set statement {} = {} was discarded.", variableName, 
assignValue);
+        } else {
+            
connectionSession.getRequiredSessionVariableRecorder().setVariable(variableName,
 assignValue);
+        }
     }
 }
diff --git 
a/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/handler/admin/postgresql/PostgreSQLAdminExecutorCreator.java
 
b/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/handler/admin/postgresql/PostgreSQLAdminExecutorCreator.java
index 5344acab355..77df8fc5cb9 100644
--- 
a/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/handler/admin/postgresql/PostgreSQLAdminExecutorCreator.java
+++ 
b/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/handler/admin/postgresql/PostgreSQLAdminExecutorCreator.java
@@ -28,6 +28,7 @@ import 
org.apache.shardingsphere.sql.parser.sql.common.segment.generic.table.Sim
 import 
org.apache.shardingsphere.sql.parser.sql.common.segment.generic.table.SubqueryTableSegment;
 import 
org.apache.shardingsphere.sql.parser.sql.common.segment.generic.table.TableSegment;
 import org.apache.shardingsphere.sql.parser.sql.common.statement.SQLStatement;
+import 
org.apache.shardingsphere.sql.parser.sql.common.statement.dal.ResetParameterStatement;
 import 
org.apache.shardingsphere.sql.parser.sql.common.statement.dal.SetStatement;
 import 
org.apache.shardingsphere.sql.parser.sql.common.statement.dml.SelectStatement;
 
@@ -76,7 +77,13 @@ public final class PostgreSQLAdminExecutorCreator implements 
DatabaseAdminExecut
                 }
             }
         }
-        return sqlStatement instanceof SetStatement ? Optional.of(new 
PostgreSQLSetVariableAdminExecutor((SetStatement) sqlStatement)) : 
Optional.empty();
+        if (sqlStatement instanceof SetStatement) {
+            return Optional.of(new 
PostgreSQLSetVariableAdminExecutor((SetStatement) sqlStatement));
+        }
+        if (sqlStatement instanceof ResetParameterStatement) {
+            return Optional.of(new 
PostgreSQLResetVariableAdminExecutor((ResetParameterStatement) sqlStatement));
+        }
+        return Optional.empty();
     }
     
     private boolean isQueryPgTable(final Collection<String> 
selectedTableNames) {
diff --git 
a/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/handler/admin/postgresql/DefaultPostgreSQLSessionVariableHandler.java
 
b/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/handler/admin/postgresql/PostgreSQLResetVariableAdminExecutor.java
similarity index 53%
copy from 
shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/handler/admin/postgresql/DefaultPostgreSQLSessionVariableHandler.java
copy to 
shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/handler/admin/postgresql/PostgreSQLResetVariableAdminExecutor.java
index 8a7fda73950..b10d93e7cd8 100644
--- 
a/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/handler/admin/postgresql/DefaultPostgreSQLSessionVariableHandler.java
+++ 
b/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/handler/admin/postgresql/PostgreSQLResetVariableAdminExecutor.java
@@ -17,17 +17,26 @@
 
 package org.apache.shardingsphere.proxy.backend.handler.admin.postgresql;
 
-import lombok.extern.slf4j.Slf4j;
+import lombok.RequiredArgsConstructor;
+import 
org.apache.shardingsphere.proxy.backend.handler.admin.executor.DatabaseAdminExecutor;
 import org.apache.shardingsphere.proxy.backend.session.ConnectionSession;
+import 
org.apache.shardingsphere.sql.parser.sql.common.statement.dal.ResetParameterStatement;
+
+import java.sql.SQLException;
 
 /**
- * Default session variable handler for PostgreSQL.
+ * Reset variable admin executor for PostgreSQL.
  */
-@Slf4j
-public final class DefaultPostgreSQLSessionVariableHandler implements 
PostgreSQLSessionVariableHandler {
+@RequiredArgsConstructor
+public final class PostgreSQLResetVariableAdminExecutor implements 
DatabaseAdminExecutor {
+    
+    private static final String DEFAULT = "DEFAULT";
+    
+    private final ResetParameterStatement resetParameterStatement;
     
     @Override
-    public void handle(final ConnectionSession connectionSession, final String 
variableName, final String assignValue) {
-        log.debug("Set statement {} = {} was discarded.", variableName, 
assignValue);
+    public void execute(final ConnectionSession connectionSession) throws 
SQLException {
+        String variableName = 
resetParameterStatement.getConfigurationParameter();
+        
PostgreSQLSessionVariableHandlerFactory.getHandler(variableName).handle(connectionSession,
 variableName, DEFAULT);
     }
 }
diff --git 
a/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/session/ConnectionSession.java
 
b/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/session/ConnectionSession.java
index 11ee8452468..7fe7ec5efff 100644
--- 
a/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/session/ConnectionSession.java
+++ 
b/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/session/ConnectionSession.java
@@ -77,6 +77,8 @@ public final class ConnectionSession {
     
     private final PreparedStatementRegistry preparedStatementRegistry = new 
PreparedStatementRegistry();
     
+    private final RequiredSessionVariableRecorder 
requiredSessionVariableRecorder = new RequiredSessionVariableRecorder();
+    
     public ConnectionSession(final DatabaseType databaseType, final 
TransactionType initialTransactionType, final AttributeMap attributeMap) {
         this.databaseType = databaseType;
         transactionStatus = new TransactionStatus(initialTransactionType);
diff --git 
a/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/session/RequiredSessionVariableRecorder.java
 
b/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/session/RequiredSessionVariableRecorder.java
new file mode 100644
index 00000000000..8259f73fc93
--- /dev/null
+++ 
b/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/session/RequiredSessionVariableRecorder.java
@@ -0,0 +1,129 @@
+/*
+ * 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.session;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.StringJoiner;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * This class only records variables need to be replayed on connections.
+ */
+public final class RequiredSessionVariableRecorder {
+    
+    private static final String DEFAULT = "DEFAULT";
+    
+    private final Map<String, String> sessionVariables = new 
ConcurrentHashMap<>();
+    
+    /**
+     * Set variable.
+     *
+     * @param variableName variable name
+     * @param variableValue variable value
+     */
+    public void setVariable(final String variableName, final String 
variableValue) {
+        sessionVariables.put(variableName, variableValue);
+    }
+    
+    /**
+     * Return true if no session variable was set.
+     *
+     * @return true if no session variable was set
+     */
+    public boolean isEmpty() {
+        return sessionVariables.isEmpty();
+    }
+    
+    /**
+     * Get set SQLs for database.
+     *
+     * @param databaseType database type
+     * @return set SQLs
+     */
+    public List<String> toSetSQLs(final String databaseType) {
+        if (sessionVariables.isEmpty()) {
+            return Collections.emptyList();
+        }
+        // TODO Refactor the following switch by SPI if we support more 
database in future
+        switch (databaseType) {
+            case "MySQL":
+                return Collections.singletonList(aggregateToMySQLSetSQL());
+            case "PostgreSQL":
+                return convertToPostgreSQLSetSQLs();
+            default:
+                return Collections.emptyList();
+        }
+    }
+    
+    private String aggregateToMySQLSetSQL() {
+        StringJoiner result = new StringJoiner(",", "SET ", "");
+        for (Entry<String, String> stringStringEntry : 
sessionVariables.entrySet()) {
+            String s = stringStringEntry.getKey() + "=" + 
stringStringEntry.getValue();
+            result.add(s);
+        }
+        return result.toString();
+    }
+    
+    private List<String> convertToPostgreSQLSetSQLs() {
+        List<String> result = new ArrayList<>(sessionVariables.size());
+        for (Entry<String, String> entry : sessionVariables.entrySet()) {
+            result.add("SET " + entry.getKey() + "=" + entry.getValue());
+        }
+        return result;
+    }
+    
+    /**
+     * Get reset SQLs for database.
+     *
+     * @param databaseType database type
+     * @return reset SQLs
+     */
+    public List<String> toResetSQLs(final String databaseType) {
+        if (sessionVariables.isEmpty()) {
+            return Collections.emptyList();
+        }
+        // TODO Refactor the following switch by SPI if we support more 
database in future
+        switch (databaseType) {
+            case "MySQL":
+                return 
Collections.singletonList(aggregateToMySQLSetDefaultSQLs());
+            case "PostgreSQL":
+                return Collections.singletonList("RESET ALL");
+            default:
+                return Collections.emptyList();
+        }
+    }
+    
+    private String aggregateToMySQLSetDefaultSQLs() {
+        StringJoiner result = new StringJoiner(",", "SET ", "");
+        for (String each : sessionVariables.keySet()) {
+            result.add(each + "=" + DEFAULT);
+        }
+        return result.toString();
+    }
+    
+    /**
+     * Remove variables with default value.
+     */
+    public void removeVariablesWithDefaultValue() {
+        sessionVariables.entrySet().removeIf(entry -> 
DEFAULT.equalsIgnoreCase(entry.getValue()));
+    }
+}
diff --git 
a/shardingsphere-proxy/shardingsphere-proxy-backend/src/test/java/org/apache/shardingsphere/proxy/backend/communication/jdbc/connection/JDBCBackendConnectionTest.java
 
b/shardingsphere-proxy/shardingsphere-proxy-backend/src/test/java/org/apache/shardingsphere/proxy/backend/communication/jdbc/connection/JDBCBackendConnectionTest.java
index 05b84612991..9c1b9bcd5c0 100644
--- 
a/shardingsphere-proxy/shardingsphere-proxy-backend/src/test/java/org/apache/shardingsphere/proxy/backend/communication/jdbc/connection/JDBCBackendConnectionTest.java
+++ 
b/shardingsphere-proxy/shardingsphere-proxy-backend/src/test/java/org/apache/shardingsphere/proxy/backend/communication/jdbc/connection/JDBCBackendConnectionTest.java
@@ -35,6 +35,7 @@ import 
org.apache.shardingsphere.proxy.backend.context.ProxyContext;
 import 
org.apache.shardingsphere.proxy.backend.exception.BackendConnectionException;
 import org.apache.shardingsphere.proxy.backend.handler.ProxyBackendHandler;
 import org.apache.shardingsphere.proxy.backend.session.ConnectionSession;
+import 
org.apache.shardingsphere.proxy.backend.session.RequiredSessionVariableRecorder;
 import 
org.apache.shardingsphere.proxy.backend.session.transaction.TransactionStatus;
 import org.apache.shardingsphere.proxy.backend.util.ProxyContextRestorer;
 import org.apache.shardingsphere.transaction.core.TransactionType;
@@ -44,6 +45,7 @@ import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Answers;
 import org.mockito.Mock;
+import org.mockito.MockedStatic;
 import org.mockito.junit.MockitoJUnitRunner;
 
 import java.lang.reflect.Field;
@@ -51,6 +53,7 @@ import java.sql.Connection;
 import java.sql.SQLException;
 import java.sql.Statement;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.List;
@@ -63,11 +66,13 @@ import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertThat;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
 import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.mockStatic;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.times;
@@ -98,6 +103,7 @@ public final class JDBCBackendConnectionTest extends 
ProxyContextRestorer {
         JDBCBackendStatement backendStatement = new JDBCBackendStatement();
         backendStatement.setDatabaseName(connectionSession.getDatabaseName());
         
when(connectionSession.getStatementManager()).thenReturn(backendStatement);
+        
when(connectionSession.getRequiredSessionVariableRecorder()).thenReturn(new 
RequiredSessionVariableRecorder());
     }
     
     private void setContextManager() {
@@ -265,6 +271,43 @@ public final class JDBCBackendConnectionTest extends 
ProxyContextRestorer {
         verify(connection, times(1)).createStatement();
     }
     
+    @Test
+    public void assertGetConnectionsAndReplaySessionVariables() throws 
SQLException {
+        
connectionSession.getRequiredSessionVariableRecorder().setVariable("key", 
"value");
+        List<Connection> actualConnections;
+        try (MockedStatic<ProxyContext> mockedStatic = 
mockStatic(ProxyContext.class)) {
+            ProxyContext proxyContext = mock(ProxyContext.class, 
RETURNS_DEEP_STUBS);
+            
mockedStatic.when(ProxyContext::getInstance).thenReturn(proxyContext);
+            Connection connection = mock(Connection.class, RETURNS_DEEP_STUBS);
+            
when(connection.getMetaData().getDatabaseProductName()).thenReturn("PostgreSQL");
+            
when(proxyContext.getBackendDataSource().getConnections(anyString(), 
anyString(), anyInt(), any(ConnectionMode.class)))
+                    .thenReturn(Collections.singletonList(connection));
+            actualConnections = backendConnection.getConnections("", 1, 
ConnectionMode.CONNECTION_STRICTLY);
+        }
+        Connection actualConnection = actualConnections.get(0);
+        verify(actualConnection.createStatement()).execute("SET key=value");
+    }
+    
+    @Test
+    public void assertGetConnectionsAndFailedToReplaySessionVariables() throws 
SQLException {
+        
connectionSession.getRequiredSessionVariableRecorder().setVariable("key", 
"value");
+        Connection connection = null;
+        SQLException expectedException = new SQLException();
+        try (MockedStatic<ProxyContext> mockedStatic = 
mockStatic(ProxyContext.class)) {
+            ProxyContext proxyContext = mock(ProxyContext.class, 
RETURNS_DEEP_STUBS);
+            
mockedStatic.when(ProxyContext::getInstance).thenReturn(proxyContext);
+            connection = mock(Connection.class, RETURNS_DEEP_STUBS);
+            
when(connection.getMetaData().getDatabaseProductName()).thenReturn("PostgreSQL");
+            when(connection.createStatement().execute("SET 
key=value")).thenThrow(expectedException);
+            
when(proxyContext.getBackendDataSource().getConnections(anyString(), 
anyString(), anyInt(), any(ConnectionMode.class)))
+                    .thenReturn(Collections.singletonList(connection));
+            backendConnection.getConnections("", 1, 
ConnectionMode.CONNECTION_STRICTLY);
+        } catch (SQLException ex) {
+            assertThat(ex, is(expectedException));
+            verify(connection).close();
+        }
+    }
+    
     @Test
     public void assertGetConnectionsWithoutTransactions() throws SQLException {
         connectionSession.getTransactionStatus().setInTransaction(false);
@@ -392,4 +435,38 @@ public final class JDBCBackendConnectionTest extends 
ProxyContextRestorer {
         verify(backendConnection).closeHandlers(true);
         verify(backendConnection).closeConnections(true);
     }
+    
+    @Test
+    public void assertCloseConnectionsAndResetVariables() throws SQLException {
+        
connectionSession.getRequiredSessionVariableRecorder().setVariable("key", 
"default");
+        Connection connection = mock(Connection.class, RETURNS_DEEP_STUBS);
+        
when(connection.getMetaData().getDatabaseProductName()).thenReturn("PostgreSQL");
+        backendConnection.getCachedConnections().put("", connection);
+        backendConnection.closeConnections(false);
+        verify(connection.createStatement()).execute("RESET ALL");
+        
assertTrue(connectionSession.getRequiredSessionVariableRecorder().isEmpty());
+    }
+    
+    @Test
+    public void assertCloseConnectionsAndFailedToGetDatabaseType() throws 
SQLException {
+        
connectionSession.getRequiredSessionVariableRecorder().setVariable("key", 
"default");
+        Connection connection = mock(Connection.class, RETURNS_DEEP_STUBS);
+        SQLException expectedException = new SQLException();
+        
when(connection.getMetaData().getDatabaseProductName()).thenThrow(expectedException);
+        backendConnection.getCachedConnections().put("", connection);
+        Collection<SQLException> actualExceptions = 
backendConnection.closeConnections(false);
+        assertThat(actualExceptions, 
is(Collections.singletonList(expectedException)));
+    }
+    
+    @Test
+    public void assertCloseConnectionsAndFailedToResetVariables() throws 
SQLException {
+        
connectionSession.getRequiredSessionVariableRecorder().setVariable("key", 
"default");
+        Connection connection = mock(Connection.class, RETURNS_DEEP_STUBS);
+        
when(connection.getMetaData().getDatabaseProductName()).thenReturn("PostgreSQL");
+        SQLException expectedException = new SQLException();
+        when(connection.createStatement()).thenThrow(expectedException);
+        backendConnection.getCachedConnections().put("", connection);
+        Collection<SQLException> actualExceptions = 
backendConnection.closeConnections(false);
+        assertThat(actualExceptions, 
is(Collections.singletonList(expectedException)));
+    }
 }
diff --git 
a/shardingsphere-proxy/shardingsphere-proxy-backend/src/test/java/org/apache/shardingsphere/proxy/backend/handler/admin/postgresql/DefaultPostgreSQLSessionVariableHandlerTest.java
 
b/shardingsphere-proxy/shardingsphere-proxy-backend/src/test/java/org/apache/shardingsphere/proxy/backend/handler/admin/executor/ReplayRequiredSessionVariablesLoaderTest.java
similarity index 56%
copy from 
shardingsphere-proxy/shardingsphere-proxy-backend/src/test/java/org/apache/shardingsphere/proxy/backend/handler/admin/postgresql/DefaultPostgreSQLSessionVariableHandlerTest.java
copy to 
shardingsphere-proxy/shardingsphere-proxy-backend/src/test/java/org/apache/shardingsphere/proxy/backend/handler/admin/executor/ReplayRequiredSessionVariablesLoaderTest.java
index a1e78e45359..39cd9448c09 100644
--- 
a/shardingsphere-proxy/shardingsphere-proxy-backend/src/test/java/org/apache/shardingsphere/proxy/backend/handler/admin/postgresql/DefaultPostgreSQLSessionVariableHandlerTest.java
+++ 
b/shardingsphere-proxy/shardingsphere-proxy-backend/src/test/java/org/apache/shardingsphere/proxy/backend/handler/admin/executor/ReplayRequiredSessionVariablesLoaderTest.java
@@ -15,20 +15,25 @@
  * limitations under the License.
  */
 
-package org.apache.shardingsphere.proxy.backend.handler.admin.postgresql;
+package org.apache.shardingsphere.proxy.backend.handler.admin.executor;
 
-import org.apache.shardingsphere.proxy.backend.session.ConnectionSession;
 import org.junit.Test;
 
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verifyNoInteractions;
+import java.util.Collections;
 
-public final class DefaultPostgreSQLSessionVariableHandlerTest {
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+
+public final class ReplayRequiredSessionVariablesLoaderTest {
+    
+    @Test
+    public void assertGetVariablesForUnknownDatabaseType() {
+        
assertTrue(ReplayRequiredSessionVariablesLoader.getVariables("unknown").isEmpty());
+    }
     
     @Test
-    public void assertHandle() {
-        ConnectionSession connectionSession = mock(ConnectionSession.class);
-        new 
DefaultPostgreSQLSessionVariableHandler().handle(connectionSession, "", "");
-        verifyNoInteractions(connectionSession);
+    public void assertGetVariablesForExistType() {
+        
assertThat(ReplayRequiredSessionVariablesLoader.getVariables("fixture"), 
is(Collections.singleton("fixture_variable")));
     }
 }
diff --git 
a/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/handler/admin/mysql/DefaultMySQLSessionVariableHandler.java
 
b/shardingsphere-proxy/shardingsphere-proxy-backend/src/test/java/org/apache/shardingsphere/proxy/backend/handler/admin/fixture/FixtureReplayRequiredSessionVariables.java
similarity index 60%
copy from 
shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/handler/admin/mysql/DefaultMySQLSessionVariableHandler.java
copy to 
shardingsphere-proxy/shardingsphere-proxy-backend/src/test/java/org/apache/shardingsphere/proxy/backend/handler/admin/fixture/FixtureReplayRequiredSessionVariables.java
index 21bd448ac35..ad6b684f4b3 100644
--- 
a/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/handler/admin/mysql/DefaultMySQLSessionVariableHandler.java
+++ 
b/shardingsphere-proxy/shardingsphere-proxy-backend/src/test/java/org/apache/shardingsphere/proxy/backend/handler/admin/fixture/FixtureReplayRequiredSessionVariables.java
@@ -15,19 +15,22 @@
  * limitations under the License.
  */
 
-package org.apache.shardingsphere.proxy.backend.handler.admin.mysql;
+package org.apache.shardingsphere.proxy.backend.handler.admin.fixture;
 
-import lombok.extern.slf4j.Slf4j;
-import org.apache.shardingsphere.proxy.backend.session.ConnectionSession;
+import 
org.apache.shardingsphere.proxy.backend.handler.admin.executor.ReplayRequiredSessionVariables;
 
-/**
- * Default session variable handler for MySQL.
- */
-@Slf4j
-public final class DefaultMySQLSessionVariableHandler implements 
MySQLSessionVariableHandler {
+import java.util.Collection;
+import java.util.Collections;
+
+public final class FixtureReplayRequiredSessionVariables implements 
ReplayRequiredSessionVariables {
+    
+    @Override
+    public Collection<String> getReplayRequiredVariables() {
+        return Collections.singleton("fixture_variable");
+    }
     
     @Override
-    public void handle(final ConnectionSession connectionSession, final String 
variableName, final String assignValue) {
-        log.debug("Set statement {} = {} was discarded.", variableName, 
assignValue);
+    public String getType() {
+        return "fixture";
     }
 }
diff --git 
a/shardingsphere-proxy/shardingsphere-proxy-backend/src/test/java/org/apache/shardingsphere/proxy/backend/handler/admin/mysql/DefaultMySQLSessionVariableHandlerTest.java
 
b/shardingsphere-proxy/shardingsphere-proxy-backend/src/test/java/org/apache/shardingsphere/proxy/backend/handler/admin/mysql/DefaultMySQLSessionVariableHandlerTest.java
new file mode 100644
index 00000000000..95a2e4b6b06
--- /dev/null
+++ 
b/shardingsphere-proxy/shardingsphere-proxy-backend/src/test/java/org/apache/shardingsphere/proxy/backend/handler/admin/mysql/DefaultMySQLSessionVariableHandlerTest.java
@@ -0,0 +1,53 @@
+/*
+ * 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.handler.admin.mysql;
+
+import 
org.apache.shardingsphere.proxy.backend.handler.admin.executor.ReplayRequiredSessionVariablesLoader;
+import org.apache.shardingsphere.proxy.backend.session.ConnectionSession;
+import 
org.apache.shardingsphere.proxy.backend.session.RequiredSessionVariableRecorder;
+import org.junit.Test;
+import org.mockito.MockedStatic;
+
+import java.util.Collections;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.mockStatic;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoInteractions;
+import static org.mockito.Mockito.when;
+
+public final class DefaultMySQLSessionVariableHandlerTest {
+    
+    @Test
+    public void assertHandleDiscard() {
+        ConnectionSession connectionSession = mock(ConnectionSession.class);
+        new DefaultMySQLSessionVariableHandler().handle(connectionSession, "", 
"");
+        verifyNoInteractions(connectionSession);
+    }
+    
+    @Test
+    public void assertHandleRecord() {
+        ConnectionSession connectionSession = mock(ConnectionSession.class);
+        
when(connectionSession.getRequiredSessionVariableRecorder()).thenReturn(mock(RequiredSessionVariableRecorder.class));
+        try (MockedStatic<ReplayRequiredSessionVariablesLoader> mockedStatic = 
mockStatic(ReplayRequiredSessionVariablesLoader.class)) {
+            mockedStatic.when(() -> 
ReplayRequiredSessionVariablesLoader.getVariables("MySQL")).thenReturn(Collections.singleton("sql_mode"));
+            new DefaultMySQLSessionVariableHandler().handle(connectionSession, 
"sql_mode", "''");
+            
verify(connectionSession.getRequiredSessionVariableRecorder()).setVariable("sql_mode",
 "''");
+        }
+    }
+}
diff --git 
a/shardingsphere-proxy/shardingsphere-proxy-backend/src/test/java/org/apache/shardingsphere/proxy/backend/handler/admin/postgresql/DefaultPostgreSQLSessionVariableHandlerTest.java
 
b/shardingsphere-proxy/shardingsphere-proxy-backend/src/test/java/org/apache/shardingsphere/proxy/backend/handler/admin/postgresql/DefaultPostgreSQLSessionVariableHandlerTest.java
index a1e78e45359..a1302748961 100644
--- 
a/shardingsphere-proxy/shardingsphere-proxy-backend/src/test/java/org/apache/shardingsphere/proxy/backend/handler/admin/postgresql/DefaultPostgreSQLSessionVariableHandlerTest.java
+++ 
b/shardingsphere-proxy/shardingsphere-proxy-backend/src/test/java/org/apache/shardingsphere/proxy/backend/handler/admin/postgresql/DefaultPostgreSQLSessionVariableHandlerTest.java
@@ -17,18 +17,37 @@
 
 package org.apache.shardingsphere.proxy.backend.handler.admin.postgresql;
 
+import 
org.apache.shardingsphere.proxy.backend.handler.admin.executor.ReplayRequiredSessionVariablesLoader;
 import org.apache.shardingsphere.proxy.backend.session.ConnectionSession;
+import 
org.apache.shardingsphere.proxy.backend.session.RequiredSessionVariableRecorder;
 import org.junit.Test;
+import org.mockito.MockedStatic;
+
+import java.util.Collections;
 
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.mockStatic;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoInteractions;
+import static org.mockito.Mockito.when;
 
 public final class DefaultPostgreSQLSessionVariableHandlerTest {
     
     @Test
-    public void assertHandle() {
+    public void assertHandleDiscard() {
         ConnectionSession connectionSession = mock(ConnectionSession.class);
         new 
DefaultPostgreSQLSessionVariableHandler().handle(connectionSession, "", "");
         verifyNoInteractions(connectionSession);
     }
+    
+    @Test
+    public void assertHandleRecord() {
+        ConnectionSession connectionSession = mock(ConnectionSession.class);
+        
when(connectionSession.getRequiredSessionVariableRecorder()).thenReturn(mock(RequiredSessionVariableRecorder.class));
+        try (MockedStatic<ReplayRequiredSessionVariablesLoader> mockedStatic = 
mockStatic(ReplayRequiredSessionVariablesLoader.class)) {
+            mockedStatic.when(() -> 
ReplayRequiredSessionVariablesLoader.getVariables("PostgreSQL")).thenReturn(Collections.singleton("datestyle"));
+            new 
DefaultPostgreSQLSessionVariableHandler().handle(connectionSession, 
"datestyle", "postgres");
+            
verify(connectionSession.getRequiredSessionVariableRecorder()).setVariable("datestyle",
 "postgres");
+        }
+    }
 }
diff --git 
a/shardingsphere-proxy/shardingsphere-proxy-backend/src/test/java/org/apache/shardingsphere/proxy/backend/handler/admin/postgresql/PostgreSQLAdminExecutorCreatorTest.java
 
b/shardingsphere-proxy/shardingsphere-proxy-backend/src/test/java/org/apache/shardingsphere/proxy/backend/handler/admin/postgresql/PostgreSQLAdminExecutorCreatorTest.java
index 8d4b49df73b..8c8143b5f9e 100644
--- 
a/shardingsphere-proxy/shardingsphere-proxy-backend/src/test/java/org/apache/shardingsphere/proxy/backend/handler/admin/postgresql/PostgreSQLAdminExecutorCreatorTest.java
+++ 
b/shardingsphere-proxy/shardingsphere-proxy-backend/src/test/java/org/apache/shardingsphere/proxy/backend/handler/admin/postgresql/PostgreSQLAdminExecutorCreatorTest.java
@@ -29,6 +29,7 @@ import 
org.apache.shardingsphere.proxy.backend.handler.admin.postgresql.executor
 import org.apache.shardingsphere.sql.parser.api.CacheOption;
 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.postgresql.dal.PostgreSQLResetParameterStatement;
 import 
org.apache.shardingsphere.sql.parser.sql.dialect.statement.postgresql.dal.PostgreSQLSetStatement;
 import 
org.apache.shardingsphere.sql.parser.sql.dialect.statement.postgresql.dml.PostgreSQLDeleteStatement;
 import 
org.apache.shardingsphere.sql.parser.sql.dialect.statement.postgresql.dml.PostgreSQLSelectStatement;
@@ -119,6 +120,14 @@ public final class PostgreSQLAdminExecutorCreatorTest {
         assertThat(actual.get(), 
instanceOf(PostgreSQLSetVariableAdminExecutor.class));
     }
     
+    @Test
+    public void assertCreateWithResetStatement() {
+        Optional<DatabaseAdminExecutor> actual = new 
PostgreSQLAdminExecutorCreator()
+                .create(new CommonSQLStatementContext<>(new 
PostgreSQLResetParameterStatement("client_encoding")), "RESET client_encoding", 
"");
+        assertTrue(actual.isPresent());
+        assertThat(actual.get(), 
instanceOf(PostgreSQLResetVariableAdminExecutor.class));
+    }
+    
     @Test
     public void assertCreateWithDMLStatement() {
         DeleteStatementContext sqlStatementContext = new 
DeleteStatementContext(new PostgreSQLDeleteStatement());
diff --git 
a/shardingsphere-proxy/shardingsphere-proxy-backend/src/test/java/org/apache/shardingsphere/proxy/backend/handler/admin/postgresql/PostgreSQLResetVariableAdminExecutorTest.java
 
b/shardingsphere-proxy/shardingsphere-proxy-backend/src/test/java/org/apache/shardingsphere/proxy/backend/handler/admin/postgresql/PostgreSQLResetVariableAdminExecutorTest.java
new file mode 100644
index 00000000000..f80afddab13
--- /dev/null
+++ 
b/shardingsphere-proxy/shardingsphere-proxy-backend/src/test/java/org/apache/shardingsphere/proxy/backend/handler/admin/postgresql/PostgreSQLResetVariableAdminExecutorTest.java
@@ -0,0 +1,42 @@
+/*
+ * 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.handler.admin.postgresql;
+
+import 
org.apache.shardingsphere.sql.parser.sql.dialect.statement.postgresql.dal.PostgreSQLResetParameterStatement;
+import org.junit.Test;
+import org.mockito.MockedStatic;
+
+import java.sql.SQLException;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.mockStatic;
+import static org.mockito.Mockito.verify;
+
+public final class PostgreSQLResetVariableAdminExecutorTest {
+    
+    @Test
+    public void assertExecute() throws SQLException {
+        PostgreSQLResetVariableAdminExecutor executor = new 
PostgreSQLResetVariableAdminExecutor(new 
PostgreSQLResetParameterStatement("key"));
+        try (MockedStatic<PostgreSQLSessionVariableHandlerFactory> mockStatic 
= mockStatic(PostgreSQLSessionVariableHandlerFactory.class)) {
+            PostgreSQLSessionVariableHandler mockHandler = 
mock(PostgreSQLSessionVariableHandler.class);
+            mockStatic.when(() -> 
PostgreSQLSessionVariableHandlerFactory.getHandler("key")).thenReturn(mockHandler);
+            executor.execute(null);
+            verify(mockHandler).handle(null, "key", "DEFAULT");
+        }
+    }
+}
diff --git 
a/shardingsphere-proxy/shardingsphere-proxy-backend/src/test/java/org/apache/shardingsphere/proxy/backend/session/RequiredSessionVariableRecorderTest.java
 
b/shardingsphere-proxy/shardingsphere-proxy-backend/src/test/java/org/apache/shardingsphere/proxy/backend/session/RequiredSessionVariableRecorderTest.java
new file mode 100644
index 00000000000..326e9c9836d
--- /dev/null
+++ 
b/shardingsphere-proxy/shardingsphere-proxy-backend/src/test/java/org/apache/shardingsphere/proxy/backend/session/RequiredSessionVariableRecorderTest.java
@@ -0,0 +1,75 @@
+/*
+ * 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.session;
+
+import org.junit.Test;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+
+public final class RequiredSessionVariableRecorderTest {
+    
+    @Test
+    public void assertRecordMySQLVariables() {
+        RequiredSessionVariableRecorder recorder = new 
RequiredSessionVariableRecorder();
+        assertTrue(recorder.isEmpty());
+        String databaseType = "MySQL";
+        assertTrue(recorder.toSetSQLs(databaseType).isEmpty());
+        assertTrue(recorder.toResetSQLs(databaseType).isEmpty());
+        recorder.setVariable("sql_mode", "default");
+        recorder.setVariable("max_sort_length", "1024");
+        assertFalse(recorder.isEmpty());
+        assertThat(recorder.toSetSQLs(databaseType), 
is(Collections.singletonList("SET sql_mode=default,max_sort_length=1024")));
+        assertThat(recorder.toResetSQLs(databaseType), 
is(Collections.singletonList("SET sql_mode=DEFAULT,max_sort_length=DEFAULT")));
+        recorder.removeVariablesWithDefaultValue();
+        assertThat(recorder.toSetSQLs(databaseType), 
is(Collections.singletonList("SET max_sort_length=1024")));
+        assertThat(recorder.toResetSQLs(databaseType), 
is(Collections.singletonList("SET max_sort_length=DEFAULT")));
+    }
+    
+    @Test
+    public void assertRecordPostgreSQLVariables() {
+        RequiredSessionVariableRecorder recorder = new 
RequiredSessionVariableRecorder();
+        assertTrue(recorder.isEmpty());
+        String databaseType = "PostgreSQL";
+        assertTrue(recorder.toSetSQLs(databaseType).isEmpty());
+        assertTrue(recorder.toResetSQLs(databaseType).isEmpty());
+        recorder.setVariable("client_encoding", "utf8");
+        recorder.setVariable("datestyle", "default");
+        assertFalse(recorder.isEmpty());
+        assertThat(new HashSet<>(recorder.toSetSQLs(databaseType)), is(new 
HashSet<>(Arrays.asList("SET client_encoding=utf8", "SET datestyle=default"))));
+        assertThat(recorder.toResetSQLs(databaseType), 
is(Collections.singletonList("RESET ALL")));
+        recorder.removeVariablesWithDefaultValue();
+        assertThat(recorder.toSetSQLs(databaseType), 
is(Collections.singletonList("SET client_encoding=utf8")));
+        assertThat(recorder.toResetSQLs(databaseType), 
is(Collections.singletonList("RESET ALL")));
+    }
+    
+    @Test
+    public void assertRecordUnsupportedDatabaseType() {
+        RequiredSessionVariableRecorder recorder = new 
RequiredSessionVariableRecorder();
+        assertTrue(recorder.isEmpty());
+        recorder.setVariable("key", "value");
+        assertTrue(recorder.toSetSQLs("unsupported").isEmpty());
+        assertTrue(recorder.toResetSQLs("unsupported").isEmpty());
+    }
+}
diff --git 
a/shardingsphere-proxy/shardingsphere-proxy-backend/src/test/resources/META-INF/services/org.apache.shardingsphere.proxy.backend.handler.admin.executor.ReplayRequiredSessionVariables
 
b/shardingsphere-proxy/shardingsphere-proxy-backend/src/test/resources/META-INF/services/org.apache.shardingsphere.proxy.backend.handler.admin.executor.ReplayRequiredSessionVariables
new file mode 100644
index 00000000000..fb0d9f3b112
--- /dev/null
+++ 
b/shardingsphere-proxy/shardingsphere-proxy-backend/src/test/resources/META-INF/services/org.apache.shardingsphere.proxy.backend.handler.admin.executor.ReplayRequiredSessionVariables
@@ -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.handler.admin.fixture.FixtureReplayRequiredSessionVariables

Reply via email to