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.infra.binder.context.statement.SQLStatementContext;
22 import org.apache.shardingsphere.infra.binder.engine.SQLBindEngine;
23 import org.apache.shardingsphere.infra.database.core.type.DatabaseType;
24 import org.apache.shardingsphere.infra.exception.mysql.exception.UnknownSystemVariableException;
25 import org.apache.shardingsphere.infra.hint.HintValueContext;
26 import org.apache.shardingsphere.infra.session.query.QueryContext;
27 import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;
28 import org.apache.shardingsphere.mode.metadata.MetaDataContexts;
29 import org.apache.shardingsphere.parser.rule.SQLParserRule;
30 import org.apache.shardingsphere.proxy.backend.connector.DatabaseConnectorFactory;
31 import org.apache.shardingsphere.proxy.backend.context.ProxyContext;
32 import org.apache.shardingsphere.proxy.backend.handler.admin.executor.DatabaseAdminExecutor;
33 import org.apache.shardingsphere.proxy.backend.handler.admin.executor.variable.charset.CharsetSetExecutor;
34 import org.apache.shardingsphere.proxy.backend.handler.admin.executor.variable.session.SessionVariableRecordExecutor;
35 import org.apache.shardingsphere.proxy.backend.handler.data.DatabaseBackendHandler;
36 import org.apache.shardingsphere.proxy.backend.mysql.handler.admin.executor.sysvar.MySQLSystemVariable;
37 import org.apache.shardingsphere.proxy.backend.mysql.handler.admin.executor.sysvar.Scope;
38 import org.apache.shardingsphere.proxy.backend.session.ConnectionSession;
39 import org.apache.shardingsphere.sql.parser.sql.common.segment.dal.VariableAssignSegment;
40 import org.apache.shardingsphere.sql.parser.sql.common.statement.SQLStatement;
41 import org.apache.shardingsphere.sql.parser.sql.common.statement.dal.SetStatement;
42
43 import java.sql.SQLException;
44 import java.util.Collection;
45 import java.util.Collections;
46 import java.util.LinkedHashMap;
47 import java.util.Map;
48 import java.util.stream.Collectors;
49
50
51
52
53 @RequiredArgsConstructor
54 public final class MySQLSetVariableAdminExecutor implements DatabaseAdminExecutor {
55
56 private final DatabaseType databaseType = TypedSPILoader.getService(DatabaseType.class, "MySQL");
57
58 private final SetStatement setStatement;
59
60 @Override
61 public void execute(final ConnectionSession connectionSession) throws SQLException {
62 Map<String, String> sessionVariables = extractSessionVariables();
63 validateSessionVariables(sessionVariables.keySet());
64 new CharsetSetExecutor(databaseType, connectionSession).set(sessionVariables);
65 new SessionVariableRecordExecutor(databaseType, connectionSession).recordVariable(sessionVariables);
66 executeSetGlobalVariablesIfPresent(connectionSession);
67 }
68
69 private Map<String, String> extractSessionVariables() {
70 return setStatement.getVariableAssigns().stream().filter(each -> !"global".equalsIgnoreCase(each.getVariable().getScope().orElse("")))
71 .collect(Collectors.toMap(each -> each.getVariable().getVariable(), VariableAssignSegment::getAssignValue));
72 }
73
74 private void validateSessionVariables(final Collection<String> sessionVariables) {
75 for (String each : sessionVariables) {
76 MySQLSystemVariable systemVariable = MySQLSystemVariable.findSystemVariable(each).orElseThrow(() -> new UnknownSystemVariableException(each));
77 systemVariable.validateSetTargetScope(Scope.SESSION);
78 }
79 }
80
81 private void executeSetGlobalVariablesIfPresent(final ConnectionSession connectionSession) throws SQLException {
82 if (null == connectionSession.getDatabaseName()) {
83 return;
84 }
85 String concatenatedGlobalVariables = extractGlobalVariables().entrySet().stream().map(entry -> String.format("@@GLOBAL.%s = %s", entry.getKey(), entry.getValue()))
86 .collect(Collectors.joining(", "));
87 if (concatenatedGlobalVariables.isEmpty()) {
88 return;
89 }
90 String sql = "SET " + concatenatedGlobalVariables;
91 MetaDataContexts metaDataContexts = ProxyContext.getInstance().getContextManager().getMetaDataContexts();
92 SQLParserRule sqlParserRule = metaDataContexts.getMetaData().getGlobalRuleMetaData().getSingleRule(SQLParserRule.class);
93 SQLStatement sqlStatement = sqlParserRule.getSQLParserEngine(TypedSPILoader.getService(DatabaseType.class, "MySQL")).parse(sql, false);
94 SQLStatementContext sqlStatementContext = new SQLBindEngine(ProxyContext.getInstance().getContextManager().getMetaDataContexts().getMetaData(),
95 connectionSession.getDefaultDatabaseName(), new HintValueContext()).bind(sqlStatement, Collections.emptyList());
96 DatabaseBackendHandler databaseBackendHandler = DatabaseConnectorFactory.getInstance()
97 .newInstance(new QueryContext(sqlStatementContext, sql, Collections.emptyList(), new HintValueContext()), connectionSession.getDatabaseConnectionManager(), false);
98 try {
99 databaseBackendHandler.execute();
100 } finally {
101 databaseBackendHandler.close();
102 }
103 }
104
105 private Map<String, String> extractGlobalVariables() {
106 return setStatement.getVariableAssigns().stream().filter(each -> "global".equalsIgnoreCase(each.getVariable().getScope().orElse("")))
107 .collect(Collectors.toMap(each -> each.getVariable().getVariable(), VariableAssignSegment::getAssignValue, (oldValue, newValue) -> newValue, LinkedHashMap::new));
108 }
109 }