http://git-wip-us.apache.org/repos/asf/phoenix/blob/8c340f5a/phoenix-core/src/main/java/org/apache/phoenix/optimize/QueryOptimizer.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/optimize/QueryOptimizer.java b/phoenix-core/src/main/java/org/apache/phoenix/optimize/QueryOptimizer.java index 9c5c2cd..a51723b 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/optimize/QueryOptimizer.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/optimize/QueryOptimizer.java @@ -37,13 +37,15 @@ import org.apache.phoenix.compile.SubqueryRewriter; import org.apache.phoenix.iterate.ParallelIteratorFactory; import org.apache.phoenix.jdbc.PhoenixStatement; import org.apache.phoenix.parse.AliasedNode; -import org.apache.phoenix.parse.HintNode; -import org.apache.phoenix.parse.HintNode.Hint; import org.apache.phoenix.parse.AndParseNode; import org.apache.phoenix.parse.BooleanParseNodeVisitor; import org.apache.phoenix.parse.ColumnParseNode; +import org.apache.phoenix.parse.IndexExpressionParseNodeRewriter; +import org.apache.phoenix.parse.HintNode; +import org.apache.phoenix.parse.HintNode.Hint; import org.apache.phoenix.parse.ParseNode; import org.apache.phoenix.parse.ParseNodeFactory; +import org.apache.phoenix.parse.ParseNodeRewriter; import org.apache.phoenix.parse.SelectStatement; import org.apache.phoenix.parse.TableNode; import org.apache.phoenix.query.QueryServices; @@ -54,9 +56,8 @@ import org.apache.phoenix.schema.PDatum; import org.apache.phoenix.schema.PIndexState; import org.apache.phoenix.schema.PTable; import org.apache.phoenix.schema.PTable.IndexType; -import org.apache.phoenix.schema.types.PDataType; import org.apache.phoenix.schema.PTableType; -import org.apache.phoenix.schema.SaltingUtil; +import org.apache.phoenix.schema.types.PDataType; import org.apache.phoenix.util.IndexUtil; import com.google.common.collect.Lists; @@ -232,7 +233,10 @@ public class QueryOptimizer { // Check index state of now potentially updated index table to make sure it's active if (PIndexState.ACTIVE.equals(resolver.getTables().get(0).getTable().getIndexState())) { try { + // translate nodes that match expressions that are indexed to the associated column parse node + indexSelect = ParseNodeRewriter.rewrite(indexSelect, new IndexExpressionParseNodeRewriter(index, statement.getConnection())); QueryCompiler compiler = new QueryCompiler(statement, indexSelect, resolver, targetColumns, parallelIteratorFactory, dataPlan.getContext().getSequenceManager()); + QueryPlan plan = compiler.compile(); // If query doesn't have where clause and some of columns to project are missing // in the index then we need to get missing columns from main table for each row in
http://git-wip-us.apache.org/repos/asf/phoenix/blob/8c340f5a/phoenix-core/src/main/java/org/apache/phoenix/parse/BetweenParseNode.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/parse/BetweenParseNode.java b/phoenix-core/src/main/java/org/apache/phoenix/parse/BetweenParseNode.java index cc65d89..961af20 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/parse/BetweenParseNode.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/parse/BetweenParseNode.java @@ -49,4 +49,26 @@ public class BetweenParseNode extends CompoundParseNode { } return visitor.visitLeave(this, l); } + + @Override + public int hashCode() { + final int prime = 31; + int result = super.hashCode(); + result = prime * result + (negate ? 1231 : 1237); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (!super.equals(obj)) + return false; + if (getClass() != obj.getClass()) + return false; + BetweenParseNode other = (BetweenParseNode) obj; + if (negate != other.negate) + return false; + return true; + } } http://git-wip-us.apache.org/repos/asf/phoenix/blob/8c340f5a/phoenix-core/src/main/java/org/apache/phoenix/parse/BindParseNode.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/parse/BindParseNode.java b/phoenix-core/src/main/java/org/apache/phoenix/parse/BindParseNode.java index 75dfa90..5f649de 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/parse/BindParseNode.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/parse/BindParseNode.java @@ -56,4 +56,26 @@ public class BindParseNode extends NamedParseNode { return ":" + index; } + @Override + public int hashCode() { + final int prime = 31; + int result = super.hashCode(); + result = prime * result + index; + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (!super.equals(obj)) + return false; + if (getClass() != obj.getClass()) + return false; + BindParseNode other = (BindParseNode) obj; + if (index != other.index) + return false; + return true; + } + } http://git-wip-us.apache.org/repos/asf/phoenix/blob/8c340f5a/phoenix-core/src/main/java/org/apache/phoenix/parse/CastParseNode.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/parse/CastParseNode.java b/phoenix-core/src/main/java/org/apache/phoenix/parse/CastParseNode.java index ea4e587..598a190 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/parse/CastParseNode.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/parse/CastParseNode.java @@ -104,4 +104,42 @@ public class CastParseNode extends UnaryParseNode { throw TypeMismatchException.newException(fromDataType, targetDataType, firstChildExpr.toString()); } } + + @Override + public int hashCode() { + final int prime = 31; + int result = super.hashCode(); + result = prime * result + ((dt == null) ? 0 : dt.hashCode()); + result = prime * result + + ((maxLength == null) ? 0 : maxLength.hashCode()); + result = prime * result + ((scale == null) ? 0 : scale.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (!super.equals(obj)) + return false; + if (getClass() != obj.getClass()) + return false; + CastParseNode other = (CastParseNode) obj; + if (dt == null) { + if (other.dt != null) + return false; + } else if (!dt.equals(other.dt)) + return false; + if (maxLength == null) { + if (other.maxLength != null) + return false; + } else if (!maxLength.equals(other.maxLength)) + return false; + if (scale == null) { + if (other.scale != null) + return false; + } else if (!scale.equals(other.scale)) + return false; + return true; + } } http://git-wip-us.apache.org/repos/asf/phoenix/blob/8c340f5a/phoenix-core/src/main/java/org/apache/phoenix/parse/ColumnDef.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/parse/ColumnDef.java b/phoenix-core/src/main/java/org/apache/phoenix/parse/ColumnDef.java index 169754c..8032ba5 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/parse/ColumnDef.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/parse/ColumnDef.java @@ -36,7 +36,7 @@ import com.google.common.base.Preconditions; /** * * Represents a column definition during DDL - * + * * * @since 0.1 */ @@ -50,9 +50,10 @@ public class ColumnDef { private final SortOrder sortOrder; private final boolean isArray; private final Integer arrSize; + private final String expressionStr; ColumnDef(ColumnName columnDefName, String sqlTypeName, boolean isArray, Integer arrSize, Boolean isNull, Integer maxLength, - Integer scale, boolean isPK, SortOrder sortOrder) { + Integer scale, boolean isPK, SortOrder sortOrder, String expressionStr) { try { Preconditions.checkNotNull(sortOrder); PDataType localType = null; @@ -133,13 +134,14 @@ public class ColumnDef { if(this.isArray) { this.dataType = localType; } + this.expressionStr = expressionStr; } catch (SQLException e) { throw new ParseException(e); } } ColumnDef(ColumnName columnDefName, String sqlTypeName, Boolean isNull, Integer maxLength, - Integer scale, boolean isPK, SortOrder sortOrder) { - this(columnDefName, sqlTypeName, false, 0, isNull, maxLength, scale, isPK, sortOrder); + Integer scale, boolean isPK, SortOrder sortOrder, String expressionStr) { + this(columnDefName, sqlTypeName, false, 0, isNull, maxLength, scale, isPK, sortOrder, expressionStr); } public ColumnName getColumnDefName() { @@ -183,4 +185,8 @@ public class ColumnDef { public Integer getArraySize() { return arrSize; } + + public String getExpression() { + return expressionStr; + } } http://git-wip-us.apache.org/repos/asf/phoenix/blob/8c340f5a/phoenix-core/src/main/java/org/apache/phoenix/parse/ColumnName.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/parse/ColumnName.java b/phoenix-core/src/main/java/org/apache/phoenix/parse/ColumnName.java index f613a05..82439ec 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/parse/ColumnName.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/parse/ColumnName.java @@ -73,7 +73,7 @@ public class ColumnName { @Override public String toString() { - return SchemaUtil.getColumnName(getFamilyName(),getColumnName()); + return SchemaUtil.getColumnName(getFamilyName(),getColumnName()); } @Override http://git-wip-us.apache.org/repos/asf/phoenix/blob/8c340f5a/phoenix-core/src/main/java/org/apache/phoenix/parse/ColumnParseNode.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/parse/ColumnParseNode.java b/phoenix-core/src/main/java/org/apache/phoenix/parse/ColumnParseNode.java index 19dbc68..e7489fd 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/parse/ColumnParseNode.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/parse/ColumnParseNode.java @@ -28,6 +28,7 @@ import org.apache.phoenix.query.QueryConstants; * @since 0.1 */ public class ColumnParseNode extends NamedParseNode { + // table name can also represent a column family private final TableName tableName; private final String fullName; private final String alias; http://git-wip-us.apache.org/repos/asf/phoenix/blob/8c340f5a/phoenix-core/src/main/java/org/apache/phoenix/parse/CompoundParseNode.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/parse/CompoundParseNode.java b/phoenix-core/src/main/java/org/apache/phoenix/parse/CompoundParseNode.java index 053a9cc..e0ab22b 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/parse/CompoundParseNode.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/parse/CompoundParseNode.java @@ -31,7 +31,8 @@ import java.util.List; * @since 0.1 */ public abstract class CompoundParseNode extends ParseNode { - private final List<ParseNode> children; + + private final List<ParseNode> children; private final boolean isStateless; CompoundParseNode(List<ParseNode> children) { @@ -70,4 +71,33 @@ public abstract class CompoundParseNode extends ParseNode { public String toString() { return this.getClass().getName() + children.toString(); } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + + ((children == null) ? 0 : children.hashCode()); + result = prime * result + (isStateless ? 1231 : 1237); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + CompoundParseNode other = (CompoundParseNode) obj; + if (children == null) { + if (other.children != null) + return false; + } else if (!children.equals(other.children)) + return false; + if (isStateless != other.isStateless) + return false; + return true; + } } http://git-wip-us.apache.org/repos/asf/phoenix/blob/8c340f5a/phoenix-core/src/main/java/org/apache/phoenix/parse/CreateIndexStatement.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/parse/CreateIndexStatement.java b/phoenix-core/src/main/java/org/apache/phoenix/parse/CreateIndexStatement.java index 669dc3f..bf76174 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/parse/CreateIndexStatement.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/parse/CreateIndexStatement.java @@ -29,7 +29,7 @@ import com.google.common.collect.ListMultimap; public class CreateIndexStatement extends SingleTableStatement { private final TableName indexTableName; - private final PrimaryKeyConstraint indexConstraint; + private final IndexKeyConstraint indexKeyConstraint; private final List<ColumnName> includeColumns; private final List<ParseNode> splitNodes; private final ListMultimap<String,Pair<String,Object>> props; @@ -37,11 +37,11 @@ public class CreateIndexStatement extends SingleTableStatement { private final IndexType indexType; public CreateIndexStatement(NamedNode indexTableName, NamedTableNode dataTable, - PrimaryKeyConstraint indexConstraint, List<ColumnName> includeColumns, List<ParseNode> splits, + IndexKeyConstraint indexKeyConstraint, List<ColumnName> includeColumns, List<ParseNode> splits, ListMultimap<String,Pair<String,Object>> props, boolean ifNotExists, IndexType indexType, int bindCount) { super(dataTable, bindCount); this.indexTableName =TableName.create(dataTable.getName().getSchemaName(),indexTableName.getName()); - this.indexConstraint = indexConstraint == null ? PrimaryKeyConstraint.EMPTY : indexConstraint; + this.indexKeyConstraint = indexKeyConstraint == null ? IndexKeyConstraint.EMPTY : indexKeyConstraint; this.includeColumns = includeColumns == null ? Collections.<ColumnName>emptyList() : includeColumns; this.splitNodes = splits == null ? Collections.<ParseNode>emptyList() : splits; this.props = props == null ? ArrayListMultimap.<String,Pair<String,Object>>create() : props; @@ -49,8 +49,8 @@ public class CreateIndexStatement extends SingleTableStatement { this.indexType = indexType; } - public PrimaryKeyConstraint getIndexConstraint() { - return indexConstraint; + public IndexKeyConstraint getIndexConstraint() { + return indexKeyConstraint; } public List<ColumnName> getIncludeColumns() { http://git-wip-us.apache.org/repos/asf/phoenix/blob/8c340f5a/phoenix-core/src/main/java/org/apache/phoenix/parse/ExistsParseNode.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/parse/ExistsParseNode.java b/phoenix-core/src/main/java/org/apache/phoenix/parse/ExistsParseNode.java index 45ccdfe..fde7d76 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/parse/ExistsParseNode.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/parse/ExistsParseNode.java @@ -50,4 +50,26 @@ public class ExistsParseNode extends UnaryParseNode { } return visitor.visitLeave(this, l); } + + @Override + public int hashCode() { + final int prime = 31; + int result = super.hashCode(); + result = prime * result + (negate ? 1231 : 1237); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (!super.equals(obj)) + return false; + if (getClass() != obj.getClass()) + return false; + ExistsParseNode other = (ExistsParseNode) obj; + if (negate != other.negate) + return false; + return true; + } } http://git-wip-us.apache.org/repos/asf/phoenix/blob/8c340f5a/phoenix-core/src/main/java/org/apache/phoenix/parse/FamilyWildcardParseNode.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/parse/FamilyWildcardParseNode.java b/phoenix-core/src/main/java/org/apache/phoenix/parse/FamilyWildcardParseNode.java index 9cfb345..2c939fc 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/parse/FamilyWildcardParseNode.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/parse/FamilyWildcardParseNode.java @@ -49,5 +49,27 @@ public class FamilyWildcardParseNode extends NamedParseNode { public boolean isRewrite() { return isRewrite; } + + @Override + public int hashCode() { + final int prime = 31; + int result = super.hashCode(); + result = prime * result + (isRewrite ? 1231 : 1237); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (!super.equals(obj)) + return false; + if (getClass() != obj.getClass()) + return false; + FamilyWildcardParseNode other = (FamilyWildcardParseNode) obj; + if (isRewrite != other.isRewrite) + return false; + return true; + } } http://git-wip-us.apache.org/repos/asf/phoenix/blob/8c340f5a/phoenix-core/src/main/java/org/apache/phoenix/parse/FunctionParseNode.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/parse/FunctionParseNode.java b/phoenix-core/src/main/java/org/apache/phoenix/parse/FunctionParseNode.java index e6ce6d1..c41fa4f 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/parse/FunctionParseNode.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/parse/FunctionParseNode.java @@ -428,4 +428,35 @@ public class FunctionParseNode extends CompoundParseNode { return allowedValues; } } + + @Override + public int hashCode() { + final int prime = 31; + int result = super.hashCode(); + result = prime * result + ((info == null) ? 0 : info.hashCode()); + result = prime * result + ((name == null) ? 0 : name.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (!super.equals(obj)) + return false; + if (getClass() != obj.getClass()) + return false; + FunctionParseNode other = (FunctionParseNode) obj; + if (info == null) { + if (other.info != null) + return false; + } else if (!info.equals(other.info)) + return false; + if (name == null) { + if (other.name != null) + return false; + } else if (!name.equals(other.name)) + return false; + return true; + } } http://git-wip-us.apache.org/repos/asf/phoenix/blob/8c340f5a/phoenix-core/src/main/java/org/apache/phoenix/parse/InListParseNode.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/parse/InListParseNode.java b/phoenix-core/src/main/java/org/apache/phoenix/parse/InListParseNode.java index 91f2b5c..fae15f5 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/parse/InListParseNode.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/parse/InListParseNode.java @@ -61,4 +61,26 @@ public class InListParseNode extends CompoundParseNode { } return visitor.visitLeave(this, l); } + + @Override + public int hashCode() { + final int prime = 31; + int result = super.hashCode(); + result = prime * result + (negate ? 1231 : 1237); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (!super.equals(obj)) + return false; + if (getClass() != obj.getClass()) + return false; + InListParseNode other = (InListParseNode) obj; + if (negate != other.negate) + return false; + return true; + } } http://git-wip-us.apache.org/repos/asf/phoenix/blob/8c340f5a/phoenix-core/src/main/java/org/apache/phoenix/parse/InParseNode.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/parse/InParseNode.java b/phoenix-core/src/main/java/org/apache/phoenix/parse/InParseNode.java index acd71b1..84984e9 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/parse/InParseNode.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/parse/InParseNode.java @@ -56,4 +56,29 @@ public class InParseNode extends BinaryParseNode { } return visitor.visitLeave(this, l); } + + @Override + public int hashCode() { + final int prime = 31; + int result = super.hashCode(); + result = prime * result + (isSubqueryDistinct ? 1231 : 1237); + result = prime * result + (negate ? 1231 : 1237); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (!super.equals(obj)) + return false; + if (getClass() != obj.getClass()) + return false; + InParseNode other = (InParseNode) obj; + if (isSubqueryDistinct != other.isSubqueryDistinct) + return false; + if (negate != other.negate) + return false; + return true; + } } http://git-wip-us.apache.org/repos/asf/phoenix/blob/8c340f5a/phoenix-core/src/main/java/org/apache/phoenix/parse/IndexExpressionParseNodeRewriter.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/parse/IndexExpressionParseNodeRewriter.java b/phoenix-core/src/main/java/org/apache/phoenix/parse/IndexExpressionParseNodeRewriter.java new file mode 100644 index 0000000..efa3835 --- /dev/null +++ b/phoenix-core/src/main/java/org/apache/phoenix/parse/IndexExpressionParseNodeRewriter.java @@ -0,0 +1,104 @@ +/* + * 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.phoenix.parse; + +import java.sql.SQLException; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import org.apache.phoenix.compile.ColumnResolver; +import org.apache.phoenix.compile.ExpressionCompiler; +import org.apache.phoenix.compile.FromCompiler; +import org.apache.phoenix.compile.IndexStatementRewriter; +import org.apache.phoenix.compile.StatementContext; +import org.apache.phoenix.expression.Expression; +import org.apache.phoenix.jdbc.PhoenixConnection; +import org.apache.phoenix.jdbc.PhoenixStatement; +import org.apache.phoenix.schema.PColumn; +import org.apache.phoenix.schema.PTable; +import org.apache.phoenix.schema.types.PDataType; +import org.apache.phoenix.util.IndexUtil; + +import com.google.common.collect.Maps; + +/** + * Used to replace parse nodes in a SelectStatement that match expressions that are present in an indexed with the + * corresponding {@link ColumnParseNode} + */ +public class IndexExpressionParseNodeRewriter extends ParseNodeRewriter { + + private final Map<ParseNode, ParseNode> indexedParseNodeToColumnParseNodeMap; + + private static class ColumnParseNodeVisitor extends StatelessTraverseAllParseNodeVisitor { + + private boolean isParseNodeCaseSensitive; + + public void reset() { + this.isParseNodeCaseSensitive = false; + } + + @Override + public Void visit(ColumnParseNode node) throws SQLException { + isParseNodeCaseSensitive = isParseNodeCaseSensitive || node.isCaseSensitive() || node.isTableNameCaseSensitive(); + return null; + } + + public boolean isParseNodeCaseSensitive() { + return isParseNodeCaseSensitive; + } + + } + + public IndexExpressionParseNodeRewriter(PTable index, PhoenixConnection connection) throws SQLException { + indexedParseNodeToColumnParseNodeMap = Maps.newHashMapWithExpectedSize(index.getColumns().size()); + NamedTableNode tableNode = NamedTableNode.create(null, + TableName.create(index.getParentSchemaName().getString(), index.getParentTableName().getString()), + Collections.<ColumnDef> emptyList()); + ColumnResolver dataResolver = FromCompiler.getResolver(tableNode, connection); + StatementContext context = new StatementContext(new PhoenixStatement(connection), dataResolver); + IndexStatementRewriter rewriter = new IndexStatementRewriter(dataResolver, null); + ExpressionCompiler expressionCompiler = new ExpressionCompiler(context); + ColumnParseNodeVisitor columnParseNodeVisitor = new ColumnParseNodeVisitor(); + int indexPosOffset = (index.getBucketNum() == null ? 0 : 1) + (index.isMultiTenant() ? 1 : 0) + (index.getViewIndexId() == null ? 0 : 1); + List<PColumn> pkColumns = index.getPKColumns(); + for (int i=indexPosOffset; i<pkColumns.size(); ++i) { + PColumn column = pkColumns.get(i); + if (column.getExpressionStr()==null) { + continue; + } + ParseNode expressionParseNode = SQLParser.parseCondition(column.getExpressionStr()); + columnParseNodeVisitor.reset(); + expressionParseNode.accept(columnParseNodeVisitor); + String colName = column.getName().getString(); + if (columnParseNodeVisitor.isParseNodeCaseSensitive()) { + // force column name to be case sensitive name by surround with double quotes + colName = "\"" + colName + "\""; + } + + Expression dataExpression = expressionParseNode.accept(expressionCompiler); + PDataType expressionDataType = dataExpression.getDataType(); + ParseNode indexedParseNode = expressionParseNode.accept(rewriter); + PDataType indexColType = IndexUtil.getIndexColumnDataType(dataExpression.isNullable(), expressionDataType); + ParseNode columnParseNode = new ColumnParseNode(null, colName, null); + if ( indexColType != expressionDataType) { + columnParseNode = NODE_FACTORY.cast(columnParseNode, expressionDataType, null, null); + } + indexedParseNodeToColumnParseNodeMap.put(indexedParseNode, columnParseNode); + } + } + + @Override + protected ParseNode leaveCompoundNode(CompoundParseNode node, List<ParseNode> children, CompoundNodeFactory factory) { + return indexedParseNodeToColumnParseNodeMap.containsKey(node) ? indexedParseNodeToColumnParseNodeMap.get(node) + : super.leaveCompoundNode(node, children, factory); + } + +} http://git-wip-us.apache.org/repos/asf/phoenix/blob/8c340f5a/phoenix-core/src/main/java/org/apache/phoenix/parse/IndexKeyConstraint.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/parse/IndexKeyConstraint.java b/phoenix-core/src/main/java/org/apache/phoenix/parse/IndexKeyConstraint.java index 7043b9d..ef40c78 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/parse/IndexKeyConstraint.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/parse/IndexKeyConstraint.java @@ -17,21 +17,25 @@ */ package org.apache.phoenix.parse; +import java.util.Collections; import java.util.List; import org.apache.hadoop.hbase.util.Pair; import com.google.common.collect.ImmutableList; + import org.apache.phoenix.schema.SortOrder; public class IndexKeyConstraint { - private final List<Pair<ColumnParseNode, SortOrder>> columnNameToSortOrder; + public static final IndexKeyConstraint EMPTY = new IndexKeyConstraint(Collections.<Pair<ParseNode, SortOrder>>emptyList()); + + private final List<Pair<ParseNode, SortOrder>> columnNameToSortOrder; - IndexKeyConstraint(List<Pair<ColumnParseNode, SortOrder>> columnNameAndSortOrder) { - this.columnNameToSortOrder = ImmutableList.copyOf(columnNameAndSortOrder); + IndexKeyConstraint(List<Pair<ParseNode, SortOrder>> parseNodeAndSortOrder) { + this.columnNameToSortOrder = ImmutableList.copyOf(parseNodeAndSortOrder); } - public List<Pair<ColumnParseNode, SortOrder>> getColumns() { + public List<Pair<ParseNode, SortOrder>> getParseNodeAndSortOrderList() { return columnNameToSortOrder; } } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/phoenix/blob/8c340f5a/phoenix-core/src/main/java/org/apache/phoenix/parse/IsNullParseNode.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/parse/IsNullParseNode.java b/phoenix-core/src/main/java/org/apache/phoenix/parse/IsNullParseNode.java index 21d0f8e..614cfd0 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/parse/IsNullParseNode.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/parse/IsNullParseNode.java @@ -50,4 +50,26 @@ public class IsNullParseNode extends UnaryParseNode { } return visitor.visitLeave(this, l); } + + @Override + public int hashCode() { + final int prime = 31; + int result = super.hashCode(); + result = prime * result + (negate ? 1231 : 1237); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (!super.equals(obj)) + return false; + if (getClass() != obj.getClass()) + return false; + IsNullParseNode other = (IsNullParseNode) obj; + if (negate != other.negate) + return false; + return true; + } } http://git-wip-us.apache.org/repos/asf/phoenix/blob/8c340f5a/phoenix-core/src/main/java/org/apache/phoenix/parse/LikeParseNode.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/parse/LikeParseNode.java b/phoenix-core/src/main/java/org/apache/phoenix/parse/LikeParseNode.java index 9cec70e..41d252d 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/parse/LikeParseNode.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/parse/LikeParseNode.java @@ -59,4 +59,30 @@ public class LikeParseNode extends BinaryParseNode { } return visitor.visitLeave(this, l); } + + @Override + public int hashCode() { + final int prime = 31; + int result = super.hashCode(); + result = prime * result + + ((likeType == null) ? 0 : likeType.hashCode()); + result = prime * result + (negate ? 1231 : 1237); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (!super.equals(obj)) + return false; + if (getClass() != obj.getClass()) + return false; + LikeParseNode other = (LikeParseNode) obj; + if (likeType != other.likeType) + return false; + if (negate != other.negate) + return false; + return true; + } } http://git-wip-us.apache.org/repos/asf/phoenix/blob/8c340f5a/phoenix-core/src/main/java/org/apache/phoenix/parse/LiteralParseNode.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/parse/LiteralParseNode.java b/phoenix-core/src/main/java/org/apache/phoenix/parse/LiteralParseNode.java index b83ce23..9e9184f 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/parse/LiteralParseNode.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/parse/LiteralParseNode.java @@ -80,4 +80,25 @@ public class LiteralParseNode extends TerminalParseNode { public String toString() { return type == PVarchar.INSTANCE ? ("'" + value.toString() + "'") : value == null ? "null" : value.toString(); } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((type == null) ? 0 : type.hashCode()); + result = prime * result + ((value == null) ? 0 : value.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + LiteralParseNode other = (LiteralParseNode) obj; + return type.isComparableTo(other.type) && type.compareTo(value, other.value, other.type) == 0; + } } http://git-wip-us.apache.org/repos/asf/phoenix/blob/8c340f5a/phoenix-core/src/main/java/org/apache/phoenix/parse/NamedNode.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/parse/NamedNode.java b/phoenix-core/src/main/java/org/apache/phoenix/parse/NamedNode.java index e799875..6cfeb60 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/parse/NamedNode.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/parse/NamedNode.java @@ -28,7 +28,7 @@ public class NamedNode { return new NamedNode(name,true); } - private NamedNode(String name, boolean isCaseSensitive) { + NamedNode(String name, boolean isCaseSensitive) { this.name = name; this.isCaseSensitive = isCaseSensitive; } http://git-wip-us.apache.org/repos/asf/phoenix/blob/8c340f5a/phoenix-core/src/main/java/org/apache/phoenix/parse/NamedParseNode.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/parse/NamedParseNode.java b/phoenix-core/src/main/java/org/apache/phoenix/parse/NamedParseNode.java index fa4872f..51da80a 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/parse/NamedParseNode.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/parse/NamedParseNode.java @@ -35,6 +35,10 @@ public abstract class NamedParseNode extends TerminalParseNode{ NamedParseNode(String name) { this.namedNode = new NamedNode(name); } + + NamedParseNode(String name, boolean isCaseSensitive) { + this.namedNode = new NamedNode(name, isCaseSensitive); + } public String getName() { return namedNode.getName(); @@ -48,4 +52,30 @@ public abstract class NamedParseNode extends TerminalParseNode{ public String toString() { return getName(); } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + + ((namedNode == null) ? 0 : namedNode.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + NamedParseNode other = (NamedParseNode) obj; + if (namedNode == null) { + if (other.namedNode != null) + return false; + } else if (!namedNode.equals(other.namedNode)) + return false; + return true; + } } http://git-wip-us.apache.org/repos/asf/phoenix/blob/8c340f5a/phoenix-core/src/main/java/org/apache/phoenix/parse/ParseNodeFactory.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/parse/ParseNodeFactory.java b/phoenix-core/src/main/java/org/apache/phoenix/parse/ParseNodeFactory.java index 0f40ece..57507b8 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/parse/ParseNodeFactory.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/parse/ParseNodeFactory.java @@ -53,16 +53,15 @@ import org.apache.phoenix.util.SchemaUtil; import com.google.common.collect.ListMultimap; import com.google.common.collect.Maps; - /** - * + * * Factory used by parser to construct object model while parsing a SQL statement - * + * * * @since 0.1 */ public class ParseNodeFactory { - private static final String ARRAY_ELEM = "ARRAY_ELEM"; + private static final String ARRAY_ELEM = "ARRAY_ELEM"; // TODO: Use Google's Reflection library instead to find aggregate functions @SuppressWarnings("unchecked") private static final List<Class<? extends FunctionExpression>> CLIENT_SIDE_BUILT_IN_FUNCTIONS = Arrays.<Class<? extends FunctionExpression>>asList( @@ -241,10 +240,10 @@ public class ParseNodeFactory { return new StringConcatParseNode(children); } - public ColumnParseNode column(TableName tableName, String name, String alias) { - return new ColumnParseNode(tableName,name,alias); + public ColumnParseNode column(TableName tableName, String columnName, String alias) { + return new ColumnParseNode(tableName, columnName, alias); } - + public ColumnName columnName(String columnName) { return new ColumnName(columnName); } @@ -261,25 +260,29 @@ public class ParseNodeFactory { return new PropertyName(familyName, propertyName); } - public ColumnDef columnDef(ColumnName columnDefName, String sqlTypeName, boolean isNull, Integer maxLength, Integer scale, boolean isPK, SortOrder sortOrder) { - return new ColumnDef(columnDefName, sqlTypeName, isNull, maxLength, scale, isPK, sortOrder); + public ColumnDef columnDef(ColumnName columnDefName, String sqlTypeName, boolean isNull, Integer maxLength, Integer scale, boolean isPK, SortOrder sortOrder, String expressionStr) { + return new ColumnDef(columnDefName, sqlTypeName, isNull, maxLength, scale, isPK, sortOrder, expressionStr); } public ColumnDef columnDef(ColumnName columnDefName, String sqlTypeName, boolean isArray, Integer arrSize, Boolean isNull, Integer maxLength, Integer scale, boolean isPK, SortOrder sortOrder) { - return new ColumnDef(columnDefName, sqlTypeName, isArray, arrSize, isNull, maxLength, scale, isPK, sortOrder); + return new ColumnDef(columnDefName, sqlTypeName, isArray, arrSize, isNull, maxLength, scale, isPK, sortOrder, null); } public PrimaryKeyConstraint primaryKey(String name, List<Pair<ColumnName, SortOrder>> columnNameAndSortOrder) { return new PrimaryKeyConstraint(name, columnNameAndSortOrder); } + + public IndexKeyConstraint indexKey( List<Pair<ParseNode, SortOrder>> parseNodeAndSortOrder) { + return new IndexKeyConstraint(parseNodeAndSortOrder); + } public CreateTableStatement createTable(TableName tableName, ListMultimap<String,Pair<String,Object>> props, List<ColumnDef> columns, PrimaryKeyConstraint pkConstraint, List<ParseNode> splits, PTableType tableType, boolean ifNotExists, TableName baseTableName, ParseNode tableTypeIdNode, int bindCount) { return new CreateTableStatement(tableName, props, columns, pkConstraint, splits, tableType, ifNotExists, baseTableName, tableTypeIdNode, bindCount); } - public CreateIndexStatement createIndex(NamedNode indexName, NamedTableNode dataTable, PrimaryKeyConstraint pkConstraint, List<ColumnName> includeColumns, List<ParseNode> splits, ListMultimap<String,Pair<String,Object>> props, boolean ifNotExists, IndexType indexType, int bindCount) { - return new CreateIndexStatement(indexName, dataTable, pkConstraint, includeColumns, splits, props, ifNotExists, indexType, bindCount); + public CreateIndexStatement createIndex(NamedNode indexName, NamedTableNode dataTable, IndexKeyConstraint ikConstraint, List<ColumnName> includeColumns, List<ParseNode> splits, ListMultimap<String,Pair<String,Object>> props, boolean ifNotExists, IndexType indexType, int bindCount) { + return new CreateIndexStatement(indexName, dataTable, ikConstraint, includeColumns, splits, props, ifNotExists, indexType, bindCount); } public CreateSequenceStatement createSequence(TableName tableName, ParseNode startsWith, @@ -599,7 +602,12 @@ public class ParseNodeFactory { return select(statement.getFrom(), statement.getHint(), statement.isDistinct(), statement.getSelect(), where, statement.getGroupBy(), having, statement.getOrderBy(), statement.getLimit(), statement.getBindCount(), statement.isAggregate(), statement.hasSequence()); } - + + public SelectStatement select(SelectStatement statement, List<AliasedNode> select, ParseNode where, List<ParseNode> groupBy, ParseNode having, List<OrderByNode> orderBy) { + return select(statement.getFrom(), statement.getHint(), statement.isDistinct(), + select, where, groupBy, having, orderBy, statement.getLimit(), statement.getBindCount(), statement.isAggregate(), statement.hasSequence()); + } + public SelectStatement select(SelectStatement statement, TableNode table) { return select(table, statement.getHint(), statement.isDistinct(), statement.getSelect(), statement.getWhere(), statement.getGroupBy(), statement.getHaving(), statement.getOrderBy(), statement.getLimit(), statement.getBindCount(), statement.isAggregate(), http://git-wip-us.apache.org/repos/asf/phoenix/blob/8c340f5a/phoenix-core/src/main/java/org/apache/phoenix/parse/SequenceValueParseNode.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/parse/SequenceValueParseNode.java b/phoenix-core/src/main/java/org/apache/phoenix/parse/SequenceValueParseNode.java index f29d79e..260584f 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/parse/SequenceValueParseNode.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/parse/SequenceValueParseNode.java @@ -60,4 +60,33 @@ public class SequenceValueParseNode extends TerminalParseNode { public Op getOp() { return op; } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((op == null) ? 0 : op.hashCode()); + result = prime * result + + ((tableName == null) ? 0 : tableName.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + SequenceValueParseNode other = (SequenceValueParseNode) obj; + if (op != other.op) + return false; + if (tableName == null) { + if (other.tableName != null) + return false; + } else if (!tableName.equals(other.tableName)) + return false; + return true; + } } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/phoenix/blob/8c340f5a/phoenix-core/src/main/java/org/apache/phoenix/parse/SubqueryParseNode.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/parse/SubqueryParseNode.java b/phoenix-core/src/main/java/org/apache/phoenix/parse/SubqueryParseNode.java index 92c5284..b7bcb64 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/parse/SubqueryParseNode.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/parse/SubqueryParseNode.java @@ -49,5 +49,33 @@ public class SubqueryParseNode extends TerminalParseNode { public <T> T accept(ParseNodeVisitor<T> visitor) throws SQLException { return visitor.visit(this); } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + (expectSingleRow ? 1231 : 1237); + result = prime * result + ((select == null) ? 0 : select.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + SubqueryParseNode other = (SubqueryParseNode) obj; + if (expectSingleRow != other.expectSingleRow) + return false; + if (select == null) { + if (other.select != null) + return false; + } else if (!select.equals(other.select)) + return false; + return true; + } } http://git-wip-us.apache.org/repos/asf/phoenix/blob/8c340f5a/phoenix-core/src/main/java/org/apache/phoenix/parse/TableName.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/parse/TableName.java b/phoenix-core/src/main/java/org/apache/phoenix/parse/TableName.java index 9717067..654e899 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/parse/TableName.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/parse/TableName.java @@ -21,6 +21,7 @@ import org.apache.phoenix.query.QueryConstants; import org.apache.phoenix.util.SchemaUtil; public class TableName { + private final String tableName; private final String schemaName; private final boolean isTableNameCaseSensitive; @@ -61,7 +62,7 @@ public class TableName { public String toString() { return (schemaName == null ? "" : schemaName + QueryConstants.NAME_SEPARATOR) + tableName; } - + @Override public int hashCode() { final int prime = 31; http://git-wip-us.apache.org/repos/asf/phoenix/blob/8c340f5a/phoenix-core/src/main/java/org/apache/phoenix/parse/TableWildcardParseNode.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/parse/TableWildcardParseNode.java b/phoenix-core/src/main/java/org/apache/phoenix/parse/TableWildcardParseNode.java index 768ba5d..7292347 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/parse/TableWildcardParseNode.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/parse/TableWildcardParseNode.java @@ -46,5 +46,34 @@ public class TableWildcardParseNode extends NamedParseNode { return visitor.visit(this); } + @Override + public int hashCode() { + final int prime = 31; + int result = super.hashCode(); + result = prime * result + (isRewrite ? 1231 : 1237); + result = prime * result + + ((tableName == null) ? 0 : tableName.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (!super.equals(obj)) + return false; + if (getClass() != obj.getClass()) + return false; + TableWildcardParseNode other = (TableWildcardParseNode) obj; + if (isRewrite != other.isRewrite) + return false; + if (tableName == null) { + if (other.tableName != null) + return false; + } else if (!tableName.equals(other.tableName)) + return false; + return true; + } + } http://git-wip-us.apache.org/repos/asf/phoenix/blob/8c340f5a/phoenix-core/src/main/java/org/apache/phoenix/parse/WildcardParseNode.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/parse/WildcardParseNode.java b/phoenix-core/src/main/java/org/apache/phoenix/parse/WildcardParseNode.java index 59feeb5..fdfb64f 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/parse/WildcardParseNode.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/parse/WildcardParseNode.java @@ -51,6 +51,28 @@ public class WildcardParseNode extends TerminalParseNode { public boolean isRewrite() { return isRewrite; - } + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + (isRewrite ? 1231 : 1237); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + WildcardParseNode other = (WildcardParseNode) obj; + if (isRewrite != other.isRewrite) + return false; + return true; + } } http://git-wip-us.apache.org/repos/asf/phoenix/blob/8c340f5a/phoenix-core/src/main/java/org/apache/phoenix/schema/DelegateColumn.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/schema/DelegateColumn.java b/phoenix-core/src/main/java/org/apache/phoenix/schema/DelegateColumn.java index be85635..6c6bcf7 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/schema/DelegateColumn.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/schema/DelegateColumn.java @@ -21,6 +21,7 @@ import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; +import org.apache.phoenix.expression.Expression; import org.apache.phoenix.util.SizedUtil; public class DelegateColumn extends DelegateDatum implements PColumn { @@ -73,4 +74,9 @@ public class DelegateColumn extends DelegateDatum implements PColumn { public boolean isViewReferenced() { return getDelegate().isViewReferenced(); } + + @Override + public String getExpressionStr() { + return getDelegate().getExpressionStr(); + } } http://git-wip-us.apache.org/repos/asf/phoenix/blob/8c340f5a/phoenix-core/src/main/java/org/apache/phoenix/schema/DelegateTable.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/schema/DelegateTable.java b/phoenix-core/src/main/java/org/apache/phoenix/schema/DelegateTable.java index 38aac31..b719aae 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/schema/DelegateTable.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/schema/DelegateTable.java @@ -22,6 +22,7 @@ import java.util.List; import org.apache.hadoop.hbase.io.ImmutableBytesWritable; import org.apache.phoenix.hbase.index.util.KeyValueBuilder; import org.apache.phoenix.index.IndexMaintainer; +import org.apache.phoenix.jdbc.PhoenixConnection; import org.apache.phoenix.schema.stats.PTableStats; public class DelegateTable implements PTable { @@ -161,13 +162,13 @@ public class DelegateTable implements PTable { } @Override - public void getIndexMaintainers(ImmutableBytesWritable ptr) { - delegate.getIndexMaintainers(ptr); + public void getIndexMaintainers(ImmutableBytesWritable ptr, PhoenixConnection connection) { + delegate.getIndexMaintainers(ptr, connection); } @Override - public IndexMaintainer getIndexMaintainer(PTable dataTable) { - return delegate.getIndexMaintainer(dataTable); + public IndexMaintainer getIndexMaintainer(PTable dataTable, PhoenixConnection connection) { + return delegate.getIndexMaintainer(dataTable, connection); } @Override http://git-wip-us.apache.org/repos/asf/phoenix/blob/8c340f5a/phoenix-core/src/main/java/org/apache/phoenix/schema/MetaDataClient.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/schema/MetaDataClient.java b/phoenix-core/src/main/java/org/apache/phoenix/schema/MetaDataClient.java index 5791c82..09d2f66 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/schema/MetaDataClient.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/schema/MetaDataClient.java @@ -24,6 +24,7 @@ import static org.apache.hadoop.hbase.HColumnDescriptor.TTL; import static org.apache.phoenix.exception.SQLExceptionCode.INSUFFICIENT_MULTI_TENANT_COLUMNS; import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.ARRAY_SIZE; import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.COLUMN_COUNT; +import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.COLUMN_DEF; import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.COLUMN_FAMILY; import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.COLUMN_NAME; import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.COLUMN_SIZE; @@ -102,11 +103,13 @@ import org.apache.hadoop.hbase.util.Pair; import org.apache.phoenix.compile.ColumnResolver; import org.apache.phoenix.compile.ExplainPlan; import org.apache.phoenix.compile.FromCompiler; +import org.apache.phoenix.compile.IndexExpressionCompiler; import org.apache.phoenix.compile.MutationPlan; import org.apache.phoenix.compile.PostDDLCompiler; import org.apache.phoenix.compile.PostIndexDDLCompiler; import org.apache.phoenix.compile.QueryPlan; import org.apache.phoenix.compile.StatementContext; +import org.apache.phoenix.compile.StatementNormalizer; import org.apache.phoenix.coprocessor.BaseScannerRegionObserver; import org.apache.phoenix.coprocessor.MetaDataProtocol; import org.apache.phoenix.coprocessor.MetaDataProtocol.MetaDataMutationResult; @@ -114,6 +117,9 @@ import org.apache.phoenix.coprocessor.MetaDataProtocol.MutationCode; import org.apache.phoenix.exception.SQLExceptionCode; import org.apache.phoenix.exception.SQLExceptionInfo; import org.apache.phoenix.execute.MutationState; +import org.apache.phoenix.expression.Determinism; +import org.apache.phoenix.expression.Expression; +import org.apache.phoenix.expression.RowKeyColumnExpression; import org.apache.phoenix.hbase.index.covered.update.ColumnReference; import org.apache.phoenix.index.IndexMaintainer; import org.apache.phoenix.jdbc.PhoenixConnection; @@ -131,7 +137,9 @@ import org.apache.phoenix.parse.DropColumnStatement; import org.apache.phoenix.parse.DropIndexStatement; import org.apache.phoenix.parse.DropSequenceStatement; import org.apache.phoenix.parse.DropTableStatement; +import org.apache.phoenix.parse.IndexKeyConstraint; import org.apache.phoenix.parse.NamedTableNode; +import org.apache.phoenix.parse.ParseNode; import org.apache.phoenix.parse.ParseNodeFactory; import org.apache.phoenix.parse.PrimaryKeyConstraint; import org.apache.phoenix.parse.TableName; @@ -257,8 +265,9 @@ public class MetaDataClient { VIEW_CONSTANT + "," + IS_VIEW_REFERENCED + "," + PK_NAME + "," + // write this both in the column and table rows for access by metadata APIs - KEY_SEQ + - ") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; + KEY_SEQ + "," + + COLUMN_DEF + + ") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; private static final String UPDATE_COLUMN_POSITION = "UPSERT INTO " + SYSTEM_CATALOG_SCHEMA + ".\"" + SYSTEM_CATALOG_TABLE + "\" ( " + TENANT_ID + "," + @@ -322,6 +331,7 @@ public class MetaDataClient { table = connection.getMetaDataCache().getTable(new PTableKey(tenantId, fullTableName)); tableTimestamp = table.getTimeStamp(); } catch (TableNotFoundException e) { + System.err.println(e); // TODO: Try again on services cache, as we may be looking for // a global multi-tenant table } @@ -499,6 +509,11 @@ public class MetaDataClient { } else { colUpsert.setShort(17, keySeq); } + if (column.getExpressionStr() == null) { + colUpsert.setNull(18, Types.VARCHAR); + } else { + colUpsert.setString(18, column.getExpressionStr()); + } colUpsert.execute(); } @@ -545,7 +560,7 @@ public class MetaDataClient { } PColumn column = new PColumnImpl(PNameFactory.newName(columnName), familyName, def.getDataType(), - def.getMaxLength(), def.getScale(), isNull, position, sortOrder, def.getArraySize(), null, false); + def.getMaxLength(), def.getScale(), isNull, position, sortOrder, def.getArraySize(), null, false, def.getExpression()); return column; } catch (IllegalArgumentException e) { // Based on precondition check in constructor throw new SQLException(e); @@ -762,11 +777,11 @@ public class MetaDataClient { List<PTable> indexes = Lists.newArrayListWithExpectedSize(1); // Only build newly created index. indexes.add(index); - IndexMaintainer.serialize(dataTable, ptr, indexes); + IndexMaintainer.serialize(dataTable, ptr, indexes, plan.getContext().getConnection()); scan.setAttribute(BaseScannerRegionObserver.LOCAL_INDEX_BUILD, ByteUtil.copyKeyBytesIfNecessary(ptr)); // By default, we'd use a FirstKeyOnly filter as nothing else needs to be projected for count(*). // However, in this case, we need to project all of the data columns that contribute to the index. - IndexMaintainer indexMaintainer = index.getIndexMaintainer(dataTable); + IndexMaintainer indexMaintainer = index.getIndexMaintainer(dataTable, connection); for (ColumnReference columnRef : indexMaintainer.getAllColumns()) { scan.addColumn(columnRef.getFamily(), columnRef.getQualifier()); } @@ -884,10 +899,10 @@ public class MetaDataClient { * @throws SQLException */ public MutationState createIndex(CreateIndexStatement statement, byte[][] splits) throws SQLException { - PrimaryKeyConstraint pk = statement.getIndexConstraint(); + IndexKeyConstraint ik = statement.getIndexConstraint(); TableName indexTableName = statement.getIndexTableName(); - - List<Pair<ColumnName, SortOrder>> indexedPkColumns = pk.getColumnNames(); + + List<Pair<ParseNode, SortOrder>> indexParseNodeAndSortOrderList = ik.getParseNodeAndSortOrderList(); List<ColumnName> includedColumns = statement.getIncludeColumns(); TableRef tableRef = null; PTable table = null; @@ -915,24 +930,30 @@ public class MetaDataClient { } } int posOffset = 0; - Set<PColumn> unusedPkColumns; + List<PColumn> pkColumns = dataTable.getPKColumns(); + Set<RowKeyColumnExpression> unusedPkColumns; if (dataTable.getBucketNum() != null) { // Ignore SALT column - unusedPkColumns = new LinkedHashSet<PColumn>(dataTable.getPKColumns().subList(1, dataTable.getPKColumns().size())); - posOffset++; + unusedPkColumns = Sets.newLinkedHashSetWithExpectedSize(pkColumns.size()-1); + posOffset++; } else { - unusedPkColumns = new LinkedHashSet<PColumn>(dataTable.getPKColumns()); + unusedPkColumns = Sets.newLinkedHashSetWithExpectedSize(pkColumns.size()); + } + for (int i = posOffset; i < pkColumns.size(); i++) { + PColumn column = pkColumns.get(i); + unusedPkColumns.add(new RowKeyColumnExpression(column, new RowKeyValueAccessor(pkColumns, i), "\""+column.getName().getString()+"\"")); } List<Pair<ColumnName, SortOrder>> allPkColumns = Lists.newArrayListWithExpectedSize(unusedPkColumns.size()); - List<ColumnDef> columnDefs = Lists.newArrayListWithExpectedSize(includedColumns.size() + indexedPkColumns.size()); - + List<ColumnDef> columnDefs = Lists.newArrayListWithExpectedSize(includedColumns.size() + indexParseNodeAndSortOrderList.size()); + if (dataTable.isMultiTenant()) { // Add tenant ID column as first column in index PColumn col = dataTable.getPKColumns().get(posOffset); - unusedPkColumns.remove(col); + RowKeyColumnExpression columnExpression = new RowKeyColumnExpression(col, new RowKeyValueAccessor(pkColumns, posOffset), col.getName().getString()); + unusedPkColumns.remove(columnExpression); PDataType dataType = IndexUtil.getIndexColumnDataType(col); ColumnName colName = ColumnName.caseSensitiveColumnName(IndexUtil.getIndexColumnName(col)); allPkColumns.add(new Pair<ColumnName, SortOrder>(colName, col.getSortOrder())); - columnDefs.add(FACTORY.columnDef(colName, dataType.getSqlTypeName(), col.isNullable(), col.getMaxLength(), col.getScale(), false, SortOrder.getDefault())); + columnDefs.add(FACTORY.columnDef(colName, dataType.getSqlTypeName(), col.isNullable(), col.getMaxLength(), col.getScale(), false, SortOrder.getDefault(), col.getName().getString())); } /* * Allocate an index ID in two circumstances: @@ -945,55 +966,81 @@ public class MetaDataClient { PDataType dataType = MetaDataUtil.getViewIndexIdDataType(); ColumnName colName = ColumnName.caseSensitiveColumnName(MetaDataUtil.getViewIndexIdColumnName()); allPkColumns.add(new Pair<ColumnName, SortOrder>(colName, SortOrder.getDefault())); - columnDefs.add(FACTORY.columnDef(colName, dataType.getSqlTypeName(), false, null, null, false, SortOrder.getDefault())); + columnDefs.add(FACTORY.columnDef(colName, dataType.getSqlTypeName(), false, null, null, false, SortOrder.getDefault(), null)); } - // First columns are the indexed ones - for (Pair<ColumnName, SortOrder> pair : indexedPkColumns) { - ColumnName colName = pair.getFirst(); - PColumn col = resolver.resolveColumn(null, colName.getFamilyName(), colName.getColumnName()).getColumn(); - unusedPkColumns.remove(col); - // Ignore view constants for updatable views as we don't need these in the index - if (col.getViewConstant() == null) { - PDataType dataType = IndexUtil.getIndexColumnDataType(col); - colName = ColumnName.caseSensitiveColumnName(IndexUtil.getIndexColumnName(col)); - allPkColumns.add(new Pair<ColumnName, SortOrder>(colName, pair.getSecond())); - columnDefs.add(FACTORY.columnDef(colName, dataType.getSqlTypeName(), col.isNullable(), col.getMaxLength(), col.getScale(), false, SortOrder.getDefault())); - } + + PhoenixStatement phoenixStatment = new PhoenixStatement(connection); + StatementContext context = new StatementContext(phoenixStatment, resolver); + IndexExpressionCompiler expressionIndexCompiler = new IndexExpressionCompiler(context); + Set<ColumnName> indexedColumnNames = Sets.newHashSetWithExpectedSize(indexParseNodeAndSortOrderList.size()); + for (Pair<ParseNode, SortOrder> pair : indexParseNodeAndSortOrderList) { + ParseNode parseNode = pair.getFirst(); + // normalize the parse node + parseNode = StatementNormalizer.normalize(parseNode, resolver); + // compile the parseNode to get an expression + expressionIndexCompiler.reset(); + Expression expression = parseNode.accept(expressionIndexCompiler); + if (expressionIndexCompiler.isAggregate()) { + throw new SQLExceptionInfo.Builder(SQLExceptionCode.AGGREGATE_EXPRESSION_NOT_ALLOWED_IN_INDEX).build().buildException(); + } + if (expression.getDeterminism() != Determinism.ALWAYS) { + throw new SQLExceptionInfo.Builder(SQLExceptionCode.NON_DETERMINISTIC_EXPRESSION_NOT_ALLOWED_IN_INDEX).build().buildException(); + } + // true for any constant (including a view constant), as we don't need these in the index + if (expression.isStateless()) { + continue; + } + unusedPkColumns.remove(expression); + + ColumnName colName = null; + ColumnRef colRef = expressionIndexCompiler.getColumnRef(); + if (colRef!=null) { + // if this is a regular column + PColumn column = colRef.getColumn(); + String columnFamilyName = column.getFamilyName()!=null ? column.getFamilyName().getString() : null; + colName = ColumnName.caseSensitiveColumnName(IndexUtil.getIndexColumnName(columnFamilyName, column.getName().getString())); + } + else { + // if this is an expression + // TODO column names cannot have double quotes, remove this once this PHOENIX-1621 is fixed + String name = expression.toString().replaceAll("\"", "'"); + colName = ColumnName.caseSensitiveColumnName(IndexUtil.getIndexColumnName(null, name)); + } + indexedColumnNames.add(colName); + PDataType dataType = IndexUtil.getIndexColumnDataType(expression.isNullable(), expression.getDataType()); + allPkColumns.add(new Pair<ColumnName, SortOrder>(colName, pair.getSecond())); + columnDefs.add(FACTORY.columnDef(colName, dataType.getSqlTypeName(), expression.isNullable(), expression.getMaxLength(), expression.getScale(), false, pair.getSecond(), expression.toString())); } // Next all the PK columns from the data table that aren't indexed if (!unusedPkColumns.isEmpty()) { - for (PColumn col : unusedPkColumns) { + for (RowKeyColumnExpression colExpression : unusedPkColumns) { + PColumn col = dataTable.getPKColumns().get(colExpression.getPosition()); // Don't add columns with constant values from updatable views, as // we don't need these in the index if (col.getViewConstant() == null) { ColumnName colName = ColumnName.caseSensitiveColumnName(IndexUtil.getIndexColumnName(col)); - allPkColumns.add(new Pair<ColumnName, SortOrder>(colName, col.getSortOrder())); - PDataType dataType = IndexUtil.getIndexColumnDataType(col); - columnDefs.add(FACTORY.columnDef(colName, dataType.getSqlTypeName(), col.isNullable(), col.getMaxLength(), col.getScale(), false, col.getSortOrder())); + allPkColumns.add(new Pair<ColumnName, SortOrder>(colName, colExpression.getSortOrder())); + PDataType dataType = IndexUtil.getIndexColumnDataType(colExpression.isNullable(), colExpression.getDataType()); + columnDefs.add(FACTORY.columnDef(colName, dataType.getSqlTypeName(), + colExpression.isNullable(), colExpression.getMaxLength(), colExpression.getScale(), + false, colExpression.getSortOrder(), colExpression.toString())); } } } - pk = FACTORY.primaryKey(null, allPkColumns); - + // Last all the included columns (minus any PK columns) for (ColumnName colName : includedColumns) { PColumn col = resolver.resolveColumn(null, colName.getFamilyName(), colName.getColumnName()).getColumn(); - if (SchemaUtil.isPKColumn(col)) { - if (!unusedPkColumns.contains(col)) { - throw new SQLExceptionInfo.Builder(SQLExceptionCode.COLUMN_EXIST_IN_DEF).build().buildException(); - } - } else { - colName = ColumnName.caseSensitiveColumnName(IndexUtil.getIndexColumnName(col)); - // Check for duplicates between indexed and included columns - if (pk.contains(colName)) { - throw new SQLExceptionInfo.Builder(SQLExceptionCode.COLUMN_EXIST_IN_DEF).build().buildException(); - } - if (!SchemaUtil.isPKColumn(col) && col.getViewConstant() == null) { - // Need to re-create ColumnName, since the above one won't have the column family name - colName = ColumnName.caseSensitiveColumnName(col.getFamilyName().getString(), IndexUtil.getIndexColumnName(col)); - columnDefs.add(FACTORY.columnDef(colName, col.getDataType().getSqlTypeName(), col.isNullable(), col.getMaxLength(), col.getScale(), false, col.getSortOrder())); - } + colName = ColumnName.caseSensitiveColumnName(IndexUtil.getIndexColumnName(col)); + // Check for duplicates between indexed and included columns + if (indexedColumnNames.contains(colName)) { + throw new SQLExceptionInfo.Builder(SQLExceptionCode.COLUMN_EXIST_IN_DEF).build().buildException(); + } + if (!SchemaUtil.isPKColumn(col) && col.getViewConstant() == null) { + // Need to re-create ColumnName, since the above one won't have the column family name + colName = ColumnName.caseSensitiveColumnName(col.getFamilyName().getString(), IndexUtil.getIndexColumnName(col)); + columnDefs.add(FACTORY.columnDef(colName, col.getDataType().getSqlTypeName(), col.isNullable(), col.getMaxLength(), col.getScale(), false, col.getSortOrder(), null)); } } @@ -1030,6 +1077,7 @@ public class MetaDataClient { if (dataTable.getDefaultFamilyName() != null && dataTable.getType() != PTableType.VIEW && indexId == null) { statement.getProps().put("", new Pair<String,Object>(DEFAULT_COLUMN_FAMILY_NAME,dataTable.getDefaultFamilyName().getString())); } + PrimaryKeyConstraint pk = FACTORY.primaryKey(null, allPkColumns); CreateTableStatement tableStatement = FACTORY.createTable(indexTableName, statement.getProps(), columnDefs, pk, statement.getSplitNodes(), PTableType.INDEX, statement.ifNotExists(), null, null, statement.getBindCount()); table = createTableInternal(tableStatement, splits, dataTable, null, null, null, null, indexId, statement.getIndexType()); break; @@ -2051,7 +2099,7 @@ public class MetaDataClient { } } - boolean isAddingPKColumn = false; + int numPkColumnsAdded = 0; PreparedStatement colUpsert = connection.prepareStatement(INSERT_COLUMN); List<PColumn> columns = Lists.newArrayListWithExpectedSize(columnDefs.size()); @@ -2077,7 +2125,7 @@ public class MetaDataClient { // TODO: support setting properties on other families? if (column.getFamilyName() == null) { - isAddingPKColumn = true; + ++numPkColumnsAdded; pkName = table.getPKName() == null ? null : table.getPKName().getString(); keySeq = ++nextKeySeq; } else { @@ -2088,15 +2136,26 @@ public class MetaDataClient { } // Add any new PK columns to end of index PK - if (isAddingPKColumn) { + if (numPkColumnsAdded>0) { + // create PK column list that includes the newly created columns + List<PColumn> pkColumns = Lists.newArrayListWithExpectedSize(table.getPKColumns().size()+numPkColumnsAdded); + pkColumns.addAll(table.getPKColumns()); + for (int i=0; i<columnDefs.size(); ++i) { + if (columnDefs.get(i).isPK()) { + pkColumns.add(columns.get(i)); + } + } + int pkSlotPosition = table.getPKColumns().size()-1; for (PTable index : table.getIndexes()) { short nextIndexKeySeq = SchemaUtil.getMaxKeySeq(index); int indexPosition = index.getColumns().size(); - for (ColumnDef colDef : columnDefs) { + for (int i=0; i<columnDefs.size(); ++i) { + ColumnDef colDef = columnDefs.get(i); if (colDef.isPK()) { PDataType indexColDataType = IndexUtil.getIndexColumnDataType(colDef.isNull(), colDef.getDataType()); ColumnName indexColName = ColumnName.caseSensitiveColumnName(IndexUtil.getIndexColumnName(null, colDef.getColumnDefName().getColumnName())); - ColumnDef indexColDef = FACTORY.columnDef(indexColName, indexColDataType.getSqlTypeName(), colDef.isNull(), colDef.getMaxLength(), colDef.getScale(), true, colDef.getSortOrder()); + Expression expression = new RowKeyColumnExpression(columns.get(i), new RowKeyValueAccessor(pkColumns, ++pkSlotPosition)); + ColumnDef indexColDef = FACTORY.columnDef(indexColName, indexColDataType.getSqlTypeName(), colDef.isNull(), colDef.getMaxLength(), colDef.getScale(), true, colDef.getSortOrder(), expression.toString()); PColumn indexColumn = newColumn(indexPosition++, indexColDef, PrimaryKeyConstraint.EMPTY, null, true); addColumnMutation(schemaName, index.getTableName().getString(), indexColumn, colUpsert, index.getParentTableName().getString(), index.getPKName() == null ? null : index.getPKName().getString(), ++nextIndexKeySeq, index.getBucketNum() != null); } @@ -2124,7 +2183,7 @@ public class MetaDataClient { } } - if (isAddingPKColumn && !table.getIndexes().isEmpty()) { + if (numPkColumnsAdded>0 && !table.getIndexes().isEmpty()) { for (PTable index : table.getIndexes()) { incrementTableSeqNum(index, index.getType(), 1); } @@ -2172,7 +2231,7 @@ public class MetaDataClient { // Only update client side cache if we aren't adding a PK column to a table with indexes. // We could update the cache manually then too, it'd just be a pain. - if (!isAddingPKColumn || table.getIndexes().isEmpty()) { + if (numPkColumnsAdded==0 || table.getIndexes().isEmpty()) { connection.addColumn(tenantId, SchemaUtil.getTableName(schemaName, tableName), columns, result.getMutationTime(), seqNum, isImmutableRows == null ? table.isImmutableRows() : isImmutableRows, disableWAL == null ? table.isWALDisabled() : disableWAL, multiTenant == null ? table.isMultiTenant() : multiTenant, storeNulls == null ? table.getStoreNulls() : storeNulls); } // Delete rows in view index if we haven't dropped it already http://git-wip-us.apache.org/repos/asf/phoenix/blob/8c340f5a/phoenix-core/src/main/java/org/apache/phoenix/schema/PColumn.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/schema/PColumn.java b/phoenix-core/src/main/java/org/apache/phoenix/schema/PColumn.java index 54eeaf0..fbc737c 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/schema/PColumn.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/schema/PColumn.java @@ -17,6 +17,7 @@ */ package org.apache.phoenix.schema; + /** * Definition of a Phoenix column * @@ -50,4 +51,6 @@ public interface PColumn extends PDatum { boolean isViewReferenced(); int getEstimatedSize(); + + String getExpressionStr(); } http://git-wip-us.apache.org/repos/asf/phoenix/blob/8c340f5a/phoenix-core/src/main/java/org/apache/phoenix/schema/PColumnImpl.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/schema/PColumnImpl.java b/phoenix-core/src/main/java/org/apache/phoenix/schema/PColumnImpl.java index 47963c2..11cc53d 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/schema/PColumnImpl.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/schema/PColumnImpl.java @@ -37,6 +37,7 @@ public class PColumnImpl implements PColumn { private Integer arraySize; private byte[] viewConstant; private boolean isViewReferenced; + private String expressionStr; public PColumnImpl() { } @@ -48,13 +49,13 @@ public class PColumnImpl implements PColumn { Integer scale, boolean nullable, int position, - SortOrder sortOrder, Integer arrSize, byte[] viewConstant, boolean isViewReferenced) { - init(name, familyName, dataType, maxLength, scale, nullable, position, sortOrder, arrSize, viewConstant, isViewReferenced); + SortOrder sortOrder, Integer arrSize, byte[] viewConstant, boolean isViewReferenced, String expressionStr) { + init(name, familyName, dataType, maxLength, scale, nullable, position, sortOrder, arrSize, viewConstant, isViewReferenced, expressionStr); } public PColumnImpl(PColumn column, int position) { this(column.getName(), column.getFamilyName(), column.getDataType(), column.getMaxLength(), - column.getScale(), column.isNullable(), position, column.getSortOrder(), column.getArraySize(), column.getViewConstant(), column.isViewReferenced()); + column.getScale(), column.isNullable(), position, column.getSortOrder(), column.getArraySize(), column.getViewConstant(), column.isViewReferenced(), column.getExpressionStr()); } private void init(PName name, @@ -66,7 +67,7 @@ public class PColumnImpl implements PColumn { int position, SortOrder sortOrder, Integer arrSize, - byte[] viewConstant, boolean isViewReferenced) { + byte[] viewConstant, boolean isViewReferenced, String expressionStr) { Preconditions.checkNotNull(sortOrder); this.dataType = dataType; if (familyName == null) { @@ -88,6 +89,7 @@ public class PColumnImpl implements PColumn { this.arraySize = arrSize; this.viewConstant = viewConstant; this.isViewReferenced = isViewReferenced; + this.expressionStr = expressionStr; } @Override @@ -121,6 +123,11 @@ public class PColumnImpl implements PColumn { public Integer getScale() { return scale; } + + @Override + public String getExpressionStr() { + return expressionStr; + } @Override public boolean isNullable() { @@ -221,9 +228,12 @@ public class PColumnImpl implements PColumn { if (column.hasViewReferenced()) { isViewReferenced = column.getViewReferenced(); } - + String expressionStr = null; + if (column.hasExpression()) { + expressionStr = column.getExpression(); + } return new PColumnImpl(columnName, familyName, dataType, maxLength, scale, nullable, position, sortOrder, - arraySize, viewConstant, isViewReferenced); + arraySize, viewConstant, isViewReferenced, expressionStr); } public static PTableProtos.PColumn toProto(PColumn column) { @@ -249,6 +259,10 @@ public class PColumnImpl implements PColumn { builder.setViewConstant(HBaseZeroCopyByteString.wrap(column.getViewConstant())); } builder.setViewReferenced(column.isViewReferenced()); + + if (column.getExpressionStr() != null) { + builder.setExpression(column.getExpressionStr()); + } return builder.build(); } } http://git-wip-us.apache.org/repos/asf/phoenix/blob/8c340f5a/phoenix-core/src/main/java/org/apache/phoenix/schema/PMetaDataImpl.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/schema/PMetaDataImpl.java b/phoenix-core/src/main/java/org/apache/phoenix/schema/PMetaDataImpl.java index d3f4273..2f84c95 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/schema/PMetaDataImpl.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/schema/PMetaDataImpl.java @@ -393,7 +393,7 @@ public class PMetaDataImpl implements PMetaData { // Update position of columns that follow removed column for (int i = position+1; i < oldColumns.size(); i++) { PColumn oldColumn = oldColumns.get(i); - PColumn newColumn = new PColumnImpl(oldColumn.getName(), oldColumn.getFamilyName(), oldColumn.getDataType(), oldColumn.getMaxLength(), oldColumn.getScale(), oldColumn.isNullable(), i-1+positionOffset, oldColumn.getSortOrder(), oldColumn.getArraySize(), oldColumn.getViewConstant(), oldColumn.isViewReferenced()); + PColumn newColumn = new PColumnImpl(oldColumn.getName(), oldColumn.getFamilyName(), oldColumn.getDataType(), oldColumn.getMaxLength(), oldColumn.getScale(), oldColumn.isNullable(), i-1+positionOffset, oldColumn.getSortOrder(), oldColumn.getArraySize(), oldColumn.getViewConstant(), oldColumn.isViewReferenced(), null); columns.add(newColumn); } http://git-wip-us.apache.org/repos/asf/phoenix/blob/8c340f5a/phoenix-core/src/main/java/org/apache/phoenix/schema/PTable.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/schema/PTable.java b/phoenix-core/src/main/java/org/apache/phoenix/schema/PTable.java index ee4bebc..d0fea88 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/schema/PTable.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/schema/PTable.java @@ -23,6 +23,7 @@ import org.apache.hadoop.hbase.io.ImmutableBytesWritable; import org.apache.hadoop.hbase.util.Bytes; import org.apache.phoenix.hbase.index.util.KeyValueBuilder; import org.apache.phoenix.index.IndexMaintainer; +import org.apache.phoenix.jdbc.PhoenixConnection; import org.apache.phoenix.schema.stats.PTableStats; @@ -208,7 +209,7 @@ public interface PTable { * @throws AmbiguousColumnException if multiple columns are found with the given name */ PColumn getColumn(String name) throws ColumnNotFoundException, AmbiguousColumnException; - + /** * Get the PK column with the given name. * @param name the column name @@ -306,8 +307,8 @@ public interface PTable { PName getPhysicalName(); boolean isImmutableRows(); - void getIndexMaintainers(ImmutableBytesWritable ptr); - IndexMaintainer getIndexMaintainer(PTable dataTable); + void getIndexMaintainers(ImmutableBytesWritable ptr, PhoenixConnection connection); + IndexMaintainer getIndexMaintainer(PTable dataTable, PhoenixConnection connection); PName getDefaultFamilyName(); boolean isWALDisabled(); http://git-wip-us.apache.org/repos/asf/phoenix/blob/8c340f5a/phoenix-core/src/main/java/org/apache/phoenix/schema/PTableImpl.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/schema/PTableImpl.java b/phoenix-core/src/main/java/org/apache/phoenix/schema/PTableImpl.java index acce857..08f74b7 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/schema/PTableImpl.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/schema/PTableImpl.java @@ -46,6 +46,7 @@ import org.apache.phoenix.coprocessor.generated.PTableProtos; import org.apache.phoenix.hbase.index.util.ImmutableBytesPtr; import org.apache.phoenix.hbase.index.util.KeyValueBuilder; import org.apache.phoenix.index.IndexMaintainer; +import org.apache.phoenix.jdbc.PhoenixConnection; import org.apache.phoenix.protobuf.ProtobufUtil; import org.apache.phoenix.query.QueryConstants; import org.apache.phoenix.schema.RowKeySchema.RowKeySchemaBuilder; @@ -324,15 +325,16 @@ public class PTableImpl implements PTable { this.tableStats = stats; List<PColumn> pkColumns; PColumn[] allColumns; - + this.columnsByName = ArrayListMultimap.create(columns.size(), 1); + int numPKColumns = 0; if (bucketNum != null) { // Add salt column to allColumns and pkColumns, but don't add to // columnsByName, since it should not be addressable via name. allColumns = new PColumn[columns.size()+1]; allColumns[SALTING_COLUMN.getPosition()] = SALTING_COLUMN; pkColumns = Lists.newArrayListWithExpectedSize(columns.size()+1); - pkColumns.add(SALTING_COLUMN); + ++numPKColumns; } else { allColumns = new PColumn[columns.size()]; pkColumns = Lists.newArrayListWithExpectedSize(columns.size()); @@ -342,7 +344,7 @@ public class PTableImpl implements PTable { allColumns[column.getPosition()] = column; PName familyName = column.getFamilyName(); if (familyName == null) { - pkColumns.add(column); + ++numPKColumns; } String columnName = column.getName().getString(); if (columnsByName.put(columnName, column)) { @@ -360,19 +362,21 @@ public class PTableImpl implements PTable { estimatedSize += SizedUtil.sizeOfMap(allColumns.length, SizedUtil.POINTER_SIZE, SizedUtil.sizeOfArrayList(1)); // for multi-map this.bucketNum = bucketNum; - this.pkColumns = ImmutableList.copyOf(pkColumns); this.allColumns = ImmutableList.copyOf(allColumns); - estimatedSize += SizedUtil.sizeOfMap(pkColumns.size()) + SizedUtil.sizeOfMap(allColumns.length); + estimatedSize += SizedUtil.sizeOfMap(numPKColumns) + SizedUtil.sizeOfMap(allColumns.length); - RowKeySchemaBuilder builder = new RowKeySchemaBuilder(pkColumns.size()); + RowKeySchemaBuilder builder = new RowKeySchemaBuilder(numPKColumns); // Two pass so that column order in column families matches overall column order // and to ensure that column family order is constant - int maxExpectedSize = allColumns.length - pkColumns.size(); + int maxExpectedSize = allColumns.length - numPKColumns; // Maintain iteration order so that column families are ordered as they are listed Map<PName, List<PColumn>> familyMap = Maps.newLinkedHashMap(); for (PColumn column : allColumns) { PName familyName = column.getFamilyName(); if (familyName == null) { + pkColumns.add(column); + } + if (familyName == null) { estimatedSize += column.getEstimatedSize(); // PK columns builder.addField(column, column.isNullable(), column.getSortOrder()); } else { @@ -384,6 +388,7 @@ public class PTableImpl implements PTable { columnsInFamily.add(column); } } + this.pkColumns = ImmutableList.copyOf(pkColumns); this.rowKeySchema = builder.build(); estimatedSize += rowKeySchema.getEstimatedSize(); Iterator<Map.Entry<PName,List<PColumn>>> iterator = familyMap.entrySet().iterator(); @@ -804,21 +809,21 @@ public class PTableImpl implements PTable { } @Override - public synchronized IndexMaintainer getIndexMaintainer(PTable dataTable) { + public synchronized IndexMaintainer getIndexMaintainer(PTable dataTable, PhoenixConnection connection) { if (indexMaintainer == null) { - indexMaintainer = IndexMaintainer.create(dataTable, this); + indexMaintainer = IndexMaintainer.create(dataTable, this, connection); } return indexMaintainer; } @Override - public synchronized void getIndexMaintainers(ImmutableBytesWritable ptr) { + public synchronized void getIndexMaintainers(ImmutableBytesWritable ptr, PhoenixConnection connection) { if (indexMaintainersPtr == null) { indexMaintainersPtr = new ImmutableBytesWritable(); if (indexes.isEmpty()) { indexMaintainersPtr.set(ByteUtil.EMPTY_BYTE_ARRAY); } else { - IndexMaintainer.serialize(this, indexMaintainersPtr); + IndexMaintainer.serialize(this, indexMaintainersPtr, connection); } } ptr.set(indexMaintainersPtr.get(), indexMaintainersPtr.getOffset(), indexMaintainersPtr.getLength());