View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *     http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.shardingsphere.proxy.backend.mysql.handler.admin.executor;
19  
20  import lombok.Getter;
21  import lombok.RequiredArgsConstructor;
22  import org.apache.shardingsphere.infra.database.core.metadata.database.system.SystemDatabase;
23  import org.apache.shardingsphere.infra.database.core.type.DatabaseType;
24  import org.apache.shardingsphere.infra.executor.sql.execute.result.query.QueryResult;
25  import org.apache.shardingsphere.infra.executor.sql.execute.result.query.QueryResultMetaData;
26  import org.apache.shardingsphere.infra.executor.sql.execute.result.query.impl.raw.metadata.RawQueryResultColumnMetaData;
27  import org.apache.shardingsphere.infra.executor.sql.execute.result.query.impl.raw.metadata.RawQueryResultMetaData;
28  import org.apache.shardingsphere.infra.executor.sql.execute.result.query.impl.raw.type.RawMemoryQueryResult;
29  import org.apache.shardingsphere.infra.executor.sql.execute.result.query.type.memory.row.MemoryQueryResultDataRow;
30  import org.apache.shardingsphere.infra.merge.result.MergedResult;
31  import org.apache.shardingsphere.infra.merge.result.impl.transparent.TransparentMergedResult;
32  import org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereTable;
33  import org.apache.shardingsphere.infra.util.regex.RegexUtils;
34  import org.apache.shardingsphere.proxy.backend.context.ProxyContext;
35  import org.apache.shardingsphere.proxy.backend.handler.admin.executor.DatabaseAdminQueryExecutor;
36  import org.apache.shardingsphere.proxy.backend.session.ConnectionSession;
37  import org.apache.shardingsphere.sql.parser.statement.mysql.dal.show.table.MySQLShowTablesStatement;
38  
39  import java.sql.Types;
40  import java.util.Arrays;
41  import java.util.Collection;
42  import java.util.Collections;
43  import java.util.Comparator;
44  import java.util.LinkedList;
45  import java.util.List;
46  import java.util.Optional;
47  import java.util.regex.Pattern;
48  import java.util.stream.Collectors;
49  
50  /**
51   * Show tables executor.
52   */
53  @RequiredArgsConstructor
54  public final class ShowTablesExecutor implements DatabaseAdminQueryExecutor {
55      
56      private final MySQLShowTablesStatement sqlStatement;
57      
58      private final DatabaseType databaseType;
59      
60      @Getter
61      private QueryResultMetaData queryResultMetaData;
62      
63      @Getter
64      private MergedResult mergedResult;
65      
66      @Override
67      public void execute(final ConnectionSession connectionSession) {
68          String databaseName = sqlStatement.getFromDatabase().map(schema -> schema.getDatabase().getIdentifier().getValue()).orElseGet(connectionSession::getUsedDatabaseName);
69          queryResultMetaData = createQueryResultMetaData(databaseName);
70          mergedResult = new TransparentMergedResult(getQueryResult(databaseName));
71      }
72      
73      private QueryResultMetaData createQueryResultMetaData(final String databaseName) {
74          List<RawQueryResultColumnMetaData> columnNames = new LinkedList<>();
75          String tableColumnName = String.format("Tables_in_%s", databaseName);
76          columnNames.add(new RawQueryResultColumnMetaData("", tableColumnName, tableColumnName, Types.VARCHAR, "VARCHAR", 255, 0));
77          if (sqlStatement.isContainsFull()) {
78              columnNames.add(new RawQueryResultColumnMetaData("", "Table_type", "Table_type", Types.VARCHAR, "VARCHAR", 20, 0));
79          }
80          return new RawQueryResultMetaData(columnNames);
81      }
82      
83      private QueryResult getQueryResult(final String databaseName) {
84          SystemDatabase systemDatabase = new SystemDatabase(databaseType);
85          if (!systemDatabase.getSystemSchemas().contains(databaseName) && !ProxyContext.getInstance().getContextManager().getDatabase(databaseName).isComplete()) {
86              return new RawMemoryQueryResult(queryResultMetaData, Collections.emptyList());
87          }
88          List<MemoryQueryResultDataRow> rows = getTables(databaseName).stream().map(this::getRow).collect(Collectors.toList());
89          return new RawMemoryQueryResult(queryResultMetaData, rows);
90      }
91      
92      private MemoryQueryResultDataRow getRow(final ShardingSphereTable table) {
93          return sqlStatement.isContainsFull()
94                  ? new MemoryQueryResultDataRow(Arrays.asList(table.getName(), table.getType()))
95                  : new MemoryQueryResultDataRow(Collections.singletonList(table.getName()));
96      }
97      
98      private Collection<ShardingSphereTable> getTables(final String databaseName) {
99          if (null == ProxyContext.getInstance().getContextManager().getDatabase(databaseName).getSchema(databaseName)) {
100             return Collections.emptyList();
101         }
102         Collection<ShardingSphereTable> tables = ProxyContext.getInstance().getContextManager().getDatabase(databaseName).getSchema(databaseName).getAllTables();
103         Collection<ShardingSphereTable> filteredTables = filterByLike(tables);
104         return filteredTables.stream().sorted(Comparator.comparing(ShardingSphereTable::getName)).collect(Collectors.toList());
105     }
106     
107     private Collection<ShardingSphereTable> filterByLike(final Collection<ShardingSphereTable> tables) {
108         Optional<Pattern> likePattern = getLikePattern();
109         return likePattern.isPresent() ? tables.stream().filter(each -> likePattern.get().matcher(each.getName()).matches()).collect(Collectors.toList()) : tables;
110     }
111     
112     private Optional<Pattern> getLikePattern() {
113         if (!sqlStatement.getFilter().isPresent()) {
114             return Optional.empty();
115         }
116         Optional<String> regex = sqlStatement.getFilter().get().getLike().map(optional -> RegexUtils.convertLikePatternToRegex(optional.getPattern()));
117         return regex.map(optional -> Pattern.compile(optional, Pattern.CASE_INSENSITIVE));
118     }
119 }