| // Licensed to the Apache Software Foundation (ASF) under one |
| // or more contributor license agreements. See the NOTICE file |
| // distributed with this work for additional information |
| // regarding copyright ownership. The ASF licenses this file |
| // to you under the Apache License, Version 2.0 (the |
| // "License"); you may not use this file except in compliance |
| // with the License. You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, |
| // software distributed under the License is distributed on an |
| // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| // KIND, either express or implied. See the License for the |
| // specific language governing permissions and limitations |
| // under the License. |
| |
| package org.apache.impala.catalog; |
| |
| import java.util.List; |
| import java.util.Set; |
| |
| import org.apache.hadoop.hive.metastore.IMetaStoreClient; |
| import org.apache.hadoop.hive.metastore.api.FieldSchema; |
| import org.apache.impala.analysis.Parser; |
| import org.apache.impala.analysis.QueryStmt; |
| import org.apache.impala.analysis.StatementBase; |
| import org.apache.impala.common.AnalysisException; |
| import org.apache.impala.thrift.TCatalogObjectType; |
| import org.apache.impala.thrift.TTable; |
| import org.apache.impala.thrift.TTableDescriptor; |
| import org.apache.impala.thrift.TTableStats; |
| import org.apache.impala.thrift.TTableType; |
| |
| import com.google.common.collect.Lists; |
| |
| /** |
| * Table metadata representing a catalog view or a local view from a WITH clause. |
| * Most methods inherited from Table are not supposed to be called on this class because |
| * views are substituted with their underlying definition during analysis of a statement. |
| * |
| * Refreshing or invalidating a view will reload the view's definition but will not |
| * affect the metadata of the underlying tables (if any). |
| */ |
| public class View extends Table implements FeView { |
| |
| // View definition created by parsing inlineViewDef_ into a QueryStmt. |
| private QueryStmt queryStmt_; |
| |
| // Set if this View is from a WITH clause and not persisted in the catalog. |
| private final boolean isLocalView_; |
| |
| // Set if this View is from a WITH clause with column labels. |
| private List<String> colLabels_; |
| |
| public View(org.apache.hadoop.hive.metastore.api.Table msTable, |
| Db db, String name, String owner) { |
| super(msTable, db, name, owner); |
| isLocalView_ = false; |
| } |
| |
| /** |
| * C'tor for WITH-clause views that already have a parsed QueryStmt and an optional |
| * list of column labels. |
| */ |
| public View(String alias, QueryStmt queryStmt, List<String> colLabels) { |
| super(null, null, alias, null); |
| isLocalView_ = true; |
| queryStmt_ = queryStmt; |
| colLabels_ = colLabels; |
| } |
| |
| /** |
| * Creates a view for testing purposes. |
| */ |
| private View(Db db, String name, QueryStmt queryStmt) { |
| super(null, db, name, null); |
| isLocalView_ = false; |
| queryStmt_ = queryStmt; |
| colLabels_ = null; |
| } |
| |
| @Override |
| public void load(boolean reuseMetadata, IMetaStoreClient client, |
| org.apache.hadoop.hive.metastore.api.Table msTbl, String reason) |
| throws TableLoadingException { |
| try { |
| clearColumns(); |
| msTable_ = msTbl; |
| // Load columns. |
| List<FieldSchema> fieldSchemas = client.getFields(db_.getName(), name_); |
| for (int i = 0; i < fieldSchemas.size(); ++i) { |
| FieldSchema s = fieldSchemas.get(i); |
| Type type = parseColumnType(s); |
| Column col = new Column(s.getName(), type, s.getComment(), i); |
| addColumn(col); |
| } |
| // These fields are irrelevant for views. |
| numClusteringCols_ = 0; |
| tableStats_ = new TTableStats(-1); |
| tableStats_.setTotal_file_bytes(-1); |
| queryStmt_ = parseViewDef(this); |
| refreshLastUsedTime(); |
| } catch (TableLoadingException e) { |
| throw e; |
| } catch (Exception e) { |
| throw new TableLoadingException("Failed to load metadata for view: " + name_, e); |
| } |
| } |
| |
| @Override |
| protected void loadFromThrift(TTable t) throws TableLoadingException { |
| super.loadFromThrift(t); |
| queryStmt_ = parseViewDef(this); |
| } |
| |
| /** |
| * Parse the expanded view definition SQL-string. |
| * Throws a TableLoadingException if there was any error parsing the |
| * the SQL or if the view definition did not parse into a QueryStmt. |
| */ |
| public static QueryStmt parseViewDef(FeView view) throws TableLoadingException { |
| // Query statement (as SQL string) that defines the View for view substitution. |
| // It is a transformation of the original view definition, e.g., to enforce the |
| // explicit column definitions even if the original view definition has explicit |
| // column aliases. |
| // If column definitions were given, then this "expanded" view definition |
| // wraps the original view definition in a select stmt as follows. |
| // |
| // SELECT viewName.origCol1 AS colDesc1, viewName.origCol2 AS colDesc2, ... |
| // FROM (originalViewDef) AS viewName |
| // |
| // Corresponds to Hive's viewExpandedText, but is not identical to the SQL |
| // Hive would produce in view creation. |
| String inlineViewDef = view.getMetaStoreTable().getViewExpandedText(); |
| |
| // Parse the expanded view definition SQL-string into a QueryStmt and |
| // populate a view definition. |
| StatementBase node; |
| try { |
| node = Parser.parse(inlineViewDef); |
| } catch (AnalysisException e) { |
| // Do not pass e as the exception cause because it might reveal the existence |
| // of tables that the user triggering this load may not have privileges on. |
| throw new TableLoadingException( |
| String.format("Failed to parse view-definition statement of view: " + |
| "%s", view.getFullName())); |
| } |
| // Make sure the view definition parses to a query statement. |
| if (!(node instanceof QueryStmt)) { |
| throw new TableLoadingException(String.format("View definition of %s " + |
| "is not a query statement", view.getFullName())); |
| } |
| return (QueryStmt) node; |
| } |
| |
| @Override |
| public TCatalogObjectType getCatalogObjectType() { return TCatalogObjectType.VIEW; } |
| |
| @Override // FeView |
| public QueryStmt getQueryStmt() { return queryStmt_; } |
| |
| @Override // FeView |
| public boolean isLocalView() { return isLocalView_; } |
| |
| /** |
| * Returns the column labels the user specified in the WITH-clause. |
| */ |
| public List<String> getOriginalColLabels() { return colLabels_; } |
| |
| @Override |
| public List<String> getColLabels() { |
| if (colLabels_ == null) return null; |
| if (colLabels_.size() >= queryStmt_.getColLabels().size()) return colLabels_; |
| List<String> explicitColLabels = Lists.newArrayList(colLabels_); |
| explicitColLabels.addAll(queryStmt_.getColLabels().subList( |
| colLabels_.size(), queryStmt_.getColLabels().size())); |
| return explicitColLabels; |
| } |
| |
| @Override |
| public TTableDescriptor toThriftDescriptor(int tableId, Set<Long> referencedPartitions) { |
| throw new IllegalStateException("Cannot call toThriftDescriptor() on a view."); |
| } |
| |
| @Override |
| public TTable toThrift() { |
| TTable view = super.toThrift(); |
| view.setTable_type(TTableType.VIEW); |
| return view; |
| } |
| |
| public static View createTestView(Db db, String name, QueryStmt viewDefStmt) { |
| return new View(db, name, viewDefStmt); |
| } |
| } |