Impala
Impalaistheopensource,nativeanalyticdatabaseforApacheHadoop.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
TupleIsNullPredicate.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.util.List;
18 import java.util.Set;
19 
23 import com.cloudera.impala.thrift.TExprNode;
24 import com.cloudera.impala.thrift.TExprNodeType;
25 import com.cloudera.impala.thrift.TTupleIsNullPredicate;
26 import com.google.common.base.Preconditions;
27 import com.google.common.collect.Lists;
28 import com.google.common.collect.Sets;
29 
39 public class TupleIsNullPredicate extends Predicate {
40  private final Set<TupleId> tupleIds_;
42 
43  public TupleIsNullPredicate(List<TupleId> tupleIds) {
44  Preconditions.checkState(tupleIds != null && !tupleIds.isEmpty());
45  this.tupleIds_ = Sets.newHashSet(tupleIds);
46  }
47 
52  super(other);
53  tupleIds_ = Sets.newHashSet(other.tupleIds_);
54  analyzer_ = other.analyzer_;
55  }
56 
57  @Override
58  public void analyze(Analyzer analyzer) throws AnalysisException {
59  if (isAnalyzed_) return;
60  super.analyze(analyzer);
61  analyzer_ = analyzer;
62  }
63 
64  @Override
65  protected void toThrift(TExprNode msg) {
66  msg.node_type = TExprNodeType.TUPLE_IS_NULL_PRED;
67  msg.tuple_is_null_pred = new TTupleIsNullPredicate();
68  Preconditions.checkNotNull(analyzer_);
69  for (TupleId tid: tupleIds_) {
70  // Check that all referenced tuples are materialized.
71  TupleDescriptor tupleDesc = analyzer_.getTupleDesc(tid);
72  Preconditions.checkNotNull(tupleDesc, "Unknown tuple id: " + tid.toString());
73  Preconditions.checkState(tupleDesc.isMaterialized(),
74  String.format("Illegal reference to non-materialized tuple: tid=%s", tid));
75  msg.tuple_is_null_pred.addToTuple_ids(tid.asInt());
76  }
77  }
78 
79  @Override
80  public boolean equals(Object o) {
81  if (!super.equals(o)) return false;
83  return other.tupleIds_.containsAll(tupleIds_) &&
84  tupleIds_.containsAll(other.tupleIds_);
85  }
86 
87  @Override
88  protected String toSqlImpl() { return "TupleIsNull()"; }
89 
90  public Set<TupleId> getTupleIds() { return tupleIds_; }
91 
92  @Override
93  public boolean isConstant() { return false; }
94 
105  public static List<Expr> wrapExprs(List<Expr> inputExprs,
106  List<TupleId> tids, Analyzer analyzer) throws InternalException {
107  // Assert that all tids are materialized.
108  for (TupleId tid: tids) {
109  TupleDescriptor tupleDesc = analyzer.getTupleDesc(tid);
110  Preconditions.checkState(tupleDesc.isMaterialized());
111  }
112  // Perform the wrapping.
113  List<Expr> result = Lists.newArrayListWithCapacity(inputExprs.size());
114  for (Expr e: inputExprs) {
115  result.add(wrapExpr(e, tids, analyzer));
116  }
117  return result;
118  }
119 
124  public static Expr wrapExpr(Expr expr, List<TupleId> tids, Analyzer analyzer)
125  throws InternalException {
126  if (!requiresNullWrapping(expr, analyzer)) return expr;
127  List<Expr> params = Lists.newArrayList();
128  params.add(new TupleIsNullPredicate(tids));
129  params.add(new NullLiteral());
130  params.add(expr);
131  Expr ifExpr = new FunctionCallExpr("if", params);
132  ifExpr.analyzeNoThrow(analyzer);
133  return ifExpr;
134  }
135 
141  private static boolean requiresNullWrapping(Expr expr, Analyzer analyzer)
142  throws InternalException {
143  Preconditions.checkNotNull(expr);
144  // If the expr is already wrapped in an IF(TupleIsNull(), NULL, expr)
145  // then it must definitely be wrapped again at this level.
146  // Do not try to execute expr because a TupleIsNullPredicate is not constant.
147  if (expr.contains(TupleIsNullPredicate.class)) return true;
148 
149  // Map for substituting SlotRefs with NullLiterals.
150  ExprSubstitutionMap nullSmap = new ExprSubstitutionMap();
151  List<SlotRef> slotRefs = Lists.newArrayList();
152  expr.collect(SlotRef.class, slotRefs);
153  for (SlotRef slotRef: slotRefs) {
154  // The rhs null literal should have the same type as the lhs SlotRef to ensure
155  // exprs resolve to the same signature after applying this smap.
156  nullSmap.put(slotRef, NullLiteral.create(slotRef.getType()));
157  }
158 
159  // Replace all SlotRefs in expr with NullLiterals, and wrap the result
160  // with an IS NOT NULL predicate.
161  Expr isNotNullLiteralPred =
162  new IsNullPredicate(expr.substitute(nullSmap, analyzer, false), true);
163  Preconditions.checkState(isNotNullLiteralPred.isConstant());
164  // analyze to insert casts, etc.
165  isNotNullLiteralPred.analyzeNoThrow(analyzer);
166  return FeSupport.EvalPredicate(isNotNullLiteralPred, analyzer.getQueryCtx());
167  }
168 
169  @Override
170  public Expr clone() { return new TupleIsNullPredicate(this); }
171 }
static boolean requiresNullWrapping(Expr expr, Analyzer analyzer)
static List< Expr > wrapExprs(List< Expr > inputExprs, List< TupleId > tids, Analyzer analyzer)
static Expr wrapExpr(Expr expr, List< TupleId > tids, Analyzer analyzer)