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.infra.binder.statement.dml;
19  
20  import lombok.SneakyThrows;
21  import org.apache.shardingsphere.infra.binder.segment.combine.CombineSegmentBinder;
22  import org.apache.shardingsphere.infra.binder.segment.from.TableSegmentBinder;
23  import org.apache.shardingsphere.infra.binder.segment.from.TableSegmentBinderContext;
24  import org.apache.shardingsphere.infra.binder.segment.lock.LockSegmentBinder;
25  import org.apache.shardingsphere.infra.binder.segment.projection.ProjectionsSegmentBinder;
26  import org.apache.shardingsphere.infra.binder.segment.where.WhereSegmentBinder;
27  import org.apache.shardingsphere.infra.binder.segment.with.WithSegmentBinder;
28  import org.apache.shardingsphere.infra.binder.statement.SQLStatementBinder;
29  import org.apache.shardingsphere.infra.binder.statement.SQLStatementBinderContext;
30  import org.apache.shardingsphere.infra.metadata.ShardingSphereMetaData;
31  import org.apache.shardingsphere.sql.parser.sql.common.segment.generic.table.TableSegment;
32  import org.apache.shardingsphere.sql.parser.sql.common.statement.dml.SelectStatement;
33  import org.apache.shardingsphere.sql.parser.sql.dialect.handler.dml.SelectStatementHandler;
34  
35  import java.util.Collections;
36  import java.util.LinkedHashMap;
37  import java.util.Map;
38  import java.util.Optional;
39  
40  /**
41   * Select statement binder.
42   */
43  public final class SelectStatementBinder implements SQLStatementBinder<SelectStatement> {
44      
45      @SneakyThrows
46      @Override
47      public SelectStatement bind(final SelectStatement sqlStatement, final ShardingSphereMetaData metaData, final String defaultDatabaseName) {
48          return bind(sqlStatement, metaData, defaultDatabaseName, Collections.emptyMap(), Collections.emptyMap());
49      }
50      
51      @SneakyThrows
52      private SelectStatement bind(final SelectStatement sqlStatement, final ShardingSphereMetaData metaData, final String defaultDatabaseName,
53                                   final Map<String, TableSegmentBinderContext> outerTableBinderContexts, final Map<String, TableSegmentBinderContext> externalTableBinderContexts) {
54          SelectStatement result = sqlStatement.getClass().getDeclaredConstructor().newInstance();
55          Map<String, TableSegmentBinderContext> tableBinderContexts = new LinkedHashMap<>();
56          SQLStatementBinderContext statementBinderContext = new SQLStatementBinderContext(metaData, defaultDatabaseName, sqlStatement.getDatabaseType(), sqlStatement.getVariableNames());
57          statementBinderContext.getExternalTableBinderContexts().putAll(externalTableBinderContexts);
58          SelectStatementHandler.getWithSegment(sqlStatement).ifPresent(optional -> SelectStatementHandler.setWithSegment(result,
59                  WithSegmentBinder.bind(optional, statementBinderContext, tableBinderContexts, statementBinderContext.getExternalTableBinderContexts())));
60          Optional<TableSegment> boundedTableSegment = sqlStatement.getFrom().map(optional -> TableSegmentBinder.bind(optional, statementBinderContext, tableBinderContexts, outerTableBinderContexts));
61          boundedTableSegment.ifPresent(result::setFrom);
62          result.setProjections(ProjectionsSegmentBinder.bind(sqlStatement.getProjections(), statementBinderContext, boundedTableSegment.orElse(null), tableBinderContexts, outerTableBinderContexts));
63          sqlStatement.getWhere().ifPresent(optional -> result.setWhere(WhereSegmentBinder.bind(optional, statementBinderContext, tableBinderContexts, outerTableBinderContexts)));
64          // TODO support other segment bind in select statement
65          sqlStatement.getGroupBy().ifPresent(result::setGroupBy);
66          sqlStatement.getHaving().ifPresent(result::setHaving);
67          sqlStatement.getOrderBy().ifPresent(result::setOrderBy);
68          sqlStatement.getCombine().ifPresent(optional -> result.setCombine(CombineSegmentBinder.bind(optional, statementBinderContext)));
69          SelectStatementHandler.getLimitSegment(sqlStatement).ifPresent(optional -> SelectStatementHandler.setLimitSegment(result, optional));
70          SelectStatementHandler.getLockSegment(sqlStatement)
71                  .ifPresent(optional -> SelectStatementHandler.setLockSegment(result, LockSegmentBinder.bind(optional, statementBinderContext, tableBinderContexts, outerTableBinderContexts)));
72          SelectStatementHandler.getWindowSegment(sqlStatement).ifPresent(optional -> SelectStatementHandler.setWindowSegment(result, optional));
73          SelectStatementHandler.getModelSegment(sqlStatement).ifPresent(optional -> SelectStatementHandler.setModelSegment(result, optional));
74          result.addParameterMarkerSegments(sqlStatement.getParameterMarkerSegments());
75          result.getCommentSegments().addAll(sqlStatement.getCommentSegments());
76          return result;
77      }
78      
79      /**
80       * Bind correlate subquery select statement.
81       *
82       * @param sqlStatement subquery select statement
83       * @param metaData meta data
84       * @param defaultDatabaseName default database name
85       * @param outerTableBinderContexts outer select statement table binder contexts
86       * @param externalTableBinderContexts external table binder contexts
87       * @return bounded correlate subquery select statement
88       */
89      @SneakyThrows
90      public SelectStatement bindCorrelateSubquery(final SelectStatement sqlStatement, final ShardingSphereMetaData metaData, final String defaultDatabaseName,
91                                                   final Map<String, TableSegmentBinderContext> outerTableBinderContexts, final Map<String, TableSegmentBinderContext> externalTableBinderContexts) {
92          return bind(sqlStatement, metaData, defaultDatabaseName, outerTableBinderContexts, externalTableBinderContexts);
93      }
94      
95      /**
96       * Bind with external table contexts.
97       *
98       * @param statement select statement
99       * @param metaData meta data
100      * @param defaultDatabaseName default database name
101      * @param externalTableContexts external table contexts
102      * @return select statement
103      */
104     public SelectStatement bindWithExternalTableContexts(final SelectStatement statement, final ShardingSphereMetaData metaData, final String defaultDatabaseName,
105                                                          final Map<String, TableSegmentBinderContext> externalTableContexts) {
106         return bind(statement, metaData, defaultDatabaseName, Collections.emptyMap(), externalTableContexts);
107     }
108 }