Repository: phoenix Updated Branches: refs/heads/3.0 80e218c24 -> 9cf34400a
PHOENIX-1030 Change Expression.isDeterministic() to return a enum of values ALWAYS, PER_STATEMENT, PER_ROW (Thomas D'Silva) Project: http://git-wip-us.apache.org/repos/asf/phoenix/repo Commit: http://git-wip-us.apache.org/repos/asf/phoenix/commit/9cf34400 Tree: http://git-wip-us.apache.org/repos/asf/phoenix/tree/9cf34400 Diff: http://git-wip-us.apache.org/repos/asf/phoenix/diff/9cf34400 Branch: refs/heads/3.0 Commit: 9cf34400a1da6520e0573258287049242ed22c10 Parents: 80e218c Author: James Taylor <jtay...@salesforce.com> Authored: Fri Oct 3 22:39:36 2014 -0700 Committer: James Taylor <jtay...@salesforce.com> Committed: Fri Oct 3 22:39:36 2014 -0700 ---------------------------------------------------------------------- .../phoenix/compile/CreateTableCompiler.java | 4 +- .../phoenix/compile/ExpressionCompiler.java | 64 ++++++------- .../apache/phoenix/compile/SequenceManager.java | 5 +- .../apache/phoenix/compile/UpsertCompiler.java | 7 +- .../apache/phoenix/compile/WhereCompiler.java | 3 +- .../apache/phoenix/compile/WhereOptimizer.java | 3 +- .../apache/phoenix/execute/HashJoinPlan.java | 3 +- .../phoenix/expression/AndExpression.java | 6 +- .../expression/BaseCompoundExpression.java | 11 +-- .../phoenix/expression/BaseExpression.java | 6 +- .../expression/ComparisonExpression.java | 34 +++---- .../expression/CurrentDateTimeFunction.java | 4 +- .../apache/phoenix/expression/Determinism.java | 19 ++++ .../apache/phoenix/expression/Expression.java | 6 +- .../phoenix/expression/InListExpression.java | 4 +- .../phoenix/expression/IsNullExpression.java | 4 +- .../phoenix/expression/LiteralExpression.java | 99 +++++++++++--------- .../phoenix/expression/NotExpression.java | 4 +- .../expression/function/AggregateFunction.java | 5 +- .../function/CeilDecimalExpression.java | 8 +- .../expression/function/CoalesceFunction.java | 3 +- .../function/CountAggregateFunction.java | 4 +- .../function/FloorDecimalExpression.java | 8 +- .../function/RoundDateExpression.java | 5 +- .../function/RoundDecimalExpression.java | 5 +- .../function/SingleAggregateFunction.java | 4 +- .../apache/phoenix/parse/FunctionParseNode.java | 10 +- .../org/apache/phoenix/util/ExpressionUtil.java | 28 +++--- .../phoenix/expression/DeterminismTest.java | 37 ++++++++ 29 files changed, 248 insertions(+), 155 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/phoenix/blob/9cf34400/phoenix-core/src/main/java/org/apache/phoenix/compile/CreateTableCompiler.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/compile/CreateTableCompiler.java b/phoenix-core/src/main/java/org/apache/phoenix/compile/CreateTableCompiler.java index 7794416..7a8ebf4 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/compile/CreateTableCompiler.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/compile/CreateTableCompiler.java @@ -32,6 +32,7 @@ import org.apache.phoenix.exception.SQLExceptionInfo; import org.apache.phoenix.execute.MutationState; import org.apache.phoenix.expression.AndExpression; import org.apache.phoenix.expression.ComparisonExpression; +import org.apache.phoenix.expression.Determinism; import org.apache.phoenix.expression.Expression; import org.apache.phoenix.expression.IsNullExpression; import org.apache.phoenix.expression.KeyValueColumnExpression; @@ -257,7 +258,8 @@ public class CreateTableCompiler { @Override public Iterator<Expression> visitEnter(ComparisonExpression node) { - if (node.getFilterOp() == CompareOp.EQUAL && node.getChildren().get(1).isStateless() && node.getChildren().get(1).isDeterministic()) { + if (node.getFilterOp() == CompareOp.EQUAL && node.getChildren().get(1).isStateless() + && node.getChildren().get(1).getDeterminism() == Determinism.ALWAYS ) { return Iterators.singletonIterator(node.getChildren().get(0)); } return super.visitEnter(node); http://git-wip-us.apache.org/repos/asf/phoenix/blob/9cf34400/phoenix-core/src/main/java/org/apache/phoenix/compile/ExpressionCompiler.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/compile/ExpressionCompiler.java b/phoenix-core/src/main/java/org/apache/phoenix/compile/ExpressionCompiler.java index bd68ccb..41f6d83 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/compile/ExpressionCompiler.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/compile/ExpressionCompiler.java @@ -41,6 +41,7 @@ import org.apache.phoenix.expression.DecimalAddExpression; import org.apache.phoenix.expression.DecimalDivideExpression; import org.apache.phoenix.expression.DecimalMultiplyExpression; import org.apache.phoenix.expression.DecimalSubtractExpression; +import org.apache.phoenix.expression.Determinism; import org.apache.phoenix.expression.DoubleAddExpression; import org.apache.phoenix.expression.DoubleDivideExpression; import org.apache.phoenix.expression.DoubleMultiplyExpression; @@ -223,7 +224,7 @@ public class ExpressionCompiler extends UnsupportedAllParseNodeVisitor<Expressio private Expression orExpression(List<Expression> children) throws SQLException { Iterator<Expression> iterator = children.iterator(); - boolean isDeterministic = true; + Determinism determinism = Determinism.ALWAYS; while (iterator.hasNext()) { Expression child = iterator.next(); if (child.getDataType() != PDataType.BOOLEAN) { @@ -235,10 +236,10 @@ public class ExpressionCompiler extends UnsupportedAllParseNodeVisitor<Expressio if (LiteralExpression.isTrue(child)) { return child; } - isDeterministic &= child.isDeterministic(); + determinism = determinism.combine(child.getDeterminism()); } if (children.size() == 0) { - return LiteralExpression.newConstant(true, isDeterministic); + return LiteralExpression.newConstant(true, determinism); } if (children.size() == 1) { return children.get(0); @@ -376,12 +377,12 @@ public class ExpressionCompiler extends UnsupportedAllParseNodeVisitor<Expressio @Override public Expression visit(BindParseNode node) throws SQLException { Object value = context.getBindManager().getBindValue(node); - return LiteralExpression.newConstant(value, true); + return LiteralExpression.newConstant(value, Determinism.ALWAYS); } @Override public Expression visit(LiteralParseNode node) throws SQLException { - return LiteralExpression.newConstant(node.getValue(), node.getType(), true); + return LiteralExpression.newConstant(node.getValue(), node.getType(), Determinism.ALWAYS); } @Override @@ -401,13 +402,12 @@ public class ExpressionCompiler extends UnsupportedAllParseNodeVisitor<Expressio return true; } - private static boolean isDeterministic(List<Expression> l) { + private static Determinism getDeterminism(List<Expression> l) { + Determinism determinism = Determinism.ALWAYS; for (Expression e : l) { - if (!e.isDeterministic()) { - return false; - } + determinism.combine(e.getDeterminism()); } - return true; + return determinism; } @Override @@ -423,7 +423,7 @@ public class ExpressionCompiler extends UnsupportedAllParseNodeVisitor<Expressio ImmutableBytesWritable ptr = context.getTempPtr(); int index = caseExpression.evaluateIndexOf(null, ptr); if (index < 0) { - return LiteralExpression.newConstant(null, isDeterministic(l)); + return LiteralExpression.newConstant(null, getDeterminism(l)); } return caseExpression.getChildren().get(index); } @@ -455,7 +455,7 @@ public class ExpressionCompiler extends UnsupportedAllParseNodeVisitor<Expressio if (rhs instanceof LiteralExpression) { String pattern = (String)((LiteralExpression)rhs).getValue(); if (pattern == null || pattern.length() == 0) { - return LiteralExpression.newConstant(null, rhs.isDeterministic()); + return LiteralExpression.newConstant(null, rhs.getDeterminism()); } // TODO: for pattern of '%' optimize to strlength(lhs) > 0 // We can't use lhs IS NOT NULL b/c if lhs is NULL we need @@ -464,19 +464,19 @@ public class ExpressionCompiler extends UnsupportedAllParseNodeVisitor<Expressio // Can't possibly be as long as the constant, then FALSE Integer lhsMaxLength = lhs.getMaxLength(); if (lhsMaxLength != null && lhsMaxLength < index) { - return LiteralExpression.newConstant(false, rhs.isDeterministic()); + return LiteralExpression.newConstant(false, rhs.getDeterminism()); } if (index == -1) { String rhsLiteral = LikeExpression.unescapeLike(pattern); if (lhsMaxLength != null && lhsMaxLength != rhsLiteral.length()) { - return LiteralExpression.newConstant(false, rhs.isDeterministic()); + return LiteralExpression.newConstant(false, rhs.getDeterminism()); } if (node.getLikeType() == LikeType.CASE_SENSITIVE) { CompareOp op = node.isNegate() ? CompareOp.NOT_EQUAL : CompareOp.EQUAL; if (pattern.equals(rhsLiteral)) { return new ComparisonExpression(op, children); } else { - rhs = LiteralExpression.newConstant(rhsLiteral, PDataType.CHAR, rhs.isDeterministic()); + rhs = LiteralExpression.newConstant(rhsLiteral, PDataType.CHAR, rhs.getDeterminism()); return new ComparisonExpression(op, Arrays.asList(lhs,rhs)); } } @@ -486,9 +486,9 @@ public class ExpressionCompiler extends UnsupportedAllParseNodeVisitor<Expressio if (ExpressionUtil.isConstant(expression)) { ImmutableBytesWritable ptr = context.getTempPtr(); if (!expression.evaluate(null, ptr)) { - return LiteralExpression.newConstant(null, expression.isDeterministic()); + return LiteralExpression.newConstant(null, expression.getDeterminism()); } else { - return LiteralExpression.newConstant(Boolean.TRUE.equals(PDataType.BOOLEAN.toObject(ptr)) ^ node.isNegate(), expression.isDeterministic()); + return LiteralExpression.newConstant(Boolean.TRUE.equals(PDataType.BOOLEAN.toObject(ptr)) ^ node.isNegate(), expression.getDeterminism()); } } if (node.isNegate()) { @@ -672,7 +672,7 @@ public class ExpressionCompiler extends UnsupportedAllParseNodeVisitor<Expressio return ExpressionUtil.getConstantExpression(expression, ptr); } else if (isNull) { - return LiteralExpression.newConstant(null, expression.getDataType(), expression.isDeterministic()); + return LiteralExpression.newConstant(null, expression.getDataType(), expression.getDeterminism()); } // Otherwise create and return the expression return wrapGroupByExpression(expression); @@ -721,11 +721,11 @@ public class ExpressionCompiler extends UnsupportedAllParseNodeVisitor<Expressio @Override public Expression create(ArithmeticParseNode node, List<Expression> children) throws SQLException { boolean foundDate = false; - boolean isDeterministic = true; + Determinism determinism = Determinism.ALWAYS; PDataType theType = null; for(int i = 0; i < children.size(); i++) { Expression e = children.get(i); - isDeterministic &= e.isDeterministic(); + determinism = determinism.combine(e.getDeterminism()); PDataType type = e.getDataType(); if (type == null) { continue; @@ -760,7 +760,7 @@ public class ExpressionCompiler extends UnsupportedAllParseNodeVisitor<Expressio } else if (theType == PDataType.DOUBLE) { return new DoubleAddExpression(children); } else if (theType == null) { - return LiteralExpression.newConstant(null, theType, isDeterministic); + return LiteralExpression.newConstant(null, theType, determinism); } else if (theType == PDataType.TIMESTAMP || theType == PDataType.UNSIGNED_TIMESTAMP) { return new TimestampAddExpression(children); } else if (theType.isCoercibleTo(PDataType.DATE)) { @@ -848,7 +848,7 @@ public class ExpressionCompiler extends UnsupportedAllParseNodeVisitor<Expressio PDataType theType = null; Expression e1 = children.get(0); Expression e2 = children.get(1); - boolean isDeterministic = e1.isDeterministic() && e2.isDeterministic(); + Determinism determinism = e1.getDeterminism().combine(e2.getDeterminism()); PDataType type1 = e1.getDataType(); PDataType type2 = e2.getDataType(); // TODO: simplify this special case for DATE conversion @@ -900,7 +900,7 @@ public class ExpressionCompiler extends UnsupportedAllParseNodeVisitor<Expressio // This logic finds the common type to which all child types are coercible // without losing precision. Expression e = children.get(i); - isDeterministic &= e.isDeterministic(); + determinism = determinism.combine(e.getDeterminism()); PDataType type = e.getDataType(); if (type == null) { continue; @@ -933,7 +933,7 @@ public class ExpressionCompiler extends UnsupportedAllParseNodeVisitor<Expressio } else if (theType == PDataType.DOUBLE) { return new DoubleSubtractExpression(children); } else if (theType == null) { - return LiteralExpression.newConstant(null, theType, isDeterministic); + return LiteralExpression.newConstant(null, theType, determinism); } else if (theType == PDataType.TIMESTAMP || theType == PDataType.UNSIGNED_TIMESTAMP) { return new TimestampSubtractExpression(children); } else if (theType.isCoercibleTo(PDataType.DATE)) { @@ -956,10 +956,10 @@ public class ExpressionCompiler extends UnsupportedAllParseNodeVisitor<Expressio @Override public Expression create(ArithmeticParseNode node, List<Expression> children) throws SQLException { PDataType theType = null; - boolean isDeterministic = true; + Determinism determinism = Determinism.ALWAYS; for(int i = 0; i < children.size(); i++) { Expression e = children.get(i); - isDeterministic &= e.isDeterministic(); + determinism = determinism.combine(e.getDeterminism()); PDataType type = e.getDataType(); if (type == null) { continue; @@ -985,7 +985,7 @@ public class ExpressionCompiler extends UnsupportedAllParseNodeVisitor<Expressio case DOUBLE: return new DoubleMultiplyExpression( children); default: - return LiteralExpression.newConstant(null, theType, isDeterministic); + return LiteralExpression.newConstant(null, theType, determinism); } } }); @@ -1017,10 +1017,10 @@ public class ExpressionCompiler extends UnsupportedAllParseNodeVisitor<Expressio @Override public Expression create(ArithmeticParseNode node, List<Expression> children) throws SQLException { PDataType theType = null; - boolean isDeterministic = true; + Determinism determinism = Determinism.ALWAYS; for(int i = 0; i < children.size(); i++) { Expression e = children.get(i); - isDeterministic &= e.isDeterministic(); + determinism = determinism.combine(e.getDeterminism()); PDataType type = e.getDataType(); if (type == null) { continue; @@ -1046,7 +1046,7 @@ public class ExpressionCompiler extends UnsupportedAllParseNodeVisitor<Expressio case DOUBLE: return new DoubleDivideExpression(children); default: - return LiteralExpression.newConstant(null, theType, isDeterministic); + return LiteralExpression.newConstant(null, theType, determinism); } } }); @@ -1211,11 +1211,11 @@ public class ExpressionCompiler extends UnsupportedAllParseNodeVisitor<Expressio Expression child = children.get(i); child.evaluate(null, ptr); Object value = arrayElemDataType.toObject(ptr, child.getDataType(), child.getSortOrder()); - elements[i] = LiteralExpression.newConstant(value, child.getDataType(), child.isDeterministic()).getValue(); + elements[i] = LiteralExpression.newConstant(value, child.getDataType(), child.getDeterminism()).getValue(); } Object value = PArrayDataType.instantiatePhoenixArray(arrayElemDataType, elements); return LiteralExpression.newConstant(value, - PDataType.fromTypeId(arrayElemDataType.getSqlType() + PDataType.ARRAY_TYPE_BASE), true); + PDataType.fromTypeId(arrayElemDataType.getSqlType() + PDataType.ARRAY_TYPE_BASE), Determinism.ALWAYS); } return wrapGroupByExpression(arrayExpression); http://git-wip-us.apache.org/repos/asf/phoenix/blob/9cf34400/phoenix-core/src/main/java/org/apache/phoenix/compile/SequenceManager.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/compile/SequenceManager.java b/phoenix-core/src/main/java/org/apache/phoenix/compile/SequenceManager.java index de352b5..9be45a4 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/compile/SequenceManager.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/compile/SequenceManager.java @@ -26,6 +26,7 @@ import java.util.Map; import org.apache.hadoop.hbase.HConstants; import org.apache.hadoop.hbase.io.ImmutableBytesWritable; import org.apache.phoenix.expression.BaseTerminalExpression; +import org.apache.phoenix.expression.Determinism; import org.apache.phoenix.jdbc.PhoenixStatement; import org.apache.phoenix.parse.SequenceValueParseNode; import org.apache.phoenix.parse.TableName; @@ -202,8 +203,8 @@ public class SequenceManager { } @Override - public boolean isDeterministic() { - return false; + public Determinism getDeterminism() { + return Determinism.PER_ROW; } @Override http://git-wip-us.apache.org/repos/asf/phoenix/blob/9cf34400/phoenix-core/src/main/java/org/apache/phoenix/compile/UpsertCompiler.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/compile/UpsertCompiler.java b/phoenix-core/src/main/java/org/apache/phoenix/compile/UpsertCompiler.java index b8e1a6d..add8e61 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/compile/UpsertCompiler.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/compile/UpsertCompiler.java @@ -42,6 +42,7 @@ import org.apache.phoenix.exception.SQLExceptionCode; import org.apache.phoenix.exception.SQLExceptionInfo; import org.apache.phoenix.execute.AggregatePlan; import org.apache.phoenix.execute.MutationState; +import org.apache.phoenix.expression.Determinism; import org.apache.phoenix.expression.Expression; import org.apache.phoenix.expression.LiteralExpression; import org.apache.phoenix.hbase.index.util.ImmutableBytesPtr; @@ -511,7 +512,7 @@ public class UpsertCompiler { } // Add literal null for missing PK columns pos = projectedExpressions.size(); - Expression literalNull = LiteralExpression.newConstant(null, column.getDataType(), true); + Expression literalNull = LiteralExpression.newConstant(null, column.getDataType(), Determinism.ALWAYS); projectedExpressions.add(literalNull); allColumnsIndexes[pos] = column.getPosition(); } @@ -812,7 +813,7 @@ public class UpsertCompiler { if (isTopLevel()) { context.getBindManager().addParamMetaData(node, column); Object value = context.getBindManager().getBindValue(node); - return LiteralExpression.newConstant(value, column.getDataType(), column.getSortOrder(), true); + return LiteralExpression.newConstant(value, column.getDataType(), column.getSortOrder(), Determinism.ALWAYS); } return super.visit(node); } @@ -820,7 +821,7 @@ public class UpsertCompiler { @Override public Expression visit(LiteralParseNode node) throws SQLException { if (isTopLevel()) { - return LiteralExpression.newConstant(node.getValue(), column.getDataType(), column.getSortOrder(), true); + return LiteralExpression.newConstant(node.getValue(), column.getDataType(), column.getSortOrder(), Determinism.ALWAYS); } return super.visit(node); } http://git-wip-us.apache.org/repos/asf/phoenix/blob/9cf34400/phoenix-core/src/main/java/org/apache/phoenix/compile/WhereCompiler.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/compile/WhereCompiler.java b/phoenix-core/src/main/java/org/apache/phoenix/compile/WhereCompiler.java index cd06554..b5f120f 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/compile/WhereCompiler.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/compile/WhereCompiler.java @@ -29,6 +29,7 @@ import org.apache.hadoop.hbase.filter.Filter; import org.apache.phoenix.exception.SQLExceptionCode; import org.apache.phoenix.exception.SQLExceptionInfo; import org.apache.phoenix.expression.AndExpression; +import org.apache.phoenix.expression.Determinism; import org.apache.phoenix.expression.Expression; import org.apache.phoenix.expression.KeyValueColumnExpression; import org.apache.phoenix.expression.LiteralExpression; @@ -118,7 +119,7 @@ public class WhereCompiler { Set<Expression> extractedNodes = Sets.<Expression>newHashSet(); WhereExpressionCompiler whereCompiler = new WhereExpressionCompiler(context); - Expression expression = where == null ? LiteralExpression.newConstant(true,PDataType.BOOLEAN,true) : where.accept(whereCompiler); + Expression expression = where == null ? LiteralExpression.newConstant(true,PDataType.BOOLEAN,Determinism.ALWAYS) : where.accept(whereCompiler); if (whereCompiler.isAggregate()) { throw new SQLExceptionInfo.Builder(SQLExceptionCode.AGGREGATE_IN_WHERE).build().buildException(); } http://git-wip-us.apache.org/repos/asf/phoenix/blob/9cf34400/phoenix-core/src/main/java/org/apache/phoenix/compile/WhereOptimizer.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/compile/WhereOptimizer.java b/phoenix-core/src/main/java/org/apache/phoenix/compile/WhereOptimizer.java index 634bd15..ec763fd 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/compile/WhereOptimizer.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/compile/WhereOptimizer.java @@ -37,6 +37,7 @@ import org.apache.phoenix.expression.BaseExpression.ExpressionComparabilityWrapp import org.apache.phoenix.expression.BaseTerminalExpression; import org.apache.phoenix.expression.CoerceExpression; import org.apache.phoenix.expression.ComparisonExpression; +import org.apache.phoenix.expression.Determinism; import org.apache.phoenix.expression.Expression; import org.apache.phoenix.expression.InListExpression; import org.apache.phoenix.expression.IsNullExpression; @@ -407,7 +408,7 @@ public class WhereOptimizer { if (l.size() != node.getChildren().size()) { if (l.isEmpty()) { // Don't return null here, because then our defaultReturn will kick in - return LiteralExpression.newConstant(true, true); + return LiteralExpression.newConstant(true, Determinism.ALWAYS); } if (l.size() == 1) { return l.get(0); http://git-wip-us.apache.org/repos/asf/phoenix/blob/9cf34400/phoenix-core/src/main/java/org/apache/phoenix/execute/HashJoinPlan.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/execute/HashJoinPlan.java b/phoenix-core/src/main/java/org/apache/phoenix/execute/HashJoinPlan.java index 5ffcaeb..8d141dd 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/execute/HashJoinPlan.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/execute/HashJoinPlan.java @@ -47,6 +47,7 @@ import org.apache.phoenix.exception.SQLExceptionCode; import org.apache.phoenix.exception.SQLExceptionInfo; import org.apache.phoenix.expression.AndExpression; import org.apache.phoenix.expression.ComparisonExpression; +import org.apache.phoenix.expression.Determinism; import org.apache.phoenix.expression.Expression; import org.apache.phoenix.expression.InListExpression; import org.apache.phoenix.expression.LiteralExpression; @@ -213,7 +214,7 @@ public class HashJoinPlan implements QueryPlan { Expression rhsExpression, List<ImmutableBytesWritable> rhsValues, ImmutableBytesWritable ptr, boolean hasFilters) throws SQLException { if (rhsValues.isEmpty()) - return LiteralExpression.newConstant(null, PDataType.BOOLEAN, true); + return LiteralExpression.newConstant(null, PDataType.BOOLEAN, Determinism.ALWAYS); PDataType type = rhsExpression.getDataType(); if (!useInClause(hasFilters)) { http://git-wip-us.apache.org/repos/asf/phoenix/blob/9cf34400/phoenix-core/src/main/java/org/apache/phoenix/expression/AndExpression.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/AndExpression.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/AndExpression.java index 2806394..e9c2740 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/expression/AndExpression.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/AndExpression.java @@ -37,7 +37,7 @@ public class AndExpression extends AndOrExpression { private static final String AND = "AND"; public static Expression create(List<Expression> children) throws SQLException { - boolean isDeterministic = true; + Determinism determinism = Determinism.ALWAYS; Iterator<Expression> iterator = children.iterator(); while (iterator.hasNext()) { Expression child = iterator.next(); @@ -50,10 +50,10 @@ public class AndExpression extends AndOrExpression { if (LiteralExpression.isTrue(child)) { iterator.remove(); } - isDeterministic &= child.isDeterministic(); + determinism.combine(child.getDeterminism()); } if (children.size() == 0) { - return LiteralExpression.newConstant(true, isDeterministic); + return LiteralExpression.newConstant(true, determinism); } if (children.size() == 1) { return children.get(0); http://git-wip-us.apache.org/repos/asf/phoenix/blob/9cf34400/phoenix-core/src/main/java/org/apache/phoenix/expression/BaseCompoundExpression.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/BaseCompoundExpression.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/BaseCompoundExpression.java index 03df653..bd6161c 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/expression/BaseCompoundExpression.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/BaseCompoundExpression.java @@ -34,7 +34,7 @@ public abstract class BaseCompoundExpression extends BaseExpression { protected List<Expression> children; private boolean isNullable; private boolean isStateless; - private boolean isDeterministic; + private Determinism determinism; private boolean requiresFinalEvaluation; public BaseCompoundExpression() { @@ -48,18 +48,17 @@ public abstract class BaseCompoundExpression extends BaseExpression { private void init(List<Expression> children) { this.children = ImmutableList.copyOf(children); boolean isStateless = true; - boolean isDeterministic = true; boolean isNullable = false; boolean requiresFinalEvaluation = false; + this.determinism = Determinism.ALWAYS; for (int i = 0; i < children.size(); i++) { Expression child = children.get(i); isNullable |= child.isNullable(); isStateless &= child.isStateless(); - isDeterministic &= child.isDeterministic(); + this.determinism = this.determinism.combine(child.getDeterminism()); requiresFinalEvaluation |= child.requiresFinalEvaluation(); } this.isStateless = isStateless; - this.isDeterministic = isDeterministic; this.isNullable = isNullable; this.requiresFinalEvaluation = requiresFinalEvaluation; } @@ -71,8 +70,8 @@ public abstract class BaseCompoundExpression extends BaseExpression { @Override - public boolean isDeterministic() { - return isDeterministic; + public Determinism getDeterminism() { + return determinism; } @Override http://git-wip-us.apache.org/repos/asf/phoenix/blob/9cf34400/phoenix-core/src/main/java/org/apache/phoenix/expression/BaseExpression.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/BaseExpression.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/BaseExpression.java index fac82a8..8993e37 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/expression/BaseExpression.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/BaseExpression.java @@ -168,7 +168,7 @@ public abstract class BaseExpression implements Expression { } else if (lhs == null) { return rhs; } else if (rhs == null) { - return LiteralExpression.newConstant(null, lhs.getDataType(), lhs.isDeterministic()); + return LiteralExpression.newConstant(null, lhs.getDataType(), lhs.getDeterminism()); } else { if (rhs.getDataType() != null && lhs.getDataType() != null && !rhs.getDataType().isCastableTo(lhs.getDataType())) { throw TypeMismatchException.newException(lhs.getDataType(), rhs.getDataType()); @@ -239,8 +239,8 @@ public abstract class BaseExpression implements Expression { } @Override - public boolean isDeterministic() { - return true; + public Determinism getDeterminism() { + return Determinism.ALWAYS; } @Override http://git-wip-us.apache.org/repos/asf/phoenix/blob/9cf34400/phoenix-core/src/main/java/org/apache/phoenix/expression/ComparisonExpression.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/ComparisonExpression.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/ComparisonExpression.java index 8e352e6..a1ed221 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/expression/ComparisonExpression.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/ComparisonExpression.java @@ -133,7 +133,7 @@ public class ComparisonExpression extends BaseCompoundExpression { } else if(lhsExprDataType != null && rhsExprDataType != null && !lhsExprDataType.isComparableTo(rhsExprDataType)) { throw TypeMismatchException.newException(lhsExprDataType, rhsExprDataType, toString(op, children)); } - boolean isDeterministic = lhsExpr.isDeterministic() || rhsExpr.isDeterministic(); + Determinism determinism = lhsExpr.getDeterminism().combine(rhsExpr.getDeterminism()); Object lhsValue = null; // Can't use lhsNode.isConstant(), because we have cases in which we don't know @@ -142,7 +142,7 @@ public class ComparisonExpression extends BaseCompoundExpression { if (lhsExpr instanceof LiteralExpression) { lhsValue = ((LiteralExpression)lhsExpr).getValue(); if (lhsValue == null) { - return LiteralExpression.newConstant(false, PDataType.BOOLEAN, lhsExpr.isDeterministic()); + return LiteralExpression.newConstant(false, PDataType.BOOLEAN, lhsExpr.getDeterminism()); } } Object rhsValue = null; @@ -150,11 +150,11 @@ public class ComparisonExpression extends BaseCompoundExpression { if (rhsExpr instanceof LiteralExpression) { rhsValue = ((LiteralExpression)rhsExpr).getValue(); if (rhsValue == null) { - return LiteralExpression.newConstant(false, PDataType.BOOLEAN, rhsExpr.isDeterministic()); + return LiteralExpression.newConstant(false, PDataType.BOOLEAN, rhsExpr.getDeterminism()); } } if (lhsValue != null && rhsValue != null) { - return LiteralExpression.newConstant(ByteUtil.compare(op,lhsExprDataType.compareTo(lhsValue, rhsValue, rhsExprDataType)), isDeterministic); + return LiteralExpression.newConstant(ByteUtil.compare(op,lhsExprDataType.compareTo(lhsValue, rhsValue, rhsExprDataType)), determinism); } // Coerce constant to match type of lhs so that we don't need to // convert at filter time. Since we normalize the select statement @@ -168,11 +168,11 @@ public class ComparisonExpression extends BaseCompoundExpression { // TODO: if lengths are unequal and fixed width? if (rhsExprDataType.isCoercibleTo(lhsExprDataType, rhsValue)) { // will convert 2.0 -> 2 children = Arrays.asList(children.get(0), LiteralExpression.newConstant(rhsValue, lhsExprDataType, - lhsExpr.getMaxLength(), null, lhsExpr.getSortOrder(), isDeterministic)); + lhsExpr.getMaxLength(), null, lhsExpr.getSortOrder(), determinism)); } else if (op == CompareOp.EQUAL) { - return LiteralExpression.newConstant(false, PDataType.BOOLEAN, true); + return LiteralExpression.newConstant(false, PDataType.BOOLEAN, Determinism.ALWAYS); } else if (op == CompareOp.NOT_EQUAL) { - return LiteralExpression.newConstant(true, PDataType.BOOLEAN, true); + return LiteralExpression.newConstant(true, PDataType.BOOLEAN, Determinism.ALWAYS); } else { // TODO: generalize this with PDataType.getMinValue(), PDataTypeType.getMaxValue() methods switch(rhsExprDataType) { case DECIMAL: @@ -190,7 +190,7 @@ public class ComparisonExpression extends BaseCompoundExpression { default: // Else, we truncate the value BigDecimal bd = (BigDecimal)rhsValue; rhsValue = bd.longValue() + increment; - children = Arrays.asList(lhsExpr, LiteralExpression.newConstant(rhsValue, lhsExprDataType, lhsExpr.getSortOrder(), rhsExpr.isDeterministic())); + children = Arrays.asList(lhsExpr, LiteralExpression.newConstant(rhsValue, lhsExprDataType, lhsExpr.getSortOrder(), rhsExpr.getDeterminism())); break; } break; @@ -212,16 +212,16 @@ public class ComparisonExpression extends BaseCompoundExpression { case LESS: case LESS_OR_EQUAL: if ((Long)rhsValue > 0) { - return LiteralExpression.newConstant(true, PDataType.BOOLEAN, isDeterministic); + return LiteralExpression.newConstant(true, PDataType.BOOLEAN, determinism); } else { - return LiteralExpression.newConstant(false, PDataType.BOOLEAN, isDeterministic); + return LiteralExpression.newConstant(false, PDataType.BOOLEAN, determinism); } case GREATER: case GREATER_OR_EQUAL: if ((Long)rhsValue > 0) { - return LiteralExpression.newConstant(false, PDataType.BOOLEAN, isDeterministic); + return LiteralExpression.newConstant(false, PDataType.BOOLEAN, determinism); } else { - return LiteralExpression.newConstant(true, PDataType.BOOLEAN, isDeterministic); + return LiteralExpression.newConstant(true, PDataType.BOOLEAN, determinism); } default: break; @@ -230,15 +230,15 @@ public class ComparisonExpression extends BaseCompoundExpression { switch (op) { case LESS: case LESS_OR_EQUAL: - return LiteralExpression.newConstant(false, PDataType.BOOLEAN, isDeterministic); + return LiteralExpression.newConstant(false, PDataType.BOOLEAN, determinism); case GREATER: case GREATER_OR_EQUAL: - return LiteralExpression.newConstant(true, PDataType.BOOLEAN, isDeterministic); + return LiteralExpression.newConstant(true, PDataType.BOOLEAN, determinism); default: break; } } - children = Arrays.asList(lhsExpr, LiteralExpression.newConstant(rhsValue, rhsExprDataType, lhsExpr.getSortOrder(), isDeterministic)); + children = Arrays.asList(lhsExpr, LiteralExpression.newConstant(rhsValue, rhsExprDataType, lhsExpr.getSortOrder(), determinism)); break; } } @@ -249,9 +249,9 @@ public class ComparisonExpression extends BaseCompoundExpression { if (children.get(1).getMaxLength() != null && lhsExpr.getMaxLength() != null && lhsExpr.getMaxLength() < children.get(1).getMaxLength()) { switch (op) { case EQUAL: - return LiteralExpression.newConstant(false, PDataType.BOOLEAN, isDeterministic); + return LiteralExpression.newConstant(false, PDataType.BOOLEAN, determinism); case NOT_EQUAL: - return LiteralExpression.newConstant(true, PDataType.BOOLEAN, isDeterministic); + return LiteralExpression.newConstant(true, PDataType.BOOLEAN, determinism); default: break; } http://git-wip-us.apache.org/repos/asf/phoenix/blob/9cf34400/phoenix-core/src/main/java/org/apache/phoenix/expression/CurrentDateTimeFunction.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/CurrentDateTimeFunction.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/CurrentDateTimeFunction.java index 63e6d23..0b5faa2 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/expression/CurrentDateTimeFunction.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/CurrentDateTimeFunction.java @@ -36,7 +36,7 @@ public abstract class CurrentDateTimeFunction extends ScalarFunction { } @Override - public boolean isDeterministic() { - return false; + public Determinism getDeterminism() { + return Determinism.PER_STATEMENT; } } http://git-wip-us.apache.org/repos/asf/phoenix/blob/9cf34400/phoenix-core/src/main/java/org/apache/phoenix/expression/Determinism.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/Determinism.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/Determinism.java new file mode 100644 index 0000000..b2f3524 --- /dev/null +++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/Determinism.java @@ -0,0 +1,19 @@ +/* + * 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.expression; + +public enum Determinism { + + ALWAYS, PER_STATEMENT, PER_ROW; + + public Determinism combine (Determinism that) { + return Determinism.values()[Math.max(this.ordinal(), that.ordinal())]; + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/phoenix/blob/9cf34400/phoenix-core/src/main/java/org/apache/phoenix/expression/Expression.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/Expression.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/Expression.java index ccd4d7b..aeea0c8 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/expression/Expression.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/Expression.java @@ -34,6 +34,7 @@ import org.apache.phoenix.schema.tuple.Tuple; * @since 0.1 */ public interface Expression extends PDatum, Writable { + /** * Access the value by setting a pointer to it (as opposed to making * a copy of it which can be expensive) @@ -75,10 +76,9 @@ public interface Expression extends PDatum, Writable { boolean isStateless(); /** - * @return true if the expression returns the same output every - * time given the same input. + * @return Determinism enum */ - boolean isDeterministic(); + Determinism getDeterminism(); /** * Determines if an evaluate is required after partial evaluation http://git-wip-us.apache.org/repos/asf/phoenix/blob/9cf34400/phoenix-core/src/main/java/org/apache/phoenix/expression/InListExpression.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/InListExpression.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/InListExpression.java index c171153..fdb20ff 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/expression/InListExpression.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/InListExpression.java @@ -60,7 +60,7 @@ public class InListExpression extends BaseSingleExpression { Expression firstChild = children.get(0); if (firstChild.isStateless() && (!firstChild.evaluate(null, ptr) || ptr.getLength() == 0)) { - return LiteralExpression.newConstant(null, PDataType.BOOLEAN, firstChild.isDeterministic()); + return LiteralExpression.newConstant(null, PDataType.BOOLEAN, firstChild.getDeterminism()); } if (children.size() == 2) { return ComparisonExpression.create(isNegate ? CompareOp.NOT_EQUAL : CompareOp.EQUAL, children, ptr); @@ -86,7 +86,7 @@ public class InListExpression extends BaseSingleExpression { throw sqlE; } if (coercedKeyExpressions.size() == 2 && addedNull) { - return LiteralExpression.newConstant(null, PDataType.BOOLEAN, true); + return LiteralExpression.newConstant(null, PDataType.BOOLEAN, Determinism.ALWAYS); } Expression expression = new InListExpression(coercedKeyExpressions); if (isNegate) { http://git-wip-us.apache.org/repos/asf/phoenix/blob/9cf34400/phoenix-core/src/main/java/org/apache/phoenix/expression/IsNullExpression.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/IsNullExpression.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/IsNullExpression.java index 4162dfc..3fb7a62 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/expression/IsNullExpression.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/IsNullExpression.java @@ -42,11 +42,11 @@ public class IsNullExpression extends BaseSingleExpression { public static Expression create(Expression child, boolean negate, ImmutableBytesWritable ptr) throws SQLException { if (!child.isNullable()) { - return LiteralExpression.newConstant(negate, PDataType.BOOLEAN, child.isDeterministic()); + return LiteralExpression.newConstant(negate, PDataType.BOOLEAN, child.getDeterminism()); } if (ExpressionUtil.isConstant(child)) { boolean evaluated = child.evaluate(null, ptr); - return LiteralExpression.newConstant(negate ^ (!evaluated || ptr.getLength() == 0), PDataType.BOOLEAN, child.isDeterministic()); + return LiteralExpression.newConstant(negate ^ (!evaluated || ptr.getLength() == 0), PDataType.BOOLEAN, child.getDeterminism()); } return new IsNullExpression(child, negate); } http://git-wip-us.apache.org/repos/asf/phoenix/blob/9cf34400/phoenix-core/src/main/java/org/apache/phoenix/expression/LiteralExpression.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/LiteralExpression.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/LiteralExpression.java index 91a3125..a84135c 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/expression/LiteralExpression.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/LiteralExpression.java @@ -48,25 +48,25 @@ import com.google.common.base.Preconditions; * @since 0.1 */ public class LiteralExpression extends BaseTerminalExpression { - public static final LiteralExpression NULL_EXPRESSION = new LiteralExpression(null, true); - private static final LiteralExpression ND_NULL_EXPRESSION = new LiteralExpression(null, false); + public static final LiteralExpression NULL_EXPRESSION = new LiteralExpression(null, Determinism.ALWAYS); + private static final LiteralExpression ND_NULL_EXPRESSION = new LiteralExpression(null, Determinism.PER_ROW); private static final LiteralExpression[] TYPED_NULL_EXPRESSIONS = new LiteralExpression[PDataType.values().length * 2]; static { for (int i = 0; i < PDataType.values().length; i++) { - TYPED_NULL_EXPRESSIONS[i] = new LiteralExpression(PDataType.values()[i], true); + TYPED_NULL_EXPRESSIONS[i] = new LiteralExpression(PDataType.values()[i], Determinism.ALWAYS); } for (int i = 0; i < PDataType.values().length; i++) { - TYPED_NULL_EXPRESSIONS[i+PDataType.values().length] = new LiteralExpression(PDataType.values()[i], false); + TYPED_NULL_EXPRESSIONS[i+PDataType.values().length] = new LiteralExpression(PDataType.values()[i], Determinism.PER_ROW); } } - private static final LiteralExpression FALSE_EXPRESSION = new LiteralExpression(Boolean.FALSE, PDataType.BOOLEAN, PDataType.BOOLEAN.toBytes(Boolean.FALSE), true); - private static final LiteralExpression TRUE_EXPRESSION = new LiteralExpression(Boolean.TRUE, PDataType.BOOLEAN, PDataType.BOOLEAN.toBytes(Boolean.TRUE), true); - private static final LiteralExpression ND_FALSE_EXPRESSION = new LiteralExpression(Boolean.FALSE, PDataType.BOOLEAN, PDataType.BOOLEAN.toBytes(Boolean.FALSE), false); - private static final LiteralExpression ND_TRUE_EXPRESSION = new LiteralExpression(Boolean.TRUE, PDataType.BOOLEAN, PDataType.BOOLEAN.toBytes(Boolean.TRUE), false); + private static final LiteralExpression FALSE_EXPRESSION = new LiteralExpression(Boolean.FALSE, PDataType.BOOLEAN, PDataType.BOOLEAN.toBytes(Boolean.FALSE), Determinism.ALWAYS); + private static final LiteralExpression TRUE_EXPRESSION = new LiteralExpression(Boolean.TRUE, PDataType.BOOLEAN, PDataType.BOOLEAN.toBytes(Boolean.TRUE), Determinism.ALWAYS); + private static final LiteralExpression ND_FALSE_EXPRESSION = new LiteralExpression(Boolean.FALSE, PDataType.BOOLEAN, PDataType.BOOLEAN.toBytes(Boolean.FALSE), Determinism.PER_ROW); + private static final LiteralExpression ND_TRUE_EXPRESSION = new LiteralExpression(Boolean.TRUE, PDataType.BOOLEAN, PDataType.BOOLEAN.toBytes(Boolean.TRUE), Determinism.PER_ROW); private Object value; private PDataType type; - private boolean isDeterministic; + private Determinism determinism; private byte[] byteValue; private Integer maxLength; private Integer scale; @@ -82,24 +82,24 @@ public class LiteralExpression extends BaseTerminalExpression { } public static LiteralExpression newConstant(Object value) { - return newConstant(value, true); + return newConstant(value, Determinism.ALWAYS); } // TODO: cache? - public static LiteralExpression newConstant(Object value, boolean isDeterministic) { + public static LiteralExpression newConstant(Object value, Determinism determinism) { if (Boolean.FALSE.equals(value)) { - return isDeterministic ? FALSE_EXPRESSION : ND_FALSE_EXPRESSION; + return determinism == Determinism.ALWAYS ? FALSE_EXPRESSION : ND_FALSE_EXPRESSION; } if (Boolean.TRUE.equals(value)) { - return isDeterministic ? TRUE_EXPRESSION : ND_TRUE_EXPRESSION; + return determinism == Determinism.ALWAYS ? TRUE_EXPRESSION : ND_TRUE_EXPRESSION; } if (value == null) { - return isDeterministic ? NULL_EXPRESSION : ND_NULL_EXPRESSION; + return determinism == Determinism.ALWAYS ? NULL_EXPRESSION : ND_NULL_EXPRESSION; } PDataType type = PDataType.fromLiteral(value); byte[] b = type.toBytes(value); if (type.isNull(b)) { - return TYPED_NULL_EXPRESSIONS[type.ordinal() + ( isDeterministic ? 0 : TYPED_NULL_EXPRESSIONS.length/2)]; + return TYPED_NULL_EXPRESSIONS[type.ordinal() + ( determinism == Determinism.ALWAYS ? 0 : TYPED_NULL_EXPRESSIONS.length/2)]; } if (type == PDataType.VARCHAR) { String s = (String) value; @@ -107,35 +107,35 @@ public class LiteralExpression extends BaseTerminalExpression { type = PDataType.CHAR; } } - return new LiteralExpression(value, type, b, isDeterministic); + return new LiteralExpression(value, type, b, determinism); } public static LiteralExpression newConstant(Object value, PDataType type) throws SQLException { - return newConstant(value, type, true); + return newConstant(value, type, Determinism.ALWAYS); } - public static LiteralExpression newConstant(Object value, PDataType type, boolean isDeterministic) throws SQLException { - return newConstant(value, type, SortOrder.getDefault(), isDeterministic); + public static LiteralExpression newConstant(Object value, PDataType type, Determinism determinism) throws SQLException { + return newConstant(value, type, SortOrder.getDefault(), determinism); } public static LiteralExpression newConstant(Object value, PDataType type, SortOrder sortOrder) throws SQLException { - return newConstant(value, type, null, null, sortOrder, true); + return newConstant(value, type, null, null, sortOrder, Determinism.ALWAYS); } - public static LiteralExpression newConstant(Object value, PDataType type, SortOrder sortOrder, boolean isDeterministic) throws SQLException { - return newConstant(value, type, null, null, sortOrder, isDeterministic); + public static LiteralExpression newConstant(Object value, PDataType type, SortOrder sortOrder, Determinism determinism) throws SQLException { + return newConstant(value, type, null, null, sortOrder, determinism); } public static LiteralExpression newConstant(Object value, PDataType type, Integer maxLength, Integer scale) throws SQLException { - return newConstant(value, type, maxLength, scale, SortOrder.getDefault(), true); + return newConstant(value, type, maxLength, scale, SortOrder.getDefault(), Determinism.ALWAYS); } - public static LiteralExpression newConstant(Object value, PDataType type, Integer maxLength, Integer scale, boolean isDeterministic) throws SQLException { // remove? - return newConstant(value, type, maxLength, scale, SortOrder.getDefault(), isDeterministic); + public static LiteralExpression newConstant(Object value, PDataType type, Integer maxLength, Integer scale, Determinism determinism) throws SQLException { // remove? + return newConstant(value, type, maxLength, scale, SortOrder.getDefault(), determinism); } // TODO: cache? - public static LiteralExpression newConstant(Object value, PDataType type, Integer maxLength, Integer scale, SortOrder sortOrder, boolean isDeterministic) + public static LiteralExpression newConstant(Object value, PDataType type, Integer maxLength, Integer scale, SortOrder sortOrder, Determinism determinism) throws SQLException { if (value == null) { if (type == null) { @@ -144,10 +144,10 @@ public class LiteralExpression extends BaseTerminalExpression { return TYPED_NULL_EXPRESSIONS[type.ordinal()]; } if (Boolean.FALSE.equals(value)) { - return isDeterministic ? FALSE_EXPRESSION : ND_FALSE_EXPRESSION; + return determinism == Determinism.ALWAYS ? FALSE_EXPRESSION : ND_FALSE_EXPRESSION; } if (Boolean.TRUE.equals(value)) { - return isDeterministic ? TRUE_EXPRESSION : ND_TRUE_EXPRESSION; + return determinism == Determinism.ALWAYS ? TRUE_EXPRESSION : ND_TRUE_EXPRESSION; } PDataType actualType = PDataType.fromLiteral(value); // For array we should check individual element in it? @@ -173,7 +173,7 @@ public class LiteralExpression extends BaseTerminalExpression { if (maxLength == null) { maxLength = type == null || !type.isFixedWidth() ? null : type.getMaxLength(value); } - return new LiteralExpression(value, type, b, maxLength, scale, sortOrder, isDeterministic); + return new LiteralExpression(value, type, b, maxLength, scale, sortOrder, determinism); } catch (IllegalDataException e) { throw new SQLExceptionInfo.Builder(SQLExceptionCode.ILLEGAL_DATA).setRootCause(e).build().buildException(); } @@ -182,16 +182,16 @@ public class LiteralExpression extends BaseTerminalExpression { public LiteralExpression() { } - private LiteralExpression(PDataType type, boolean isDeterministic) { - this(null, type, ByteUtil.EMPTY_BYTE_ARRAY, isDeterministic); + private LiteralExpression(PDataType type, Determinism determinism) { + this(null, type, ByteUtil.EMPTY_BYTE_ARRAY, determinism); } - private LiteralExpression(Object value, PDataType type, byte[] byteValue, boolean isDeterministic) { - this(value, type, byteValue, type == null || !type.isFixedWidth() ? null : type.getMaxLength(value), null, SortOrder.getDefault(), isDeterministic); + private LiteralExpression(Object value, PDataType type, byte[] byteValue, Determinism determinism) { + this(value, type, byteValue, type == null || !type.isFixedWidth() ? null : type.getMaxLength(value), null, SortOrder.getDefault(), determinism); } private LiteralExpression(Object value, PDataType type, byte[] byteValue, - Integer maxLength, Integer scale, SortOrder sortOrder, boolean isDeterministic) { + Integer maxLength, Integer scale, SortOrder sortOrder, Determinism deterministic) { Preconditions.checkNotNull(sortOrder); this.value = value; this.type = type; @@ -199,12 +199,12 @@ public class LiteralExpression extends BaseTerminalExpression { this.maxLength = maxLength; this.scale = scale != null ? scale : type == null ? null : type.getScale(value); this.sortOrder = sortOrder; - this.isDeterministic = isDeterministic; + this.determinism = deterministic; } @Override - public boolean isDeterministic() { - return isDeterministic; + public Determinism getDeterminism() { + return determinism; } @Override @@ -234,12 +234,22 @@ public class LiteralExpression extends BaseTerminalExpression { @Override public void readFields(DataInput input) throws IOException { - int encodedByteLengthAndBool = WritableUtils.readVInt(input); - this.isDeterministic = encodedByteLengthAndBool > 0; + int encodedByteLengthAndBool = WritableUtils.readVInt(input); int byteLength = Math.abs(encodedByteLengthAndBool)-1; this.byteValue = new byte[byteLength]; input.readFully(byteValue, 0, byteLength); - sortOrder = SortOrder.fromSystemValue(WritableUtils.readVInt(input)); + int sortOrderAndDeterminism = WritableUtils.readVInt(input); + if (sortOrderAndDeterminism<=2) { + //client is on an older version + this.determinism = encodedByteLengthAndBool > 0 ? Determinism.ALWAYS : Determinism.PER_ROW; + this.sortOrder = SortOrder.fromSystemValue(sortOrderAndDeterminism);; + } + else { + int determinismOrdinal = (sortOrderAndDeterminism>>2)-1; + this.determinism = Determinism.values()[determinismOrdinal]; + int sortOrderValue = sortOrderAndDeterminism & ((1 << 2) - 1); //get the least 2 significant bits + this.sortOrder = SortOrder.fromSystemValue(sortOrderValue); + } int typeOrdinal = WritableUtils.readVInt(input); if (typeOrdinal < 0) { this.type = null; @@ -255,10 +265,13 @@ public class LiteralExpression extends BaseTerminalExpression { @Override public void write(DataOutput output) throws IOException { - WritableUtils.writeVInt(output, (byteValue.length + 1) * (this.isDeterministic ? 1 : -1)); + WritableUtils.writeVInt(output, (byteValue.length + 1) * (this.determinism==Determinism.ALWAYS ? 1 : -1)); output.write(byteValue); - WritableUtils.writeVInt(output, sortOrder.getSystemValue()); - WritableUtils.writeVInt(output, type == null ? -1 : this.type.ordinal()); + // since we need to support clients of a lower version, serialize the determinism enum ordinal in the int used to + // serialize sort order system value (which is either 1 or 2) + int sortOrderAndDeterminism = ((this.determinism.ordinal()+1)<<2) + sortOrder.getSystemValue(); + WritableUtils.writeVInt(output, sortOrderAndDeterminism); + WritableUtils.writeVInt(output, this.type == null ? -1 : this.type.ordinal()); } @Override http://git-wip-us.apache.org/repos/asf/phoenix/blob/9cf34400/phoenix-core/src/main/java/org/apache/phoenix/expression/NotExpression.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/NotExpression.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/NotExpression.java index e25f1e2..0c17ab8 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/expression/NotExpression.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/NotExpression.java @@ -43,9 +43,9 @@ public class NotExpression extends BaseSingleExpression { } if (child.isStateless()) { if (!child.evaluate(null, ptr) || ptr.getLength() == 0) { - return LiteralExpression.newConstant(null, PDataType.BOOLEAN, child.isDeterministic()); + return LiteralExpression.newConstant(null, PDataType.BOOLEAN, child.getDeterminism()); } - return LiteralExpression.newConstant(!(Boolean)PDataType.BOOLEAN.toObject(ptr), PDataType.BOOLEAN, child.isDeterministic()); + return LiteralExpression.newConstant(!(Boolean)PDataType.BOOLEAN.toObject(ptr), PDataType.BOOLEAN, child.getDeterminism()); } return new NotExpression(child); } http://git-wip-us.apache.org/repos/asf/phoenix/blob/9cf34400/phoenix-core/src/main/java/org/apache/phoenix/expression/function/AggregateFunction.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/AggregateFunction.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/AggregateFunction.java index 257890c..32cae19 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/AggregateFunction.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/AggregateFunction.java @@ -19,6 +19,7 @@ package org.apache.phoenix.expression.function; import java.util.List; +import org.apache.phoenix.expression.Determinism; import org.apache.phoenix.expression.Expression; @@ -46,7 +47,7 @@ abstract public class AggregateFunction extends FunctionExpression { } @Override - public boolean isDeterministic() { - return false; + public Determinism getDeterminism() { + return Determinism.PER_ROW; } } http://git-wip-us.apache.org/repos/asf/phoenix/blob/9cf34400/phoenix-core/src/main/java/org/apache/phoenix/expression/function/CeilDecimalExpression.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/CeilDecimalExpression.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/CeilDecimalExpression.java index d6b4e45..bd36d0f 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/CeilDecimalExpression.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/CeilDecimalExpression.java @@ -21,13 +21,17 @@ import java.math.RoundingMode; import java.sql.SQLException; import java.util.List; +import org.apache.phoenix.expression.Determinism; import org.apache.phoenix.expression.Expression; import org.apache.phoenix.expression.LiteralExpression; import org.apache.phoenix.schema.PDataType; import com.google.common.collect.Lists; + import java.math.BigDecimal; + import org.apache.phoenix.query.KeyRange; + import static org.apache.phoenix.schema.PDataType.DECIMAL; /** @@ -53,7 +57,7 @@ public class CeilDecimalExpression extends RoundDecimalExpression { if (expr.getDataType().isCoercibleTo(PDataType.LONG)) { return expr; } - Expression scaleExpr = LiteralExpression.newConstant(scale, PDataType.INTEGER, true); + Expression scaleExpr = LiteralExpression.newConstant(scale, PDataType.INTEGER, Determinism.ALWAYS); List<Expression> expressions = Lists.newArrayList(expr, scaleExpr); return new CeilDecimalExpression(expressions); } @@ -64,7 +68,7 @@ public class CeilDecimalExpression extends RoundDecimalExpression { return expr; } if (exprs.size() == 1) { - Expression scaleExpr = LiteralExpression.newConstant(0, PDataType.INTEGER, true); + Expression scaleExpr = LiteralExpression.newConstant(0, PDataType.INTEGER, Determinism.ALWAYS); exprs = Lists.newArrayList(expr, scaleExpr); } return new CeilDecimalExpression(exprs); http://git-wip-us.apache.org/repos/asf/phoenix/blob/9cf34400/phoenix-core/src/main/java/org/apache/phoenix/expression/function/CoalesceFunction.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/CoalesceFunction.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/CoalesceFunction.java index 87fc908..2eef8b3 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/CoalesceFunction.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/CoalesceFunction.java @@ -30,6 +30,7 @@ import org.apache.phoenix.parse.FunctionParseNode.Argument; import org.apache.phoenix.parse.FunctionParseNode.BuiltInFunction; import org.apache.phoenix.schema.PDataType; import org.apache.phoenix.schema.tuple.Tuple; +import org.apache.phoenix.util.ExpressionUtil; /** @@ -59,7 +60,7 @@ public class CoalesceFunction extends ScalarFunction { Expression firstChild = children.get(0); Expression secondChild = children.get(1); - if (secondChild.isStateless() && secondChild.isDeterministic()) { // is literal + if (ExpressionUtil.isConstant(secondChild)) { // is literal ImmutableBytesWritable ptr = new ImmutableBytesPtr(); secondChild.evaluate(null, ptr); http://git-wip-us.apache.org/repos/asf/phoenix/blob/9cf34400/phoenix-core/src/main/java/org/apache/phoenix/expression/function/CountAggregateFunction.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/CountAggregateFunction.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/CountAggregateFunction.java index b7a5861..f1e8ab5 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/CountAggregateFunction.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/CountAggregateFunction.java @@ -22,7 +22,7 @@ import java.util.List; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.hbase.io.ImmutableBytesWritable; - +import org.apache.phoenix.expression.Determinism; import org.apache.phoenix.expression.Expression; import org.apache.phoenix.expression.LiteralExpression; import org.apache.phoenix.expression.aggregator.Aggregator; @@ -45,7 +45,7 @@ import org.apache.phoenix.util.SchemaUtil; @BuiltInFunction(name=CountAggregateFunction.NAME, args= {@Argument()} ) public class CountAggregateFunction extends SingleAggregateFunction { public static final String NAME = "COUNT"; - public static final List<Expression> STAR = Arrays.<Expression>asList(LiteralExpression.newConstant(1, true)); + public static final List<Expression> STAR = Arrays.<Expression>asList(LiteralExpression.newConstant(1, Determinism.ALWAYS)); public static final String NORMALIZED_NAME = SchemaUtil.normalizeIdentifier(NAME); public CountAggregateFunction() { http://git-wip-us.apache.org/repos/asf/phoenix/blob/9cf34400/phoenix-core/src/main/java/org/apache/phoenix/expression/function/FloorDecimalExpression.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/FloorDecimalExpression.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/FloorDecimalExpression.java index b5566ca..037fcc5 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/FloorDecimalExpression.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/FloorDecimalExpression.java @@ -21,13 +21,17 @@ import java.math.RoundingMode; import java.sql.SQLException; import java.util.List; +import org.apache.phoenix.expression.Determinism; import org.apache.phoenix.expression.Expression; import org.apache.phoenix.expression.LiteralExpression; import org.apache.phoenix.schema.PDataType; import com.google.common.collect.Lists; + import java.math.BigDecimal; + import org.apache.phoenix.query.KeyRange; + import static org.apache.phoenix.schema.PDataType.DECIMAL; /** @@ -54,7 +58,7 @@ public class FloorDecimalExpression extends RoundDecimalExpression { if (expr.getDataType().isCoercibleTo(PDataType.LONG)) { return expr; } - Expression scaleExpr = LiteralExpression.newConstant(scale, PDataType.INTEGER, true); + Expression scaleExpr = LiteralExpression.newConstant(scale, PDataType.INTEGER, Determinism.ALWAYS); List<Expression> expressions = Lists.newArrayList(expr, scaleExpr); return new FloorDecimalExpression(expressions); } @@ -65,7 +69,7 @@ public class FloorDecimalExpression extends RoundDecimalExpression { return expr; } if (exprs.size() == 1) { - Expression scaleExpr = LiteralExpression.newConstant(0, PDataType.INTEGER, true); + Expression scaleExpr = LiteralExpression.newConstant(0, PDataType.INTEGER, Determinism.ALWAYS); exprs = Lists.newArrayList(expr, scaleExpr); } return new FloorDecimalExpression(exprs); http://git-wip-us.apache.org/repos/asf/phoenix/blob/9cf34400/phoenix-core/src/main/java/org/apache/phoenix/expression/function/RoundDateExpression.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/RoundDateExpression.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/RoundDateExpression.java index f928218..58ff652 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/RoundDateExpression.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/RoundDateExpression.java @@ -29,6 +29,7 @@ import org.apache.hadoop.hbase.filter.CompareFilter.CompareOp; import org.apache.hadoop.hbase.io.ImmutableBytesWritable; import org.apache.hadoop.io.WritableUtils; import org.apache.phoenix.compile.KeyPart; +import org.apache.phoenix.expression.Determinism; import org.apache.phoenix.expression.Expression; import org.apache.phoenix.expression.LiteralExpression; import org.apache.phoenix.query.KeyRange; @@ -92,11 +93,11 @@ public class RoundDateExpression extends ScalarFunction { } static Expression getTimeUnitExpr(TimeUnit timeUnit) throws SQLException { - return LiteralExpression.newConstant(timeUnit.name(), PDataType.VARCHAR, true); + return LiteralExpression.newConstant(timeUnit.name(), PDataType.VARCHAR, Determinism.ALWAYS); } static Expression getMultiplierExpr(int multiplier) throws SQLException { - return LiteralExpression.newConstant(multiplier, PDataType.INTEGER, true); + return LiteralExpression.newConstant(multiplier, PDataType.INTEGER, Determinism.ALWAYS); } RoundDateExpression(List<Expression> children) { http://git-wip-us.apache.org/repos/asf/phoenix/blob/9cf34400/phoenix-core/src/main/java/org/apache/phoenix/expression/function/RoundDecimalExpression.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/RoundDecimalExpression.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/RoundDecimalExpression.java index 7e76234..713bfad 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/RoundDecimalExpression.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/RoundDecimalExpression.java @@ -32,6 +32,7 @@ import org.apache.hadoop.hbase.filter.CompareFilter; import org.apache.hadoop.hbase.io.ImmutableBytesWritable; import org.apache.hadoop.io.WritableUtils; import org.apache.phoenix.compile.KeyPart; +import org.apache.phoenix.expression.Determinism; import org.apache.phoenix.expression.Expression; import org.apache.phoenix.expression.LiteralExpression; import org.apache.phoenix.query.KeyRange; @@ -62,7 +63,7 @@ public class RoundDecimalExpression extends ScalarFunction { if (expr.getDataType().isCoercibleTo(PDataType.LONG)) { return expr; } - Expression scaleExpr = LiteralExpression.newConstant(scale, PDataType.INTEGER, true); + Expression scaleExpr = LiteralExpression.newConstant(scale, PDataType.INTEGER, Determinism.ALWAYS); List<Expression> expressions = Lists.newArrayList(expr, scaleExpr); return new RoundDecimalExpression(expressions); } @@ -81,7 +82,7 @@ public class RoundDecimalExpression extends ScalarFunction { return expr; } if (exprs.size() == 1) { - Expression scaleExpr = LiteralExpression.newConstant(0, PDataType.INTEGER, true); + Expression scaleExpr = LiteralExpression.newConstant(0, PDataType.INTEGER, Determinism.ALWAYS); exprs = Lists.newArrayList(expr, scaleExpr); } return new RoundDecimalExpression(exprs); http://git-wip-us.apache.org/repos/asf/phoenix/blob/9cf34400/phoenix-core/src/main/java/org/apache/phoenix/expression/function/SingleAggregateFunction.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/SingleAggregateFunction.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/SingleAggregateFunction.java index 154bdf8..d33d555 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/SingleAggregateFunction.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/SingleAggregateFunction.java @@ -25,7 +25,7 @@ import java.util.List; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.hbase.io.ImmutableBytesWritable; - +import org.apache.phoenix.expression.Determinism; import org.apache.phoenix.expression.Expression; import org.apache.phoenix.expression.LiteralExpression; import org.apache.phoenix.expression.aggregator.Aggregator; @@ -43,7 +43,7 @@ import org.apache.phoenix.schema.tuple.Tuple; * @since 0.1 */ abstract public class SingleAggregateFunction extends AggregateFunction { - private static final List<Expression> DEFAULT_EXPRESSION_LIST = Arrays.<Expression>asList(LiteralExpression.newConstant(1, true)); + private static final List<Expression> DEFAULT_EXPRESSION_LIST = Arrays.<Expression>asList(LiteralExpression.newConstant(1, Determinism.ALWAYS)); protected boolean isConstant; private Aggregator aggregator; http://git-wip-us.apache.org/repos/asf/phoenix/blob/9cf34400/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 10c7208..ea8c1fb 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 @@ -33,7 +33,9 @@ import java.util.Set; import org.apache.http.annotation.Immutable; import com.google.common.collect.ImmutableSet; + import org.apache.phoenix.compile.StatementContext; +import org.apache.phoenix.expression.Determinism; import org.apache.phoenix.expression.Expression; import org.apache.phoenix.expression.LiteralExpression; import org.apache.phoenix.expression.function.AggregateFunction; @@ -137,7 +139,7 @@ public class FunctionParseNode extends CompoundParseNode { if (args.length > children.size()) { List<Expression> moreChildren = new ArrayList<Expression>(children); for (int i = children.size(); i < info.getArgs().length; i++) { - moreChildren.add(LiteralExpression.newConstant(null, args[i].allowedTypes.length == 0 ? null : args[i].allowedTypes[0], true)); + moreChildren.add(LiteralExpression.newConstant(null, args[i].allowedTypes.length == 0 ? null : args[i].allowedTypes[0], Determinism.ALWAYS)); } children = moreChildren; } @@ -174,7 +176,7 @@ public class FunctionParseNode extends CompoundParseNode { // based on the function argument annonation set the parameter meta data. if (child.getDataType() == null) { if (allowedTypes.length > 0) { - context.getBindManager().addParamMetaData(bindNode, LiteralExpression.newConstant(null, allowedTypes[0], true)); + context.getBindManager().addParamMetaData(bindNode, LiteralExpression.newConstant(null, allowedTypes[0], Determinism.ALWAYS)); } } else { // Use expression as is, since we already have the data type set context.getBindManager().addParamMetaData(bindNode, child); @@ -376,11 +378,11 @@ public class FunctionParseNode extends CompoundParseNode { SQLParser parser = new SQLParser(strValue); try { LiteralParseNode node = parser.parseLiteral(); - LiteralExpression defaultValue = LiteralExpression.newConstant(node.getValue(), this.allowedTypes[0], true); + LiteralExpression defaultValue = LiteralExpression.newConstant(node.getValue(), this.allowedTypes[0], Determinism.ALWAYS); if (this.getAllowedTypes().length > 0) { for (PDataType type : this.getAllowedTypes()) { if (defaultValue.getDataType() == null || defaultValue.getDataType().isCoercibleTo(type, node.getValue())) { - return LiteralExpression.newConstant(node.getValue(), type, true); + return LiteralExpression.newConstant(node.getValue(), type, Determinism.ALWAYS); } } throw new IllegalStateException("Unable to coerce default value " + strValue + " to any of the allowed types of " + Arrays.toString(this.getAllowedTypes())); http://git-wip-us.apache.org/repos/asf/phoenix/blob/9cf34400/phoenix-core/src/main/java/org/apache/phoenix/util/ExpressionUtil.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/util/ExpressionUtil.java b/phoenix-core/src/main/java/org/apache/phoenix/util/ExpressionUtil.java index 227a385..eac396b 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/util/ExpressionUtil.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/util/ExpressionUtil.java @@ -13,6 +13,7 @@ import java.sql.SQLException; import java.util.List; import org.apache.hadoop.hbase.io.ImmutableBytesWritable; +import org.apache.phoenix.expression.Determinism; import org.apache.phoenix.expression.Expression; import org.apache.phoenix.expression.LiteralExpression; import org.apache.phoenix.expression.function.CurrentDateFunction; @@ -24,16 +25,20 @@ import com.google.common.collect.Lists; public class ExpressionUtil { - @SuppressWarnings("unchecked") - private static final List<Class<? extends FunctionExpression>> OVERRIDE_LITERAL_FUNCTIONS = Lists - .<Class<? extends FunctionExpression>> newArrayList(CurrentDateFunction.class, CurrentTimeFunction.class); + @SuppressWarnings("unchecked") + private static final List<Class<? extends FunctionExpression>> OVERRIDE_LITERAL_FUNCTIONS = Lists + .<Class<? extends FunctionExpression>> newArrayList( + CurrentDateFunction.class, CurrentTimeFunction.class); - private ExpressionUtil() {} + private ExpressionUtil() { + } - public static boolean isConstant(Expression expression) { - return (expression.isStateless() && expression.isDeterministic() || OVERRIDE_LITERAL_FUNCTIONS - .contains(expression.getClass())); - } + public static boolean isConstant(Expression expression) { + return (expression.isStateless() && (expression.getDeterminism() == Determinism.ALWAYS + || expression.getDeterminism() == Determinism.PER_STATEMENT + // TODO remove this in 3.4/4.4 (need to support clients on 3.1/4.1) + || OVERRIDE_LITERAL_FUNCTIONS.contains(expression.getClass()))); + } public static LiteralExpression getConstantExpression(Expression expression, ImmutableBytesWritable ptr) throws SQLException { @@ -42,16 +47,15 @@ public class ExpressionUtil { if (expression.evaluate(null, ptr) && ptr.getLength() != 0) { value = type.toObject(ptr); } - return LiteralExpression.newConstant(value, type, expression.isDeterministic()); + return LiteralExpression.newConstant(value, type, expression.getDeterminism()); } public static boolean isNull(Expression expression, ImmutableBytesWritable ptr) { - return expression.isStateless() && expression.isDeterministic() - && (!expression.evaluate(null, ptr) || ptr.getLength() == 0); + return isConstant(expression) && (!expression.evaluate(null, ptr) || ptr.getLength() == 0); } public static LiteralExpression getNullExpression(Expression expression) throws SQLException { - return LiteralExpression.newConstant(null, expression.getDataType(), expression.isDeterministic()); + return LiteralExpression.newConstant(null, expression.getDataType(), expression.getDeterminism()); } } http://git-wip-us.apache.org/repos/asf/phoenix/blob/9cf34400/phoenix-core/src/test/java/org/apache/phoenix/expression/DeterminismTest.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/test/java/org/apache/phoenix/expression/DeterminismTest.java b/phoenix-core/src/test/java/org/apache/phoenix/expression/DeterminismTest.java new file mode 100644 index 0000000..4e4a648 --- /dev/null +++ b/phoenix-core/src/test/java/org/apache/phoenix/expression/DeterminismTest.java @@ -0,0 +1,37 @@ +/* + * 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.expression; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +public class DeterminismTest { + @Test + public void testCombine() { + // combining a determinism enum with ALWAYS should always return the + // other determinism + assertEquals("Unexpected result ", Determinism.PER_ROW, + Determinism.ALWAYS.combine(Determinism.PER_ROW)); + assertEquals("Unexpected result ", Determinism.PER_STATEMENT, + Determinism.ALWAYS.combine(Determinism.PER_STATEMENT)); + assertEquals("Unexpected result ", Determinism.PER_STATEMENT, + Determinism.PER_STATEMENT.combine(Determinism.ALWAYS)); + assertEquals("Unexpected result ", Determinism.PER_ROW, + Determinism.PER_ROW.combine(Determinism.ALWAYS)); + + // combining PER_STATEMENT and PER_ROW should return PER_ROW + assertEquals("Unexpected result ", Determinism.PER_ROW, + Determinism.PER_STATEMENT.combine(Determinism.PER_ROW)); + assertEquals("Unexpected result ", Determinism.PER_ROW, + Determinism.PER_ROW.combine(Determinism.PER_STATEMENT)); + + } +}