Impala
Impalaistheopensource,nativeanalyticdatabaseforApacheHadoop.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
InlineViewRef.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.ArrayList;
18 import java.util.HashSet;
19 import java.util.List;
20 
21 import org.slf4j.Logger;
22 import org.slf4j.LoggerFactory;
23 
29 import com.google.common.base.Preconditions;
30 import com.google.common.collect.Lists;
31 import com.google.common.collect.Sets;
32 
37 public class InlineViewRef extends TableRef {
38  private final static Logger LOG = LoggerFactory.getLogger(SelectStmt.class);
39 
40  // Catalog or local view that is referenced.
41  // Null for inline views parsed directly from a query string.
42  private final View view_;
43 
44  // The select or union statement of the inline view
45  protected QueryStmt queryStmt_;
46 
47  // queryStmt has its own analysis context
49 
50  // list of tuple ids materialized by queryStmt
51  protected final ArrayList<TupleId> materializedTupleIds_ = Lists.newArrayList();
52 
53  // Map inline view's output slots to the corresponding resultExpr of queryStmt.
55 
56  // Map inline view's output slots to the corresponding baseTblResultExpr of queryStmt.
58 
59  // If not null, these will serve as the column labels for the inline view. This provides
60  // a layer of separation between column labels visible from outside the inline view
61  // and column labels used in the query definition. Either all or none of the column
62  // labels must be overridden.
63  private List<String> explicitColLabels_;
64 
68  public InlineViewRef(String alias, QueryStmt queryStmt) {
69  super(null, alias);
70  Preconditions.checkNotNull(queryStmt);
71  queryStmt_ = queryStmt;
72  view_ = null;
73  }
74 
75  public InlineViewRef(String alias, QueryStmt queryStmt, List<String> colLabels) {
76  this(alias, queryStmt);
77  explicitColLabels_ = Lists.newArrayList(colLabels);
78  }
79 
83  public InlineViewRef(View view, TableRef origTblRef) {
84  super(view.getTableName().toPath(), origTblRef.getExplicitAlias());
85  queryStmt_ = view.getQueryStmt().clone();
86  view_ = view;
87  setJoinAttrs(origTblRef);
88  // Set implicit aliases if no explicit one was given.
89  if (hasExplicitAlias()) return;
90  aliases_ = new String[] {
91  view_.getTableName().toString().toLowerCase(), view_.getName().toLowerCase()
92  };
93  }
94 
98  public InlineViewRef(InlineViewRef other) {
99  super(other);
100  Preconditions.checkNotNull(other.queryStmt_);
101  queryStmt_ = other.queryStmt_.clone();
102  view_ = other.view_;
103  explicitColLabels_ = other.explicitColLabels_;
104  }
105 
112  @Override
113  public void analyze(Analyzer analyzer) throws AnalysisException {
114  // Analyze the inline view query statement with its own analyzer
115  inlineViewAnalyzer_ = new Analyzer(analyzer);
116 
117  // Catalog views refs require special analysis settings for authorization.
118  boolean isCatalogView = (view_ != null && !view_.isLocalView());
119  if (isCatalogView) {
121  // If the user does not have privileges on the view's definition
122  // then we report a masked authorization error so as not to reveal
123  // privileged information (e.g., the existence of a table).
124  inlineViewAnalyzer_.setAuthErrMsg(
125  String.format("User '%s' does not have privileges to " +
126  "EXPLAIN this statement.", analyzer.getUser().getName()));
127  } else {
128  // If this is not an EXPLAIN statement, auth checks for the view
129  // definition should be disabled.
130  inlineViewAnalyzer_.setEnablePrivChecks(false);
131  }
132  }
133 
134  inlineViewAnalyzer_.setUseHiveColLabels(
135  isCatalogView ? true : analyzer.useHiveColLabels());
136  queryStmt_.analyze(inlineViewAnalyzer_);
137  if (explicitColLabels_ != null) {
138  Preconditions.checkState(
139  explicitColLabels_.size() == queryStmt_.getColLabels().size());
140  }
141 
142  inlineViewAnalyzer_.setHasLimitOffsetClause(
143  queryStmt_.hasLimit() || queryStmt_.hasOffset());
144  queryStmt_.getMaterializedTupleIds(materializedTupleIds_);
145  desc_ = analyzer.registerTableRef(this);
146  isAnalyzed_ = true; // true now that we have assigned desc
147 
148  // For constant selects we materialize its exprs into a tuple.
149  if (materializedTupleIds_.isEmpty()) {
150  Preconditions.checkState(queryStmt_ instanceof SelectStmt);
151  Preconditions.checkState(((SelectStmt) queryStmt_).getTableRefs().isEmpty());
152  desc_.setIsMaterialized(true);
153  materializedTupleIds_.add(desc_.getId());
154  }
155 
156  // create smap_ and baseTblSmap_ and register auxiliary eq predicates between our
157  // tuple descriptor's slots and our *unresolved* select list exprs;
158  // we create these auxiliary predicates so that the analyzer can compute the value
159  // transfer graph through this inline view correctly (ie, predicates can get
160  // propagated through the view);
161  // if the view stmt contains analytic functions, we cannot propagate predicates
162  // into the view, unless the predicates are compatible with the analytic
163  // function's partition by clause, because those extra filters
164  // would alter the results of the analytic functions (see IMPALA-1243)
165  // TODO: relax this a bit by allowing propagation out of the inline view (but
166  // not into it)
167  for (int i = 0; i < getColLabels().size(); ++i) {
168  String colName = getColLabels().get(i).toLowerCase();
169  Expr colExpr = queryStmt_.getResultExprs().get(i);
170  Path p = new Path(desc_, Lists.newArrayList(colName));
171  Preconditions.checkState(p.resolve());
172  SlotDescriptor slotDesc = analyzer.registerSlotRef(p);
173  slotDesc.setSourceExpr(colExpr);
174  slotDesc.setStats(ColumnStats.fromExpr(colExpr));
175  SlotRef slotRef = new SlotRef(slotDesc);
176  smap_.put(slotRef, colExpr);
177  baseTblSmap_.put(slotRef, queryStmt_.getBaseTblResultExprs().get(i));
178  if (createAuxPredicate(colExpr)) {
179  analyzer.createAuxEquivPredicate(new SlotRef(slotDesc), colExpr.clone());
180  }
181  }
182  LOG.trace("inline view " + getUniqueAlias() + " smap: " + smap_.debugString());
183  LOG.trace("inline view " + getUniqueAlias() + " baseTblSmap: " +
184  baseTblSmap_.debugString());
185 
186  // Now do the remaining join analysis
187  analyzeJoin(analyzer);
188  }
189 
195  public boolean createAuxPredicate(Expr e) {
196  if (!(queryStmt_ instanceof SelectStmt)
197  || !((SelectStmt) queryStmt_).hasAnalyticInfo()) {
198  return true;
199  }
200  AnalyticInfo analyticInfo = ((SelectStmt) queryStmt_).getAnalyticInfo();
201  return analyticInfo.getCommonPartitionExprs().contains(e);
202  }
203 
209  @Override
211  throws AnalysisException {
212  int numColLabels = getColLabels().size();
213  Preconditions.checkState(numColLabels > 0);
214  HashSet<String> uniqueColAliases = Sets.newHashSetWithExpectedSize(numColLabels);
215  ArrayList<StructField> fields = Lists.newArrayListWithCapacity(numColLabels);
216  for (int i = 0; i < numColLabels; ++i) {
217  // inline view select statement has been analyzed. Col label should be filled.
218  Expr selectItemExpr = queryStmt_.getResultExprs().get(i);
219  String colAlias = getColLabels().get(i).toLowerCase();
220 
221  // inline view col cannot have duplicate name
222  if (!uniqueColAliases.add(colAlias)) {
223  throw new AnalysisException("duplicated inline view column alias: '" +
224  colAlias + "'" + " in inline view " + "'" + getUniqueAlias() + "'");
225  }
226  fields.add(new StructField(colAlias, selectItemExpr.getType(), null));
227  }
228 
229  // Create the non-materialized tuple and set its type.
230  TupleDescriptor result = analyzer.getDescTbl().createTupleDescriptor(
231  getClass().getSimpleName() + " " + getUniqueAlias());
232  result.setIsMaterialized(false);
233  result.setType(new StructType(fields));
234  return result;
235  }
236 
237  @Override
238  public List<TupleId> getMaterializedTupleIds() {
239  Preconditions.checkState(isAnalyzed_);
240  Preconditions.checkState(materializedTupleIds_.size() > 0);
241  return materializedTupleIds_;
242  }
243 
245  Preconditions.checkState(isAnalyzed_);
246  return inlineViewAnalyzer_;
247  }
248 
250  Preconditions.checkState(isAnalyzed_);
251  return smap_;
252  }
253 
255  Preconditions.checkState(isAnalyzed_);
256  return baseTblSmap_;
257  }
258 
259  public QueryStmt getViewStmt() { return queryStmt_; }
260  public void setRewrittenViewStmt(QueryStmt stmt) {
261  Preconditions.checkState(getAnalyzer().containsSubquery());
262  queryStmt_ = stmt;
263  }
264 
265  public List<String> getExplicitColLabels() { return explicitColLabels_; }
266 
267  public List<String> getColLabels() {
268  if (explicitColLabels_ != null) return explicitColLabels_;
269  return queryStmt_.getColLabels();
270  }
271 
272  @Override
273  public TableRef clone() { return new InlineViewRef(this); }
274 
275  @Override
276  protected String tableRefToSql() {
277  // Enclose the alias in quotes if Hive cannot parse it without quotes.
278  // This is needed for view compatibility between Impala and Hive.
279  String aliasSql = null;
280  String alias = getExplicitAlias();
281  if (alias != null) aliasSql = ToSqlUtils.getIdentSql(alias);
282  if (view_ != null) {
283  return view_.getTableName().toSql() + (aliasSql == null ? "" : " " + aliasSql);
284  }
285  Preconditions.checkNotNull(aliasSql);
286  StringBuilder sql = new StringBuilder()
287  .append("(")
288  .append(queryStmt_.toSql())
289  .append(") ")
290  .append(aliasSql);
291  // Add explicit col labels for debugging even though this syntax isn't supported.
292  if (explicitColLabels_ != null) {
293  sql.append(" (");
294  for (int i = 0; i < getExplicitColLabels().size(); i++) {
295  if (i > 0) sql.append(", ");
296  sql.append(ToSqlUtils.getIdentSql(getExplicitColLabels().get(i)));
297  }
298  sql.append(")");
299  }
300  return sql.toString();
301  }
302 }
TupleDescriptor createTupleDescriptor(Analyzer analyzer)
InlineViewRef(View view, TableRef origTblRef)
final ArrayList< TupleId > materializedTupleIds_
InlineViewRef(String alias, QueryStmt queryStmt, List< String > colLabels)
void setJoinAttrs(TableRef other)
Definition: TableRef.java:181
void analyzeJoin(Analyzer analyzer)
Definition: TableRef.java:339
InlineViewRef(String alias, QueryStmt queryStmt)