You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@impala.apache.org by kw...@apache.org on 2016/09/30 02:14:56 UTC
[39/61] [partial] incubator-impala git commit: IMPALA-3786: Replace
"cloudera" with "apache" (part 1)
http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/b544f019/fe/src/main/java/com/cloudera/impala/analysis/ModifyStmt.java
----------------------------------------------------------------------
diff --git a/fe/src/main/java/com/cloudera/impala/analysis/ModifyStmt.java b/fe/src/main/java/com/cloudera/impala/analysis/ModifyStmt.java
deleted file mode 100644
index 66f97f5..0000000
--- a/fe/src/main/java/com/cloudera/impala/analysis/ModifyStmt.java
+++ /dev/null
@@ -1,292 +0,0 @@
-// 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 com.cloudera.impala.analysis;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-
-import com.cloudera.impala.authorization.Privilege;
-import com.cloudera.impala.authorization.PrivilegeRequestBuilder;
-import com.cloudera.impala.catalog.Column;
-import com.cloudera.impala.catalog.KuduTable;
-import com.cloudera.impala.catalog.Table;
-import com.cloudera.impala.common.AnalysisException;
-import com.cloudera.impala.common.Pair;
-import com.cloudera.impala.planner.DataSink;
-import com.google.common.base.Joiner;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
-import org.slf4j.LoggerFactory;
-
-import static java.lang.String.format;
-
-/**
- * Abstract super class for statements that modify existing data like
- * UPDATE and DELETE.
- *
- * The ModifyStmt has four major parts:
- * - targetTablePath (not null)
- * - fromClause (not null)
- * - assignmentExprs (not null, can be empty)
- * - wherePredicate (nullable)
- *
- * In the analysis phase, a SelectStmt is created with the result expressions set to
- * match the right-hand side of the assignments in addition to projecting the key columns
- * of the underlying table. During query execution, the plan that
- * is generated from this SelectStmt produces all rows that need to be modified.
- *
- * Currently, only Kudu tables can be modified.
- */
-public abstract class ModifyStmt extends StatementBase {
-
- private final static org.slf4j.Logger LOG = LoggerFactory.getLogger(ModifyStmt.class);
-
- // List of explicitly mentioned assignment expressions in the UPDATE's SET clause
- protected final List<Pair<SlotRef, Expr>> assignments_;
-
- // Optional WHERE clause of the statement
- protected final Expr wherePredicate_;
-
- // Path identifying the target table.
- protected final List<String> targetTablePath_;
-
- // TableRef identifying the target table, set during analysis.
- protected TableRef targetTableRef_;
-
- protected FromClause fromClause_;
-
- // Result of the analysis of the internal SelectStmt that produces the rows that
- // will be modified.
- protected SelectStmt sourceStmt_;
-
- // Target Kudu table. Since currently only Kudu tables are supported, we use a
- // concrete table class. Result of analysis.
- protected KuduTable table_;
-
- // END: Members that need to be reset()
- /////////////////////////////////////////
-
- // Position mapping of output expressions of the sourceStmt_ to column indices in the
- // target table. The i'th position in this list maps to the referencedColumns_[i]'th
- // position in the target table. Set in createSourceStmt() during analysis.
- protected ArrayList<Integer> referencedColumns_;
-
- // On tables with a primary key, ignore key not found errors.
- protected final boolean ignoreNotFound_;
-
- public ModifyStmt(List<String> targetTablePath, FromClause fromClause,
- List<Pair<SlotRef, Expr>> assignmentExprs,
- Expr wherePredicate, boolean ignoreNotFound) {
- targetTablePath_ = Preconditions.checkNotNull(targetTablePath);
- fromClause_ = Preconditions.checkNotNull(fromClause);
- assignments_ = Preconditions.checkNotNull(assignmentExprs);
- wherePredicate_ = wherePredicate;
- ignoreNotFound_ = ignoreNotFound;
- }
-
- /**
- * The analysis of the ModifyStmt proceeds as follows: First, the FROM clause is
- * analyzed and the targetTablePath is verified to be a valid alias into the FROM
- * clause. When the target table is identified, the assignment expressions are
- * validated and as a last step the internal SelectStmt is produced and analyzed.
- * Potential query rewrites for the select statement are implemented here and are not
- * triggered externally by the statement rewriter.
- */
- @Override
- public void analyze(Analyzer analyzer) throws AnalysisException {
- super.analyze(analyzer);
- fromClause_.analyze(analyzer);
-
- List<Path> candidates = analyzer.getTupleDescPaths(targetTablePath_);
- if (candidates.isEmpty()) {
- throw new AnalysisException(format("'%s' is not a valid table alias or reference.",
- Joiner.on(".").join(targetTablePath_)));
- }
-
- Preconditions.checkState(candidates.size() == 1);
- Path path = candidates.get(0);
- path.resolve();
-
- if (path.destTupleDesc() == null) {
- throw new AnalysisException(format(
- "'%s' is not a table alias. Using the FROM clause requires the target table " +
- "to be a table alias.",
- Joiner.on(".").join(targetTablePath_)));
- }
-
- targetTableRef_ = analyzer.getTableRef(path.getRootDesc().getId());
- if (targetTableRef_ instanceof InlineViewRef) {
- throw new AnalysisException(format("Cannot modify view: '%s'",
- targetTableRef_.toSql()));
- }
-
- Preconditions.checkNotNull(targetTableRef_);
- Table dstTbl = targetTableRef_.getTable();
- // Only Kudu tables can be updated
- if (!(dstTbl instanceof KuduTable)) {
- throw new AnalysisException(
- format("Impala does not support modifying a non-Kudu table: %s",
- dstTbl.getFullName()));
- }
- table_ = (KuduTable) dstTbl;
-
- // Make sure that the user is allowed to modify the target table, since no
- // UPDATE / DELETE privilege exists, we reuse the INSERT one.
- analyzer.registerPrivReq(new PrivilegeRequestBuilder()
- .onTable(table_.getDb().getName(), table_.getName())
- .allOf(Privilege.INSERT).toRequest());
-
- // Validates the assignments_ and creates the sourceStmt_.
- if (sourceStmt_ == null) createSourceStmt(analyzer);
- sourceStmt_.analyze(analyzer);
- }
-
- @Override
- public void reset() {
- super.reset();
- fromClause_.reset();
- if (sourceStmt_ != null) sourceStmt_.reset();
- table_ = null;
- }
-
- /**
- * Builds and validates the sourceStmt_. The select list of the sourceStmt_ contains
- * first the SlotRefs for the key Columns, followed by the expressions representing the
- * assignments. This method sets the member variables for the sourceStmt_ and the
- * referencedColumns_.
- *
- * This is only run once, on the first analysis. Following analysis will reset() and
- * reuse previously created statements.
- */
- private void createSourceStmt(Analyzer analyzer)
- throws AnalysisException {
- // Builds the select list and column position mapping for the target table.
- ArrayList<SelectListItem> selectList = Lists.newArrayList();
- referencedColumns_ = Lists.newArrayList();
- buildAndValidateAssignmentExprs(analyzer, selectList, referencedColumns_);
-
- // Analyze the generated select statement.
- sourceStmt_ = new SelectStmt(new SelectList(selectList), fromClause_, wherePredicate_,
- null, null, null, null);
-
- // cast result expressions to the correct type of the referenced slot of the
- // target table
- int keyColumnsOffset = table_.getKuduKeyColumnNames().size();
- for (int i = keyColumnsOffset; i < sourceStmt_.resultExprs_.size(); ++i) {
- sourceStmt_.resultExprs_.set(i, sourceStmt_.resultExprs_.get(i).castTo(
- assignments_.get(i - keyColumnsOffset).first.getType()));
- }
- }
-
- /**
- * Validates the list of value assignments that should be used to modify the target
- * table. It verifies that only those columns are referenced that belong to the target
- * table, no key columns are modified, and that a single column is not modified multiple
- * times. Analyzes the Exprs and SlotRefs of assignments_ and writes a list of
- * SelectListItems to the out parameter selectList that is used to build the select list
- * for sourceStmt_. A list of integers indicating the column position of an entry in the
- * select list in the target table is written to the out parameter referencedColumns.
- *
- * In addition to the expressions that are generated for each assignment, the
- * expression list contains an expression for each key column. The key columns
- * are always prepended to the list of expression representing the assignments.
- */
- private void buildAndValidateAssignmentExprs(Analyzer analyzer,
- ArrayList<SelectListItem> selectList, ArrayList<Integer> referencedColumns)
- throws AnalysisException {
- // The order of the referenced columns equals the order of the result expressions
- HashSet<SlotId> uniqueSlots = Sets.newHashSet();
- HashSet<SlotId> keySlots = Sets.newHashSet();
-
- // Mapping from column name to index
- ArrayList<Column> cols = table_.getColumnsInHiveOrder();
- HashMap<String, Integer> colIndexMap = Maps.newHashMap();
- for (int i = 0; i < cols.size(); i++) {
- colIndexMap.put(cols.get(i).getName(), i);
- }
-
- // Add the key columns as slot refs
- for (String k : table_.getKuduKeyColumnNames()) {
- ArrayList<String> path = Path.createRawPath(targetTableRef_.getUniqueAlias(), k);
- SlotRef ref = new SlotRef(path);
- ref.analyze(analyzer);
- selectList.add(new SelectListItem(ref, null));
- uniqueSlots.add(ref.getSlotId());
- keySlots.add(ref.getSlotId());
- referencedColumns.add(colIndexMap.get(k));
- }
-
- // Assignments are only used in the context of updates.
- for (Pair<SlotRef, Expr> valueAssignment : assignments_) {
- Expr rhsExpr = valueAssignment.second;
- rhsExpr.analyze(analyzer);
-
- SlotRef lhsSlotRef = valueAssignment.first;
- lhsSlotRef.analyze(analyzer);
-
- // Correct target table
- if (!lhsSlotRef.isBoundByTupleIds(targetTableRef_.getId().asList())) {
- throw new AnalysisException(
- format("Left-hand side column '%s' in assignment expression '%s=%s' does not "
- + "belong to target table '%s'", lhsSlotRef.toSql(), lhsSlotRef.toSql(),
- rhsExpr.toSql(), targetTableRef_.getDesc().getTable().getFullName()));
- }
-
- // No subqueries for rhs expression
- if (rhsExpr.contains(Subquery.class)) {
- throw new AnalysisException(
- format("Subqueries are not supported as update expressions for column '%s'",
- lhsSlotRef.toSql()));
- }
-
- Column c = lhsSlotRef.getResolvedPath().destColumn();
- // TODO(Kudu) Add test for this code-path when Kudu supports nested types
- if (c == null) {
- throw new AnalysisException(
- format("Left-hand side in assignment expression '%s=%s' must be a column " +
- "reference", lhsSlotRef.toSql(), rhsExpr.toSql()));
- }
-
- if (keySlots.contains(lhsSlotRef.getSlotId())) {
- throw new AnalysisException(format("Key column '%s' cannot be updated.",
- lhsSlotRef.toSql()));
- }
-
- if (uniqueSlots.contains(lhsSlotRef.getSlotId())) {
- throw new AnalysisException(
- format("Duplicate value assignment to column: '%s'", lhsSlotRef.toSql()));
- }
-
- rhsExpr = checkTypeCompatibility(
- targetTableRef_.getDesc().getTable().getFullName(), c, rhsExpr);
- uniqueSlots.add(lhsSlotRef.getSlotId());
- selectList.add(new SelectListItem(rhsExpr, null));
- referencedColumns.add(colIndexMap.get(c.getName()));
- }
- }
-
- public QueryStmt getQueryStmt() { return sourceStmt_; }
- public abstract DataSink createDataSink();
- public abstract String toSql();
-
-
-}
http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/b544f019/fe/src/main/java/com/cloudera/impala/analysis/NullLiteral.java
----------------------------------------------------------------------
diff --git a/fe/src/main/java/com/cloudera/impala/analysis/NullLiteral.java b/fe/src/main/java/com/cloudera/impala/analysis/NullLiteral.java
deleted file mode 100644
index 212d601..0000000
--- a/fe/src/main/java/com/cloudera/impala/analysis/NullLiteral.java
+++ /dev/null
@@ -1,90 +0,0 @@
-// 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 com.cloudera.impala.analysis;
-
-import com.cloudera.impala.catalog.Type;
-import com.cloudera.impala.thrift.TExprNode;
-import com.cloudera.impala.thrift.TExprNodeType;
-import com.google.common.base.Objects;
-import com.google.common.base.Preconditions;
-
-public class NullLiteral extends LiteralExpr {
-
- public NullLiteral() {
- type_ = Type.NULL;
- evalCost_ = LITERAL_COST;
- }
-
- /**
- * Copy c'tor used in clone().
- */
- protected NullLiteral(NullLiteral other) {
- super(other);
- }
-
- /**
- * Returns an analyzed NullLiteral of the specified type.
- */
- public static NullLiteral create(Type type) {
- NullLiteral l = new NullLiteral();
- l.analyzeNoThrow(null);
- l.uncheckedCastTo(type);
- return l;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (!super.equals(obj)) return false;
- return obj instanceof NullLiteral;
- }
-
- @Override
- public int hashCode() { return 0; }
-
- @Override
- public String toSqlImpl() { return getStringValue(); }
-
- @Override
- public String debugString() {
- return Objects.toStringHelper(this).addValue(super.debugString()).toString();
- }
-
- @Override
- public String getStringValue() { return "NULL"; }
-
- @Override
- protected Expr uncheckedCastTo(Type targetType) {
- Preconditions.checkState(targetType.isValid());
- type_ = targetType;
- return this;
- }
-
- @Override
- protected void toThrift(TExprNode msg) {
- msg.node_type = TExprNodeType.NULL_LITERAL;
- }
-
- @Override
- public Expr clone() { return new NullLiteral(this); }
-
- @Override
- protected void resetAnalysisState() {
- super.resetAnalysisState();
- type_ = Type.NULL;
- }
-}
http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/b544f019/fe/src/main/java/com/cloudera/impala/analysis/NumericLiteral.java
----------------------------------------------------------------------
diff --git a/fe/src/main/java/com/cloudera/impala/analysis/NumericLiteral.java b/fe/src/main/java/com/cloudera/impala/analysis/NumericLiteral.java
deleted file mode 100644
index f3bc9da..0000000
--- a/fe/src/main/java/com/cloudera/impala/analysis/NumericLiteral.java
+++ /dev/null
@@ -1,317 +0,0 @@
-// 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 com.cloudera.impala.analysis;
-
-import java.math.BigDecimal;
-import java.math.BigInteger;
-
-import com.cloudera.impala.catalog.ScalarType;
-import com.cloudera.impala.catalog.Type;
-import com.cloudera.impala.common.AnalysisException;
-import com.cloudera.impala.common.NotImplementedException;
-import com.cloudera.impala.thrift.TDecimalLiteral;
-import com.cloudera.impala.thrift.TExprNode;
-import com.cloudera.impala.thrift.TExprNodeType;
-import com.cloudera.impala.thrift.TFloatLiteral;
-import com.cloudera.impala.thrift.TIntLiteral;
-import com.google.common.base.Objects;
-import com.google.common.base.Preconditions;
-
-/**
- * Literal for all numeric values, including integer, floating-point and decimal types.
- * Analysis of this expr determines the smallest type that can hold this value.
- */
-public class NumericLiteral extends LiteralExpr {
- // Use the java BigDecimal (arbitrary scale/precision) to represent the value.
- // This object has notions of precision and scale but they do *not* match what
- // we need. BigDecimal's precision is similar to significant figures and scale
- // is the exponent.
- // ".1" could be represented with an unscaled value = 1 and scale = 1 or
- // unscaled value = 100 and scale = 3. Manipulating the value_ (e.g. multiplying
- // it by 10) does not unnecessarily change the unscaled value. Special care
- // needs to be taken when converting between the big decimals unscaled value
- // and ours. (See getUnscaledValue()).
- private BigDecimal value_;
-
- // If true, this literal has been explicitly cast to a type and should not
- // be analyzed (which infers the type from value_).
- private boolean explicitlyCast_;
-
- public NumericLiteral(BigDecimal value) {
- init(value);
- }
-
- public NumericLiteral(String value, Type t) throws AnalysisException {
- BigDecimal val = null;
- try {
- val = new BigDecimal(value);
- } catch (NumberFormatException e) {
- throw new AnalysisException("invalid numeric literal: " + value, e);
- }
- init(val);
- this.analyze(null);
- if (type_.isDecimal() && t.isDecimal()) {
- // Verify that the input decimal value is consistent with the specified
- // column type.
- ScalarType scalarType = (ScalarType) t;
- if (!scalarType.isSupertypeOf((ScalarType) type_)) {
- StringBuilder errMsg = new StringBuilder();
- errMsg.append("invalid ").append(t);
- errMsg.append(" value: " + value);
- throw new AnalysisException(errMsg.toString());
- }
- }
- if (t.isFloatingPointType()) explicitlyCastToFloat(t);
- }
-
- /**
- * The versions of the ctor that take types assume the type is correct
- * and the NumericLiteral is created as analyzed with that type. The specified
- * type is preserved across substitutions and re-analysis.
- */
- public NumericLiteral(BigInteger value, Type type) {
- isAnalyzed_ = true;
- value_ = new BigDecimal(value);
- type_ = type;
- evalCost_ = LITERAL_COST;
- explicitlyCast_ = true;
- }
-
- public NumericLiteral(BigDecimal value, Type type) {
- isAnalyzed_ = true;
- value_ = value;
- type_ = type;
- evalCost_ = LITERAL_COST;
- explicitlyCast_ = true;
- }
-
- /**
- * Copy c'tor used in clone().
- */
- protected NumericLiteral(NumericLiteral other) {
- super(other);
- value_ = other.value_;
- explicitlyCast_ = other.explicitlyCast_;
- }
-
- @Override
- public String debugString() {
- return Objects.toStringHelper(this)
- .add("value", value_)
- .add("type", type_)
- .toString();
- }
-
- @Override
- public boolean equals(Object obj) {
- if (!super.equals(obj)) return false;
- return ((NumericLiteral) obj).value_.equals(value_);
- }
-
- @Override
- public int hashCode() { return value_.hashCode(); }
-
- @Override
- public String toSqlImpl() { return getStringValue(); }
- @Override
- public String getStringValue() { return value_.toString(); }
- public double getDoubleValue() { return value_.doubleValue(); }
- public long getLongValue() { return value_.longValue(); }
- public long getIntValue() { return value_.intValue(); }
-
- @Override
- protected void toThrift(TExprNode msg) {
- switch (type_.getPrimitiveType()) {
- case TINYINT:
- case SMALLINT:
- case INT:
- case BIGINT:
- msg.node_type = TExprNodeType.INT_LITERAL;
- msg.int_literal = new TIntLiteral(value_.longValue());
- break;
- case FLOAT:
- case DOUBLE:
- msg.node_type = TExprNodeType.FLOAT_LITERAL;
- msg.float_literal = new TFloatLiteral(value_.doubleValue());
- break;
- case DECIMAL:
- msg.node_type = TExprNodeType.DECIMAL_LITERAL;
- TDecimalLiteral literal = new TDecimalLiteral();
- literal.setValue(getUnscaledValue().toByteArray());
- msg.decimal_literal = literal;
- break;
- default:
- Preconditions.checkState(false);
- }
- }
-
- public BigDecimal getValue() { return value_; }
-
- @Override
- public void analyze(Analyzer analyzer) throws AnalysisException {
- if (isAnalyzed_) return;
- super.analyze(analyzer);
- if (!explicitlyCast_) {
- // Compute the precision and scale from the BigDecimal.
- type_ = TypesUtil.computeDecimalType(value_);
- if (type_ == null) {
- Double d = new Double(value_.doubleValue());
- if (d.isInfinite()) {
- throw new AnalysisException("Numeric literal '" + toSql() +
- "' exceeds maximum range of doubles.");
- } else if (d.doubleValue() == 0 && value_ != BigDecimal.ZERO) {
- throw new AnalysisException("Numeric literal '" + toSql() +
- "' underflows minimum resolution of doubles.");
- }
-
- // Literal could not be stored in any of the supported decimal precisions and
- // scale. Store it as a float/double instead.
- float fvalue;
- fvalue = value_.floatValue();
- if (fvalue == value_.doubleValue()) {
- type_ = Type.FLOAT;
- } else {
- type_ = Type.DOUBLE;
- }
- } else {
- // Check for integer types.
- Preconditions.checkState(type_.isScalarType());
- ScalarType scalarType = (ScalarType) type_;
- if (scalarType.decimalScale() == 0) {
- if (value_.compareTo(BigDecimal.valueOf(Byte.MAX_VALUE)) <= 0 &&
- value_.compareTo(BigDecimal.valueOf(Byte.MIN_VALUE)) >= 0) {
- type_ = Type.TINYINT;
- } else if (value_.compareTo(BigDecimal.valueOf(Short.MAX_VALUE)) <= 0 &&
- value_.compareTo(BigDecimal.valueOf(Short.MIN_VALUE)) >= 0) {
- type_ = Type.SMALLINT;
- } else if (value_.compareTo(BigDecimal.valueOf(Integer.MAX_VALUE)) <= 0 &&
- value_.compareTo(BigDecimal.valueOf(Integer.MIN_VALUE)) >= 0) {
- type_ = Type.INT;
- } else if (value_.compareTo(BigDecimal.valueOf(Long.MAX_VALUE)) <= 0 &&
- value_.compareTo(BigDecimal.valueOf(Long.MIN_VALUE)) >= 0) {
- type_ = Type.BIGINT;
- }
- }
- }
- }
- evalCost_ = LITERAL_COST;
- isAnalyzed_ = true;
- }
-
- /**
- * Explicitly cast this literal to 'targetType'. The targetType must be a
- * float point type.
- */
- protected void explicitlyCastToFloat(Type targetType) {
- Preconditions.checkState(targetType.isFloatingPointType());
- type_ = targetType;
- explicitlyCast_ = true;
- }
-
- @Override
- protected Expr uncheckedCastTo(Type targetType) throws AnalysisException {
- Preconditions.checkState(targetType.isNumericType());
- // Implicit casting to decimals allows truncating digits from the left of the
- // decimal point (see TypesUtil). A literal that is implicitly cast to a decimal
- // with truncation is wrapped into a CastExpr so the BE can evaluate it and report
- // a warning. This behavior is consistent with casting/overflow of non-constant
- // exprs that return decimal.
- // IMPALA-1837: Without the CastExpr wrapping, such literals can exceed the max
- // expected byte size sent to the BE in toThrift().
- if (targetType.isDecimal()) {
- ScalarType decimalType = (ScalarType) targetType;
- // analyze() ensures that value_ never exceeds the maximum scale and precision.
- Preconditions.checkState(isAnalyzed_);
- // Sanity check that our implicit casting does not allow a reduced precision or
- // truncating values from the right of the decimal point.
- Preconditions.checkState(value_.precision() <= decimalType.decimalPrecision());
- Preconditions.checkState(value_.scale() <= decimalType.decimalScale());
- int valLeftDigits = value_.precision() - value_.scale();
- int typeLeftDigits = decimalType.decimalPrecision() - decimalType.decimalScale();
- if (typeLeftDigits < valLeftDigits) return new CastExpr(targetType, this);
- }
- type_ = targetType;
- return this;
- }
-
- @Override
- public void swapSign() throws NotImplementedException {
- // swapping sign does not change the type
- value_ = value_.negate();
- }
-
- @Override
- public int compareTo(LiteralExpr o) {
- int ret = super.compareTo(o);
- if (ret != 0) return ret;
- NumericLiteral other = (NumericLiteral) o;
- return value_.compareTo(other.value_);
- }
-
- private void init(BigDecimal value) {
- isAnalyzed_ = false;
- value_ = value;
- }
-
- // Returns the unscaled value of this literal. BigDecimal doesn't treat scale
- // the way we do. We need to pad it out with zeros or truncate as necessary.
- private BigInteger getUnscaledValue() {
- Preconditions.checkState(type_.isDecimal());
- BigInteger result = value_.unscaledValue();
- int valueScale = value_.scale();
- // If valueScale is less than 0, it indicates the power of 10 to multiply the
- // unscaled value. This path also handles this case by padding with zeros.
- // e.g. unscaled value = 123, value scale = -2 means 12300.
- ScalarType decimalType = (ScalarType) type_;
- return result.multiply(BigInteger.TEN.pow(decimalType.decimalScale() - valueScale));
- }
-
- @Override
- public Expr clone() { return new NumericLiteral(this); }
-
- /**
- * Check overflow.
- */
- public static boolean isOverflow(BigDecimal value, Type type)
- throws AnalysisException {
- switch (type.getPrimitiveType()) {
- case TINYINT:
- return (value.compareTo(BigDecimal.valueOf(Byte.MAX_VALUE)) > 0 ||
- value.compareTo(BigDecimal.valueOf(Byte.MIN_VALUE)) < 0);
- case SMALLINT:
- return (value.compareTo(BigDecimal.valueOf(Short.MAX_VALUE)) > 0 ||
- value.compareTo(BigDecimal.valueOf(Short.MIN_VALUE)) < 0);
- case INT:
- return (value.compareTo(BigDecimal.valueOf(Integer.MAX_VALUE)) > 0 ||
- value.compareTo(BigDecimal.valueOf(Integer.MIN_VALUE)) < 0);
- case BIGINT:
- return (value.compareTo(BigDecimal.valueOf(Long.MAX_VALUE)) > 0 ||
- value.compareTo(BigDecimal.valueOf(Long.MIN_VALUE)) < 0);
- case FLOAT:
- return (value.compareTo(BigDecimal.valueOf(Float.MAX_VALUE)) > 0 ||
- value.compareTo(BigDecimal.valueOf(Float.MIN_VALUE)) < 0);
- case DOUBLE:
- return (value.compareTo(BigDecimal.valueOf(Double.MAX_VALUE)) > 0 ||
- value.compareTo(BigDecimal.valueOf(Double.MIN_VALUE)) < 0);
- case DECIMAL:
- return (TypesUtil.computeDecimalType(value) == null);
- default:
- throw new AnalysisException("Overflow check on " + type + " isn't supported.");
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/b544f019/fe/src/main/java/com/cloudera/impala/analysis/OrderByElement.java
----------------------------------------------------------------------
diff --git a/fe/src/main/java/com/cloudera/impala/analysis/OrderByElement.java b/fe/src/main/java/com/cloudera/impala/analysis/OrderByElement.java
deleted file mode 100644
index d430152..0000000
--- a/fe/src/main/java/com/cloudera/impala/analysis/OrderByElement.java
+++ /dev/null
@@ -1,156 +0,0 @@
-// 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 com.cloudera.impala.analysis;
-
-import java.util.List;
-
-import com.google.common.collect.Lists;
-
-
-/**
- * Combination of expr, ASC/DESC, and nulls ordering.
- */
-public class OrderByElement {
- private Expr expr_;
- private final boolean isAsc_;
- // Represents the NULLs ordering specified: true when "NULLS FIRST", false when
- // "NULLS LAST", and null if not specified.
- private final Boolean nullsFirstParam_;
-
- /**
- * Constructs the OrderByElement.
- *
- * 'nullsFirstParam' should be true if "NULLS FIRST", false if "NULLS LAST", or null if
- * the NULLs order was not specified.
- */
- public OrderByElement(Expr expr, boolean isAsc, Boolean nullsFirstParam) {
- super();
- expr_ = expr;
- isAsc_ = isAsc;
- nullsFirstParam_ = nullsFirstParam;
- }
-
- /**
- * C'tor for cloning.
- */
- private OrderByElement(OrderByElement other) {
- expr_ = other.expr_.clone();
- isAsc_ = other.isAsc_;
- if (other.nullsFirstParam_ != null) {
- nullsFirstParam_ = new Boolean(other.nullsFirstParam_.booleanValue());
- } else {
- nullsFirstParam_ = null;
- }
- }
-
- public Expr getExpr() { return expr_; }
- public void setExpr(Expr e) { expr_ = e; }
- public boolean isAsc() { return isAsc_; }
- public Boolean getNullsFirstParam() { return nullsFirstParam_; }
- public boolean nullsFirst() { return nullsFirst(nullsFirstParam_, isAsc_); }
-
- public String toSql() {
- StringBuilder strBuilder = new StringBuilder();
- strBuilder.append(expr_.toSql());
- strBuilder.append(isAsc_ ? " ASC" : " DESC");
- // When ASC and NULLS LAST or DESC and NULLS FIRST, we do not print NULLS FIRST/LAST
- // because it is the default behavior and we want to avoid printing NULLS FIRST/LAST
- // whenever possible as it is incompatible with Hive (SQL compatibility with Hive is
- // important for views).
- if (nullsFirstParam_ != null) {
- if (isAsc_ && nullsFirstParam_) {
- // If ascending, nulls are last by default, so only add if nulls first.
- strBuilder.append(" NULLS FIRST");
- } else if (!isAsc_ && !nullsFirstParam_) {
- // If descending, nulls are first by default, so only add if nulls last.
- strBuilder.append(" NULLS LAST");
- }
- }
- return strBuilder.toString();
- }
-
- @Override
- public boolean equals(Object obj) {
- if (obj == null) return false;
- if (obj.getClass() != this.getClass()) return false;
- OrderByElement o = (OrderByElement)obj;
- boolean nullsFirstEqual =
- (nullsFirstParam_ == null) == (o.nullsFirstParam_ == null);
- if (nullsFirstParam_ != null && nullsFirstEqual) {
- nullsFirstEqual = nullsFirstParam_.equals(o.nullsFirstParam_);
- }
- return expr_.equals(o.expr_) && isAsc_ == o.isAsc_ && nullsFirstEqual;
- }
-
- @Override
- public OrderByElement clone() { return new OrderByElement(this); }
-
- /**
- * Compute nullsFirst.
- *
- * @param nullsFirstParam True if "NULLS FIRST", false if "NULLS LAST", or null if
- * the NULLs order was not specified.
- * @param isAsc
- * @return Returns true if nulls are ordered first or false if nulls are ordered last.
- * Independent of isAsc.
- */
- public static boolean nullsFirst(Boolean nullsFirstParam, boolean isAsc) {
- return nullsFirstParam == null ? !isAsc : nullsFirstParam;
- }
-
- /**
- * Returns a new list of order-by elements with the order by exprs of src substituted
- * according to smap. Preserves the other sort params from src.
- */
- public static List<OrderByElement> substitute(List<OrderByElement> src,
- ExprSubstitutionMap smap, Analyzer analyzer) {
- List<OrderByElement> result = Lists.newArrayListWithCapacity(src.size());
- for (OrderByElement element: src) {
- result.add(new OrderByElement(element.getExpr().substitute(smap, analyzer, false),
- element.isAsc_, element.nullsFirstParam_));
- }
- return result;
- }
-
- /**
- * Extracts the order-by exprs from the list of order-by elements and returns them.
- */
- public static List<Expr> getOrderByExprs(List<OrderByElement> src) {
- List<Expr> result = Lists.newArrayListWithCapacity(src.size());
- for (OrderByElement element: src) {
- result.add(element.getExpr());
- }
- return result;
- }
-
- /**
- * Returns a new list of OrderByElements with the same (cloned) expressions but the
- * ordering direction reversed (asc becomes desc, nulls first becomes nulls last, etc.)
- */
- public static List<OrderByElement> reverse(List<OrderByElement> src) {
- List<OrderByElement> result = Lists.newArrayListWithCapacity(src.size());
- for (int i = 0; i < src.size(); ++i) {
- OrderByElement element = src.get(i);
- OrderByElement reverseElement =
- new OrderByElement(element.getExpr().clone(), !element.isAsc_,
- Boolean.valueOf(!nullsFirst(element.nullsFirstParam_, element.isAsc_)));
- result.add(reverseElement);
- }
- return result;
- }
-}
http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/b544f019/fe/src/main/java/com/cloudera/impala/analysis/ParseNode.java
----------------------------------------------------------------------
diff --git a/fe/src/main/java/com/cloudera/impala/analysis/ParseNode.java b/fe/src/main/java/com/cloudera/impala/analysis/ParseNode.java
deleted file mode 100644
index 6f54e26..0000000
--- a/fe/src/main/java/com/cloudera/impala/analysis/ParseNode.java
+++ /dev/null
@@ -1,34 +0,0 @@
-// 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 com.cloudera.impala.analysis;
-
-import com.cloudera.impala.common.AnalysisException;
-
-public interface ParseNode {
-
- /**
- * Perform semantic analysis of node and all of its children.
- * Throws exception if any semantic errors were found.
- */
- public void analyze(Analyzer analyzer) throws AnalysisException;
-
- /**
- * Returns the SQL string corresponding to this node.
- */
- public String toSql();
-}
http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/b544f019/fe/src/main/java/com/cloudera/impala/analysis/PartitionKeyValue.java
----------------------------------------------------------------------
diff --git a/fe/src/main/java/com/cloudera/impala/analysis/PartitionKeyValue.java b/fe/src/main/java/com/cloudera/impala/analysis/PartitionKeyValue.java
deleted file mode 100644
index 90c44f2..0000000
--- a/fe/src/main/java/com/cloudera/impala/analysis/PartitionKeyValue.java
+++ /dev/null
@@ -1,88 +0,0 @@
-// 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 com.cloudera.impala.analysis;
-
-import com.cloudera.impala.common.AnalysisException;
-import com.google.common.base.Preconditions;
-
-/**
- * Representation of a single column:value element in the PARTITION (...) clause of an
- * insert or alter table statement.
- */
-public class PartitionKeyValue {
- // Name of partitioning column.
- private final String colName_;
- // Value of partitioning column. Set to null for dynamic inserts.
- private final Expr value_;
- // Evaluation of value for static partition keys, null otherwise. Set in analyze().
- private LiteralExpr literalValue_;
-
- public PartitionKeyValue(String colName, Expr value) {
- this.colName_ = colName.toLowerCase();
- this.value_ = value;
- }
-
- public void analyze(Analyzer analyzer) throws AnalysisException {
- if (isStatic() && !value_.isConstant()) {
- throw new AnalysisException(
- String.format("Non-constant expressions are not supported " +
- "as static partition-key values in '%s'.", toString()));
- }
- if (value_ == null) return;
- value_.analyze(analyzer);
- literalValue_ = LiteralExpr.create(value_, analyzer.getQueryCtx());
- }
-
- public String getColName() { return colName_; }
- public Expr getValue() { return value_; }
- public LiteralExpr getLiteralValue() { return literalValue_; }
- public boolean isDynamic() { return value_ == null; }
- public boolean isStatic() { return !isDynamic(); }
-
- @Override
- public String toString() {
- return isStatic() ? colName_ + "=" + value_.toSql() : colName_;
- }
-
- /**
- * Returns a binary predicate as a SQL string which matches the column and value of this
- * PartitionKeyValue. If the value is null, correctly substitutes 'IS' as the operator.
- */
- public String toPredicateSql() {
- String ident = ToSqlUtils.getIdentSql(colName_);
- if (literalValue_ instanceof NullLiteral ||
- literalValue_.getStringValue().isEmpty()) {
- return ident + " IS NULL";
- }
- return isStatic() ? ident + "=" + value_.toSql() : ident;
- }
-
- /**
- * Utility method that returns the string value for the given partition key. For
- * NULL values (a NullLiteral type) or empty literal values this will return the
- * given null partition key value.
- */
- public static String getPartitionKeyValueString(LiteralExpr literalValue,
- String nullPartitionKeyValue) {
- Preconditions.checkNotNull(literalValue);
- if (literalValue instanceof NullLiteral || literalValue.getStringValue().isEmpty()) {
- return nullPartitionKeyValue;
- }
- return literalValue.getStringValue();
- }
-}
http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/b544f019/fe/src/main/java/com/cloudera/impala/analysis/PartitionListItem.java
----------------------------------------------------------------------
diff --git a/fe/src/main/java/com/cloudera/impala/analysis/PartitionListItem.java b/fe/src/main/java/com/cloudera/impala/analysis/PartitionListItem.java
deleted file mode 100644
index 1ffc51e..0000000
--- a/fe/src/main/java/com/cloudera/impala/analysis/PartitionListItem.java
+++ /dev/null
@@ -1,37 +0,0 @@
-// 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 com.cloudera.impala.analysis;
-
-/**
- * Representation of a single column:value element in the PARTITION (...) clause of an insert
- * statement.
- */
-public class PartitionListItem {
- // Name of partitioning column.
- private final String colName_;
- // Value of partitioning column. Set to null for dynamic inserts.
- private final LiteralExpr value_;
-
- public PartitionListItem(String colName, LiteralExpr value) {
- this.colName_ = colName;
- this.value_ = value;
- }
-
- public String getColName() { return colName_; }
- public LiteralExpr getValue() { return value_; }
-}
http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/b544f019/fe/src/main/java/com/cloudera/impala/analysis/PartitionSpec.java
----------------------------------------------------------------------
diff --git a/fe/src/main/java/com/cloudera/impala/analysis/PartitionSpec.java b/fe/src/main/java/com/cloudera/impala/analysis/PartitionSpec.java
deleted file mode 100644
index 92bf0ae..0000000
--- a/fe/src/main/java/com/cloudera/impala/analysis/PartitionSpec.java
+++ /dev/null
@@ -1,201 +0,0 @@
-// 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 com.cloudera.impala.analysis;
-
-import java.util.List;
-import java.util.Set;
-
-import org.apache.hadoop.hive.metastore.api.FieldSchema;
-
-import com.cloudera.impala.authorization.Privilege;
-import com.cloudera.impala.catalog.Column;
-import com.cloudera.impala.catalog.HdfsTable;
-import com.cloudera.impala.catalog.Table;
-import com.cloudera.impala.catalog.Type;
-import com.cloudera.impala.common.AnalysisException;
-import com.cloudera.impala.thrift.TPartitionKeyValue;
-import com.google.common.base.Joiner;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Sets;
-
-/*
- * Represents a partition spec - a collection of partition key/values.
- */
-public class PartitionSpec implements ParseNode {
- private final ImmutableList<PartitionKeyValue> partitionSpec_;
- private TableName tableName_;
- private Boolean partitionShouldExist_;
- private Privilege privilegeRequirement_;
-
- // Flag to determine if the partition already exists in the target table.
- // Set during analysis.
- private Boolean partitionExists_;
-
- // The value Hive is configured to use for NULL partition key values.
- // Set during analysis.
- private String nullPartitionKeyValue_;
-
- public PartitionSpec(List<PartitionKeyValue> partitionSpec) {
- this.partitionSpec_ = ImmutableList.copyOf(partitionSpec);
- }
-
- public List<PartitionKeyValue> getPartitionSpecKeyValues() {
- return partitionSpec_;
- }
-
- public String getTbl() { return tableName_.getTbl(); }
- public void setTableName(TableName tableName) { this.tableName_ = tableName; }
- public boolean partitionExists() {
- Preconditions.checkNotNull(partitionExists_);
- return partitionExists_;
- }
-
- // The value Hive is configured to use for NULL partition key values.
- // Set during analysis.
- public String getNullPartitionKeyValue() {
- Preconditions.checkNotNull(nullPartitionKeyValue_);
- return nullPartitionKeyValue_;
- }
-
- // If set, an additional analysis check will be performed to validate the target table
- // contains the given partition spec.
- public void setPartitionShouldExist() { partitionShouldExist_ = Boolean.TRUE; }
-
- // If set, an additional analysis check will be performed to validate the target table
- // does not contain the given partition spec.
- public void setPartitionShouldNotExist() { partitionShouldExist_ = Boolean.FALSE; }
-
- // Set the privilege requirement for this partition spec. Must be set prior to
- // analysis.
- public void setPrivilegeRequirement(Privilege privilege) {
- privilegeRequirement_ = privilege;
- }
-
- @Override
- public void analyze(Analyzer analyzer) throws AnalysisException {
- Preconditions.checkNotNull(tableName_);
- Preconditions.checkNotNull(privilegeRequirement_);
-
- // Skip adding an audit event when analyzing partitions. The parent table should
- // be audited outside of the PartitionSpec.
- Table table = analyzer.getTable(tableName_, privilegeRequirement_, false);
- String tableName = table.getDb().getName() + "." + getTbl();
-
- // Make sure the target table is partitioned.
- if (table.getMetaStoreTable().getPartitionKeysSize() == 0) {
- throw new AnalysisException("Table is not partitioned: " + tableName);
- }
-
- // Make sure static partition key values only contain constant exprs.
- for (PartitionKeyValue kv: partitionSpec_) {
- kv.analyze(analyzer);
- }
-
- // Get all keys in the target table.
- Set<String> targetPartitionKeys = Sets.newHashSet();
- for (FieldSchema fs: table.getMetaStoreTable().getPartitionKeys()) {
- targetPartitionKeys.add(fs.getName().toLowerCase());
- }
-
- // All partition keys need to be specified.
- if (targetPartitionKeys.size() != partitionSpec_.size()) {
- throw new AnalysisException(String.format("Items in partition spec must exactly " +
- "match the partition columns in the table definition: %s (%d vs %d)",
- tableName, partitionSpec_.size(), targetPartitionKeys.size()));
- }
-
- Set<String> keyNames = Sets.newHashSet();
- // Validate each partition key/value specified, ensuring a matching partition column
- // exists in the target table, no duplicate keys were specified, and that all the
- // column types are compatible.
- for (PartitionKeyValue pk: partitionSpec_) {
- if (!keyNames.add(pk.getColName().toLowerCase())) {
- throw new AnalysisException("Duplicate partition key name: " + pk.getColName());
- }
-
- Column c = table.getColumn(pk.getColName());
- if (c == null) {
- throw new AnalysisException(String.format(
- "Partition column '%s' not found in table: %s", pk.getColName(), tableName));
- } else if (!targetPartitionKeys.contains(pk.getColName().toLowerCase())) {
- throw new AnalysisException(String.format(
- "Column '%s' is not a partition column in table: %s",
- pk.getColName(), tableName));
- } else if (pk.getValue() instanceof NullLiteral) {
- // No need for further analysis checks of this partition key value.
- continue;
- }
-
- Type colType = c.getType();
- Type literalType = pk.getValue().getType();
- Type compatibleType =
- Type.getAssignmentCompatibleType(colType, literalType, false);
- if (!compatibleType.isValid()) {
- throw new AnalysisException(String.format("Value of partition spec (column=%s) "
- + "has incompatible type: '%s'. Expected type: '%s'.",
- pk.getColName(), literalType, colType));
- }
- // Check for loss of precision with the partition value
- if (!compatibleType.equals(colType)) {
- throw new AnalysisException(
- String.format("Partition key value may result in loss of precision.\n" +
- "Would need to cast '%s' to '%s' for partition column: %s",
- pk.getValue().toSql(), colType.toString(), pk.getColName()));
- }
- }
- // Only HDFS tables are partitioned.
- Preconditions.checkState(table instanceof HdfsTable);
- HdfsTable hdfsTable = (HdfsTable) table;
- nullPartitionKeyValue_ = hdfsTable.getNullPartitionKeyValue();
-
- partitionExists_ = hdfsTable.getPartition(partitionSpec_) != null;
- if (partitionShouldExist_ != null) {
- if (partitionShouldExist_ && !partitionExists_) {
- throw new AnalysisException("Partition spec does not exist: (" +
- Joiner.on(", ").join(partitionSpec_) + ").");
- } else if (!partitionShouldExist_ && partitionExists_) {
- throw new AnalysisException("Partition spec already exists: (" +
- Joiner.on(", ").join(partitionSpec_) + ").");
- }
- }
- }
-
- /*
- * Returns the Thrift representation of this PartitionSpec.
- */
- public List<TPartitionKeyValue> toThrift() {
- List<TPartitionKeyValue> thriftPartitionSpec = Lists.newArrayList();
- for (PartitionKeyValue kv: partitionSpec_) {
- String value = PartitionKeyValue.getPartitionKeyValueString(
- kv.getLiteralValue(), getNullPartitionKeyValue());
- thriftPartitionSpec.add(new TPartitionKeyValue(kv.getColName(), value));
- }
- return thriftPartitionSpec;
- }
-
- @Override
- public String toSql() {
- List<String> partitionSpecStr = Lists.newArrayList();
- for (PartitionKeyValue kv: partitionSpec_) {
- partitionSpecStr.add(kv.getColName() + "=" + kv.getValue().toSql());
- }
- return String.format("PARTITION (%s)", Joiner.on(", ").join(partitionSpecStr));
- }
-}
http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/b544f019/fe/src/main/java/com/cloudera/impala/analysis/Path.java
----------------------------------------------------------------------
diff --git a/fe/src/main/java/com/cloudera/impala/analysis/Path.java b/fe/src/main/java/com/cloudera/impala/analysis/Path.java
deleted file mode 100644
index 03c601c..0000000
--- a/fe/src/main/java/com/cloudera/impala/analysis/Path.java
+++ /dev/null
@@ -1,448 +0,0 @@
-// 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 com.cloudera.impala.analysis;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import com.cloudera.impala.catalog.ArrayType;
-import com.cloudera.impala.catalog.Column;
-import com.cloudera.impala.catalog.MapType;
-import com.cloudera.impala.catalog.StructField;
-import com.cloudera.impala.catalog.StructType;
-import com.cloudera.impala.catalog.Table;
-import com.cloudera.impala.catalog.Type;
-import com.google.common.base.Joiner;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.Lists;
-
-/**
- * Represents a resolved or unresolved dot-separated path that is rooted at a registered
- * tuple descriptor, catalog table/view, or an existing resolved path.
- *
- * This class implements the resolution logic for mapping an implicit or explicit
- * raw path to the corresponding physical types/positions in the schema tree.
- *
- * Implicit vs. Explicit Paths
- * The item of an array and the key/value of maps are accessed via their implicit field
- * names. However, if the type of an array item or a map value is a struct, then we allow
- * omitting the explicit reference to the struct type in paths for accessing fields
- * within that struct as a shorthand for user convenience. An explicit reference to the
- * struct type is always legal. Paths that explicitly reference such a struct are
- * "physical" because they typically map exactly to the schema representation in the
- * underlying storage format (e.g. Parquet/Avro). Paths that omit the struct reference
- * are called "implicit". During resolution, explicit paths are always preferred over
- * implicit paths for resolving ambiguities.
- *
- * Example
- * create table d.t (
- * c array<struct<f:int,item:int,pos:int>>
- * );
- *
- * select ... from d.t.c
- * d.t.c <-- resolves to type array<struct<f:int,item:int,pos:int>>
- * c alias <-- type struct<item:struct<f:int,item:int,pos:int>,pos:bigint>>
- *
- * select c.item.f, c.f from d.t.c
- * c.item.f <-- explicit path to "f"
- * c.f <-- implicit path to "f", skips "item" reference
- * (same for the unqualified versions item.f and f)
- *
- * select c.item, c.item.item from d.t.c
- * c.item <-- explicit path to "item" struct of type struct<f:int,item:string>
- * c.item.item <-- explicit path to string "item"; there is no logical path to the
- * string "item" due to the "item" name conflict
- * c.pos <-- explicit path to "pos" of type bigint
- * c.item.pos <-- explicit path to "pos" of type int; there is no logical path to the
- * int "pos" due to the "pos" name conflict
- * (same for unqualified versions item, item.item, pos, item.pos)
- *
- * Please refer to TestImplicitAndExplicitPaths() for analogous examples for maps.
- *
- * Illegal Implicit Paths
- * The intention of implicit paths is to allow users to skip a *single* trivial level of
- * indirection in common cases. In particular, it is illegal to implicitly skip multiple
- * levels in a path, illustrated as follows.
- *
- * Example
- * create table d.t (
- * c array<array<struct<e:int,f:string>>>
- * );
- *
- * select c.f from d.t.c
- * select 1 from d.t.c, c.f
- * c.f <-- illegal path because it would have to implicitly skip two 'item' fields
- *
- *
- * Uses of Paths and Terminology
- *
- * Uncorrelated References: Star exprs, SlotRefs and TableRefs that are rooted at a
- * catalog Table or a registered TupleDescriptor in the same query block.
- *
- * Relative References: TableRefs that are rooted at a TupleDescriptor.
- *
- * Correlated References: SlotRefs and TableRefs that are rooted at a TupleDescriptor
- * registered in an ancestor query block are called 'correlated'. All correlated
- * references are relative, but not all relative references are correlated.
- *
- * A Path itself is never said to be un/correlated because it is intentionally unaware
- * of the query block that it is used in.
- */
-public class Path {
- // Implicit field names of collections.
- public static final String ARRAY_ITEM_FIELD_NAME = "item";
- public static final String ARRAY_POS_FIELD_NAME = "pos";
- public static final String MAP_KEY_FIELD_NAME = "key";
- public static final String MAP_VALUE_FIELD_NAME = "value";
-
- public static enum PathType {
- SLOT_REF,
- TABLE_REF,
- STAR,
- ANY, // Reference to any field or table in schema.
- }
-
- // Implicit or explicit raw path to be resolved relative to rootDesc_ or rootTable_.
- // Every raw-path element is mapped to zero, one or two types/positions in resolution.
- private final List<String> rawPath_;
-
- // Registered table alias that this path is rooted at, if any.
- // Null if the path is rooted at a catalog table/view.
- private final TupleDescriptor rootDesc_;
-
- // Catalog table that this resolved path is rooted at, if any.
- // Null if the path is rooted at a registered tuple that does not
- // belong to a catalog table/view.
- private final Table rootTable_;
-
- // Root path that a relative path was created from.
- private final Path rootPath_;
-
- // List of matched types and field positions set during resolution. The matched
- // types/positions describe the physical path through the schema tree.
- private final List<Type> matchedTypes_ = Lists.newArrayList();
- private final List<Integer> matchedPositions_ = Lists.newArrayList();
-
- // Remembers the indices into rawPath_ and matchedTypes_ of the first collection
- // matched during resolution.
- private int firstCollectionPathIdx_ = -1;
- private int firstCollectionTypeIdx_ = -1;
-
- // Indicates whether this path has been resolved. Set in resolve().
- private boolean isResolved_ = false;
-
- // Caches the result of getAbsolutePath() to avoid re-computing it.
- private List<Integer> absolutePath_ = null;
-
- /**
- * Constructs a Path rooted at the given rootDesc.
- */
- public Path(TupleDescriptor rootDesc, List<String> rawPath) {
- Preconditions.checkNotNull(rootDesc);
- Preconditions.checkNotNull(rawPath);
- rootTable_ = rootDesc.getTable();
- rootDesc_ = rootDesc;
- rootPath_ = null;
- rawPath_ = rawPath;
- }
-
- /**
- * Constructs a Path rooted at the given rootTable.
- */
- public Path(Table rootTable, List<String> rawPath) {
- Preconditions.checkNotNull(rootTable);
- Preconditions.checkNotNull(rawPath);
- rootTable_ = rootTable;
- rootDesc_ = null;
- rootPath_ = null;
- rawPath_ = rawPath;
- }
-
- /**
- * Constructs a new unresolved path relative to an existing resolved path.
- */
- public Path(Path rootPath, List<String> relRawPath) {
- Preconditions.checkNotNull(rootPath);
- Preconditions.checkState(rootPath.isResolved());
- Preconditions.checkNotNull(relRawPath);
- rootTable_ = rootPath.rootTable_;
- rootDesc_ = rootPath.rootDesc_;
- rootPath_ = rootPath;
- rawPath_ = Lists.newArrayListWithCapacity(
- rootPath.getRawPath().size() + relRawPath.size());
- rawPath_.addAll(rootPath.getRawPath());
- rawPath_.addAll(relRawPath);
- matchedTypes_.addAll(rootPath.matchedTypes_);
- matchedPositions_.addAll(rootPath.matchedPositions_);
- firstCollectionPathIdx_ = rootPath.firstCollectionPathIdx_;
- firstCollectionTypeIdx_ = rootPath.firstCollectionTypeIdx_;
- }
-
- /**
- * Resolves this path in the context of the root tuple descriptor / root table
- * or continues resolving this relative path from an existing root path.
- * Returns true if the path could be fully resolved, false otherwise.
- * A failed resolution leaves this Path in a partially resolved state.
- */
- public boolean resolve() {
- if (isResolved_) return true;
- Preconditions.checkState(rootDesc_ != null || rootTable_ != null);
- Type currentType = null;
- int rawPathIdx = 0;
- if (rootPath_ != null) {
- // Continue resolving this path relative to the rootPath_.
- currentType = rootPath_.destType();
- rawPathIdx = rootPath_.getRawPath().size();
- } else if (rootDesc_ != null) {
- currentType = rootDesc_.getType();
- } else {
- // Directly start from the item type because only implicit paths are allowed.
- currentType = rootTable_.getType().getItemType();
- }
-
- // Map all remaining raw-path elements to field types and positions.
- while (rawPathIdx < rawPath_.size()) {
- if (!currentType.isComplexType()) return false;
- StructType structType = getTypeAsStruct(currentType);
- // Resolve explicit path.
- StructField field = structType.getField(rawPath_.get(rawPathIdx));
- if (field == null) {
- // Resolve implicit path.
- if (structType instanceof CollectionStructType) {
- field = ((CollectionStructType) structType).getOptionalField();
- // Collections must be matched explicitly.
- if (field.getType().isCollectionType()) return false;
- } else {
- // Failed to resolve implicit or explicit path.
- return false;
- }
- // Update the physical types/positions.
- matchedTypes_.add(field.getType());
- matchedPositions_.add(field.getPosition());
- currentType = field.getType();
- // Do not consume a raw-path element.
- continue;
- }
- matchedTypes_.add(field.getType());
- matchedPositions_.add(field.getPosition());
- if (field.getType().isCollectionType() && firstCollectionPathIdx_ == -1) {
- Preconditions.checkState(firstCollectionTypeIdx_ == -1);
- firstCollectionPathIdx_ = rawPathIdx;
- firstCollectionTypeIdx_ = matchedTypes_.size() - 1;
- }
- currentType = field.getType();
- ++rawPathIdx;
- }
- Preconditions.checkState(matchedTypes_.size() == matchedPositions_.size());
- Preconditions.checkState(matchedTypes_.size() >= rawPath_.size());
- isResolved_ = true;
- return true;
- }
-
- /**
- * If the given type is a collection, returns a collection struct type representing
- * named fields of its explicit path. Returns the given type itself if it is already
- * a struct. Requires that the given type is a complex type.
- */
- public static StructType getTypeAsStruct(Type t) {
- Preconditions.checkState(t.isComplexType());
- if (t.isStructType()) return (StructType) t;
- if (t.isArrayType()) {
- return CollectionStructType.createArrayStructType((ArrayType) t);
- } else {
- Preconditions.checkState(t.isMapType());
- return CollectionStructType.createMapStructType((MapType) t);
- }
- }
-
- public Table getRootTable() { return rootTable_; }
- public TupleDescriptor getRootDesc() { return rootDesc_; }
- public boolean isRootedAtTable() { return rootTable_ != null; }
- public boolean isRootedAtTuple() { return rootDesc_ != null; }
- public List<String> getRawPath() { return rawPath_; }
- public boolean isResolved() { return isResolved_; }
-
- public List<Type> getMatchedTypes() {
- Preconditions.checkState(isResolved_);
- return matchedTypes_;
- }
-
- public List<Integer> getMatchedPositions() {
- Preconditions.checkState(isResolved_);
- return matchedPositions_;
- }
-
- public boolean hasNonDestCollection() {
- Preconditions.checkState(isResolved_);
- return firstCollectionPathIdx_ != -1 &&
- firstCollectionPathIdx_ != rawPath_.size() - 1;
- }
-
- public String getFirstCollectionName() {
- Preconditions.checkState(isResolved_);
- if (firstCollectionPathIdx_ == -1) return null;
- return rawPath_.get(firstCollectionPathIdx_);
- }
-
- public Type getFirstCollectionType() {
- Preconditions.checkState(isResolved_);
- if (firstCollectionTypeIdx_ == -1) return null;
- return matchedTypes_.get(firstCollectionTypeIdx_);
- }
-
- public int getFirstCollectionIndex() {
- Preconditions.checkState(isResolved_);
- return firstCollectionTypeIdx_;
- }
-
- public Type destType() {
- Preconditions.checkState(isResolved_);
- if (!matchedTypes_.isEmpty()) return matchedTypes_.get(matchedTypes_.size() - 1);
- if (rootDesc_ != null) return rootDesc_.getType();
- if (rootTable_ != null) return rootTable_.getType();
- return null;
- }
-
- public Table destTable() {
- Preconditions.checkState(isResolved_);
- if (rootTable_ != null && rootDesc_ == null && matchedTypes_.isEmpty()) {
- return rootTable_;
- }
- return null;
- }
-
- /**
- * Returns the destination Column of this path, or null if the destination of this
- * path is not a Column. This path must be rooted at a table or a tuple descriptor
- * corresponding to a table for the destination to be a Column.
- */
- public Column destColumn() {
- Preconditions.checkState(isResolved_);
- if (rootTable_ == null || rawPath_.size() != 1) return null;
- return rootTable_.getColumn(rawPath_.get(rawPath_.size() - 1));
- }
-
- /**
- * Returns the destination tuple descriptor of this path, or null
- * if the destination of this path is not a registered alias.
- */
- public TupleDescriptor destTupleDesc() {
- Preconditions.checkState(isResolved_);
- if (rootDesc_ != null && matchedTypes_.isEmpty()) return rootDesc_;
- return null;
- }
-
- public List<String> getFullyQualifiedRawPath() {
- Preconditions.checkState(rootTable_ != null || rootDesc_ != null);
- List<String> result = Lists.newArrayListWithCapacity(rawPath_.size() + 2);
- if (rootDesc_ != null) {
- result.addAll(Lists.newArrayList(rootDesc_.getAlias().split("\\.")));
- } else {
- result.add(rootTable_.getDb().getName());
- result.add(rootTable_.getName());
- }
- result.addAll(rawPath_);
- return result;
- }
-
- /**
- * Returns the absolute explicit path starting from the fully-qualified table name.
- * The goal is produce a canonical non-ambiguous path that can be used as an
- * identifier for table and slot references.
- *
- * Example:
- * create table mydb.test (a array<struct<f1:int,f2:string>>);
- * use mydb;
- * select f1 from test t, t.a;
- *
- * This function should return the following for the path of the 'f1' SlotRef:
- * mydb.test.a.item.f1
- */
- public List<String> getCanonicalPath() {
- List<String> result = Lists.newArrayList();
- getCanonicalPath(result);
- return result;
- }
-
- /**
- * Recursive helper for getCanonicalPath().
- */
- private void getCanonicalPath(List<String> result) {
- Type currentType = null;
- if (isRootedAtTuple()) {
- rootDesc_.getPath().getCanonicalPath(result);
- currentType = rootDesc_.getType();
- } else {
- Preconditions.checkNotNull(isRootedAtTable());
- result.add(rootTable_.getTableName().getDb());
- result.add(rootTable_.getTableName().getTbl());
- currentType = rootTable_.getType().getItemType();
- }
- // Compute the explicit path from the matched positions. Note that rawPath_ is
- // not sufficient because it could contain implicit matches.
- for (int i = 0; i < matchedPositions_.size(); ++i) {
- StructType structType = getTypeAsStruct(currentType);
- int matchPos = matchedPositions_.get(i);
- Preconditions.checkState(matchPos < structType.getFields().size());
- StructField match = structType.getFields().get(matchPos);
- result.add(match.getName());
- currentType = match.getType();
- }
- }
-
- /**
- * Returns the absolute physical path in positions starting from the schema root to the
- * destination of this path.
- */
- public List<Integer> getAbsolutePath() {
- if (absolutePath_ != null) return absolutePath_;
- Preconditions.checkState(isResolved_);
- absolutePath_ = Lists.newArrayList();
- if (rootDesc_ != null) absolutePath_.addAll(rootDesc_.getPath().getAbsolutePath());
- absolutePath_.addAll(matchedPositions_);
- return absolutePath_;
- }
-
- @Override
- public String toString() {
- Preconditions.checkState(rootTable_ != null || rootDesc_ != null);
- String pathRoot = null;
- if (rootDesc_ != null) {
- pathRoot = rootDesc_.getAlias();
- } else {
- pathRoot = rootTable_.getFullName();
- }
- if (rawPath_.isEmpty()) return pathRoot;
- return pathRoot + "." + Joiner.on(".").join(rawPath_);
- }
-
- /**
- * Returns a raw path from a known root alias and field name.
- */
- public static ArrayList<String> createRawPath(String rootAlias, String fieldName) {
- ArrayList<String> result = Lists.newArrayList(rootAlias.split("\\."));
- result.add(fieldName);
- return result;
- }
-
- public static Path createRelPath(Path rootPath, String... fieldNames) {
- Preconditions.checkState(rootPath.isResolved());
- Path result = new Path(rootPath, Lists.newArrayList(fieldNames));
- return result;
- }
-}
http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/b544f019/fe/src/main/java/com/cloudera/impala/analysis/Predicate.java
----------------------------------------------------------------------
diff --git a/fe/src/main/java/com/cloudera/impala/analysis/Predicate.java b/fe/src/main/java/com/cloudera/impala/analysis/Predicate.java
deleted file mode 100644
index 4fadbce..0000000
--- a/fe/src/main/java/com/cloudera/impala/analysis/Predicate.java
+++ /dev/null
@@ -1,97 +0,0 @@
-// 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 com.cloudera.impala.analysis;
-
-import com.cloudera.impala.catalog.Type;
-import com.cloudera.impala.common.AnalysisException;
-import com.cloudera.impala.common.Pair;
-import com.cloudera.impala.common.Reference;
-
-public abstract class Predicate extends Expr {
- protected boolean isEqJoinConjunct_;
-
- public Predicate() {
- super();
- isEqJoinConjunct_ = false;
- }
-
- /**
- * Copy c'tor used in clone().
- */
- protected Predicate(Predicate other) {
- super(other);
- isEqJoinConjunct_ = other.isEqJoinConjunct_;
- }
-
- public boolean isEqJoinConjunct() { return isEqJoinConjunct_; }
- public void setIsEqJoinConjunct(boolean v) { isEqJoinConjunct_ = v; }
-
- @Override
- public void analyze(Analyzer analyzer) throws AnalysisException {
- if (isAnalyzed_) return;
- super.analyze(analyzer);
- type_ = Type.BOOLEAN;
- // values: true/false/null
- numDistinctValues_ = 3;
- }
-
- /**
- * Returns true if one of the children is a slotref (possibly wrapped in a cast)
- * and the other children are all constant. Returns the slotref in 'slotRef' and
- * its child index in 'idx'.
- * This will pick up something like "col = 5", but not "2 * col = 10", which is
- * what we want.
- */
- public boolean isSingleColumnPredicate(
- Reference<SlotRef> slotRefRef, Reference<Integer> idxRef) {
- // find slotref
- SlotRef slotRef = null;
- int i = 0;
- for (; i < children_.size(); ++i) {
- slotRef = getChild(i).unwrapSlotRef(false);
- if (slotRef != null) break;
- }
- if (slotRef == null) return false;
-
- // make sure everything else is constant
- for (int j = 0; j < children_.size(); ++j) {
- if (i == j) continue;
- if (!getChild(j).isConstant()) return false;
- }
-
- if (slotRefRef != null) slotRefRef.setRef(slotRef);
- if (idxRef != null) idxRef.setRef(Integer.valueOf(i));
- return true;
- }
-
- public static boolean isEquivalencePredicate(Expr expr) {
- return (expr instanceof BinaryPredicate)
- && ((BinaryPredicate) expr).getOp().isEquivalence();
- }
-
- /**
- * If predicate is of the form "<slotref> = <slotref>", returns both SlotRefs,
- * otherwise returns null.
- */
- public Pair<SlotId, SlotId> getEqSlots() { return null; }
-
- /**
- * Returns the SlotRef bound by this Predicate.
- */
- public SlotRef getBoundSlot() { return null; }
-}
http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/b544f019/fe/src/main/java/com/cloudera/impala/analysis/PrivilegeSpec.java
----------------------------------------------------------------------
diff --git a/fe/src/main/java/com/cloudera/impala/analysis/PrivilegeSpec.java b/fe/src/main/java/com/cloudera/impala/analysis/PrivilegeSpec.java
deleted file mode 100644
index 2948e58..0000000
--- a/fe/src/main/java/com/cloudera/impala/analysis/PrivilegeSpec.java
+++ /dev/null
@@ -1,287 +0,0 @@
-// 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 com.cloudera.impala.analysis;
-
-import java.util.List;
-
-import com.cloudera.impala.authorization.Privilege;
-import com.cloudera.impala.catalog.DataSourceTable;
-import com.cloudera.impala.catalog.RolePrivilege;
-import com.cloudera.impala.catalog.Table;
-import com.cloudera.impala.catalog.TableLoadingException;
-import com.cloudera.impala.catalog.View;
-import com.cloudera.impala.common.AnalysisException;
-import com.cloudera.impala.thrift.TPrivilege;
-import com.cloudera.impala.thrift.TPrivilegeLevel;
-import com.cloudera.impala.thrift.TPrivilegeScope;
-import com.google.common.base.Joiner;
-import com.google.common.base.Preconditions;
-import com.google.common.base.Strings;
-import com.google.common.collect.Lists;
-
-/**
- * Represents a privilege spec from a GRANT/REVOKE statement.
- * A privilege spec may correspond to one or more privileges. Currently, a privilege spec
- * can represent multiple privileges only at the COLUMN scope.
- */
-public class PrivilegeSpec implements ParseNode {
- private final TPrivilegeScope scope_;
- private final TPrivilegeLevel privilegeLevel_;
- private final TableName tableName_;
- private final HdfsUri uri_;
- private final List<String> columnNames_;
-
- // Set/modified during analysis
- private String dbName_;
- private String serverName_;
-
- private PrivilegeSpec(TPrivilegeLevel privilegeLevel, TPrivilegeScope scope,
- String serverName, String dbName, TableName tableName, HdfsUri uri,
- List<String> columnNames) {
- Preconditions.checkNotNull(scope);
- Preconditions.checkNotNull(privilegeLevel);
- privilegeLevel_ = privilegeLevel;
- scope_ = scope;
- serverName_ = serverName;
- tableName_ = tableName;
- dbName_ = (tableName_ != null ? tableName_.getDb() : dbName);
- uri_ = uri;
- columnNames_ = columnNames;
- }
-
- public static PrivilegeSpec createServerScopedPriv(TPrivilegeLevel privilegeLevel) {
- return createServerScopedPriv(privilegeLevel, null);
- }
-
- public static PrivilegeSpec createServerScopedPriv(TPrivilegeLevel privilegeLevel,
- String serverName) {
- return new PrivilegeSpec(privilegeLevel, TPrivilegeScope.SERVER, serverName, null,
- null, null, null);
- }
-
- public static PrivilegeSpec createDbScopedPriv(TPrivilegeLevel privilegeLevel,
- String dbName) {
- Preconditions.checkNotNull(dbName);
- return new PrivilegeSpec(privilegeLevel, TPrivilegeScope.DATABASE, null, dbName,
- null, null, null);
- }
-
- public static PrivilegeSpec createTableScopedPriv(TPrivilegeLevel privilegeLevel,
- TableName tableName) {
- Preconditions.checkNotNull(tableName);
- return new PrivilegeSpec(privilegeLevel, TPrivilegeScope.TABLE, null, null, tableName,
- null, null);
- }
-
- public static PrivilegeSpec createColumnScopedPriv(TPrivilegeLevel privilegeLevel,
- TableName tableName, List<String> columnNames) {
- Preconditions.checkNotNull(tableName);
- Preconditions.checkNotNull(columnNames);
- return new PrivilegeSpec(privilegeLevel, TPrivilegeScope.COLUMN, null, null,
- tableName, null, columnNames);
- }
-
- public static PrivilegeSpec createUriScopedPriv(TPrivilegeLevel privilegeLevel,
- HdfsUri uri) {
- Preconditions.checkNotNull(uri);
- return new PrivilegeSpec(privilegeLevel, TPrivilegeScope.URI, null, null, null, uri,
- null);
- }
-
- public List<TPrivilege> toThrift() {
- List<TPrivilege> privileges = Lists.newArrayList();
- if (scope_ == TPrivilegeScope.COLUMN) {
- // Create a TPrivilege for every referenced column
- for (String column: columnNames_) {
- privileges.add(createTPrivilege(column));
- }
- } else {
- privileges.add(createTPrivilege(null));
- }
- return privileges;
- }
-
- /**
- * Helper function to construct a TPrivilege from this privilege spec. If the scope is
- * COLUMN, 'columnName' must be a non-null column name. Otherwise, 'columnName' is
- * null.
- */
- private TPrivilege createTPrivilege(String columnName) {
- Preconditions.checkState(columnName == null ^ scope_ == TPrivilegeScope.COLUMN);
- TPrivilege privilege = new TPrivilege();
- privilege.setScope(scope_);
- privilege.setServer_name(serverName_);
- // We don't currently filter on privilege level, so set it to an arbitrary value.
- privilege.setPrivilege_level(privilegeLevel_);
- if (dbName_ != null) privilege.setDb_name(dbName_);
- if (tableName_ != null) privilege.setTable_name(tableName_.getTbl());
- if (uri_ != null) privilege.setUri(uri_.toString());
- if (columnName != null) privilege.setColumn_name(columnName);
- privilege.setCreate_time_ms(-1);
- privilege.setPrivilege_name(RolePrivilege.buildRolePrivilegeName(privilege));
- return privilege;
- }
-
- /**
- * Return the table path of a COLUMN level privilege. The table path consists
- * of server name, database name and table name.
- */
- public static String getTablePath(TPrivilege privilege) {
- Preconditions.checkState(privilege.getScope() == TPrivilegeScope.COLUMN);
- Joiner joiner = Joiner.on(".");
- return joiner.join(privilege.getServer_name(), privilege.getDb_name(),
- privilege.getTable_name());
- }
-
- @Override
- public String toSql() {
- StringBuilder sb = new StringBuilder(privilegeLevel_.toString());
- sb.append(" ON ");
- sb.append(scope_.toString());
- if (scope_ == TPrivilegeScope.SERVER && serverName_ != null) {
- sb.append(" " + serverName_);
- } else if (scope_ == TPrivilegeScope.DATABASE) {
- sb.append(" " + dbName_);
- } else if (scope_ == TPrivilegeScope.TABLE) {
- sb.append(" " + tableName_.toString());
- } else if (scope_ == TPrivilegeScope.COLUMN) {
- sb.append("(");
- sb.append(Joiner.on(",").join(columnNames_));
- sb.append(")");
- sb.append(" " + tableName_.toString());
- } else if (scope_ == TPrivilegeScope.URI) {
- sb.append(" '" + uri_.getLocation() + "'");
- }
- return sb.toString();
- }
-
- @Override
- public void analyze(Analyzer analyzer) throws AnalysisException {
- String configServerName = analyzer.getAuthzConfig().getServerName();
- if (serverName_ != null && !serverName_.equals(configServerName)) {
- throw new AnalysisException(String.format("Specified server name '%s' does not " +
- "match the configured server name '%s'", serverName_, configServerName));
- }
- serverName_ = configServerName;
- Preconditions.checkState(!Strings.isNullOrEmpty(serverName_));
- Preconditions.checkNotNull(scope_);
-
- switch (scope_) {
- case SERVER:
- if (privilegeLevel_ != TPrivilegeLevel.ALL) {
- throw new AnalysisException("Only 'ALL' privilege may be applied at " +
- "SERVER scope in privilege spec.");
- }
- break;
- case DATABASE:
- Preconditions.checkState(!Strings.isNullOrEmpty(dbName_));
- try {
- analyzer.getDb(dbName_, true);
- } catch (AnalysisException e) {
- throw new AnalysisException(String.format("Error setting privileges for " +
- "database '%s'. Verify that the database exists and that you have " +
- "permissions to issue a GRANT/REVOKE statement.", dbName_));
- }
- break;
- case URI:
- Preconditions.checkNotNull(uri_);
- if (privilegeLevel_ != TPrivilegeLevel.ALL) {
- throw new AnalysisException("Only 'ALL' privilege may be applied at " +
- "URI scope in privilege spec.");
- }
- uri_.analyze(analyzer, Privilege.ALL, false);
- break;
- case TABLE:
- analyzeTargetTable(analyzer);
- break;
- case COLUMN:
- analyzeColumnPrivScope(analyzer);
- break;
- default:
- throw new IllegalStateException("Unknown TPrivilegeScope in privilege spec: " +
- scope_.toString());
- }
- }
-
- /**
- * Analyzes a privilege spec at the COLUMN scope.
- * Throws an AnalysisException in the following cases:
- * 1. No columns are specified.
- * 2. Privilege is applied on a view or an external data source.
- * 3. Referenced table and/or columns do not exist.
- * 4. Privilege level is not SELECT.
- */
- private void analyzeColumnPrivScope(Analyzer analyzer) throws AnalysisException {
- Preconditions.checkState(scope_ == TPrivilegeScope.COLUMN);
- Preconditions.checkNotNull(columnNames_);
- if (columnNames_.isEmpty()) {
- throw new AnalysisException("Empty column list in column privilege spec.");
- }
- if (privilegeLevel_ != TPrivilegeLevel.SELECT) {
- throw new AnalysisException("Only 'SELECT' privileges are allowed " +
- "in a column privilege spec.");
- }
- Table table = analyzeTargetTable(analyzer);
- if (table instanceof View) {
- throw new AnalysisException("Column-level privileges on views are not " +
- "supported.");
- }
- if (table instanceof DataSourceTable) {
- throw new AnalysisException("Column-level privileges on external data " +
- "source tables are not supported.");
- }
- for (String columnName: columnNames_) {
- if (table.getColumn(columnName) == null) {
- // The error message should not reveal the existence or absence of a column.
- throw new AnalysisException(String.format("Error setting column-level " +
- "privileges for table '%s'. Verify that both table and columns exist " +
- "and that you have permissions to issue a GRANT/REVOKE statement.",
- tableName_.toString()));
- }
- }
- }
-
- /**
- * Verifies that the table referenced in the privilege spec exists in the catalog and
- * returns the catalog object.
- * Throws an AnalysisException in the following cases:
- * 1. The table name is not valid.
- * 2. Table is not loaded in the catalog.
- * 3. Table does not exist.
- */
- private Table analyzeTargetTable(Analyzer analyzer) throws AnalysisException {
- Preconditions.checkState(scope_ == TPrivilegeScope.TABLE ||
- scope_ == TPrivilegeScope.COLUMN);
- Preconditions.checkState(!Strings.isNullOrEmpty(tableName_.getTbl()));
- Table table = null;
- try {
- dbName_ = analyzer.getTargetDbName(tableName_);
- Preconditions.checkNotNull(dbName_);
- table = analyzer.getTable(dbName_, tableName_.getTbl());
- } catch (TableLoadingException e) {
- throw new AnalysisException(e.getMessage(), e);
- } catch (AnalysisException e) {
- if (analyzer.hasMissingTbls()) throw e;
- throw new AnalysisException(String.format("Error setting privileges for " +
- "table '%s'. Verify that the table exists and that you have permissions " +
- "to issue a GRANT/REVOKE statement.", tableName_.toString()));
- }
- Preconditions.checkNotNull(table);
- return table;
- }
-}