15 package com.cloudera.impala.analysis;
17 import java.math.BigDecimal;
18 import java.math.BigInteger;
19 import java.util.ArrayList;
20 import java.util.List;
22 import org.slf4j.Logger;
23 import org.slf4j.LoggerFactory;
32 import com.cloudera.impala.common.TreeNode;
34 import com.cloudera.impala.thrift.TColumnValue;
35 import com.cloudera.impala.thrift.TExprNode;
37 import com.google.common.base.Joiner;
38 import com.google.common.base.Objects;
39 import com.google.common.base.Preconditions;
40 import com.google.common.collect.Lists;
61 private final static Logger
LOG = LoggerFactory.getLogger(AnalyticExpr.class);
78 private static String
LEAD =
"lead";
79 private static String
LAG =
"lag";
82 private static String
RANK =
"rank";
85 private static String
MIN =
"min";
86 private static String
MAX =
"max";
94 Preconditions.checkNotNull(fnCall);
96 partitionExprs_ = partitionExprs != null ? partitionExprs :
new ArrayList<Expr>();
97 if (orderByElements != null) orderByElements_.addAll(orderByElements);
109 orderByElements_.add(e.clone());
112 window_ = (other.window_ != null ? other.window_.clone() : null);
125 if (!super.equals(obj))
return false;
128 if ((
window_ == null) != (o.window_ == null))
return false;
132 return orderByElements_.equals(o.orderByElements_);
147 StringBuilder sb =
new StringBuilder();
148 sb.append(fnCall_.toSql()).append(
" OVER (");
149 boolean needsSpace =
false;
155 List<String> orderByStrings = Lists.newArrayList();
157 orderByStrings.add(e.toSql());
159 if (needsSpace) sb.append(
" ");
160 sb.append(
"ORDER BY ").append(Joiner.on(
", ").join(orderByStrings));
164 if (needsSpace) sb.append(
" ");
165 sb.append(window_.toSql());
168 return sb.toString();
173 return Objects.toStringHelper(
this)
176 .addValue(super.debugString())
217 Preconditions.checkState(boundary.getType().isOffset());
219 throw new AnalysisException(
"Only one ORDER BY expression allowed if used with "
220 +
"a RANGE window with PRECEDING/FOLLOWING: " +
toSql());
222 Expr rangeExpr = boundary.getExpr();
224 rangeExpr.
getType(), orderByElements_.get(0).getExpr().getType())) {
225 throw new AnalysisException(
226 "The value expression of a PRECEDING/FOLLOWING clause of a RANGE window must "
227 +
"be implicitly convertable to the ORDER BY expression's type: "
228 + rangeExpr.
toSql() +
" cannot be implicitly converted to "
229 + orderByElements_.get(0).getExpr().getType().
toSql());
238 Preconditions.checkState(
getFnCall().getChildren().size() > 1);
240 Preconditions.checkState(offset.getType().isIntegerType());
241 boolean isPosConstant =
true;
242 if (!offset.isConstant()) {
243 isPosConstant =
false;
246 TColumnValue val = FeSupport.EvalConstExpr(
offset, analyzer.getQueryCtx());
250 "Couldn't evaluate LEAD/LAG offset: " + exc.getMessage());
253 if (!isPosConstant) {
255 "The offset parameter of LEAD/LAG must be a constant positive integer: "
263 fnCall_.analyze(analyzer);
264 super.analyze(analyzer);
268 if (e.isConstant()) {
270 "Expressions in the PARTITION BY clause must not be constant: "
271 + e.toSql() +
" (in " +
toSql() +
")");
275 if (e.getExpr().isConstant()) {
277 "Expressions in the ORDER BY clause must not be constant: "
278 + e.getExpr().toSql() +
" (in " +
toSql() +
")");
282 if (
getFnCall().getParams().isDistinct()) {
284 "DISTINCT not allowed in analytic function: " +
getFnCall().
toSql());
291 "OVER clause requires aggregate or analytic function: "
298 String.format(
"Aggregate function '%s' not supported with OVER clause.",
303 if (orderByElements_.isEmpty()) {
309 "Windowing clause not allowed with '" +
getFnCall().
toSql() +
"'");
315 if (
getFnCall().getChildren().size() > 2) {
318 "The default parameter (parameter 3) of LEAD/LAG must be a constant: "
326 if (orderByElements_.isEmpty()) {
330 window_.analyze(analyzer);
332 if (!orderByElements_.isEmpty()
339 && window_.getRightBoundary().
getType().isOffset()) {
346 if (TreeNode.contains(getChildren(),
AnalyticExpr.class)) {
348 "Nesting of analytic expressions is not allowed: " +
toSql());
360 +
"UNBOUNDED PRECEDING start bound.");
409 Preconditions.checkState(
window_ == null,
"Unexpected window set for row_numer()");
421 Preconditions.checkState(
window_ == null);
424 List<Expr> newExprParams = null;
425 if (
getFnCall().getChildren().size() == 1) {
426 newExprParams = Lists.newArrayListWithExpectedSize(3);
427 newExprParams.addAll(
getFnCall().getChildren());
432 }
else if (
getFnCall().getChildren().size() == 2) {
433 newExprParams = Lists.newArrayListWithExpectedSize(3);
434 newExprParams.addAll(
getFnCall().getChildren());
438 Preconditions.checkState(
getFnCall().getChildren().size() == 3);
440 if (newExprParams != null) {
443 fnCall_.setIsAnalyticFnCall(
true);
444 fnCall_.analyzeNoThrow(analyzer);
456 window_.analyze(analyzer);
458 throw new IllegalStateException(e);
473 List<Expr> paramExprs = Expr.cloneList(
getFnCall().getParams().exprs());
488 window_.getLeftBoundary());
491 fnCall_.setIsInternalFnCall(
true);
493 fnCall_.setIsAnalyticFnCall(
true);
494 fnCall_.analyzeNoThrow(analyzer);
495 type_ = fnCall_.getReturnType();
496 analyticFnName =
getFnCall().getFnName();
515 if (reversedFnName != null) {
517 fnCall_.setIsAnalyticFnCall(
true);
518 fnCall_.analyzeNoThrow(analyzer);
520 analyticFnName =
getFnCall().getFnName();
544 if (offsetFnCall.getChild(1) != null)
return offsetFnCall.getChild(1);
553 int numArgs = fnCall_.getChildren().size();
554 for (
int i = 0; i < numArgs; ++i) {
555 fnCall_.setChild(i, getChild(i));
557 int numPartitionExprs = partitionExprs_.size();
558 for (
int i = 0; i < numPartitionExprs; ++i) {
559 partitionExprs_.set(i, getChild(numArgs + i));
561 for (
int i = 0; i < orderByElements_.size(); ++i) {
562 orderByElements_.get(i).setExpr(getChild(numArgs + numPartitionExprs + i));
570 getChildren().clear();
571 addChildren(
fnCall_.getChildren());
574 addChild(e.getExpr());
581 && window_.getRightBoundary().getExpr() != null) {
589 super.resetAnalysisState();
590 fnCall_.resetAnalysisState();
600 Expr e = super.substituteImpl(smap, analyzer);
AnalyticExpr(AnalyticExpr other)
AnalyticExpr(FunctionCallExpr fnCall, List< Expr > partitionExprs, List< OrderByElement > orderByElements, AnalyticWindow window)
boolean equals(Object obj)
boolean equals(Object obj)
static final ScalarType BIGINT
static boolean isAggregateFn(Function fn)
Boundary getLeftBoundary()
List< Expr > getPartitionExprs()
static final AnalyticWindow DEFAULT_WINDOW
static String FIRST_VALUE_REWRITE
Expr getOffsetExpr(FunctionCallExpr offsetFnCall)
static boolean isImplicitlyCastable(Type t1, Type t2)
void resetAnalysisState()
List< OrderByElement > orderByElements_
List< OrderByElement > getOrderByElements()
static boolean isOffsetFn(Function fn)
static boolean isMinMax(Function fn)
void analyze(Analyzer analyzer)
static double getNumericVal(TColumnValue val)
void standardize(Analyzer analyzer)
FunctionCallExpr getFnCall()
Boundary getRightBoundary()
static boolean isRankingFn(Function fn)
uint8_t offset[7 *64-sizeof(uint64_t)]
Expr substituteImpl(ExprSubstitutionMap smap, Analyzer analyzer)
AnalyticWindow getWindow()
void toThrift(TExprNode msg)
void checkRangeOffsetBoundaryExpr(AnalyticWindow.Boundary boundary)
void checkOffset(Analyzer analyzer)
static boolean isAnalyticFn(Function fn)
boolean equals(Object obj)
final List< Expr > partitionExprs_