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