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));
+
+       }
+}

Reply via email to