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.binder.context.statement.SQLStatementContext;
23  import org.apache.shardingsphere.infra.binder.engine.SQLBindEngine;
24  import org.apache.shardingsphere.infra.exception.core.ShardingSpherePreconditions;
25  import org.apache.shardingsphere.infra.exception.dialect.exception.syntax.database.NoDatabaseSelectedException;
26  import org.apache.shardingsphere.infra.exception.kernel.metadata.resource.storageunit.EmptyStorageUnitException;
27  import org.apache.shardingsphere.infra.executor.sql.execute.result.query.QueryResult;
28  import org.apache.shardingsphere.infra.executor.sql.execute.result.query.QueryResultMetaData;
29  import org.apache.shardingsphere.infra.executor.sql.execute.result.query.impl.raw.metadata.RawQueryResultColumnMetaData;
30  import org.apache.shardingsphere.infra.executor.sql.execute.result.query.impl.raw.metadata.RawQueryResultMetaData;
31  import org.apache.shardingsphere.infra.executor.sql.execute.result.query.impl.raw.type.RawMemoryQueryResult;
32  import org.apache.shardingsphere.infra.executor.sql.execute.result.query.type.memory.row.MemoryQueryResultDataRow;
33  import org.apache.shardingsphere.infra.hint.HintValueContext;
34  import org.apache.shardingsphere.infra.hint.SQLHintUtils;
35  import org.apache.shardingsphere.infra.merge.result.MergedResult;
36  import org.apache.shardingsphere.infra.merge.result.impl.transparent.TransparentMergedResult;
37  import org.apache.shardingsphere.infra.session.query.QueryContext;
38  import org.apache.shardingsphere.proxy.backend.connector.DatabaseConnector;
39  import org.apache.shardingsphere.proxy.backend.connector.DatabaseConnectorFactory;
40  import org.apache.shardingsphere.proxy.backend.context.ProxyContext;
41  import org.apache.shardingsphere.proxy.backend.handler.admin.executor.DatabaseAdminQueryExecutor;
42  import org.apache.shardingsphere.proxy.backend.response.header.ResponseHeader;
43  import org.apache.shardingsphere.proxy.backend.response.header.query.QueryHeader;
44  import org.apache.shardingsphere.proxy.backend.response.header.query.QueryResponseHeader;
45  import org.apache.shardingsphere.proxy.backend.session.ConnectionSession;
46  import org.apache.shardingsphere.sql.parser.sql.common.statement.dml.SelectStatement;
47  
48  import java.sql.SQLException;
49  import java.sql.Types;
50  import java.util.Collection;
51  import java.util.Collections;
52  import java.util.LinkedList;
53  import java.util.List;
54  import java.util.Optional;
55  import java.util.stream.Collectors;
56  
57  /**
58   * Unicast resource show executor.
59   */
60  @RequiredArgsConstructor
61  @Getter
62  public final class UnicastResourceShowExecutor implements DatabaseAdminQueryExecutor {
63      
64      private final DatabaseConnectorFactory databaseConnectorFactory = DatabaseConnectorFactory.getInstance();
65      
66      private final SelectStatement sqlStatement;
67      
68      private final String sql;
69      
70      private MergedResult mergedResult;
71      
72      private DatabaseConnector databaseConnector;
73      
74      private ResponseHeader responseHeader;
75      
76      @Override
77      public void execute(final ConnectionSession connectionSession) throws SQLException {
78          String originDatabase = connectionSession.getDatabaseName();
79          String databaseName = null == originDatabase ? getFirstDatabaseName() : originDatabase;
80          ShardingSpherePreconditions.checkState(ProxyContext.getInstance().getContextManager().getDatabase(databaseName).containsDataSource(), () -> new EmptyStorageUnitException(databaseName));
81          HintValueContext hintValueContext = SQLHintUtils.extractHint(sql);
82          try {
83              connectionSession.setCurrentDatabase(databaseName);
84              SQLStatementContext sqlStatementContext = new SQLBindEngine(ProxyContext.getInstance().getContextManager().getMetaDataContexts().getMetaData(),
85                      connectionSession.getDefaultDatabaseName(), hintValueContext).bind(sqlStatement, Collections.emptyList());
86              databaseConnector = databaseConnectorFactory.newInstance(new QueryContext(sqlStatementContext, sql, Collections.emptyList(), hintValueContext),
87                      connectionSession.getDatabaseConnectionManager(), false);
88              responseHeader = databaseConnector.execute();
89              mergedResult = new TransparentMergedResult(createQueryResult());
90          } finally {
91              connectionSession.setCurrentDatabase(originDatabase);
92              databaseConnector.close();
93          }
94      }
95      
96      private String getFirstDatabaseName() {
97          Collection<String> databaseNames = ProxyContext.getInstance().getAllDatabaseNames();
98          if (databaseNames.isEmpty()) {
99              throw new NoDatabaseSelectedException();
100         }
101         Optional<String> result = databaseNames.stream().filter(each -> ProxyContext.getInstance().getContextManager().getDatabase(each).containsDataSource()).findFirst();
102         ShardingSpherePreconditions.checkState(result.isPresent(), EmptyStorageUnitException::new);
103         return result.get();
104     }
105     
106     @Override
107     public QueryResultMetaData getQueryResultMetaData() {
108         List<RawQueryResultColumnMetaData> columns = ((QueryResponseHeader) responseHeader).getQueryHeaders().stream().map(QueryHeader::getColumnLabel)
109                 .map(each -> new RawQueryResultColumnMetaData("", each, each, Types.VARCHAR, "VARCHAR", 100, 0))
110                 .collect(Collectors.toList());
111         return new RawQueryResultMetaData(columns);
112     }
113     
114     private QueryResult createQueryResult() throws SQLException {
115         List<MemoryQueryResultDataRow> rows = new LinkedList<>();
116         while (databaseConnector.next()) {
117             List<Object> data = databaseConnector.getRowData().getData();
118             rows.add(new MemoryQueryResultDataRow(data));
119         }
120         return new RawMemoryQueryResult(getQueryResultMetaData(), rows);
121     }
122 }