You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@phoenix.apache.org by ma...@apache.org on 2015/03/04 23:40:44 UTC
[09/50] [abbrv] phoenix git commit: PHOENIX-514 Support functional
indexes (Thomas D'Silva)
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());