1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.shardingsphere.proxy.backend.mysql.handler.admin.executor;
19
20 import lombok.RequiredArgsConstructor;
21 import org.apache.shardingsphere.database.exception.mysql.exception.UnknownSystemVariableException;
22 import org.apache.shardingsphere.infra.binder.context.statement.SQLStatementContext;
23 import org.apache.shardingsphere.infra.binder.engine.SQLBindEngine;
24 import org.apache.shardingsphere.infra.hint.HintValueContext;
25 import org.apache.shardingsphere.infra.metadata.ShardingSphereMetaData;
26 import org.apache.shardingsphere.infra.session.query.QueryContext;
27 import org.apache.shardingsphere.parser.rule.SQLParserRule;
28 import org.apache.shardingsphere.proxy.backend.connector.DatabaseProxyConnectorFactory;
29 import org.apache.shardingsphere.proxy.backend.handler.admin.executor.DatabaseAdminUpdateExecutor;
30 import org.apache.shardingsphere.proxy.backend.handler.admin.executor.variable.charset.CharsetSetExecutor;
31 import org.apache.shardingsphere.proxy.backend.handler.admin.executor.variable.session.SessionVariableRecordExecutor;
32 import org.apache.shardingsphere.proxy.backend.handler.data.DatabaseProxyBackendHandler;
33 import org.apache.shardingsphere.proxy.backend.mysql.handler.admin.executor.sysvar.MySQLSystemVariable;
34 import org.apache.shardingsphere.proxy.backend.mysql.handler.admin.executor.sysvar.MySQLSystemVariableScope;
35 import org.apache.shardingsphere.proxy.backend.session.ConnectionSession;
36 import org.apache.shardingsphere.sql.parser.statement.core.segment.dal.VariableAssignSegment;
37 import org.apache.shardingsphere.sql.parser.statement.core.statement.SQLStatement;
38 import org.apache.shardingsphere.sql.parser.statement.core.statement.type.dal.SetStatement;
39
40 import java.sql.SQLException;
41 import java.util.Collection;
42 import java.util.Collections;
43 import java.util.LinkedHashMap;
44 import java.util.Map;
45 import java.util.stream.Collectors;
46
47
48
49
50 @RequiredArgsConstructor
51 public final class MySQLSetVariableAdminExecutor implements DatabaseAdminUpdateExecutor {
52
53 private final SetStatement sqlStatement;
54
55 @Override
56 public void execute(final ConnectionSession connectionSession, final ShardingSphereMetaData metaData) throws SQLException {
57 Map<String, String> sessionVariables = extractSessionVariables();
58 validateSessionVariables(sessionVariables.keySet());
59 CharsetSetExecutor charsetSetExecutor = new CharsetSetExecutor(sqlStatement.getDatabaseType(), connectionSession);
60 sessionVariables.forEach(charsetSetExecutor::set);
61 new SessionVariableRecordExecutor(sqlStatement.getDatabaseType(), connectionSession).recordVariable(sessionVariables);
62 executeSetGlobalVariablesIfPresent(connectionSession, metaData);
63 }
64
65 private Map<String, String> extractSessionVariables() {
66 return sqlStatement.getVariableAssigns().stream().filter(each -> !"global".equalsIgnoreCase(each.getVariable().getScope().orElse("")))
67 .collect(Collectors.toMap(each -> each.getVariable().getVariable(), VariableAssignSegment::getAssignValue));
68 }
69
70 private void validateSessionVariables(final Collection<String> sessionVariables) {
71 for (String each : sessionVariables) {
72 MySQLSystemVariable systemVariable = MySQLSystemVariable.findSystemVariable(each).orElseThrow(() -> new UnknownSystemVariableException(each));
73 systemVariable.validateSetTargetScope(MySQLSystemVariableScope.SESSION);
74 }
75 }
76
77 private void executeSetGlobalVariablesIfPresent(final ConnectionSession connectionSession, final ShardingSphereMetaData metaData) throws SQLException {
78 if (null == connectionSession.getUsedDatabaseName()) {
79 return;
80 }
81 String concatenatedGlobalVariables = extractGlobalVariables().entrySet().stream().map(entry -> String.format("@@GLOBAL.%s = %s", entry.getKey(), entry.getValue()))
82 .collect(Collectors.joining(", "));
83 if (concatenatedGlobalVariables.isEmpty()) {
84 return;
85 }
86 String sql = "SET " + concatenatedGlobalVariables;
87 SQLParserRule sqlParserRule = metaData.getGlobalRuleMetaData().getSingleRule(SQLParserRule.class);
88 SQLStatement sqlStatement = sqlParserRule.getSQLParserEngine(this.sqlStatement.getDatabaseType()).parse(sql, false);
89 SQLStatementContext sqlStatementContext = new SQLBindEngine(metaData,
90 connectionSession.getCurrentDatabaseName(), new HintValueContext()).bind(sqlStatement);
91 DatabaseProxyBackendHandler databaseProxyBackendHandler = DatabaseProxyConnectorFactory.newInstance(
92 new QueryContext(sqlStatementContext, sql, Collections.emptyList(), new HintValueContext(), connectionSession.getConnectionContext(), metaData),
93 connectionSession.getDatabaseConnectionManager(), false);
94 try {
95 databaseProxyBackendHandler.execute();
96 } finally {
97 databaseProxyBackendHandler.close();
98 }
99 }
100
101 private Map<String, String> extractGlobalVariables() {
102 return sqlStatement.getVariableAssigns().stream().filter(each -> "global".equalsIgnoreCase(each.getVariable().getScope().orElse("")))
103 .collect(Collectors.toMap(each -> each.getVariable().getVariable(), VariableAssignSegment::getAssignValue, (oldValue, newValue) -> newValue, LinkedHashMap::new));
104 }
105 }