Impala
Impalaistheopensource,nativeanalyticdatabaseforApacheHadoop.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
Expr.java
Go to the documentation of this file.
1 // Copyright 2012 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 
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;
22 import java.util.Set;
23 
24 import org.slf4j.Logger;
25 import org.slf4j.LoggerFactory;
26 
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;
43 
48 abstract public class Expr extends TreeNode<Expr> implements ParseNode, Cloneable {
49  private final static Logger LOG = LoggerFactory.getLogger(Expr.class);
50 
51  // Limits on the number of expr children and the depth of an expr tree. These maximum
52  // values guard against crashes due to stack overflows (IMPALA-432) and were
53  // experimentally determined to be safe.
54  public final static int EXPR_CHILDREN_LIMIT = 10000;
55  // The expr depth limit is mostly due to our recursive implementation of clone().
56  public final static int EXPR_DEPTH_LIMIT = 1000;
57 
58  // Name of the function that needs to be implemented by every Expr that
59  // supports negation.
60  private final static String NEGATE_FN = "negate";
61 
62  // to be used where we can't come up with a better estimate
63  protected static double DEFAULT_SELECTIVITY = 0.1;
64 
65  // returns true if an Expr is a non-analytic aggregate.
66  private final static com.google.common.base.Predicate<Expr> isAggregatePredicate_ =
67  new com.google.common.base.Predicate<Expr>() {
68  public boolean apply(Expr arg) {
69  return arg instanceof FunctionCallExpr &&
70  ((FunctionCallExpr)arg).isAggregateFunction();
71  }
72  };
73 
74  // Returns true if an Expr is a NOT CompoundPredicate.
75  public final static com.google.common.base.Predicate<Expr> IS_NOT_PREDICATE =
76  new com.google.common.base.Predicate<Expr>() {
77  @Override
78  public boolean apply(Expr arg) {
79  return arg instanceof CompoundPredicate &&
80  ((CompoundPredicate)arg).getOp() == CompoundPredicate.Operator.NOT;
81  }
82  };
83 
84  // Returns true if an Expr is an OR CompoundPredicate.
85  public final static com.google.common.base.Predicate<Expr> IS_OR_PREDICATE =
86  new com.google.common.base.Predicate<Expr>() {
87  @Override
88  public boolean apply(Expr arg) {
89  return arg instanceof CompoundPredicate &&
90  ((CompoundPredicate)arg).getOp() == CompoundPredicate.Operator.OR;
91  }
92  };
93 
94  // Returns true if an Expr is a scalar subquery
95  public final static com.google.common.base.Predicate<Expr> IS_SCALAR_SUBQUERY =
96  new com.google.common.base.Predicate<Expr>() {
97  @Override
98  public boolean apply(Expr arg) {
99  return arg.isScalarSubquery();
100  }
101  };
102 
103  // Returns true if an Expr is an aggregate function that returns non-null on
104  // an empty set (e.g. count).
105  public final static com.google.common.base.Predicate<Expr>
106  NON_NULL_EMPTY_AGG = new com.google.common.base.Predicate<Expr>() {
107  @Override
108  public boolean apply(Expr arg) {
109  return arg instanceof FunctionCallExpr &&
110  ((FunctionCallExpr)arg).returnsNonNullOnEmpty();
111  }
112  };
113 
114  // Returns true if an Expr is a builtin aggregate function.
115  public final static com.google.common.base.Predicate<Expr> IS_BUILTIN_AGG_FN =
116  new com.google.common.base.Predicate<Expr>() {
117  @Override
118  public boolean apply(Expr arg) {
119  return arg instanceof FunctionCallExpr &&
120  ((FunctionCallExpr)arg).getFnName().isBuiltin();
121  }
122  };
123 
124  public final static com.google.common.base.Predicate<Expr> IS_TRUE_LITERAL =
125  new com.google.common.base.Predicate<Expr>() {
126  @Override
127  public boolean apply(Expr arg) {
128  return arg instanceof BoolLiteral && ((BoolLiteral)arg).getValue();
129  }
130  };
131 
132  // id that's unique across the entire query statement and is assigned by
133  // Analyzer.registerConjuncts(); only assigned for the top-level terms of a
134  // conjunction, and therefore null for most Exprs
135  protected ExprId id_;
136 
137  // true if Expr is an auxiliary predicate that was generated by the plan generation
138  // process to facilitate predicate propagation;
139  // false if Expr originated with a query stmt directly
140  private boolean isAuxExpr_ = false;
141 
142  protected Type type_; // result of analysis
143  protected boolean isAnalyzed_; // true after analyze() has been called
144  protected boolean isWhereClauseConjunct_; // set by analyzer
145 
146  // Flag to indicate whether to wrap this expr's toSql() in parenthesis. Set by parser.
147  // Needed for properly capturing expr precedences in the SQL string.
148  protected boolean printSqlInParens_ = false;
149 
150  // estimated probability of a predicate evaluating to true;
151  // set during analysis;
152  // between 0 and 1 if valid: invalid: -1
153  protected double selectivity_;
154 
155  // estimated number of distinct values produced by Expr; invalid: -1
156  // set during analysis
157  protected long numDistinctValues_;
158 
159  // The function to call. This can either be a scalar or aggregate function.
160  // Set in analyze().
161  protected Function fn_;
162 
163  protected Expr() {
164  super();
166  selectivity_ = -1.0;
167  numDistinctValues_ = -1;
168  }
169 
173  protected Expr(Expr other) {
174  id_ = other.id_;
175  isAuxExpr_ = other.isAuxExpr_;
176  type_ = other.type_;
177  isAnalyzed_ = other.isAnalyzed_;
178  isWhereClauseConjunct_ = other.isWhereClauseConjunct_;
179  printSqlInParens_ = other.printSqlInParens_;
180  selectivity_ = other.selectivity_;
181  numDistinctValues_ = other.numDistinctValues_;
182  fn_ = other.fn_;
183  children_ = Expr.cloneList(other.children_);
184  }
185 
186  public ExprId getId() { return id_; }
187  protected void setId(ExprId id) { this.id_ = id; }
188  public Type getType() { return type_; }
189  public double getSelectivity() { return selectivity_; }
190  public long getNumDistinctValues() { return numDistinctValues_; }
191  public void setPrintSqlInParens(boolean b) { printSqlInParens_ = b; }
192  public boolean isWhereClauseConjunct() { return isWhereClauseConjunct_; }
194  public boolean isAuxExpr() { return isAuxExpr_; }
195  public boolean isRegisteredPredicate() { return id_ != null; }
196  public void setIsAuxExpr() { isAuxExpr_ = true; }
197  public Function getFn() { return fn_; }
198 
204  public void analyze(Analyzer analyzer) throws AnalysisException {
205  // Check the expr child limit.
206  if (children_.size() > EXPR_CHILDREN_LIMIT) {
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...",
211  EXPR_CHILDREN_LIMIT, children_.size(), sqlSubstr));
212  }
213 
214  // analyzer may be null for certain literal constructions (e.g. IntLiteral).
215  if (analyzer != null) {
216  analyzer.incrementCallDepth();
217  // Check the expr depth limit. Do not print the toSql() to not overflow the stack.
218  if (analyzer.getCallDepth() > EXPR_DEPTH_LIMIT) {
219  throw new AnalysisException(String.format("Exceeded the maximum depth of an " +
220  "expression tree (%s).", EXPR_DEPTH_LIMIT));
221  }
222  }
223  for (Expr child: children_) {
224  child.analyze(analyzer);
225  }
226  isAnalyzed_ = true;
228 
229  if (analyzer != null) analyzer.decrementCallDepth();
230  }
231 
238  public void analyzeNoThrow(Analyzer analyzer) {
239  try {
240  analyze(analyzer);
241  } catch (AnalysisException e) {
242  throw new IllegalStateException(e);
243  }
244  }
245 
246  protected void computeNumDistinctValues() {
247  if (isConstant()) {
248  numDistinctValues_ = 1;
249  } else {
250  // if this Expr contains slotrefs, we estimate the # of distinct values
251  // to be the maximum such number for any of the slotrefs;
252  // the subclass analyze() function may well want to override this, if it
253  // knows better
254  List<SlotRef> slotRefs = Lists.newArrayList();
255  this.collect(Predicates.instanceOf(SlotRef.class), slotRefs);
256  numDistinctValues_ = -1;
257  for (SlotRef slotRef: slotRefs) {
258  numDistinctValues_ = Math.max(numDistinctValues_, slotRef.numDistinctValues_);
259  }
260  }
261  }
262 
267  Type[] childTypes = new Type[children_.size()];
268  for (int i = 0; i < children_.size(); ++i) {
269  childTypes[i] = children_.get(i).type_;
270  }
271  return childTypes;
272  }
273 
277  public void castChildCharsToStrings(Analyzer analyzer) throws AnalysisException {
278  for (int i = 0; i < children_.size(); ++i) {
279  if (children_.get(i).getType().isScalarType(PrimitiveType.CHAR)) {
280  children_.set(i, children_.get(i).castTo(ScalarType.STRING));
281  children_.get(i).analyze(analyzer);
282  }
283  }
284  }
285 
290  protected Function getBuiltinFunction(Analyzer analyzer, String name,
291  Type[] argTypes, CompareMode mode) throws AnalysisException {
293  Function searchDesc = new Function(fnName, argTypes, Type.INVALID, false);
294  return analyzer.getCatalog().getFunction(searchDesc, mode);
295  }
296 
312  protected void castForFunctionCall(boolean ignoreWildcardDecimals)
313  throws AnalysisException {
314  Preconditions.checkState(fn_ != null);
315  Type[] fnArgs = fn_.getArgs();
316  Type resolvedWildcardType = getResolvedWildCardType();
317  for (int i = 0; i < children_.size(); ++i) {
318  // For varargs, we must compare with the last type in fnArgs.argTypes.
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)) {
324  castChild(resolvedWildcardType, i);
325  }
326  } else if (!children_.get(i).type_.matchesType(fnArgs[ix])) {
327  castChild(fnArgs[ix], i);
328  }
329  }
330  }
331 
337  Type result = null;
338  Type[] fnArgs = fn_.getArgs();
339  for (int i = 0; i < children_.size(); ++i) {
340  // For varargs, we must compare with the last type in fnArgs.argTypes.
341  int ix = Math.min(fnArgs.length - 1, i);
342  if (!fnArgs[ix].isWildcardDecimal()) continue;
343 
344  Type childType = children_.get(i).type_;
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.");
349  ScalarType decimalType = (ScalarType) childType;
350  if (result == null) {
351  result = decimalType.getMinResolutionDecimal();
352  } else {
353  result = Type.getAssignmentCompatibleType(result, childType);
354  }
355  }
356  if (result != null) {
357  if (result.isNull()) {
358  throw new AnalysisException(
359  "Cannot resolve DECIMAL precision and scale from NULL type.");
360  }
361  Preconditions.checkState(result.isDecimal() && !result.isWildcardDecimal());
362  }
363  return result;
364  }
365 
369  private boolean isExplicitCastToDecimal(Expr e) {
370  if (!(e instanceof CastExpr)) return false;
371  CastExpr c = (CastExpr)e;
372  return !c.isImplicit() && c.getType().isDecimal();
373  }
374 
380  Type targetType) throws AnalysisException {
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);
386  for (NumericLiteral l: literals) {
387  NumericLiteral castLiteral = (NumericLiteral) l.clone();
388  castLiteral.explicitlyCastToFloat(targetType);
389  smap.put(l, castLiteral);
390  }
391  return child.substitute(smap, analyzer, false);
392  }
393 
414  throws AnalysisException {
415  Preconditions.checkState(this instanceof ArithmeticExpr ||
416  this instanceof BinaryPredicate);
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;
424 
425  // Only child(0) or child(1) is a const decimal. See if we can cast it to
426  // the type of the other child.
427  if (c0IsConstantDecimal && !isExplicitCastToDecimal(getChild(0))) {
428  Expr c0 = convertNumericLiteralsToFloat(analyzer, getChild(0), t1);
429  setChild(0, c0);
430  }
431  if (c1IsConstantDecimal && !isExplicitCastToDecimal(getChild(1))) {
432  Expr c1 = convertNumericLiteralsToFloat(analyzer, getChild(1), t0);
433  setChild(1, c1);
434  }
435  }
436 
440  public static void analyze(List<? extends Expr> exprs, Analyzer analyzer)
441  throws AnalysisException {
442  if (exprs == null) return;
443  for (Expr expr: exprs) {
444  expr.analyze(analyzer);
445  }
446  }
447 
448  @Override
449  public String toSql() {
450  return (printSqlInParens_) ? "(" + toSqlImpl() + ")" : toSqlImpl();
451  }
452 
457  protected abstract String toSqlImpl();
458 
459  // Convert this expr, including all children, to its Thrift representation.
460  public TExpr treeToThrift() {
461  if (type_.isNull()) {
462  // Hack to ensure BE never sees TYPE_NULL. If an expr makes it this far without
463  // being cast to a non-NULL type, the type doesn't matter and we can cast it
464  // arbitrarily.
465  Preconditions.checkState(this instanceof NullLiteral || this instanceof SlotRef);
466  return NullLiteral.create(ScalarType.BOOLEAN).treeToThrift();
467  }
468  TExpr result = new TExpr();
469  treeToThriftHelper(result);
470  return result;
471  }
472 
473  // Append a flattened version of this expr, including all children, to 'container'.
474  protected void treeToThriftHelper(TExpr container) {
475  Preconditions.checkState(isAnalyzed_,
476  "Must be analyzed before serializing to thrift. %s", this);
477  Preconditions.checkState(!type_.isWildcardDecimal());
478  // The BE should never see TYPE_NULL
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();
483  if (fn_ != null) {
484  msg.setFn(fn_.toThrift());
485  if (fn_.hasVarArgs()) msg.setVararg_start_idx(fn_.getNumArgs() - 1);
486  }
487  toThrift(msg);
488  container.addToNodes(msg);
489  for (Expr child: children_) {
490  child.treeToThriftHelper(container);
491  }
492  }
493 
494  // Convert this expr into msg (excluding children), which requires setting
495  // msg.op as well as the expr-specific field.
496  protected abstract void toThrift(TExprNode msg);
497 
502  public static long getNumDistinctValues(List<Expr> exprs) {
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;
508  break;
509  }
510  numDistinctValues *= expr.getNumDistinctValues();
511  }
512  return numDistinctValues;
513  }
514 
515  public static List<TExpr> treesToThrift(List<? extends Expr> exprs) {
516  List<TExpr> result = Lists.newArrayList();
517  for (Expr expr: exprs) {
518  result.add(expr.treeToThrift());
519  }
520  return result;
521  }
522 
523  public static com.google.common.base.Predicate<Expr> isAggregatePredicate() {
524  return isAggregatePredicate_;
525  }
526 
527  public boolean isAggregate() {
528  return isAggregatePredicate_.apply(this);
529  }
530 
531  public List<String> childrenToSql() {
532  List<String> result = Lists.newArrayList();
533  for (Expr child: children_) {
534  result.add(child.toSql());
535  }
536  return result;
537  }
538 
539  public String debugString() {
540  return (id_ != null ? "exprid=" + id_.toString() + " " : "") + debugString(children_);
541  }
542 
543  public static String debugString(List<? extends Expr> exprs) {
544  if (exprs == null || exprs.isEmpty()) return "";
545  List<String> strings = Lists.newArrayList();
546  for (Expr expr: exprs) {
547  strings.add(expr.debugString());
548  }
549  return Joiner.on(" ").join(strings);
550  }
551 
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());
557  }
558  return Joiner.on(", ").join(strings);
559  }
560 
565  @Override
566  public boolean equals(Object obj) {
567  if (obj == null) return false;
568  if (obj.getClass() != this.getClass()) return false;
569  // don't compare type, this could be called pre-analysis
570  Expr expr = (Expr) obj;
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;
574  }
575  if (fn_ == null && expr.fn_ == null) return true;
576  if (fn_ == null || expr.fn_ == null) return false; // One null, one not
577  // Both fn_'s are not null
578  return fn_.equals(expr.fn_);
579  }
580 
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;
590  }
591  return true;
592  }
593 
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);
601  }
602 
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);
609  }
610 
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);
618  }
619  return result;
620  }
621 
626  public static void intersect(Analyzer analyzer,
627  List<Expr> l1, List<Expr> l2, ExprSubstitutionMap smap,
628  List<Expr> i1, List<Expr> i2) {
629  i1.clear();
630  i2.clear();
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);
639  if (s1.equals(s2)) {
640  i1.add(l1.get(i));
641  i2.add(l2.get(j));
642  break;
643  }
644  }
645  }
646  }
647 
648  @Override
649  public int hashCode() {
650  if (id_ == null) {
651  throw new UnsupportedOperationException("Expr.hashCode() is not implemented");
652  } else {
653  return id_.asInt();
654  }
655  }
656 
662  public List<Expr> getConjuncts() {
663  List<Expr> list = Lists.newArrayList();
664  if (this instanceof CompoundPredicate
665  && ((CompoundPredicate) this).getOp() == CompoundPredicate.Operator.AND) {
666  // TODO: we have to convert CompoundPredicate.AND to two expr trees for
667  // conjuncts because NULLs are handled differently for CompoundPredicate.AND
668  // and conjunct evaluation. This is not optimal for jitted exprs because it
669  // will result in two functions instead of one. Create a new CompoundPredicate
670  // Operator (i.e. CONJUNCT_AND) with the right NULL semantics and use that
671  // instead
672  list.addAll((getChild(0)).getConjuncts());
673  list.addAll((getChild(1)).getConjuncts());
674  } else {
675  list.add(this);
676  }
677  return list;
678  }
679 
690  boolean preserveRootType)
691  throws AnalysisException {
692  Expr result = clone();
693  // Return clone to avoid removing casts.
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_);
698  return result;
699  }
700 
711  boolean preserveRootType) {
712  try {
713  return trySubstitute(smap, analyzer, preserveRootType);
714  } catch (Exception e) {
715  throw new IllegalStateException("Failed analysis after expr substitution.", e);
716  }
717  }
718 
719  public static ArrayList<Expr> trySubstituteList(Iterable<? extends Expr> exprs,
720  ExprSubstitutionMap smap, Analyzer analyzer, boolean preserveRootTypes)
721  throws AnalysisException {
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));
726  }
727  return result;
728  }
729 
730  public static ArrayList<Expr> substituteList(Iterable<? extends Expr> exprs,
731  ExprSubstitutionMap smap, Analyzer analyzer, boolean preserveRootTypes) {
732  try {
733  return trySubstituteList(exprs, smap, analyzer, preserveRootTypes);
734  } catch (Exception e) {
735  throw new IllegalStateException("Failed analysis after expr substitution.", e);
736  }
737  }
738 
746  throws AnalysisException {
747  if (isImplicitCast()) return getChild(0).substituteImpl(smap, analyzer);
748  if (smap != null) {
749  Expr substExpr = smap.get(this);
750  if (substExpr != null) return substExpr.clone();
751  }
752  for (int i = 0; i < children_.size(); ++i) {
753  children_.set(i, children_.get(i).substituteImpl(smap, analyzer));
754  }
755  // SlotRefs must remain analyzed to support substitution across query blocks. All
756  // other exprs must be analyzed again after the substitution to add implicit casts
757  // and for resolving their correct function signature.
758  if (!(this instanceof SlotRef)) resetAnalysisState();
759  return this;
760  }
761 
766  protected void resetAnalysisState() { isAnalyzed_ = false; }
767 
771  public Expr reset() {
772  if (isImplicitCast()) return getChild(0).reset();
773  for (int i = 0; i < children_.size(); ++i) {
774  children_.set(i, children_.get(i).reset());
775  }
777  return this;
778  }
779 
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());
783  }
784  return l;
785  }
786 
791  @Override
792  public abstract Expr clone();
793 
798  public static <C extends Expr> ArrayList<C> cloneList(Iterable<C> l) {
799  Preconditions.checkNotNull(l);
800  ArrayList<C> result = new ArrayList<C>();
801  for (Expr element: l) {
802  result.add((C) element.clone());
803  }
804  return result;
805  }
806 
810  public static <C extends Expr> void removeDuplicates(List<C> l) {
811  if (l == null) return;
812  ListIterator<C> it1 = l.listIterator();
813  while (it1.hasNext()) {
814  C e1 = it1.next();
815  ListIterator<C> it2 = l.listIterator();
816  boolean duplicate = false;
817  while (it2.hasNext()) {
818  C e2 = it2.next();
819  // only check up to but excluding e1
820  if (e1 == e2) break;
821  if (e1.equals(e2)) {
822  duplicate = true;
823  break;
824  }
825  }
826  if (duplicate) it1.remove();
827  }
828  }
829 
833  public static <C extends Expr> void removeConstants(List<C> l) {
834  if (l == null) return;
835  ListIterator<C> it = l.listIterator();
836  while (it.hasNext()) {
837  C e = it.next();
838  if (e.isConstant()) it.remove();
839  }
840  }
841 
845  public boolean isBound(TupleId tid) {
846  return isBoundByTupleIds(Lists.newArrayList(tid));
847  }
848 
852  public boolean isBoundByTupleIds(List<TupleId> tids) {
853  for (Expr child: children_) {
854  if (!child.isBoundByTupleIds(tids)) return false;
855  }
856  return true;
857  }
858 
862  public boolean isBound(SlotId slotId) {
863  return isBoundBySlotIds(Lists.newArrayList(slotId));
864  }
865 
869  public boolean isBoundBySlotIds(List<SlotId> slotIds) {
870  for (Expr child: children_) {
871  if (!child.isBoundBySlotIds(slotIds)) return false;
872  }
873  return true;
874  }
875 
876  public static boolean isBound(List<? extends Expr> exprs, List<TupleId> tids) {
877  for (Expr expr: exprs) {
878  if (!expr.isBoundByTupleIds(tids)) return false;
879  }
880  return true;
881  }
882 
883  public void getIds(List<TupleId> tupleIds, List<SlotId> slotIds) {
884  Set<TupleId> tupleIdSet = Sets.newHashSet();
885  Set<SlotId> slotIdSet = Sets.newHashSet();
886  getIdsHelper(tupleIdSet, slotIdSet);
887  if (tupleIds != null) tupleIds.addAll(tupleIdSet);
888  if (slotIds != null) slotIds.addAll(slotIdSet);
889  }
890 
891  protected void getIdsHelper(Set<TupleId> tupleIds, Set<SlotId> slotIds) {
892  for (Expr child: children_) {
893  child.getIdsHelper(tupleIds, slotIds);
894  }
895  }
896 
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);
902  }
903  }
904 
908  public boolean isLiteral() {
909  return this instanceof LiteralExpr;
910  }
911 
917  public boolean isConstant() {
918  return !contains(Predicates.instanceOf(SlotRef.class)) &&
919  !contains(Predicates.instanceOf(Subquery.class));
920  }
921 
926  public boolean isNullLiteral() {
927  if (this instanceof NullLiteral) return true;
928  if (!(this instanceof CastExpr)) return false;
929  Preconditions.checkState(children_.size() == 1);
930  return children_.get(0).isNullLiteral();
931  }
932 
936  public boolean isScalarSubquery() {
937  Preconditions.checkState(isAnalyzed_);
938  return this instanceof Subquery && getType().isScalarType();
939  }
940 
947  public void checkReturnsBool(String name, boolean printExpr) throws AnalysisException {
948  if (!type_.isBoolean() && !type_.isNull()) {
949  throw new AnalysisException(
950  String.format("%s%s requires return type 'BOOLEAN'. " +
951  "Actual type is '%s'.", name, (printExpr) ? " '" + toSql() + "'" : "",
952  type_.toString()));
953  }
954  }
955 
967  public final Expr castTo(Type targetType) throws AnalysisException {
968  Type type = Type.getAssignmentCompatibleType(this.type_, targetType);
969  Preconditions.checkState(type.isValid(), "cast %s to %s", this.type_, targetType);
970  // If the targetType is NULL_TYPE then ignore the cast because NULL_TYPE
971  // is compatible with all types and no cast is necessary.
972  if (targetType.isNull()) return this;
973  if (!targetType.isDecimal()) {
974  // requested cast must be to assignment-compatible type
975  // (which implies no loss of precision)
976  Preconditions.checkArgument(targetType.equals(type),
977  "targetType=" + targetType + " type=" + type);
978  }
979  return uncheckedCastTo(targetType);
980  }
981 
995  protected Expr uncheckedCastTo(Type targetType) throws AnalysisException {
996  return new CastExpr(targetType, this);
997  }
998 
1008  public void castChild(Type targetType, int childIndex) throws AnalysisException {
1009  Expr child = getChild(childIndex);
1010  Expr newChild = child.castTo(targetType);
1011  setChild(childIndex, newChild);
1012  }
1013 
1014 
1024  protected void uncheckedCastChild(Type targetType, int childIndex)
1025  throws AnalysisException {
1026  Expr child = getChild(childIndex);
1027  Expr newChild = child.uncheckedCastTo(targetType);
1028  setChild(childIndex, newChild);
1029  }
1030 
1035  if (isImplicitCast()) return getChild(0).ignoreImplicitCast();
1036  return this;
1037  }
1038 
1042  public boolean isImplicitCast() {
1043  return this instanceof CastExpr && ((CastExpr) this).isImplicit();
1044  }
1045 
1046  @Override
1047  public String toString() {
1048  return Objects.toStringHelper(this.getClass())
1049  .add("id", id_)
1050  .add("type", type_)
1051  .add("sel", selectivity_)
1052  .add("#distinct", numDistinctValues_)
1053  .toString();
1054  }
1055 
1060  public SlotRef unwrapSlotRef(boolean implicitOnly) {
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);
1067  } else {
1068  return null;
1069  }
1070  }
1071 
1076  public static Expr pushNegationToOperands(Expr root) {
1077  Preconditions.checkNotNull(root);
1078  if (Expr.IS_NOT_PREDICATE.apply(root)) {
1079  try {
1080  // Make sure we call function 'negate' only on classes that support it,
1081  // otherwise we may recurse infinitely.
1082  Method m = root.getChild(0).getClass().getDeclaredMethod(NEGATE_FN);
1083  return pushNegationToOperands(root.getChild(0).negate());
1084  } catch (NoSuchMethodException e) {
1085  // The 'negate' function is not implemented. Break the recursion.
1086  return root;
1087  }
1088  }
1089 
1090  if (root instanceof CompoundPredicate) {
1091  Expr left = pushNegationToOperands(root.getChild(0));
1092  Expr right = pushNegationToOperands(root.getChild(1));
1093  return new CompoundPredicate(((CompoundPredicate)root).getOp(), left, right);
1094  }
1095 
1096  return root;
1097  }
1098 
1102  public Expr negate() {
1103  Preconditions.checkState(type_.getPrimitiveType() == PrimitiveType.BOOLEAN);
1104  return new CompoundPredicate(CompoundPredicate.Operator.NOT, this, null);
1105  }
1106 
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);
1120  }
1121 
1134  public void foldConstantChildren(Analyzer analyzer) throws AnalysisException {
1135  Preconditions.checkState(isAnalyzed_);
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);
1143  }
1144  isAnalyzed_ = false;
1145  }
1146 }
List< String > childrenToSql()
Definition: Expr.java:531
void analyzeNoThrow(Analyzer analyzer)
Definition: Expr.java:238
void uncheckedCastChild(Type targetType, int childIndex)
Definition: Expr.java:1024
static final com.google.common.base.Predicate< Expr > NON_NULL_EMPTY_AGG
Definition: Expr.java:106
void getIdsHelper(Set< TupleId > tupleIds, Set< SlotId > slotIds)
Definition: Expr.java:891
static void intersect(Analyzer analyzer, List< Expr > l1, List< Expr > l2, ExprSubstitutionMap smap, List< Expr > i1, List< Expr > i2)
Definition: Expr.java:626
static List< TExpr > treesToThrift(List<?extends Expr > exprs)
Definition: Expr.java:515
static< CextendsExpr > void removeConstants(List< C > l)
Definition: Expr.java:833
static com.google.common.base.Predicate< Expr > isAggregatePredicate()
Definition: Expr.java:523
static String debugString(List<?extends Expr > exprs)
Definition: Expr.java:543
void castForFunctionCall(boolean ignoreWildcardDecimals)
Definition: Expr.java:312
void analyze(Analyzer analyzer)
Definition: Expr.java:204
Expr trySubstitute(ExprSubstitutionMap smap, Analyzer analyzer, boolean preserveRootType)
Definition: Expr.java:689
boolean isBound(SlotId slotId)
Definition: Expr.java:862
void checkReturnsBool(String name, boolean printExpr)
Definition: Expr.java:947
static final ScalarType STRING
Definition: Type.java:53
static final String BUILTINS_DB
Definition: Catalog.java:61
final Expr castTo(Type targetType)
Definition: Expr.java:967
static ArrayList< Expr > resetList(ArrayList< Expr > l)
Definition: Expr.java:780
void convertNumericLiteralsFromDecimal(Analyzer analyzer)
Definition: Expr.java:413
static final ScalarType BOOLEAN
Definition: Type.java:46
Expr uncheckedCastTo(Type targetType)
Definition: Expr.java:995
void setPrintSqlInParens(boolean b)
Definition: Expr.java:191
static ArrayList< Expr > trySubstituteList(Iterable<?extends Expr > exprs, ExprSubstitutionMap smap, Analyzer analyzer, boolean preserveRootTypes)
Definition: Expr.java:719
abstract void toThrift(TExprNode msg)
static ArrayList< Expr > substituteList(Iterable<?extends Expr > exprs, ExprSubstitutionMap smap, Analyzer analyzer, boolean preserveRootTypes)
Definition: Expr.java:730
static final com.google.common.base.Predicate< Expr > IS_TRUE_LITERAL
Definition: Expr.java:124
void getIds(List< TupleId > tupleIds, List< SlotId > slotIds)
Definition: Expr.java:883
Expr convertNumericLiteralsToFloat(Analyzer analyzer, Expr child, Type targetType)
Definition: Expr.java:379
static final com.google.common.base.Predicate< Expr > IS_NOT_PREDICATE
Definition: Expr.java:75
static final int EXPR_DEPTH_LIMIT
Definition: Expr.java:56
static Expr pushNegationToOperands(Expr root)
Definition: Expr.java:1076
PrimitiveType
Definition: types.h:27
static final ScalarType DOUBLE
Definition: Type.java:52
static final Logger LOG
Definition: Expr.java:49
static< CextendsExpr > void removeDuplicates(List< C > l)
Definition: Expr.java:810
static final com.google.common.base.Predicate< Expr > isAggregatePredicate_
Definition: Expr.java:66
static< CextendsExpr > List< C > intersect(List< C > l1, List< C > l2)
Definition: Expr.java:614
static boolean isBound(List<?extends Expr > exprs, List< TupleId > tids)
Definition: Expr.java:876
void treeToThriftHelper(TExpr container)
Definition: Expr.java:474
static< CextendsExpr > boolean equalLists(List< C > l1, List< C > l2)
Definition: Expr.java:584
Expr substitute(ExprSubstitutionMap smap, Analyzer analyzer, boolean preserveRootType)
Definition: Expr.java:710
boolean equals(Object obj)
Definition: Expr.java:566
Function getBuiltinFunction(Analyzer analyzer, String name, Type[] argTypes, CompareMode mode)
Definition: Expr.java:290
static< CextendsExpr > ArrayList< C > cloneList(Iterable< C > l)
Definition: Expr.java:798
Expr substituteImpl(ExprSubstitutionMap smap, Analyzer analyzer)
Definition: Expr.java:745
static void analyze(List<?extends Expr > exprs, Analyzer analyzer)
Definition: Expr.java:440
static< CextendsExpr > boolean equalSets(List< C > l1, List< C > l2)
Definition: Expr.java:598
SlotRef unwrapSlotRef(boolean implicitOnly)
Definition: Expr.java:1060
void castChild(Type targetType, int childIndex)
Definition: Expr.java:1008
static final com.google.common.base.Predicate< Expr > IS_OR_PREDICATE
Definition: Expr.java:85
boolean isExplicitCastToDecimal(Expr e)
Definition: Expr.java:369
static final com.google.common.base.Predicate< Expr > IS_SCALAR_SUBQUERY
Definition: Expr.java:95
static final int EXPR_CHILDREN_LIMIT
Definition: Expr.java:54
static final String NEGATE_FN
Definition: Expr.java:60
static String toSql(List<?extends Expr > exprs)
Definition: Expr.java:552
static< CextendsExpr > void getIds(List<?extends Expr > exprs, List< TupleId > tupleIds, List< SlotId > slotIds)
Definition: Expr.java:897
boolean isBoundByTupleIds(List< TupleId > tids)
Definition: Expr.java:852
string name
Definition: cpu-info.cc:50
static final ScalarType INVALID
Definition: Type.java:44
boolean isBoundBySlotIds(List< SlotId > slotIds)
Definition: Expr.java:869
boolean isBound(TupleId tid)
Definition: Expr.java:845
void foldConstantChildren(Analyzer analyzer)
Definition: Expr.java:1134
static long getNumDistinctValues(List< Expr > exprs)
Definition: Expr.java:502
static final com.google.common.base.Predicate< Expr > IS_BUILTIN_AGG_FN
Definition: Expr.java:115
static< CextendsExpr > boolean isSubset(List< C > l1, List< C > l2)
Definition: Expr.java:606
static double DEFAULT_SELECTIVITY
Definition: Expr.java:63
void castChildCharsToStrings(Analyzer analyzer)
Definition: Expr.java:277