15 package com.cloudera.impala.analysis;
17 import java.math.BigDecimal;
22 import com.cloudera.impala.thrift.TAnalyticWindow;
23 import com.cloudera.impala.thrift.TAnalyticWindowBoundary;
24 import com.cloudera.impala.thrift.TAnalyticWindowBoundaryType;
25 import com.cloudera.impala.thrift.TAnalyticWindowType;
26 import com.cloudera.impala.thrift.TColumnValue;
28 import com.google.common.base.Preconditions;
52 public String
toString() {
return description_; }
54 return this == ROWS ? TAnalyticWindowType.ROWS : TAnalyticWindowType.RANGE;
72 public String
toString() {
return description_; }
73 public TAnalyticWindowBoundaryType
toThrift() {
74 Preconditions.checkState(!isAbsolutePos());
75 if (
this == CURRENT_ROW) {
76 return TAnalyticWindowBoundaryType.CURRENT_ROW;
77 }
else if (
this == PRECEDING) {
78 return TAnalyticWindowBoundaryType.PRECEDING;
79 }
else if (
this == FOLLOWING) {
80 return TAnalyticWindowBoundaryType.FOLLOWING;
86 return this == UNBOUNDED_PRECEDING ||
this == UNBOUNDED_FOLLOWING;
90 return this == PRECEDING ||
this == FOLLOWING;
94 return this == UNBOUNDED_PRECEDING ||
this == PRECEDING;
98 return this == UNBOUNDED_FOLLOWING ||
this == FOLLOWING;
103 case UNBOUNDED_PRECEDING:
return UNBOUNDED_FOLLOWING;
104 case UNBOUNDED_FOLLOWING:
return UNBOUNDED_PRECEDING;
105 case PRECEDING:
return FOLLOWING;
106 case FOLLOWING:
return PRECEDING;
107 default:
return CURRENT_ROW;
132 Preconditions.checkState(
133 (type.isOffset() && e != null)
134 || (!type.isOffset() && e == null));
141 StringBuilder sb =
new StringBuilder();
142 if (
expr_ != null) sb.append(expr_.toSql()).append(
" ");
143 sb.append(type_.toString());
144 return sb.toString();
148 TAnalyticWindowBoundary result =
new TAnalyticWindowBoundary(
type_.
toThrift());
150 result.setRows_offset_value(offsetValue_.longValue());
158 if (obj == null)
return false;
159 if (obj.getClass() != this.getClass())
return false;
161 boolean exprEqual = (
expr_ == null) == (o.
expr_ == null);
162 if (exprEqual &&
expr_ != null) exprEqual = expr_.equals(o.expr_);
163 return type_ == o.type_ && exprEqual;
179 if (
expr_ != null) expr_.analyze(analyzer);
195 Preconditions.checkNotNull(b);
202 Preconditions.checkNotNull(l);
204 Preconditions.checkNotNull(r);
213 Preconditions.checkNotNull(other.leftBoundary_);
222 Boundary newRightBoundary = leftBoundary_.converse();
227 newLeftBoundary = rightBoundary_.converse();
234 StringBuilder sb =
new StringBuilder();
235 sb.append(type_.toString()).append(
" ");
237 sb.append(leftBoundary_.toSql());
240 sb.append(rightBoundary_.toSql());
242 return sb.toString();
246 TAnalyticWindow result =
new TAnalyticWindow(
type_.
toThrift());
248 result.setWindow_start(leftBoundary_.toThrift(
type_));
252 result.setWindow_end(rightBoundary_.toThrift(
type_));
259 if (obj == null)
return false;
260 if (obj.getClass() != this.getClass())
return false;
262 boolean rightBoundaryEqual =
265 rightBoundaryEqual = rightBoundary_.equals(o.rightBoundary_);
267 return type_ == o.type_
268 && leftBoundary_.equals(o.leftBoundary_)
269 && rightBoundaryEqual;
280 Preconditions.checkState(boundary.getType().isOffset());
281 Expr e = boundary.getExpr();
282 Preconditions.checkNotNull(e);
283 boolean isPos =
true;
285 if (e.isConstant() && e.getType().isNumericType()) {
287 val = TColumnValueUtil.getNumericVal(
288 FeSupport.EvalConstExpr(e, analyzer.getQueryCtx()));
289 if (val <= 0) isPos =
false;
292 "Couldn't evaluate PRECEDING/FOLLOWING expression: " + exc.getMessage());
297 if (!e.isConstant() || !e.getType().isIntegerType() || !isPos) {
299 "For ROWS window, the value of a PRECEDING/FOLLOWING offset must be a "
300 +
"constant positive integer: " + boundary.toSql());
302 Preconditions.checkNotNull(val);
303 boundary.offsetValue_ =
new BigDecimal(val.longValue());
305 if (!e.isConstant() || !e.getType().isNumericType() || !isPos) {
307 "For RANGE window, the value of a PRECEDING/FOLLOWING offset must be a "
308 +
"constant positive number: " + boundary.toSql());
310 boundary.offsetValue_ =
new BigDecimal(val);
319 Preconditions.checkState(b1.getType().isOffset());
320 Preconditions.checkState(b2.getType().isOffset());
321 Expr e1 = b1.getExpr();
322 Preconditions.checkState(
323 e1 != null && e1.isConstant() && e1.getType().isNumericType());
324 Expr e2 = b2.getExpr();
325 Preconditions.checkState(
326 e2 != null && e2.isConstant() && e2.
getType().isNumericType());
329 TColumnValue val1 = FeSupport.EvalConstExpr(e1, analyzer.getQueryCtx());
330 TColumnValue val2 = FeSupport.EvalConstExpr(e2, analyzer.getQueryCtx());
331 double left = TColumnValueUtil.getNumericVal(val1);
332 double right = TColumnValueUtil.getNumericVal(val2);
335 "Offset boundaries are in the wrong order: " +
toSql());
339 "Couldn't evaluate PRECEDING/FOLLOWING expression: " + exc.getMessage());
345 leftBoundary_.analyze(analyzer);
364 || (leftBoundary_.type_ == BoundaryType.CURRENT_ROW
368 "RANGE is only supported with both the lower and upper bounds UNBOUNDED or"
369 +
" one UNBOUNDED and the other CURRENT ROW.");
393 +
" requires that the upper bound also be "
394 + BoundaryType.FOLLOWING.toString());
406 +
" requires that the lower bound also be "
407 + BoundaryType.PRECEDING.toString());
AnalyticWindow(Type type, Boundary l, Boundary r)
AnalyticWindow(AnalyticWindow other)
boolean equals(Object obj)
TAnalyticWindowType toThrift()
void analyze(Analyzer analyzer)
TAnalyticWindowBoundaryType toThrift()
Boundary getLeftBoundary()
TAnalyticWindow toThrift()
void checkOffsetBoundaries(Analyzer analyzer, Boundary b1, Boundary b2)
Boundary(BoundaryType type, Expr e)
static final AnalyticWindow DEFAULT_WINDOW
BigDecimal getOffsetValue()
Boundary setRightBoundary(Boundary b)
Boundary(BoundaryType type, Expr e, BigDecimal offsetValue)
final String description_
AnalyticWindow(Type type, Boundary b)
void checkOffsetExpr(Analyzer analyzer, Boundary boundary)
final String description_
Boundary getRightBoundary()
boolean equals(Object obj)
TAnalyticWindowBoundary toThrift(Type windowType)
void analyze(Analyzer analyzer)
final Boundary leftBoundary_