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;
19
20 import org.apache.shardingsphere.infra.binder.context.statement.SQLStatementContext;
21 import org.apache.shardingsphere.infra.binder.context.statement.type.dml.SelectStatementContext;
22 import org.apache.shardingsphere.proxy.backend.context.ProxyContext;
23 import org.apache.shardingsphere.proxy.backend.handler.admin.executor.DatabaseAdminExecutor;
24 import org.apache.shardingsphere.proxy.backend.handler.admin.executor.DatabaseAdminExecutorCreator;
25 import org.apache.shardingsphere.proxy.backend.mysql.handler.admin.executor.KillProcessExecutor;
26 import org.apache.shardingsphere.proxy.backend.mysql.handler.admin.executor.MySQLSetVariableAdminExecutor;
27 import org.apache.shardingsphere.proxy.backend.mysql.handler.admin.executor.MySQLSystemVariableQueryExecutor;
28 import org.apache.shardingsphere.proxy.backend.mysql.handler.admin.executor.NoResourceShowExecutor;
29 import org.apache.shardingsphere.proxy.backend.mysql.handler.admin.executor.ShowConnectionIdExecutor;
30 import org.apache.shardingsphere.proxy.backend.mysql.handler.admin.executor.ShowCreateDatabaseExecutor;
31 import org.apache.shardingsphere.proxy.backend.mysql.handler.admin.executor.ShowCurrentDatabaseExecutor;
32 import org.apache.shardingsphere.proxy.backend.mysql.handler.admin.executor.ShowCurrentUserExecutor;
33 import org.apache.shardingsphere.proxy.backend.mysql.handler.admin.executor.ShowDatabasesExecutor;
34 import org.apache.shardingsphere.proxy.backend.mysql.handler.admin.executor.ShowFunctionStatusExecutor;
35 import org.apache.shardingsphere.proxy.backend.mysql.handler.admin.executor.ShowProcedureStatusExecutor;
36 import org.apache.shardingsphere.proxy.backend.mysql.handler.admin.executor.ShowProcessListExecutor;
37 import org.apache.shardingsphere.proxy.backend.mysql.handler.admin.executor.ShowTablesExecutor;
38 import org.apache.shardingsphere.proxy.backend.mysql.handler.admin.executor.ShowVersionExecutor;
39 import org.apache.shardingsphere.proxy.backend.mysql.handler.admin.executor.UnicastResourceShowExecutor;
40 import org.apache.shardingsphere.proxy.backend.mysql.handler.admin.executor.UseDatabaseExecutor;
41 import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.item.ExpressionProjectionSegment;
42 import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.item.ProjectionSegment;
43 import org.apache.shardingsphere.sql.parser.statement.core.statement.SQLStatement;
44 import org.apache.shardingsphere.sql.parser.statement.core.statement.type.dal.SetStatement;
45 import org.apache.shardingsphere.sql.parser.statement.core.statement.type.dml.SelectStatement;
46 import org.apache.shardingsphere.sql.parser.statement.mysql.dal.MySQLKillStatement;
47 import org.apache.shardingsphere.sql.parser.statement.mysql.dal.MySQLUseStatement;
48 import org.apache.shardingsphere.sql.parser.statement.mysql.dal.show.database.MySQLShowCreateDatabaseStatement;
49 import org.apache.shardingsphere.sql.parser.statement.mysql.dal.show.database.MySQLShowDatabasesStatement;
50 import org.apache.shardingsphere.sql.parser.statement.mysql.dal.show.function.MySQLShowFunctionStatusStatement;
51 import org.apache.shardingsphere.sql.parser.statement.mysql.dal.show.procedure.MySQLShowProcedureStatusStatement;
52 import org.apache.shardingsphere.sql.parser.statement.mysql.dal.show.process.MySQLShowProcessListStatement;
53 import org.apache.shardingsphere.sql.parser.statement.mysql.dal.show.table.MySQLShowTablesStatement;
54
55 import java.util.Collection;
56 import java.util.Iterator;
57 import java.util.List;
58 import java.util.Optional;
59
60
61
62
63 public final class MySQLAdminExecutorCreator implements DatabaseAdminExecutorCreator {
64
65 private static final String INFORMATION_SCHEMA = "information_schema";
66
67 private static final String MYSQL_SCHEMA = "mysql";
68
69 private static final String PERFORMANCE_SCHEMA = "performance_schema";
70
71 private static final String SYS_SCHEMA = "sys";
72
73 @Override
74 public Optional<DatabaseAdminExecutor> create(final SQLStatementContext sqlStatementContext) {
75 return Optional.empty();
76 }
77
78 @Override
79 public Optional<DatabaseAdminExecutor> create(final SQLStatementContext sqlStatementContext, final String sql, final String databaseName, final List<Object> parameters) {
80 if (sqlStatementContext instanceof SelectStatementContext) {
81 return createExecutorForSelectStatement((SelectStatementContext) sqlStatementContext, sql, databaseName, parameters);
82 }
83 SQLStatement sqlStatement = sqlStatementContext.getSqlStatement();
84 if (sqlStatement instanceof MySQLUseStatement) {
85 return Optional.of(new UseDatabaseExecutor((MySQLUseStatement) sqlStatement));
86 }
87 if (sqlStatement instanceof MySQLShowDatabasesStatement) {
88 return Optional.of(new ShowDatabasesExecutor((MySQLShowDatabasesStatement) sqlStatement));
89 }
90 if (sqlStatement instanceof MySQLShowTablesStatement) {
91 return Optional.of(new ShowTablesExecutor((MySQLShowTablesStatement) sqlStatement, sqlStatementContext.getSqlStatement().getDatabaseType()));
92 }
93 if (sqlStatement instanceof MySQLShowCreateDatabaseStatement) {
94 return Optional.of(new ShowCreateDatabaseExecutor((MySQLShowCreateDatabaseStatement) sqlStatement));
95 }
96 if (sqlStatement instanceof MySQLShowFunctionStatusStatement) {
97 return Optional.of(new ShowFunctionStatusExecutor((MySQLShowFunctionStatusStatement) sqlStatement));
98 }
99 if (sqlStatement instanceof MySQLShowProcedureStatusStatement) {
100 return Optional.of(new ShowProcedureStatusExecutor((MySQLShowProcedureStatusStatement) sqlStatement));
101 }
102 if (sqlStatement instanceof SetStatement) {
103 return Optional.of(new MySQLSetVariableAdminExecutor((SetStatement) sqlStatement));
104 }
105 if (sqlStatement instanceof MySQLShowProcessListStatement) {
106 return Optional.of(new ShowProcessListExecutor(((MySQLShowProcessListStatement) sqlStatement).isFull()));
107 }
108 if (sqlStatement instanceof MySQLKillStatement) {
109 return Optional.of(new KillProcessExecutor((MySQLKillStatement) sqlStatement));
110 }
111 return Optional.empty();
112 }
113
114 private Optional<DatabaseAdminExecutor> createExecutorForSelectStatement(final SelectStatementContext selectStatementContext, final String sql,
115 final String databaseName, final List<Object> parameters) {
116 if (!selectStatementContext.getSqlStatement().getFrom().isPresent()) {
117 return findAdminExecutorForSelectWithoutFrom(selectStatementContext.getSqlStatement(), sql, databaseName);
118 }
119 if (INFORMATION_SCHEMA.equalsIgnoreCase(databaseName) && !ProxyContext.getInstance().getContextManager().getDatabase(databaseName).isComplete()) {
120 return MySQLInformationSchemaExecutorFactory.newInstance(selectStatementContext, sql, parameters);
121 }
122 if (PERFORMANCE_SCHEMA.equalsIgnoreCase(databaseName) && !ProxyContext.getInstance().getContextManager().getDatabase(databaseName).isComplete()) {
123 return MySQLPerformanceSchemaExecutorFactory.newInstance(selectStatementContext, sql, parameters);
124 }
125 if (MYSQL_SCHEMA.equalsIgnoreCase(databaseName) && !ProxyContext.getInstance().getContextManager().getDatabase(databaseName).isComplete()) {
126 return MySQLMySQLSchemaExecutorFactory.newInstance(selectStatementContext, sql, parameters);
127 }
128 if (SYS_SCHEMA.equalsIgnoreCase(databaseName) && !ProxyContext.getInstance().getContextManager().getDatabase(databaseName).isComplete()) {
129 return MySQLSysSchemaExecutorFactory.newInstance(selectStatementContext, sql, parameters);
130 }
131 return Optional.empty();
132 }
133
134 private Optional<DatabaseAdminExecutor> findAdminExecutorForSelectWithoutFrom(final SelectStatement selectStatement, final String sql, final String databaseName) {
135 Optional<DatabaseAdminExecutor> result = MySQLSystemVariableQueryExecutor.tryGetSystemVariableQueryExecutor(selectStatement);
136 return result.isPresent() ? result : getSelectFunctionOrVariableExecutor(selectStatement, sql, databaseName);
137 }
138
139 private Optional<DatabaseAdminExecutor> getSelectFunctionOrVariableExecutor(final SelectStatement selectStatement, final String sql, final String databaseName) {
140 if (isShowSpecialFunction(selectStatement, ShowConnectionIdExecutor.FUNCTION_NAME)) {
141 return Optional.of(new ShowConnectionIdExecutor(selectStatement));
142 }
143 if (isShowSpecialFunction(selectStatement, ShowVersionExecutor.FUNCTION_NAME)) {
144 return Optional.of(new ShowVersionExecutor(selectStatement));
145 }
146 if (isShowSpecialFunction(selectStatement, ShowCurrentUserExecutor.FUNCTION_NAME) || isShowSpecialFunction(selectStatement, ShowCurrentUserExecutor.FUNCTION_NAME_ALIAS)) {
147 return Optional.of(new ShowCurrentUserExecutor());
148 }
149 if (isShowSpecialFunction(selectStatement, ShowCurrentDatabaseExecutor.FUNCTION_NAME)) {
150 return Optional.of(new ShowCurrentDatabaseExecutor());
151 }
152 return mockExecutor(databaseName, selectStatement, sql);
153 }
154
155 private boolean isShowSpecialFunction(final SelectStatement sqlStatement, final String functionName) {
156 Iterator<ProjectionSegment> segmentIterator = sqlStatement.getProjections().getProjections().iterator();
157 ProjectionSegment firstProjection = segmentIterator.next();
158 return !segmentIterator.hasNext() && firstProjection instanceof ExpressionProjectionSegment && functionName.equalsIgnoreCase(((ExpressionProjectionSegment) firstProjection).getText());
159 }
160
161 private Optional<DatabaseAdminExecutor> mockExecutor(final String databaseName, final SelectStatement sqlStatement, final String sql) {
162 if (hasNoResource()) {
163 return Optional.of(new NoResourceShowExecutor(sqlStatement));
164 }
165 boolean isUseSchema = null != databaseName || sqlStatement.getFrom().isPresent();
166 return isUseSchema ? Optional.empty() : Optional.of(new UnicastResourceShowExecutor(sqlStatement, sql));
167 }
168
169 private boolean hasNoResource() {
170 Collection<String> databaseNames = ProxyContext.getInstance().getAllDatabaseNames();
171 if (databaseNames.isEmpty()) {
172 return true;
173 }
174 for (String each : databaseNames) {
175 if (ProxyContext.getInstance().getContextManager().getDatabase(each).containsDataSource()) {
176 return false;
177 }
178 }
179 return true;
180 }
181
182 @Override
183 public String getDatabaseType() {
184 return "MySQL";
185 }
186 }