Impala
Impalaistheopensource,nativeanalyticdatabaseforApacheHadoop.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
LimitElement.java
Go to the documentation of this file.
1 // Copyright 2013 Cloudera Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 package com.cloudera.impala.analysis;
16 
20 import com.cloudera.impala.thrift.TColumnValue;
21 import com.google.common.base.Preconditions;
22 
26 class LimitElement {
27  private final Expr limitExpr_;
28  private final Expr offsetExpr_;
29  private long limit_;
30  private long offset_;
31  private boolean isAnalyzed_;
32 
38  public LimitElement(Expr limitExpr, Expr offsetExpr) {
39  this.limitExpr_ = limitExpr;
40  this.offsetExpr_ = offsetExpr;
41  isAnalyzed_ = false;
42  limit_ = -1;
43  offset_ = 0;
44  }
45 
49  protected LimitElement(LimitElement other) {
50  limitExpr_ = (other.limitExpr_ == null) ? null : other.limitExpr_.clone().reset();
51  offsetExpr_ = (other.offsetExpr_ == null) ? null : other.offsetExpr_.clone().reset();
52  limit_ = other.limit_;
53  offset_ = other.offset_;
54  isAnalyzed_ = other.isAnalyzed_;
55  }
56 
57  public Expr getLimitExpr() { return limitExpr_; }
58  public Expr getOffsetExpr() { return offsetExpr_; }
59 
64  public long getLimit() {
65  Preconditions.checkState(isAnalyzed_);
66  return limit_;
67  }
68 
69  public boolean hasLimit() {
70  Preconditions.checkState(isAnalyzed_);
71  return limit_ != -1;
72  }
73 
78  public long getOffset() {
79  Preconditions.checkState(isAnalyzed_);
80  return offset_;
81  }
82 
83  public String toSql() {
84  StringBuilder sb = new StringBuilder();
85  if (limitExpr_ != null) {
86  sb.append(" LIMIT ");
87  sb.append(limitExpr_.toSql());
88  }
89  // Don't add the offset if it is the default value. However, we do print it if it
90  // hasn't been analyzed yet because we need to output the expression used in errors.
91  if (offsetExpr_ != null && (offset_ != 0 || !isAnalyzed_)) {
92  sb.append(" OFFSET ");
93  sb.append(offsetExpr_.toSql());
94  }
95  return sb.toString();
96  }
97 
98  public void analyze(Analyzer analyzer) throws AnalysisException {
99  isAnalyzed_ = true;
100  if (limitExpr_ != null) {
101  if (!limitExpr_.isConstant()) {
102  throw new AnalysisException("LIMIT expression must be a constant expression: " +
103  limitExpr_.toSql());
104  }
105 
106  limitExpr_.analyze(analyzer);
107  if (!limitExpr_.getType().isIntegerType()) {
108  throw new AnalysisException("LIMIT expression must be an integer type but is '" +
109  limitExpr_.getType() + "': " + limitExpr_.toSql());
110  }
111  limit_ = evalIntegerExpr(analyzer, limitExpr_, "LIMIT");
112  }
113  if (limit_ == 0) analyzer.setHasEmptyResultSet();
114 
115  if (offsetExpr_ != null) {
116  if (!offsetExpr_.isConstant()) {
117  throw new AnalysisException("OFFSET expression must be a constant expression: " +
118  offsetExpr_.toSql());
119  }
120 
121  offsetExpr_.analyze(analyzer);
122  if (!offsetExpr_.getType().isIntegerType()) {
123  throw new AnalysisException("OFFSET expression must be an integer type but " +
124  "is '" + offsetExpr_.getType() + "': " + offsetExpr_.toSql());
125  }
126  offset_ = evalIntegerExpr(analyzer, offsetExpr_, "OFFSET");
127  }
128  }
129 
136  private static long evalIntegerExpr(Analyzer analyzer, Expr expr, String name)
137  throws AnalysisException {
138  TColumnValue val = null;
139  try {
140  val = FeSupport.EvalConstExpr(expr, analyzer.getQueryCtx());
141  } catch (InternalException e) {
142  throw new AnalysisException("Failed to evaluate expr: " + expr.toSql(), e);
143  }
144  long value;
145  if (val.isSetLong_val()) {
146  value = val.getLong_val();
147  } else if (val.isSetInt_val()) {
148  value = val.getInt_val();
149  } else if (val.isSetShort_val()) {
150  value = val.getShort_val();
151  } else if (val.isSetByte_val()) {
152  value = val.getByte_val();
153  } else {
154  throw new AnalysisException(name + " expression evaluates to NULL: " +
155  expr.toSql());
156  }
157  if (value < 0) {
158  throw new AnalysisException(name + " must be a non-negative integer: " +
159  expr.toSql() + " = " + value);
160  }
161  return value;
162  }
163 
164  @Override
165  public LimitElement clone() { return new LimitElement(this); }
166 }
LimitElement(Expr limitExpr, Expr offsetExpr)
static long evalIntegerExpr(Analyzer analyzer, Expr expr, String name)
string name
Definition: cpu-info.cc:50