15 package com.cloudera.impala.analysis;
17 import java.lang.reflect.Method;
18 import java.util.ArrayList;
19 import java.util.Iterator;
20 import java.util.List;
21 import java.util.ListIterator;
24 import org.slf4j.Logger;
25 import org.slf4j.LoggerFactory;
34 import com.cloudera.impala.common.TreeNode;
35 import com.cloudera.impala.thrift.TExpr;
36 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.base.Predicates;
41 import com.google.common.collect.Lists;
42 import com.google.common.collect.Sets;
49 private final static Logger
LOG = LoggerFactory.getLogger(Expr.class);
67 new com.google.common.base.Predicate<
Expr>() {
68 public boolean apply(
Expr arg) {
76 new com.google.common.base.Predicate<
Expr>() {
78 public boolean apply(
Expr arg) {
86 new com.google.common.base.Predicate<
Expr>() {
88 public boolean apply(
Expr arg) {
96 new com.google.common.base.Predicate<
Expr>() {
98 public boolean apply(
Expr arg) {
99 return arg.isScalarSubquery();
105 public final static com.google.common.base.Predicate<
Expr>
108 public boolean apply(
Expr arg) {
116 new com.google.common.base.Predicate<
Expr>() {
118 public boolean apply(
Expr arg) {
125 new com.google.common.base.Predicate<
Expr>() {
127 public boolean apply(
Expr arg) {
183 children_ = Expr.cloneList(other.children_);
207 String sql =
toSql();
208 String sqlSubstr = sql.substring(0, Math.min(80, sql.length()));
209 throw new AnalysisException(String.format(
"Exceeded the maximum number of child " +
210 "expressions (%s).\nExpression has %s children:\n%s...",
215 if (analyzer != null) {
216 analyzer.incrementCallDepth();
223 for (
Expr child: children_) {
224 child.analyze(analyzer);
229 if (analyzer != null) analyzer.decrementCallDepth();
242 throw new IllegalStateException(e);
254 List<SlotRef> slotRefs = Lists.newArrayList();
255 this.collect(Predicates.instanceOf(SlotRef.class), slotRefs);
257 for (
SlotRef slotRef: slotRefs) {
267 Type[] childTypes =
new Type[children_.size()];
268 for (
int i = 0; i < children_.size(); ++i) {
269 childTypes[i] = children_.get(i).
type_;
278 for (
int i = 0; i < children_.size(); ++i) {
281 children_.get(i).
analyze(analyzer);
294 return analyzer.getCatalog().getFunction(searchDesc, mode);
314 Preconditions.checkState(
fn_ != null);
315 Type[] fnArgs = fn_.getArgs();
317 for (
int i = 0; i < children_.size(); ++i) {
319 int ix = Math.min(fnArgs.length - 1, i);
320 if (fnArgs[ix].isWildcardDecimal()) {
321 if (children_.get(i).type_.isDecimal() && ignoreWildcardDecimals)
continue;
322 Preconditions.checkState(resolvedWildcardType != null);
323 if (!children_.get(i).type_.equals(resolvedWildcardType)) {
326 }
else if (!children_.get(i).type_.matchesType(fnArgs[ix])) {
338 Type[] fnArgs = fn_.getArgs();
339 for (
int i = 0; i < children_.size(); ++i) {
341 int ix = Math.min(fnArgs.length - 1, i);
342 if (!fnArgs[ix].isWildcardDecimal())
continue;
345 Preconditions.checkState(!childType.isWildcardDecimal(),
346 "Child expr should have been resolved.");
347 Preconditions.checkState(childType.isScalarType(),
348 "Function should not have resolved with a non-scalar child type.");
350 if (result == null) {
351 result = decimalType.getMinResolutionDecimal();
353 result = Type.getAssignmentCompatibleType(result, childType);
356 if (result != null) {
358 throw new AnalysisException(
359 "Cannot resolve DECIMAL precision and scale from NULL type.");
370 if (!(e instanceof
CastExpr))
return false;
371 CastExpr c = (CastExpr)e;
372 return !c.isImplicit() && c.
getType().isDecimal();
381 if (!targetType.isFloatingPointType() && !targetType.isIntegerType())
return child;
382 if (targetType.isIntegerType()) targetType =
Type.
DOUBLE;
383 List<NumericLiteral> literals = Lists.newArrayList();
384 child.collectAll(Predicates.instanceOf(NumericLiteral.class), literals);
388 castLiteral.explicitlyCastToFloat(targetType);
389 smap.put(l, castLiteral);
391 return child.substitute(smap, analyzer,
false);
417 Preconditions.checkState(children_.size() == 2);
418 Type t0 = getChild(0).getType();
419 Type t1 = getChild(1).getType();
420 boolean c0IsConstantDecimal = getChild(0).isConstant() && t0.
isDecimal();
421 boolean c1IsConstantDecimal = getChild(1).isConstant() && t1.isDecimal();
422 if (c0IsConstantDecimal && c1IsConstantDecimal)
return;
423 if (!c0IsConstantDecimal && !c1IsConstantDecimal)
return;
442 if (exprs == null)
return;
443 for (
Expr expr: exprs) {
444 expr.analyze(analyzer);
468 TExpr result =
new TExpr();
476 "Must be analyzed before serializing to thrift. %s",
this);
477 Preconditions.checkState(!type_.isWildcardDecimal());
479 Preconditions.checkState(!type_.isNull(),
"Expr has type null!");
480 TExprNode msg =
new TExprNode();
481 msg.type = type_.toThrift();
482 msg.num_children = children_.size();
484 msg.setFn(fn_.toThrift());
488 container.addToNodes(msg);
489 for (
Expr child: children_) {
490 child.treeToThriftHelper(container);
496 protected abstract void toThrift(TExprNode msg);
503 if (exprs == null || exprs.isEmpty())
return 0;
504 long numDistinctValues = 1;
505 for (
Expr expr: exprs) {
506 if (expr.getNumDistinctValues() == -1) {
507 numDistinctValues = -1;
510 numDistinctValues *= expr.getNumDistinctValues();
512 return numDistinctValues;
516 List<TExpr> result = Lists.newArrayList();
517 for (
Expr expr: exprs) {
518 result.add(expr.treeToThrift());
528 return isAggregatePredicate_.apply(
this);
532 List<String> result = Lists.newArrayList();
533 for (
Expr child: children_) {
534 result.add(child.toSql());
540 return (
id_ != null ?
"exprid=" +
id_.toString() +
" " :
"") +
debugString(children_);
544 if (exprs == null || exprs.isEmpty())
return "";
545 List<String> strings = Lists.newArrayList();
546 for (
Expr expr: exprs) {
547 strings.add(expr.debugString());
549 return Joiner.on(
" ").join(strings);
552 public static String
toSql(List<? extends Expr> exprs) {
553 if (exprs == null || exprs.isEmpty())
return "";
554 List<String> strings = Lists.newArrayList();
555 for (
Expr expr: exprs) {
556 strings.add(expr.toSql());
558 return Joiner.on(
", ").join(strings);
567 if (obj == null)
return false;
568 if (obj.getClass() != this.getClass())
return false;
571 if (children_.size() != expr.children_.size())
return false;
572 for (
int i = 0; i < children_.size(); ++i) {
573 if (!children_.get(i).equals(expr.children_.get(i)))
return false;
575 if (
fn_ == null && expr.
fn_ == null)
return true;
576 if (
fn_ == null || expr.
fn_ == null)
return false;
578 return fn_.equals(expr.fn_);
584 public static <C extends Expr>
boolean equalLists(List<C> l1, List<C> l2) {
585 if (l1.size() != l2.size())
return false;
586 Iterator<C> l1Iter = l1.iterator();
587 Iterator<C> l2Iter = l2.iterator();
588 while (l1Iter.hasNext()) {
589 if (!l1Iter.next().equals(l2Iter.next()))
return false;
598 public static <C extends Expr>
boolean equalSets(List<C> l1, List<C> l2) {
599 if (l1.size() != l2.size())
return false;
600 return l1.containsAll(l2) && l2.containsAll(l1);
606 public static <C extends Expr>
boolean isSubset(List<C> l1, List<C> l2) {
607 if (l1.size() > l2.size())
return false;
608 return l2.containsAll(l1);
614 public static <C extends Expr> List<C>
intersect(List<C> l1, List<C> l2) {
615 List<C> result =
new ArrayList<C>();
616 for (C element: l1) {
617 if (l2.contains(element)) result.add(element);
628 List<Expr> i1, List<Expr> i2) {
631 List<Expr> s1List = Expr.substituteList(l1, smap, analyzer,
false);
632 Preconditions.checkState(s1List.size() == l1.size());
633 List<Expr> s2List = Expr.substituteList(l2, smap, analyzer,
false);
634 Preconditions.checkState(s2List.size() == l2.size());
635 for (
int i = 0; i < s1List.size(); ++i) {
636 Expr s1 = s1List.get(i);
637 for (
int j = 0; j < s2List.size(); ++j) {
638 Expr s2 = s2List.get(j);
651 throw new UnsupportedOperationException(
"Expr.hashCode() is not implemented");
663 List<Expr> list = Lists.newArrayList();
690 boolean preserveRootType)
694 if (smap == null)
return result;
695 result = result.substituteImpl(smap, analyzer);
696 result.analyze(analyzer);
697 if (preserveRootType && !
type_.equals(result.
getType())) result = result.castTo(
type_);
711 boolean preserveRootType) {
714 }
catch (Exception e) {
715 throw new IllegalStateException(
"Failed analysis after expr substitution.", e);
722 if (exprs == null)
return null;
723 ArrayList<Expr> result =
new ArrayList<Expr>();
724 for (
Expr e: exprs) {
725 result.add(e.trySubstitute(smap, analyzer, preserveRootTypes));
734 }
catch (Exception e) {
735 throw new IllegalStateException(
"Failed analysis after expr substitution.", e);
747 if (
isImplicitCast())
return getChild(0).substituteImpl(smap, analyzer);
749 Expr substExpr = smap.get(
this);
750 if (substExpr != null)
return substExpr.clone();
752 for (
int i = 0; i < children_.size(); ++i) {
753 children_.set(i, children_.get(i).
substituteImpl(smap, analyzer));
773 for (
int i = 0; i < children_.size(); ++i) {
774 children_.set(i, children_.get(i).
reset());
780 public static ArrayList<Expr>
resetList(ArrayList<Expr> l) {
781 for (
int i = 0; i < l.size(); ++i) {
782 l.set(i, l.get(i).
reset());
799 Preconditions.checkNotNull(l);
800 ArrayList<C> result =
new ArrayList<C>();
801 for (
Expr element: l) {
802 result.add((C) element.clone());
811 if (l == null)
return;
812 ListIterator<C> it1 = l.listIterator();
813 while (it1.hasNext()) {
815 ListIterator<C> it2 = l.listIterator();
816 boolean duplicate =
false;
817 while (it2.hasNext()) {
826 if (duplicate) it1.remove();
834 if (l == null)
return;
835 ListIterator<C> it = l.listIterator();
836 while (it.hasNext()) {
838 if (e.isConstant()) it.remove();
853 for (
Expr child: children_) {
854 if (!child.isBoundByTupleIds(tids))
return false;
870 for (
Expr child: children_) {
871 if (!child.isBoundBySlotIds(slotIds))
return false;
876 public static boolean isBound(List<? extends Expr> exprs, List<TupleId> tids) {
877 for (
Expr expr: exprs) {
878 if (!expr.isBoundByTupleIds(tids))
return false;
883 public void getIds(List<TupleId> tupleIds, List<SlotId> slotIds) {
884 Set<TupleId> tupleIdSet = Sets.newHashSet();
885 Set<SlotId> slotIdSet = Sets.newHashSet();
887 if (tupleIds != null) tupleIds.addAll(tupleIdSet);
888 if (slotIds != null) slotIds.addAll(slotIdSet);
891 protected void getIdsHelper(Set<TupleId> tupleIds, Set<SlotId> slotIds) {
892 for (
Expr child: children_) {
893 child.getIdsHelper(tupleIds, slotIds);
897 public static <C extends Expr>
void getIds(List<? extends Expr> exprs,
898 List<TupleId> tupleIds, List<SlotId> slotIds) {
899 if (exprs == null)
return;
900 for (
Expr e: exprs) {
901 e.getIds(tupleIds, slotIds);
918 return !contains(Predicates.instanceOf(
SlotRef.class)) &&
919 !contains(Predicates.instanceOf(
Subquery.class));
928 if (!(
this instanceof
CastExpr))
return false;
929 Preconditions.checkState(children_.size() == 1);
950 String.format(
"%s%s requires return type 'BOOLEAN'. " +
951 "Actual type is '%s'.",
name, (printExpr) ?
" '" +
toSql() +
"'" :
"",
968 Type type = Type.getAssignmentCompatibleType(this.type_, targetType);
969 Preconditions.checkState(type.isValid(),
"cast %s to %s", this.
type_, targetType);
972 if (targetType.isNull())
return this;
973 if (!targetType.isDecimal()) {
976 Preconditions.checkArgument(targetType.equals(type),
977 "targetType=" + targetType +
" type=" + type);
996 return new CastExpr(targetType,
this);
1009 Expr child = getChild(childIndex);
1010 Expr newChild = child.castTo(targetType);
1011 setChild(childIndex, newChild);
1026 Expr child = getChild(childIndex);
1027 Expr newChild = child.uncheckedCastTo(targetType);
1028 setChild(childIndex, newChild);
1048 return Objects.toStringHelper(this.getClass())
1061 if (
this instanceof
SlotRef) {
1062 return (SlotRef)
this;
1063 }
else if (
this instanceof
CastExpr
1064 && (!implicitOnly || ((
CastExpr)
this).isImplicit())
1065 && getChild(0) instanceof SlotRef) {
1066 return (SlotRef) getChild(0);
1077 Preconditions.checkNotNull(root);
1082 Method m = root.getChild(0).getClass().getDeclaredMethod(
NEGATE_FN);
1084 }
catch (NoSuchMethodException e) {
1093 return new CompoundPredicate(((CompoundPredicate)root).getOp(), left, right);
1115 if (!contains(
Subquery.class))
return null;
1116 List<Subquery> subqueries = Lists.newArrayList();
1117 collect(
Subquery.class, subqueries);
1118 Preconditions.checkState(subqueries.size() == 1);
1119 return subqueries.get(0);
1136 Preconditions.checkNotNull(analyzer);
1137 for (
int i = 0; i < children_.size(); ++i) {
1138 Expr child = getChild(i);
1139 if (child.
isLiteral() || !child.isConstant())
continue;
1140 LiteralExpr literalExpr = LiteralExpr.create(child, analyzer.getQueryCtx());
1141 Preconditions.checkNotNull(literalExpr);
1142 setChild(i, literalExpr);
boolean isWildcardDecimal()
List< String > childrenToSql()
void analyzeNoThrow(Analyzer analyzer)
void uncheckedCastChild(Type targetType, int childIndex)
static final com.google.common.base.Predicate< Expr > NON_NULL_EMPTY_AGG
boolean isWhereClauseConjunct()
void getIdsHelper(Set< TupleId > tupleIds, Set< SlotId > slotIds)
void computeNumDistinctValues()
static void intersect(Analyzer analyzer, List< Expr > l1, List< Expr > l2, ExprSubstitutionMap smap, List< Expr > i1, List< Expr > i2)
static List< TExpr > treesToThrift(List<?extends Expr > exprs)
static< CextendsExpr > void removeConstants(List< C > l)
boolean printSqlInParens_
static com.google.common.base.Predicate< Expr > isAggregatePredicate()
static String debugString(List<?extends Expr > exprs)
void castForFunctionCall(boolean ignoreWildcardDecimals)
void analyze(Analyzer analyzer)
Expr trySubstitute(ExprSubstitutionMap smap, Analyzer analyzer, boolean preserveRootType)
boolean isBound(SlotId slotId)
boolean isScalarSubquery()
void checkReturnsBool(String name, boolean printExpr)
static final ScalarType STRING
static final String BUILTINS_DB
final Expr castTo(Type targetType)
static ArrayList< Expr > resetList(ArrayList< Expr > l)
void convertNumericLiteralsFromDecimal(Analyzer analyzer)
static final ScalarType BOOLEAN
Expr uncheckedCastTo(Type targetType)
void setPrintSqlInParens(boolean b)
static ArrayList< Expr > trySubstituteList(Iterable<?extends Expr > exprs, ExprSubstitutionMap smap, Analyzer analyzer, boolean preserveRootTypes)
abstract void toThrift(TExprNode msg)
static ArrayList< Expr > substituteList(Iterable<?extends Expr > exprs, ExprSubstitutionMap smap, Analyzer analyzer, boolean preserveRootTypes)
Type getResolvedWildCardType()
abstract String toSqlImpl()
static final com.google.common.base.Predicate< Expr > IS_TRUE_LITERAL
Type[] collectChildReturnTypes()
void getIds(List< TupleId > tupleIds, List< SlotId > slotIds)
void resetAnalysisState()
Expr convertNumericLiteralsToFloat(Analyzer analyzer, Expr child, Type targetType)
static final com.google.common.base.Predicate< Expr > IS_NOT_PREDICATE
static final int EXPR_DEPTH_LIMIT
long getNumDistinctValues()
static Expr pushNegationToOperands(Expr root)
static final ScalarType DOUBLE
static< CextendsExpr > void removeDuplicates(List< C > l)
static final com.google.common.base.Predicate< Expr > isAggregatePredicate_
static< CextendsExpr > List< C > intersect(List< C > l1, List< C > l2)
static boolean isBound(List<?extends Expr > exprs, List< TupleId > tids)
void treeToThriftHelper(TExpr container)
static< CextendsExpr > boolean equalLists(List< C > l1, List< C > l2)
Expr substitute(ExprSubstitutionMap smap, Analyzer analyzer, boolean preserveRootType)
boolean equals(Object obj)
Function getBuiltinFunction(Analyzer analyzer, String name, Type[] argTypes, CompareMode mode)
boolean isRegisteredPredicate()
boolean isWhereClauseConjunct_
static< CextendsExpr > ArrayList< C > cloneList(Iterable< C > l)
Expr ignoreImplicitCast()
Expr substituteImpl(ExprSubstitutionMap smap, Analyzer analyzer)
static void analyze(List<?extends Expr > exprs, Analyzer analyzer)
static< CextendsExpr > boolean equalSets(List< C > l1, List< C > l2)
SlotRef unwrapSlotRef(boolean implicitOnly)
void castChild(Type targetType, int childIndex)
static final com.google.common.base.Predicate< Expr > IS_OR_PREDICATE
void setIsWhereClauseConjunct()
boolean isExplicitCastToDecimal(Expr e)
static final com.google.common.base.Predicate< Expr > IS_SCALAR_SUBQUERY
static final int EXPR_CHILDREN_LIMIT
static final String NEGATE_FN
static String toSql(List<?extends Expr > exprs)
static< CextendsExpr > void getIds(List<?extends Expr > exprs, List< TupleId > tupleIds, List< SlotId > slotIds)
boolean isBoundByTupleIds(List< TupleId > tids)
List< Expr > getConjuncts()
static final ScalarType INVALID
boolean isBoundBySlotIds(List< SlotId > slotIds)
boolean isBound(TupleId tid)
void foldConstantChildren(Analyzer analyzer)
static long getNumDistinctValues(List< Expr > exprs)
static final com.google.common.base.Predicate< Expr > IS_BUILTIN_AGG_FN
static< CextendsExpr > boolean isSubset(List< C > l1, List< C > l2)
static double DEFAULT_SELECTIVITY
void castChildCharsToStrings(Analyzer analyzer)