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.context.segment.select.pagination;
19  
20  import lombok.Getter;
21  import org.apache.shardingsphere.infra.binder.context.statement.type.dml.SelectStatementContext;
22  import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.pagination.NumberLiteralPaginationValueSegment;
23  import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.pagination.PaginationValueSegment;
24  import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.pagination.ParameterMarkerPaginationValueSegment;
25  import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.pagination.limit.LimitValueSegment;
26  import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.pagination.rownum.ExpressionRowNumberValueSegment;
27  
28  import java.util.List;
29  import java.util.Optional;
30  
31  /**
32   * Pagination context.
33   */
34  public final class PaginationContext {
35      
36      @Getter
37      private final boolean hasPagination;
38      
39      private final PaginationValueSegment offsetSegment;
40      
41      private final PaginationValueSegment rowCountSegment;
42      
43      private final Long actualOffset;
44      
45      private final Long actualRowCount;
46      
47      public PaginationContext(final PaginationValueSegment offsetSegment, final PaginationValueSegment rowCountSegment, final List<Object> params) {
48          hasPagination = null != offsetSegment || null != rowCountSegment;
49          this.offsetSegment = offsetSegment;
50          this.rowCountSegment = rowCountSegment;
51          actualOffset = null == offsetSegment ? Long.valueOf(0L) : getValue(offsetSegment, params);
52          actualRowCount = null == rowCountSegment ? null : getValue(rowCountSegment, params);
53      }
54      
55      private Long getValue(final PaginationValueSegment paginationValueSegment, final List<Object> params) {
56          if (paginationValueSegment instanceof ParameterMarkerPaginationValueSegment) {
57              Object obj = null == params || params.isEmpty() ? 0L : params.get(((ParameterMarkerPaginationValueSegment) paginationValueSegment).getParameterIndex());
58              if (null == obj) {
59                  return null;
60              }
61              return obj instanceof Long ? (long) obj : (int) obj;
62          }
63          if (paginationValueSegment instanceof ExpressionRowNumberValueSegment) {
64              return ((ExpressionRowNumberValueSegment) paginationValueSegment).getValue(params);
65          }
66          return ((NumberLiteralPaginationValueSegment) paginationValueSegment).getValue();
67      }
68      
69      /**
70       * Get offset segment.
71       *
72       * @return offset segment
73       */
74      public Optional<PaginationValueSegment> getOffsetSegment() {
75          return Optional.ofNullable(offsetSegment);
76      }
77      
78      /**
79       * Get row count segment.
80       *
81       * @return row count segment
82       */
83      public Optional<PaginationValueSegment> getRowCountSegment() {
84          return Optional.ofNullable(rowCountSegment);
85      }
86      
87      /**
88       * Get actual offset.
89       *
90       * @return actual offset
91       */
92      public long getActualOffset() {
93          if (null == offsetSegment) {
94              return 0L;
95          }
96          return offsetSegment.isBoundOpened() ? actualOffset - 1 : actualOffset;
97      }
98      
99      /**
100      * Get actual row count.
101      *
102      * @return actual row count
103      */
104     public Optional<Long> getActualRowCount() {
105         if (null == rowCountSegment) {
106             return Optional.empty();
107         }
108         return Optional.of(rowCountSegment.isBoundOpened() ? actualRowCount + 1L : actualRowCount);
109     }
110     
111     /**
112      * Get offset parameter index.
113      *
114      * @return offset parameter index
115      */
116     public Optional<Integer> getOffsetParameterIndex() {
117         // TODO handle offsetSegment instance of ExpressionRowNumberValueSegment
118         return offsetSegment instanceof ParameterMarkerPaginationValueSegment ? Optional.of(((ParameterMarkerPaginationValueSegment) offsetSegment).getParameterIndex()) : Optional.empty();
119     }
120     
121     /**
122      * Get row count parameter index.
123      *
124      * @return row count parameter index
125      */
126     public Optional<Integer> getRowCountParameterIndex() {
127         // TODO handle offsetSegment instance of ExpressionRowNumberValueSegment
128         return rowCountSegment instanceof ParameterMarkerPaginationValueSegment
129                 ? Optional.of(((ParameterMarkerPaginationValueSegment) rowCountSegment).getParameterIndex())
130                 : Optional.empty();
131     }
132     
133     /**
134      * Get revised offset.
135      *
136      * @return revised offset
137      */
138     public long getRevisedOffset() {
139         return 0L;
140     }
141     
142     /**
143      * Get revised row count.
144      *
145      * @param selectStatementContext select statement context
146      * @return revised row count
147      */
148     public long getRevisedRowCount(final SelectStatementContext selectStatementContext) {
149         if (isMaxRowCount(selectStatementContext)) {
150             return Integer.MAX_VALUE;
151         }
152         return rowCountSegment instanceof LimitValueSegment ? actualOffset + actualRowCount : actualRowCount;
153     }
154     
155     private boolean isMaxRowCount(final SelectStatementContext selectStatementContext) {
156         return (!selectStatementContext.getGroupByContext().getItems().isEmpty()
157                 || !selectStatementContext.getProjectionsContext().getAggregationProjections().isEmpty()) && !selectStatementContext.isSameGroupByAndOrderByItems();
158     }
159 }