You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@phoenix.apache.org by ma...@apache.org on 2015/08/23 19:16:05 UTC

[40/40] phoenix git commit: Fix conflicts and bugs after merge

Fix conflicts and bugs after merge


Project: http://git-wip-us.apache.org/repos/asf/phoenix/repo
Commit: http://git-wip-us.apache.org/repos/asf/phoenix/commit/ab97f1cc
Tree: http://git-wip-us.apache.org/repos/asf/phoenix/tree/ab97f1cc
Diff: http://git-wip-us.apache.org/repos/asf/phoenix/diff/ab97f1cc

Branch: refs/heads/calcite
Commit: ab97f1ccdbe9d74c04a897e98d5ade6e0c9b7dd5
Parents: aa26d84 aa86c89
Author: maryannxue <we...@intel.com>
Authored: Sun Aug 23 13:14:46 2015 -0400
Committer: maryannxue <we...@intel.com>
Committed: Sun Aug 23 13:14:46 2015 -0400

----------------------------------------------------------------------
 dev/make_rc.sh                                  |   59 +-
 phoenix-assembly/pom.xml                        |    2 +-
 phoenix-core/pom.xml                            |    2 +-
 .../apache/phoenix/end2end/AlterTableIT.java    |  929 +--------------
 .../phoenix/end2end/AlterTableWithViewsIT.java  | 1118 ++++++++++++++++++
 .../org/apache/phoenix/end2end/ArrayIT.java     |  201 +++-
 .../org/apache/phoenix/end2end/BaseQueryIT.java |   10 -
 .../end2end/BaseTenantSpecificViewIndexIT.java  |   33 +-
 .../apache/phoenix/end2end/CreateTableIT.java   |   25 +
 .../end2end/GetSetByteBitFunctionEnd2EndIT.java |  100 ++
 .../org/apache/phoenix/end2end/InListIT.java    |   53 +-
 .../phoenix/end2end/LikeExpressionIT.java       |   38 +
 .../apache/phoenix/end2end/LpadFunctionIT.java  |   48 +-
 .../end2end/OctetLengthFunctionEnd2EndIT.java   |   73 ++
 .../apache/phoenix/end2end/RTrimFunctionIT.java |   71 ++
 .../org/apache/phoenix/end2end/SequenceIT.java  |   33 +
 .../org/apache/phoenix/end2end/SortOrderIT.java |  171 ++-
 .../end2end/StringToArrayFunctionIT.java        |  423 +++++++
 .../apache/phoenix/end2end/TenantIdTypeIT.java  |  226 ++++
 .../end2end/TenantSpecificTablesDDLIT.java      |   59 +-
 .../end2end/TenantSpecificViewIndexIT.java      |    5 +
 .../apache/phoenix/mapreduce/IndexToolIT.java   |   42 +-
 .../org/apache/phoenix/rpc/UpdateCacheIT.java   |   17 +
 .../apache/phoenix/calcite/CalciteUtils.java    |   26 +-
 .../phoenix/calcite/rel/PhoenixValues.java      |    4 +-
 .../apache/phoenix/compile/DeleteCompiler.java  |    3 +-
 .../phoenix/compile/ExpressionCompiler.java     |   17 +-
 .../apache/phoenix/compile/HavingCompiler.java  |    2 +-
 .../org/apache/phoenix/compile/KeyPart.java     |    8 +-
 .../phoenix/compile/ListJarsQueryPlan.java      |   17 +
 .../apache/phoenix/compile/QueryCompiler.java   |    4 +-
 .../org/apache/phoenix/compile/ScanRanges.java  |    7 +-
 .../apache/phoenix/compile/UpsertCompiler.java  |    3 +-
 .../apache/phoenix/compile/WhereCompiler.java   |    2 +-
 .../apache/phoenix/compile/WhereOptimizer.java  |  121 +-
 .../coprocessor/MetaDataEndpointImpl.java       |  805 ++++++++-----
 .../UngroupedAggregateRegionObserver.java       |   39 +-
 .../phoenix/exception/SQLExceptionCode.java     |    3 +-
 .../apache/phoenix/execute/BaseQueryPlan.java   |   14 +-
 .../DescVarLengthFastByteComparisons.java       |   12 +
 .../apache/phoenix/execute/HashJoinPlan.java    |    6 +-
 .../execute/LiteralResultIterationPlan.java     |  118 ++
 .../LiteralResultIterationQueryPlan.java        |  118 --
 .../apache/phoenix/execute/MutationState.java   |   23 +-
 .../expression/ArrayConstructorExpression.java  |   28 +-
 .../phoenix/expression/BaseExpression.java      |   43 +-
 .../phoenix/expression/CoerceExpression.java    |   39 +-
 .../expression/ComparisonExpression.java        |   36 +-
 .../phoenix/expression/ExpressionType.java      |   14 +-
 .../phoenix/expression/InListExpression.java    |   26 +-
 .../phoenix/expression/LiteralExpression.java   |   40 +-
 .../expression/function/ArrayFillFunction.java  |   17 +
 .../expression/function/GetBitFunction.java     |   96 ++
 .../expression/function/GetByteFunction.java    |   96 ++
 .../expression/function/InvertFunction.java     |   14 +-
 .../function/OctetLengthFunction.java           |   66 ++
 .../expression/function/PrefixFunction.java     |   37 +-
 .../expression/function/RTrimFunction.java      |   64 +-
 .../function/RoundDateExpression.java           |   12 +-
 .../function/RoundDecimalExpression.java        |   22 +-
 .../expression/function/SetBitFunction.java     |   81 ++
 .../expression/function/SetByteFunction.java    |   81 ++
 .../function/StringToArrayFunction.java         |   91 ++
 .../visitor/CloneExpressionVisitor.java         |    2 +-
 .../apache/phoenix/filter/SkipScanFilter.java   |   13 +-
 .../apache/phoenix/iterate/ExplainTable.java    |    4 +-
 .../phoenix/jdbc/PhoenixDatabaseMetaData.java   |    2 +-
 .../phoenix/mapreduce/index/IndexTool.java      |    6 +-
 .../index/PhoenixIndexImportMapper.java         |    2 +-
 .../util/ColumnInfoToStringEncoderDecoder.java  |   41 +-
 .../util/PhoenixConfigurationUtil.java          |  135 ++-
 .../mapreduce/util/PhoenixMapReduceUtil.java    |    2 +-
 .../phoenix/parse/DeleteJarStatement.java       |   17 +
 .../query/ConnectionQueryServicesImpl.java      |   36 +-
 .../java/org/apache/phoenix/query/KeyRange.java |   42 +-
 .../org/apache/phoenix/query/QueryServices.java |    1 +
 .../phoenix/query/QueryServicesOptions.java     |    4 +-
 .../apache/phoenix/schema/MetaDataClient.java   |    4 +-
 .../org/apache/phoenix/schema/PTableImpl.java   |   33 +-
 .../org/apache/phoenix/schema/Sequence.java     |    3 +-
 .../phoenix/schema/SequenceAllocation.java      |   19 +-
 .../phoenix/schema/types/PArrayDataType.java    |   34 +-
 .../apache/phoenix/schema/types/PBinary.java    |   30 +-
 .../phoenix/schema/types/PBinaryBase.java       |   98 ++
 .../org/apache/phoenix/schema/types/PChar.java  |   11 +
 .../apache/phoenix/schema/types/PDataType.java  |    8 +-
 .../apache/phoenix/schema/types/PDouble.java    |   18 +-
 .../org/apache/phoenix/schema/types/PFloat.java |   18 +-
 .../apache/phoenix/schema/types/PVarbinary.java |    2 +-
 .../phoenix/schema/types/PhoenixArray.java      |    4 -
 .../org/apache/phoenix/util/PhoenixRuntime.java |   49 +-
 .../java/org/apache/phoenix/util/ScanUtil.java  |   97 +-
 .../org/apache/phoenix/util/SchemaUtil.java     |    2 +-
 .../org/apache/phoenix/util/StringUtil.java     |    7 -
 .../org/apache/phoenix/util/UpgradeUtil.java    |  261 ++--
 .../phoenix/compile/WhereOptimizerTest.java     |   53 +-
 .../DescVarLengthFastByteComparisonsTest.java   |   45 +
 .../expression/ArrayToStringFunctionTest.java   |    7 +-
 .../expression/GetSetByteBitFunctionTest.java   |  189 +++
 .../phoenix/expression/NullValueTest.java       |   59 +
 .../expression/OctetLengthFunctionTest.java     |   67 ++
 .../expression/SortOrderExpressionTest.java     |   13 +-
 .../expression/StringToArrayFunctionTest.java   |  275 +++++
 .../hbase/index/write/TestIndexWriter.java      |    2 +-
 .../ColumnInfoToStringEncoderDecoderTest.java   |   42 +-
 .../util/PhoenixConfigurationUtilTest.java      |    5 +-
 .../java/org/apache/phoenix/query/BaseTest.java |   16 +
 .../phoenix/schema/SequenceAllocationTest.java  |   17 +
 .../phoenix/schema/types/PDataTypeTest.java     |   33 +
 .../util/TenantIdByteConversionTest.java        |  294 +++++
 .../java/org/apache/phoenix/util/TestUtil.java  |    5 +-
 phoenix-flume/pom.xml                           |    2 +-
 phoenix-pherf/cluster/pherf.sh                  |    4 +-
 phoenix-pherf/config/env.sh                     |    4 +-
 phoenix-pherf/pom.xml                           |  550 +++------
 .../org/apache/phoenix/pherf/DataIngestIT.java  |   71 +-
 phoenix-pherf/src/main/assembly/cluster.xml     |   11 +-
 .../src/main/assembly/components-minimal.xml    |   33 +
 phoenix-pherf/src/main/assembly/minimal.xml     |   31 +
 phoenix-pherf/src/main/assembly/standalone.xml  |   13 +-
 .../java/org/apache/phoenix/pherf/Pherf.java    |   23 +-
 .../apache/phoenix/pherf/PherfConstants.java    |    5 +
 .../phoenix/pherf/configuration/Scenario.java   |   25 +-
 .../pherf/configuration/XMLConfigParser.java    |   23 +-
 .../apache/phoenix/pherf/util/PhoenixUtil.java  |   86 +-
 .../phoenix/pherf/workload/QueryExecutor.java   |    3 +-
 .../apache/phoenix/pherf/workload/Workload.java |   17 +
 .../phoenix/pherf/workload/WriteWorkload.java   |   64 +-
 .../org/apache/phoenix/pherf/PherfTest.java     |    2 +-
 .../datamodel/test_schema_mt_table.sql          |   31 +
 .../resources/datamodel/test_schema_mt_view.sql |    1 +
 .../test/resources/scenario/test_scenario.xml   |   22 +
 phoenix-pig/pom.xml                             |    2 +-
 .../phoenix/pig/PhoenixHBaseLoaderIT.java       |  136 ++-
 .../phoenix/pig/udf/ReserveNSequenceTestIT.java |   16 +-
 .../apache/phoenix/pig/PhoenixHBaseLoader.java  |    2 +-
 .../apache/phoenix/pig/PhoenixHBaseStorage.java |    3 +-
 .../phoenix/pig/util/PhoenixPigSchemaUtil.java  |   14 +-
 .../org/apache/phoenix/pig/util/TypeUtil.java   |    5 +-
 .../pig/util/PhoenixPigSchemaUtilTest.java      |   30 +-
 phoenix-server-client/pom.xml                   |    2 +-
 phoenix-server/pom.xml                          |    2 +-
 phoenix-spark/pom.xml                           |    2 +-
 .../phoenix/spark/ConfigurationUtil.scala       |   18 +-
 .../phoenix/spark/DataFrameFunctions.scala      |   35 +-
 .../phoenix/spark/PhoenixRecordWritable.scala   |   20 +-
 .../phoenix/spark/ProductRDDFunctions.scala     |   28 +-
 pom.xml                                         |   17 +-
 148 files changed, 6968 insertions(+), 2505 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/phoenix/blob/ab97f1cc/phoenix-core/pom.xml
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/phoenix/blob/ab97f1cc/phoenix-core/src/main/java/org/apache/phoenix/calcite/CalciteUtils.java
----------------------------------------------------------------------
diff --cc phoenix-core/src/main/java/org/apache/phoenix/calcite/CalciteUtils.java
index 3aa2404,0000000..d3666d2
mode 100644,000000..100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/calcite/CalciteUtils.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/calcite/CalciteUtils.java
@@@ -1,824 -1,0 +1,824 @@@
 +package org.apache.phoenix.calcite;
 +
 +import java.sql.SQLException;
 +import java.util.Arrays;
 +import java.util.List;
 +import java.util.Map;
 +import java.util.concurrent.atomic.AtomicInteger;
 +
 +import org.apache.calcite.avatica.util.ByteString;
 +import org.apache.calcite.rex.RexCall;
 +import org.apache.calcite.rex.RexInputRef;
 +import org.apache.calcite.rex.RexLiteral;
 +import org.apache.calcite.rex.RexNode;
 +import org.apache.calcite.sql.SqlAggFunction;
 +import org.apache.calcite.sql.SqlFunction;
 +import org.apache.calcite.sql.SqlKind;
 +import org.apache.calcite.sql.SqlOperator;
 +import org.apache.calcite.sql.fun.SqlStdOperatorTable;
 +import org.apache.calcite.sql.type.SqlTypeName;
 +import org.apache.calcite.util.NlsString;
 +import org.apache.hadoop.hbase.filter.CompareFilter.CompareOp;
 +import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
 +import org.apache.phoenix.calcite.rel.PhoenixRel.Implementor;
 +import org.apache.phoenix.expression.AndExpression;
 +import org.apache.phoenix.expression.CoerceExpression;
 +import org.apache.phoenix.expression.ComparisonExpression;
 +import org.apache.phoenix.expression.DateAddExpression;
 +import org.apache.phoenix.expression.DateSubtractExpression;
 +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;
 +import org.apache.phoenix.expression.DoubleSubtractExpression;
 +import org.apache.phoenix.expression.Expression;
 +import org.apache.phoenix.expression.ExpressionType;
 +import org.apache.phoenix.expression.IsNullExpression;
 +import org.apache.phoenix.expression.LiteralExpression;
 +import org.apache.phoenix.expression.LongAddExpression;
 +import org.apache.phoenix.expression.LongDivideExpression;
 +import org.apache.phoenix.expression.LongMultiplyExpression;
 +import org.apache.phoenix.expression.LongSubtractExpression;
 +import org.apache.phoenix.expression.NotExpression;
 +import org.apache.phoenix.expression.OrExpression;
 +import org.apache.phoenix.expression.StringBasedLikeExpression;
 +import org.apache.phoenix.expression.TimestampAddExpression;
 +import org.apache.phoenix.expression.TimestampSubtractExpression;
 +import org.apache.phoenix.expression.function.AbsFunction;
 +import org.apache.phoenix.expression.function.AggregateFunction;
 +import org.apache.phoenix.expression.function.CeilDateExpression;
 +import org.apache.phoenix.expression.function.CeilDecimalExpression;
 +import org.apache.phoenix.expression.function.CeilTimestampExpression;
 +import org.apache.phoenix.expression.function.CoalesceFunction;
 +import org.apache.phoenix.expression.function.CountAggregateFunction;
 +import org.apache.phoenix.expression.function.CurrentDateFunction;
 +import org.apache.phoenix.expression.function.CurrentTimeFunction;
 +import org.apache.phoenix.expression.function.ExpFunction;
 +import org.apache.phoenix.expression.function.FloorDateExpression;
 +import org.apache.phoenix.expression.function.FloorDecimalExpression;
 +import org.apache.phoenix.expression.function.FunctionExpression;
 +import org.apache.phoenix.expression.function.LnFunction;
 +import org.apache.phoenix.expression.function.LowerFunction;
 +import org.apache.phoenix.expression.function.MaxAggregateFunction;
 +import org.apache.phoenix.expression.function.MinAggregateFunction;
 +import org.apache.phoenix.expression.function.PowerFunction;
 +import org.apache.phoenix.expression.function.RoundDecimalExpression;
 +import org.apache.phoenix.expression.function.RoundTimestampExpression;
 +import org.apache.phoenix.expression.function.SqrtFunction;
 +import org.apache.phoenix.expression.function.TrimFunction;
 +import org.apache.phoenix.expression.function.UpperFunction;
 +import org.apache.phoenix.schema.SortOrder;
 +import org.apache.phoenix.schema.TypeMismatchException;
 +import org.apache.phoenix.schema.types.PDataType;
 +import org.apache.phoenix.schema.types.PDate;
 +import org.apache.phoenix.schema.types.PDecimal;
 +import org.apache.phoenix.schema.types.PDouble;
 +import org.apache.phoenix.schema.types.PLong;
 +import org.apache.phoenix.schema.types.PTimestamp;
 +import org.apache.phoenix.schema.types.PUnsignedTimestamp;
 +
 +import com.google.common.collect.Lists;
 +import com.google.common.collect.Maps;
 +
 +/**
 + * Utilities for interacting with Calcite.
 + */
 +public class CalciteUtils {
 +    private CalciteUtils() {}
 +    
 +    private static AtomicInteger tempAliasCounter = new AtomicInteger(0);
 +  
 +    public static String createTempAlias() {
 +        return "$" + tempAliasCounter.incrementAndGet();
 +    }
 +    
 +    @SuppressWarnings("rawtypes")
 +    public static PDataType sqlTypeNameToPDataType(SqlTypeName sqlTypeName) {
 +        return PDataType.fromTypeId(sqlTypeName.getJdbcOrdinal());
 +    }
 +
 +	private static final Map<SqlKind, ExpressionFactory> EXPRESSION_MAP = Maps
 +			.newHashMapWithExpectedSize(ExpressionType.values().length);
 +	private static final ExpressionFactory getFactory(RexNode node) {
 +		ExpressionFactory eFactory = EXPRESSION_MAP.get(node.getKind());
 +		if (eFactory == null) {
 +			throw new UnsupportedOperationException("Unsupported RexNode: "
 +					+ node);
 +		}
 +		return eFactory;
 +	}
 +	static {
 +        EXPRESSION_MAP.put(SqlKind.AND, new ExpressionFactory() {
 +
 +            @Override
 +            public Expression newExpression(RexNode node, Implementor implementor) {
 +                try {
 +                    return AndExpression.create(convertChildren((RexCall) node, implementor));
 +                } catch (SQLException e) {
 +                    throw new RuntimeException(e);
 +                }
 +            }
 +            
 +        });
 +        EXPRESSION_MAP.put(SqlKind.OR, new ExpressionFactory() {
 +
 +            @Override
 +            public Expression newExpression(RexNode node, Implementor implementor) {
 +                return new OrExpression(convertChildren((RexCall) node, implementor));
 +            }
 +            
 +        });
 +		EXPRESSION_MAP.put(SqlKind.EQUALS, new ExpressionFactory() {
 +
 +			@Override
 +			public Expression newExpression(RexNode node, Implementor implementor) {
 +				ImmutableBytesWritable ptr = new ImmutableBytesWritable();
 +				try {
- 					return ComparisonExpression.create(CompareOp.EQUAL, convertChildren((RexCall) node, implementor), ptr);
++					return ComparisonExpression.create(CompareOp.EQUAL, convertChildren((RexCall) node, implementor), ptr, implementor.getTableRef().getTable().rowKeyOrderOptimizable());
 +				} catch (SQLException e) {
 +					throw new RuntimeException(e);
 +				}
 +			}
 +			
 +		});
 +        EXPRESSION_MAP.put(SqlKind.NOT_EQUALS, new ExpressionFactory() {
 +
 +            @Override
 +            public Expression newExpression(RexNode node, Implementor implementor) {
 +                ImmutableBytesWritable ptr = new ImmutableBytesWritable();
 +                try {
-                     return ComparisonExpression.create(CompareOp.NOT_EQUAL, convertChildren((RexCall) node, implementor), ptr);
++                    return ComparisonExpression.create(CompareOp.NOT_EQUAL, convertChildren((RexCall) node, implementor), ptr, implementor.getTableRef().getTable().rowKeyOrderOptimizable());
 +                } catch (SQLException e) {
 +                    throw new RuntimeException(e);
 +                }
 +            }
 +            
 +        });
 +        EXPRESSION_MAP.put(SqlKind.GREATER_THAN, new ExpressionFactory() {
 +
 +            @Override
 +            public Expression newExpression(RexNode node, Implementor implementor) {
 +                ImmutableBytesWritable ptr = new ImmutableBytesWritable();
 +                try {
-                     return ComparisonExpression.create(CompareOp.GREATER, convertChildren((RexCall) node, implementor), ptr);
++                    return ComparisonExpression.create(CompareOp.GREATER, convertChildren((RexCall) node, implementor), ptr, implementor.getTableRef().getTable().rowKeyOrderOptimizable());
 +                } catch (SQLException e) {
 +                    throw new RuntimeException(e);
 +                }
 +            }
 +            
 +        });
 +        EXPRESSION_MAP.put(SqlKind.GREATER_THAN_OR_EQUAL, new ExpressionFactory() {
 +
 +            @Override
 +            public Expression newExpression(RexNode node, Implementor implementor) {
 +                ImmutableBytesWritable ptr = new ImmutableBytesWritable();
 +                try {
-                     return ComparisonExpression.create(CompareOp.GREATER_OR_EQUAL, convertChildren((RexCall) node, implementor), ptr);
++                    return ComparisonExpression.create(CompareOp.GREATER_OR_EQUAL, convertChildren((RexCall) node, implementor), ptr, implementor.getTableRef().getTable().rowKeyOrderOptimizable());
 +                } catch (SQLException e) {
 +                    throw new RuntimeException(e);
 +                }
 +            }
 +            
 +        });
 +        EXPRESSION_MAP.put(SqlKind.LESS_THAN, new ExpressionFactory() {
 +
 +            @Override
 +            public Expression newExpression(RexNode node, Implementor implementor) {
 +                ImmutableBytesWritable ptr = new ImmutableBytesWritable();
 +                try {
-                     return ComparisonExpression.create(CompareOp.LESS, convertChildren((RexCall) node, implementor), ptr);
++                    return ComparisonExpression.create(CompareOp.LESS, convertChildren((RexCall) node, implementor), ptr, implementor.getTableRef().getTable().rowKeyOrderOptimizable());
 +                } catch (SQLException e) {
 +                    throw new RuntimeException(e);
 +                }
 +            }
 +            
 +        });
 +        EXPRESSION_MAP.put(SqlKind.LESS_THAN_OR_EQUAL, new ExpressionFactory() {
 +
 +            @Override
 +            public Expression newExpression(RexNode node, Implementor implementor) {
 +                ImmutableBytesWritable ptr = new ImmutableBytesWritable();
 +                try {
-                     return ComparisonExpression.create(CompareOp.LESS_OR_EQUAL, convertChildren((RexCall) node, implementor), ptr);
++                    return ComparisonExpression.create(CompareOp.LESS_OR_EQUAL, convertChildren((RexCall) node, implementor), ptr, implementor.getTableRef().getTable().rowKeyOrderOptimizable());
 +                } catch (SQLException e) {
 +                    throw new RuntimeException(e);
 +                }
 +            }
 +            
 +        });
 +        EXPRESSION_MAP.put(SqlKind.PLUS, new ExpressionFactory() {
 +
 +            @SuppressWarnings("rawtypes")
 +            @Override
 +            public Expression newExpression(RexNode node, Implementor implementor) {
 +                try {
 +                    List<Expression> children = convertChildren((RexCall) node, implementor);
 +                    Expression expr = null;
 +                    boolean foundDate = false;
 +                    Determinism determinism = Determinism.ALWAYS;
 +                    PDataType theType = null;
 +                    for(int i = 0; i < children.size(); i++) {
 +                        Expression e = children.get(i);
 +                        determinism = determinism.combine(e.getDeterminism());
 +                        PDataType type = e.getDataType();
 +                        if (type == null) {
 +                            continue; 
 +                        } else if (type.isCoercibleTo(PTimestamp.INSTANCE)) {
 +                            if (foundDate) {
 +                                throw TypeMismatchException.newException(type, node.toString());
 +                            }
 +                            if (theType == null || (theType != PTimestamp.INSTANCE && theType != PUnsignedTimestamp.INSTANCE)) {
 +                                theType = type;
 +                            }
 +                            foundDate = true;
 +                        }else if (type == PDecimal.INSTANCE) {
 +                            if (theType == null || !theType.isCoercibleTo(PTimestamp.INSTANCE)) {
 +                                theType = PDecimal.INSTANCE;
 +                            }
 +                        } else if (type.isCoercibleTo(PLong.INSTANCE)) {
 +                            if (theType == null) {
 +                                theType = PLong.INSTANCE;
 +                            }
 +                        } else if (type.isCoercibleTo(PDouble.INSTANCE)) {
 +                            if (theType == null) {
 +                                theType = PDouble.INSTANCE;
 +                            }
 +                        } else {
 +                            throw TypeMismatchException.newException(type, node.toString());
 +                        }
 +                    }
 +                    if (theType == PDecimal.INSTANCE) {
 +                        expr = new DecimalAddExpression(children);
 +                    } else if (theType == PLong.INSTANCE) {
 +                        expr = new LongAddExpression(children);
 +                    } else if (theType == PDouble.INSTANCE) {
 +                        expr = new DoubleAddExpression(children);
 +                    } else if (theType == null) {
 +                        expr = LiteralExpression.newConstant(null, theType, determinism);
 +                    } else if (theType == PTimestamp.INSTANCE || theType == PUnsignedTimestamp.INSTANCE) {
 +                        expr = new TimestampAddExpression(children);
 +                    } else if (theType.isCoercibleTo(PDate.INSTANCE)) {
 +                        expr = new DateAddExpression(children);
 +                    } else {
 +                        throw TypeMismatchException.newException(theType, node.toString());
 +                    }
 +                    
 +                    PDataType targetType = sqlTypeNameToPDataType(node.getType().getSqlTypeName());
-                     return cast(targetType, expr);
++                    return cast(targetType, expr, implementor);
 +                } catch (SQLException e) {
 +                    throw new RuntimeException(e);
 +                }
 +            }
 +            
 +        });
 +        EXPRESSION_MAP.put(SqlKind.MINUS, new ExpressionFactory() {
 +
 +            @SuppressWarnings("rawtypes")
 +            @Override
 +            public Expression newExpression(RexNode node, Implementor implementor) {
 +                try {
 +                    List<Expression> children = convertChildren((RexCall) node, implementor);
 +                    Expression expr = null;
 +                    int i = 0;
 +                    PDataType theType = null;
 +                    Expression e1 = children.get(0);
 +                    Expression e2 = children.get(1);
 +                    Determinism determinism = e1.getDeterminism().combine(e2.getDeterminism());
 +                    PDataType type1 = e1.getDataType();
 +                    PDataType type2 = e2.getDataType();
 +                    // TODO: simplify this special case for DATE conversion
 +                    /**
 +                     * For date1-date2, we want to coerce to a LONG because this
 +                     * cannot be compared against another date. It has essentially
 +                     * become a number. For date1-5, we want to preserve the DATE
 +                     * type because this can still be compared against another date
 +                     * and cannot be multiplied or divided. Any other time occurs is
 +                     * an error. For example, 5-date1 is an error. The nulls occur if
 +                     * we have bind variables.
 +                     */
 +                    boolean isType1Date = 
 +                            type1 != null 
 +                            && type1 != PTimestamp.INSTANCE
 +                            && type1 != PUnsignedTimestamp.INSTANCE
 +                            && type1.isCoercibleTo(PDate.INSTANCE);
 +                    boolean isType2Date = 
 +                            type2 != null
 +                            && type2 != PTimestamp.INSTANCE
 +                            && type2 != PUnsignedTimestamp.INSTANCE
 +                            && type2.isCoercibleTo(PDate.INSTANCE);
 +                    if (isType1Date || isType2Date) {
 +                        if (isType1Date && isType2Date) {
 +                            i = 2;
 +                            theType = PDecimal.INSTANCE;
 +                        } else if (isType1Date && type2 != null
 +                                && type2.isCoercibleTo(PDecimal.INSTANCE)) {
 +                            i = 2;
 +                            theType = PDate.INSTANCE;
 +                        } else if (type1 == null || type2 == null) {
 +                            /*
 +                             * FIXME: Could be either a Date or BigDecimal, but we
 +                             * don't know if we're comparing to a date or a number
 +                             * which would be disambiguate it.
 +                             */
 +                            i = 2;
 +                            theType = null;
 +                        }
 +                    } else if(type1 == PTimestamp.INSTANCE || type2 == PTimestamp.INSTANCE) {
 +                        i = 2;
 +                        theType = PTimestamp.INSTANCE;
 +                    } else if(type1 == PUnsignedTimestamp.INSTANCE || type2 == PUnsignedTimestamp.INSTANCE) {
 +                        i = 2;
 +                        theType = PUnsignedTimestamp.INSTANCE;
 +                    }
 +                    
 +                    for (; i < children.size(); i++) {
 +                        // This logic finds the common type to which all child types are coercible
 +                        // without losing precision.
 +                        Expression e = children.get(i);
 +                        determinism = determinism.combine(e.getDeterminism());
 +                        PDataType type = e.getDataType();
 +                        if (type == null) {
 +                            continue;
 +                        } else if (type.isCoercibleTo(PLong.INSTANCE)) {
 +                            if (theType == null) {
 +                                theType = PLong.INSTANCE;
 +                            }
 +                        } else if (type == PDecimal.INSTANCE) {
 +                            // Coerce return type to DECIMAL from LONG or DOUBLE if DECIMAL child found,
 +                            // unless we're doing date arithmetic.
 +                            if (theType == null
 +                                    || !theType.isCoercibleTo(PDate.INSTANCE)) {
 +                                theType = PDecimal.INSTANCE;
 +                            }
 +                        } else if (type.isCoercibleTo(PDouble.INSTANCE)) {
 +                            // Coerce return type to DOUBLE from LONG if DOUBLE child found,
 +                            // unless we're doing date arithmetic or we've found another child of type DECIMAL
 +                            if (theType == null
 +                                    || (theType != PDecimal.INSTANCE && !theType.isCoercibleTo(PDate.INSTANCE) )) {
 +                                theType = PDouble.INSTANCE;
 +                            }
 +                        } else {
 +                            throw TypeMismatchException.newException(type, node.toString());
 +                        }
 +                    }
 +                    if (theType == PDecimal.INSTANCE) {
 +                        expr = new DecimalSubtractExpression(children);
 +                    } else if (theType == PLong.INSTANCE) {
 +                        expr = new LongSubtractExpression(children);
 +                    } else if (theType == PDouble.INSTANCE) {
 +                        expr = new DoubleSubtractExpression(children);
 +                    } else if (theType == null) {
 +                        expr = LiteralExpression.newConstant(null, theType, determinism);
 +                    } else if (theType == PTimestamp.INSTANCE || theType == PUnsignedTimestamp.INSTANCE) {
 +                        expr = new TimestampSubtractExpression(children);
 +                    } else if (theType.isCoercibleTo(PDate.INSTANCE)) {
 +                        expr = new DateSubtractExpression(children);
 +                    } else {
 +                        throw TypeMismatchException.newException(theType, node.toString());
 +                    }
 +                    PDataType targetType = sqlTypeNameToPDataType(node.getType().getSqlTypeName());
-                     return cast(targetType, expr);
++                    return cast(targetType, expr, implementor);
 +                } catch (SQLException e) {
 +                    throw new RuntimeException(e);
 +                }
 +            }
 +            
 +        });
 +        EXPRESSION_MAP.put(SqlKind.TIMES, new ExpressionFactory() {
 +
 +            @SuppressWarnings("rawtypes")
 +            @Override
 +            public Expression newExpression(RexNode node, Implementor implementor) {
 +                try {
 +                    List<Expression> children = convertChildren((RexCall) node, implementor);
 +                    Expression expr = null;
 +                    PDataType theType = null;
 +                    Determinism determinism = Determinism.ALWAYS;
 +                    for(int i = 0; i < children.size(); i++) {
 +                        Expression e = children.get(i);
 +                        determinism = determinism.combine(e.getDeterminism());
 +                        PDataType type = e.getDataType();
 +                        if (type == null) {
 +                            continue;
 +                        } else if (type == PDecimal.INSTANCE) {
 +                            theType = PDecimal.INSTANCE;
 +                        } else if (type.isCoercibleTo(PLong.INSTANCE)) {
 +                            if (theType == null) {
 +                                theType = PLong.INSTANCE;
 +                            }
 +                        } else if (type.isCoercibleTo(PDouble.INSTANCE)) {
 +                            if (theType == null) {
 +                                theType = PDouble.INSTANCE;
 +                            }
 +                        } else {
 +                            throw TypeMismatchException.newException(type, node.toString());
 +                        }
 +                    }
 +                    if (theType == PDecimal.INSTANCE) {
 +                        expr = new DecimalMultiplyExpression(children);
 +                    } else if (theType == PLong.INSTANCE) {
 +                        expr = new LongMultiplyExpression(children);
 +                    } else if (theType == PDouble.INSTANCE) {
 +                        expr = new DoubleMultiplyExpression(children);
 +                    } else {
 +                        expr = LiteralExpression.newConstant(null, theType, determinism);
 +                    }
 +                    PDataType targetType = sqlTypeNameToPDataType(node.getType().getSqlTypeName());
-                     return cast(targetType, expr);
++                    return cast(targetType, expr, implementor);
 +                } catch (SQLException e) {
 +                    throw new RuntimeException(e);
 +                }
 +            }
 +            
 +        });
 +        EXPRESSION_MAP.put(SqlKind.DIVIDE, new ExpressionFactory() {
 +
 +            @SuppressWarnings("rawtypes")
 +            @Override
 +            public Expression newExpression(RexNode node, Implementor implementor) {
 +                try {
 +                    List<Expression> children = convertChildren((RexCall) node, implementor);
 +                    Expression expr = null;
 +                    PDataType theType = null;
 +                    Determinism determinism = Determinism.ALWAYS;
 +                    for(int i = 0; i < children.size(); i++) {
 +                        Expression e = children.get(i);
 +                        determinism = determinism.combine(e.getDeterminism());
 +                        PDataType type = e.getDataType();
 +                        if (type == null) {
 +                            continue;
 +                        } else if (type == PDecimal.INSTANCE) {
 +                            theType = PDecimal.INSTANCE;
 +                        } else if (type.isCoercibleTo(PLong.INSTANCE)) {
 +                            if (theType == null) {
 +                                theType = PLong.INSTANCE;
 +                            }
 +                        } else if (type.isCoercibleTo(PDouble.INSTANCE)) {
 +                            if (theType == null) {
 +                                theType = PDouble.INSTANCE;
 +                            }
 +                        } else {
 +                            throw TypeMismatchException.newException(type, node.toString());
 +                        }
 +                    }
 +                    if (theType == PDecimal.INSTANCE) {
 +                        expr = new DecimalDivideExpression( children);
 +                    } else if (theType == PLong.INSTANCE) {
 +                        expr = new LongDivideExpression( children);
 +                    } else if (theType == PDouble.INSTANCE) {
 +                        expr = new DoubleDivideExpression(children);
 +                    } else {
 +                        expr = LiteralExpression.newConstant(null, theType, determinism);
 +                    }
 +                    PDataType targetType = sqlTypeNameToPDataType(node.getType().getSqlTypeName());
-                     return cast(targetType, expr);
++                    return cast(targetType, expr, implementor);
 +                } catch (SQLException e) {
 +                    throw new RuntimeException(e);
 +                }
 +            }
 +            
 +        });
 +		EXPRESSION_MAP.put(SqlKind.LITERAL, new ExpressionFactory() {
 +
 +			@SuppressWarnings("rawtypes")
 +            @Override
 +			public Expression newExpression(RexNode node, Implementor implementor) {
 +				RexLiteral lit = (RexLiteral) node;
 +                PDataType targetType = sqlTypeNameToPDataType(node.getType().getSqlTypeName());
 +				Object o = lit.getValue();
 +				if (o instanceof NlsString) {
 +				    o = ((NlsString) o).getValue();
 +				} else if (o instanceof ByteString) {
 +				    o = ((ByteString) o).getBytes();
 +				}
 +				try {
 +                    return LiteralExpression.newConstant(o, targetType);
 +                } catch (SQLException e) {
 +                    throw new RuntimeException(e);
 +                }
 +			}
 +			
 +		});
 +		EXPRESSION_MAP.put(SqlKind.INPUT_REF, new ExpressionFactory() {
 +
 +			@Override
 +			public Expression newExpression(RexNode node, Implementor implementor) {
 +				RexInputRef ref = (RexInputRef) node;
 +				int index = ref.getIndex();
 +				return implementor.newColumnExpression(index);
 +			}
 +			
 +		});
 +		EXPRESSION_MAP.put(SqlKind.CAST, new ExpressionFactory() {
 +
 +            @SuppressWarnings("rawtypes")
 +            @Override
 +            public Expression newExpression(RexNode node,
 +                    Implementor implementor) {                
 +                List<Expression> children = convertChildren((RexCall) node, implementor);
 +                PDataType targetType = sqlTypeNameToPDataType(node.getType().getSqlTypeName());
 +                try {
-                     return cast(targetType, children.get(0));
++                    return cast(targetType, children.get(0), implementor);
 +                } catch (SQLException e) {
 +                    throw new RuntimeException(e);
 +                }
 +            }
 +        });
 +        EXPRESSION_MAP.put(SqlKind.OTHER_FUNCTION, new ExpressionFactory() {
 +            @Override
 +            public Expression newExpression(RexNode node,
 +                    Implementor implementor) {
 +                RexCall call = (RexCall) node;
 +                List<Expression> children = convertChildren(call, implementor);
 +                SqlOperator op = call.getOperator();
 +                try {
 +                    if (op == SqlStdOperatorTable.SQRT) {
 +                        return new SqrtFunction(children);
 +                    } else if (op == SqlStdOperatorTable.POWER) {
 +                        return new PowerFunction(children);
 +                    } else if (op == SqlStdOperatorTable.LN) {
 +                        return new LnFunction(children);
 +                    } else if (op == SqlStdOperatorTable.EXP) {
 +                        return new ExpFunction(children);
 +                    } else if (op == SqlStdOperatorTable.ABS) {
 +                        return new AbsFunction(children);
 +                    } else if (op == SqlStdOperatorTable.CURRENT_DATE) {
 +                        return new CurrentDateFunction();
 +                    } else if (op == SqlStdOperatorTable.CURRENT_TIME) {
 +                        return new CurrentTimeFunction();
 +                    } else if (op == SqlStdOperatorTable.LOWER) {
 +                        return new LowerFunction(children);
 +                    } else if (op == SqlStdOperatorTable.UPPER) {
 +                        return new UpperFunction(children);
 +                    } else if (op == SqlStdOperatorTable.COALESCE) {
 +                        return new CoalesceFunction(children);
 +                    }
 +                } catch (SQLException e) {
 +                    throw new RuntimeException(e);
 +                }
 +
 +                throw new UnsupportedOperationException(
 +                        "Unsupported SqlFunction: " + op.getName());
 +            }
 +		});
 +        EXPRESSION_MAP.put(SqlKind.NOT, new ExpressionFactory() {
 +            @Override
 +            public Expression newExpression(RexNode node, Implementor implementor) {
 +                return new NotExpression(convertChildren((RexCall) node, implementor));
 +            }
 +        });
 +        EXPRESSION_MAP.put(SqlKind.IS_TRUE, new ExpressionFactory() {
 +            @Override
 +            public Expression newExpression(RexNode node, Implementor implementor) {
 +                List<Expression> children = convertChildren((RexCall) node, implementor);
 +                return children.get(0);
 +            }
 +        });
 +        EXPRESSION_MAP.put(SqlKind.IS_NOT_TRUE, new ExpressionFactory() {
 +            @Override
 +            public Expression newExpression(RexNode node, Implementor implementor) {
 +                return new NotExpression(convertChildren((RexCall) node, implementor));
 +            }
 +        });
 +        EXPRESSION_MAP.put(SqlKind.IS_FALSE, new ExpressionFactory() {
 +            @Override
 +            public Expression newExpression(RexNode node, Implementor implementor) {
 +                return new NotExpression(convertChildren((RexCall) node, implementor));
 +            }
 +        });
 +        EXPRESSION_MAP.put(SqlKind.IS_NOT_FALSE, new ExpressionFactory() {
 +            @Override
 +            public Expression newExpression(RexNode node, Implementor implementor) {
 +                List<Expression> children = convertChildren((RexCall) node, implementor);
 +                return children.get(0);
 +            }
 +        });
 +        //TODO different kind of LikeExpression based on configuration
 +        EXPRESSION_MAP.put(SqlKind.LIKE, new ExpressionFactory() {
 +            @Override
 +            public Expression newExpression(RexNode node, Implementor implementor) {
 +                List<Expression> children = convertChildren((RexCall) node, implementor);
 +                return new StringBasedLikeExpression(children);
 +            }
 +        });
 +        EXPRESSION_MAP.put(SqlKind.IS_NULL, new ExpressionFactory() {
 +            @Override
 +            public Expression newExpression(RexNode node, Implementor implementor) {
 +                return new IsNullExpression(convertChildren((RexCall) node, implementor), false);
 +            }
 +        });
 +        EXPRESSION_MAP.put(SqlKind.IS_NOT_NULL, new ExpressionFactory() {
 +            @Override
 +            public Expression newExpression(RexNode node, Implementor implementor) {
 +                return new IsNullExpression(convertChildren((RexCall) node, implementor), true);
 +            }
 +        });
 +        EXPRESSION_MAP.put(SqlKind.TRIM, new ExpressionFactory() {
 +            @Override
 +            public Expression newExpression(RexNode node, Implementor implementor) {
 +                //TODO Phoenix only support separate arguments.
 +                try {
 +                    return new TrimFunction(convertChildren((RexCall) node, implementor));
 +                } catch (SQLException e) {
 +                    throw new RuntimeException(e);
 +                }
 +            }
 +        });
 +        EXPRESSION_MAP.put(SqlKind.CEIL, new ExpressionFactory() {
 +            @Override
 +            public Expression newExpression(RexNode node, Implementor implementor) {
 +                //TODO Phoenix only support separate arguments.
 +                List<Expression> children = convertChildren((RexCall) node, implementor);
 +                final Expression firstChild = children.get(0);
 +                final PDataType firstChildDataType = firstChild.getDataType();
 +                try {
 +                    if (firstChildDataType.isCoercibleTo(PDate.INSTANCE)) {
 +                        return CeilDateExpression.create(children);
 +                    } else if (firstChildDataType == PTimestamp.INSTANCE
 +                            || firstChildDataType == PUnsignedTimestamp.INSTANCE) {
 +                        return CeilTimestampExpression.create(children);
 +                    } else if (firstChildDataType.isCoercibleTo(PDecimal.INSTANCE)) {
 +                        return CeilDecimalExpression.create(children);
 +                    } else {
 +                        throw TypeMismatchException.newException(firstChildDataType, "1");
 +                    }
 +                } catch (SQLException e) {
 +                    throw new RuntimeException(e);
 +                }
 +            }
 +        });
 +        EXPRESSION_MAP.put(SqlKind.FLOOR, new ExpressionFactory() {
 +            @Override
 +            public Expression newExpression(RexNode node, Implementor implementor) {
 +                // TODO Phoenix only support separate arguments.
 +                List<Expression> children = convertChildren((RexCall) node, implementor);
 +                final Expression firstChild = children.get(0);
 +                final PDataType firstChildDataType = firstChild.getDataType();
 +                try {
 +                    if (firstChildDataType.isCoercibleTo(PTimestamp.INSTANCE)) {
 +                        return FloorDateExpression.create(children);
 +                    } else if (firstChildDataType.isCoercibleTo(PDecimal.INSTANCE)) {
 +                        return FloorDecimalExpression.create(children);
 +                    } else {
 +                        throw TypeMismatchException.newException(firstChildDataType, "1");
 +                    }
 +                } catch (SQLException e) {
 +                    throw new RuntimeException(e);
 +                }
 +            }
 +        });
 +        // TODO: SqlKind.CASE
 +	}
 +	
 +    private static final Map<String, FunctionFactory> FUNCTION_MAP = Maps
 +            .newHashMapWithExpectedSize(ExpressionType.values().length);
 +    private static final FunctionFactory getFactory(SqlFunction func) {
 +        FunctionFactory fFactory = FUNCTION_MAP.get(func.getName());
 +        if (fFactory == null) {
 +            throw new UnsupportedOperationException("Unsupported SqlFunction: "
 +                    + func);
 +        }
 +        return fFactory;
 +    }
 +    static {
 +        FUNCTION_MAP.put("COUNT", new FunctionFactory() {
 +            @Override
 +            public FunctionExpression newFunction(SqlFunction sqlFunc,
 +                    List<Expression> args) {
 +                if (args.isEmpty()) {
 +                    args = Lists.asList(LiteralExpression.newConstant(1), new Expression[0]);
 +                }
 +                return new CountAggregateFunction(args);
 +            }
 +        });
 +        // TODO Buggy. Disable for now.
 +        //FUNCTION_MAP.put("$SUM0", new FunctionFactory() {
 +        //    @Override
 +        //    public FunctionExpression newFunction(SqlFunction sqlFunc,
 +        //            List<Expression> args) {
 +        //        return new SumAggregateFunction(args);
 +        //    }
 +        //});
 +        FUNCTION_MAP.put("MAX", new FunctionFactory() {
 +            @Override
 +            public FunctionExpression newFunction(SqlFunction sqlFunc,
 +                    List<Expression> args) {
 +                return new MaxAggregateFunction(args, null);
 +            }
 +        });
 +        FUNCTION_MAP.put("MIN", new FunctionFactory() {
 +            @Override
 +            public FunctionExpression newFunction(SqlFunction sqlFunc,
 +                    List<Expression> args) {
 +                return new MinAggregateFunction(args, null);
 +            }
 +        });
 +    }
 +    
 +    private static List<Expression> convertChildren(RexCall call, Implementor implementor) {
 +        List<Expression> children = Lists.newArrayListWithExpectedSize(call.getOperands().size());
 +        for (RexNode op : call.getOperands()) {
 +            Expression child = getFactory(op).newExpression(op, implementor);
 +            children.add(child);
 +        }
 +        return children;
 +    }
 +    
 +    @SuppressWarnings("rawtypes")
-     private static Expression cast(PDataType targetDataType, Expression childExpr) throws SQLException {
++    private static Expression cast(PDataType targetDataType, Expression childExpr, Implementor implementor) throws SQLException {
 +        PDataType fromDataType = childExpr.getDataType();
 +        
 +        Expression expr = childExpr;
 +        if(fromDataType != null) {
 +            expr =  convertToRoundExpressionIfNeeded(fromDataType, targetDataType, childExpr);
 +        }
-         return CoerceExpression.create(expr, targetDataType, SortOrder.getDefault(), expr.getMaxLength());
++        return CoerceExpression.create(expr, targetDataType, SortOrder.getDefault(), expr.getMaxLength(), implementor.getTableRef().getTable().rowKeyOrderOptimizable());
 +    }
 +    
 +    @SuppressWarnings("rawtypes")
 +    private static Expression convertToRoundExpressionIfNeeded(PDataType fromDataType, PDataType targetDataType, Expression expr) throws SQLException {
 +        if(fromDataType == targetDataType) {
 +            return expr;
 +        } else if((fromDataType == PDecimal.INSTANCE || fromDataType == PTimestamp.INSTANCE || fromDataType == PUnsignedTimestamp.INSTANCE) && targetDataType.isCoercibleTo(
 +          PLong.INSTANCE)) {
 +            return RoundDecimalExpression.create(Arrays.asList(expr));
 +        } else if((fromDataType == PDecimal.INSTANCE || fromDataType == PTimestamp.INSTANCE || fromDataType == PUnsignedTimestamp.INSTANCE) && targetDataType.isCoercibleTo(
 +          PDate.INSTANCE)) {
 +            return RoundTimestampExpression.create(Arrays.asList(expr));
 +        } else if(fromDataType.isCastableTo(targetDataType)) {
 +            return expr;
 +        } else {
 +            throw TypeMismatchException.newException(fromDataType, targetDataType, expr.toString());
 +        }
 +    }
 +
 +    public static boolean isExpressionSupported(RexNode node) {
 +        try {
 +            getFactory(node);
 +        } catch (UnsupportedOperationException e) {
 +            return false;
 +        }
 +        if (node instanceof RexCall) {
 +            for (RexNode op : ((RexCall) node).getOperands()) {
 +                if (!isExpressionSupported(op)) {
 +                    return false;
 +                }
 +            }
 +        }
 +        
 +        return true;
 +    }
 +    
 +    public static boolean isAggregateFunctionSupported(SqlAggFunction aggFunc) {
 +        try {
 +            getFactory(aggFunc);
 +        } catch (UnsupportedOperationException e) {
 +            return false;
 +        }
 +
 +        return true;
 +    }
 +
 +	public static Expression toExpression(RexNode node, Implementor implementor) {
 +		ExpressionFactory eFactory = getFactory(node);
 +		Expression expression = eFactory.newExpression(node, implementor);
 +		return expression;
 +	}
 +	
 +	public static AggregateFunction toAggregateFunction(SqlAggFunction aggFunc, List<Integer> args, Implementor implementor) {
 +	    FunctionFactory fFactory = getFactory(aggFunc);
 +	    List<Expression> exprs = Lists.newArrayListWithExpectedSize(args.size());
 +	    for (Integer index : args) {
 +	        exprs.add(implementor.newColumnExpression(index));
 +	    }
 +	    
 +	    return (AggregateFunction) (fFactory.newFunction(aggFunc, exprs));
 +	}
 +	
 +	public static Object evaluateStatelessExpression(RexNode node) {
 +	    try {
 +	        Expression expression = toExpression(node, null);
 +	        if (expression.isStateless() && expression.getDeterminism() == Determinism.ALWAYS) {
 +	            ImmutableBytesWritable ptr = new ImmutableBytesWritable();
 +	            expression.evaluate(null, ptr);
 +	            return expression.getDataType().toObject(ptr);
 +	        }
 +	    } catch (Exception e) {
 +	        // Expression is not stateless. do nothing.
 +	    }
 +	    
 +	    return null;
 +	}
 +	
 +	public static interface ExpressionFactory {
 +		public Expression newExpression(RexNode node, Implementor implementor);
 +	}
 +	
 +	public static interface FunctionFactory {
 +	    public FunctionExpression newFunction(SqlFunction sqlFunc, List<Expression> args);
 +	}
 +}

http://git-wip-us.apache.org/repos/asf/phoenix/blob/ab97f1cc/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixValues.java
----------------------------------------------------------------------
diff --cc phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixValues.java
index 44480b8,0000000..b65b1b8
mode 100644,000000..100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixValues.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/calcite/rel/PhoenixValues.java
@@@ -1,129 -1,0 +1,129 @@@
 +package org.apache.phoenix.calcite.rel;
 +
 +import static org.apache.phoenix.util.PhoenixRuntime.CONNECTIONLESS;
 +import static org.apache.phoenix.util.PhoenixRuntime.JDBC_PROTOCOL;
 +import static org.apache.phoenix.util.PhoenixRuntime.JDBC_PROTOCOL_SEPARATOR;
 +
 +import java.sql.Connection;
 +import java.sql.DriverManager;
 +import java.sql.SQLException;
 +import java.util.Iterator;
 +import java.util.List;
 +
 +import org.apache.calcite.plan.RelOptCluster;
 +import org.apache.calcite.plan.RelOptCost;
 +import org.apache.calcite.plan.RelOptPlanner;
 +import org.apache.calcite.plan.RelTraitSet;
 +import org.apache.calcite.rel.RelCollation;
 +import org.apache.calcite.rel.RelCollationTraitDef;
 +import org.apache.calcite.rel.RelDistribution;
 +import org.apache.calcite.rel.RelDistributionTraitDef;
 +import org.apache.calcite.rel.RelNode;
 +import org.apache.calcite.rel.core.Values;
 +import org.apache.calcite.rel.metadata.RelMdCollation;
 +import org.apache.calcite.rel.metadata.RelMdDistribution;
 +import org.apache.calcite.rel.type.RelDataType;
 +import org.apache.calcite.rex.RexLiteral;
 +import org.apache.hadoop.hbase.KeyValue;
 +import org.apache.hadoop.hbase.client.Scan;
 +import org.apache.phoenix.calcite.CalciteUtils;
 +import org.apache.phoenix.compile.OrderByCompiler.OrderBy;
 +import org.apache.phoenix.compile.ColumnResolver;
 +import org.apache.phoenix.compile.FromCompiler;
 +import org.apache.phoenix.compile.QueryPlan;
 +import org.apache.phoenix.compile.RowProjector;
 +import org.apache.phoenix.compile.SequenceManager;
 +import org.apache.phoenix.compile.StatementContext;
- import org.apache.phoenix.execute.LiteralResultIterationQueryPlan;
++import org.apache.phoenix.execute.LiteralResultIterationPlan;
 +import org.apache.phoenix.execute.TupleProjector;
 +import org.apache.phoenix.expression.Expression;
 +import org.apache.phoenix.jdbc.PhoenixConnection;
 +import org.apache.phoenix.jdbc.PhoenixStatement;
 +import org.apache.phoenix.parse.SelectStatement;
 +import org.apache.phoenix.schema.TableRef;
 +import org.apache.phoenix.schema.tuple.SingleKeyValueTuple;
 +import org.apache.phoenix.schema.tuple.Tuple;
 +
 +import com.google.common.base.Supplier;
 +import com.google.common.collect.ImmutableList;
 +import com.google.common.collect.Lists;
 +
 +/**
 + * Implementation of {@link org.apache.calcite.rel.core.Values}
 + * relational expression in Phoenix.
 + */
 +public class PhoenixValues extends Values implements PhoenixRel {
 +    
 +    private static final PhoenixConnection phoenixConnection;
 +    static {
 +        try {
 +            Class.forName("org.apache.phoenix.jdbc.PhoenixDriver");
 +            final Connection connection =
 +                DriverManager.getConnection(JDBC_PROTOCOL + JDBC_PROTOCOL_SEPARATOR + CONNECTIONLESS);
 +            phoenixConnection =
 +                connection.unwrap(PhoenixConnection.class);
 +        } catch (ClassNotFoundException e) {
 +            throw new RuntimeException(e);
 +        } catch (SQLException e) {
 +            throw new RuntimeException(e);
 +        }
 +    }
 +    
 +    public static PhoenixValues create(RelOptCluster cluster, final RelDataType rowType, final ImmutableList<ImmutableList<RexLiteral>> tuples) {
 +        final RelTraitSet traits =
 +                cluster.traitSetOf(PhoenixRel.CLIENT_CONVENTION)
 +                .replaceIfs(RelCollationTraitDef.INSTANCE,
 +                        new Supplier<List<RelCollation>>() {
 +                    public List<RelCollation> get() {
 +                        return RelMdCollation.values(rowType, tuples);
 +                    }
 +                })
 +                .replaceIf(RelDistributionTraitDef.INSTANCE,
 +                        new Supplier<RelDistribution>() {
 +                    public RelDistribution get() {
 +                        return RelMdDistribution.values(rowType, tuples);
 +                    }
 +                });
 +        return new PhoenixValues(cluster, rowType, tuples, traits);
 +    }
 +    
 +    private PhoenixValues(RelOptCluster cluster, RelDataType rowType, ImmutableList<ImmutableList<RexLiteral>> tuples, RelTraitSet traits) {
 +        super(cluster, rowType, tuples, traits);
 +    }
 +
 +    @Override
 +    public PhoenixValues copy(RelTraitSet traitSet, List<RelNode> inputs) {
 +        assert inputs.isEmpty();
 +        return create(getCluster(), rowType, tuples);
 +    }
 +
 +    @Override
 +    public RelOptCost computeSelfCost(RelOptPlanner planner) {
 +        return super.computeSelfCost(planner).multiplyBy(PHOENIX_FACTOR);
 +    }
 +
 +    @Override
 +    public QueryPlan implement(Implementor implementor) {
 +        List<Tuple> literalResult = Lists.newArrayList();
 +        Iterator<ImmutableList<RexLiteral>> iter = getTuples().iterator();
 +        Tuple baseTuple = new SingleKeyValueTuple(KeyValue.LOWESTKEY);
 +        while (iter.hasNext()) {
 +            ImmutableList<RexLiteral> row = iter.next();
 +            List<Expression> exprs = Lists.newArrayListWithExpectedSize(row.size());
 +            for (RexLiteral rexLiteral : row) {
 +                exprs.add(CalciteUtils.toExpression(rexLiteral, implementor));
 +            }
 +            TupleProjector projector = implementor.project(exprs);
 +            literalResult.add(projector.projectResults(baseTuple));
 +        }
 +        
 +        try {
 +            PhoenixStatement stmt = new PhoenixStatement(phoenixConnection);
 +            ColumnResolver resolver = FromCompiler.getResolver(implementor.getTableRef());
 +            StatementContext context = new StatementContext(stmt, resolver, new Scan(), new SequenceManager(stmt));
-             return new LiteralResultIterationQueryPlan(literalResult.iterator(), context, SelectStatement.SELECT_ONE, TableRef.EMPTY_TABLE_REF, RowProjector.EMPTY_PROJECTOR, null, OrderBy.EMPTY_ORDER_BY, null);
++            return new LiteralResultIterationPlan(literalResult.iterator(), context, SelectStatement.SELECT_ONE, TableRef.EMPTY_TABLE_REF, RowProjector.EMPTY_PROJECTOR, null, OrderBy.EMPTY_ORDER_BY, null);
 +        } catch (SQLException e) {
 +            throw new RuntimeException(e);
 +        }
 +    }
 +}

http://git-wip-us.apache.org/repos/asf/phoenix/blob/ab97f1cc/phoenix-core/src/main/java/org/apache/phoenix/compile/ListJarsQueryPlan.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/phoenix/blob/ab97f1cc/phoenix-core/src/main/java/org/apache/phoenix/compile/WhereCompiler.java
----------------------------------------------------------------------
diff --cc phoenix-core/src/main/java/org/apache/phoenix/compile/WhereCompiler.java
index 16405c0,13963d7..3089b03
--- a/phoenix-core/src/main/java/org/apache/phoenix/compile/WhereCompiler.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/compile/WhereCompiler.java
@@@ -232,10 -232,10 +232,10 @@@ public class WhereCompiler 
       * @param context the shared context during query compilation
       * @param whereClause the final where clause expression.
       */
 -    private static void setScanFilter(StatementContext context, FilterableStatement statement, Expression whereClause, boolean disambiguateWithFamily, boolean hashJoinOptimization) {
 +    public static void setScanFilter(StatementContext context, FilterableStatement statement, Expression whereClause, boolean disambiguateWithFamily, boolean hashJoinOptimization) {
          Scan scan = context.getScan();
  
-         if (LiteralExpression.isFalse(whereClause)) {
+         if (LiteralExpression.isBooleanFalseOrNull(whereClause)) {
              context.setScanRanges(ScanRanges.NOTHING);
          } else if (whereClause != null && !LiteralExpression.isTrue(whereClause) && !hashJoinOptimization) {
              Filter filter = null;

http://git-wip-us.apache.org/repos/asf/phoenix/blob/ab97f1cc/phoenix-core/src/main/java/org/apache/phoenix/execute/HashJoinPlan.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/phoenix/blob/ab97f1cc/phoenix-core/src/main/java/org/apache/phoenix/execute/LiteralResultIterationPlan.java
----------------------------------------------------------------------
diff --cc phoenix-core/src/main/java/org/apache/phoenix/execute/LiteralResultIterationPlan.java
index 0000000,e7230cc..58c78d2
mode 000000,100644..100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/execute/LiteralResultIterationPlan.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/execute/LiteralResultIterationPlan.java
@@@ -1,0 -1,108 +1,118 @@@
+ /*
+  * 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.execute;
+ 
+ import java.sql.SQLException;
+ import java.util.Collections;
+ import java.util.Iterator;
+ import java.util.List;
+ 
+ import org.apache.hadoop.hbase.KeyValue;
+ import org.apache.hadoop.hbase.client.Scan;
+ import org.apache.phoenix.compile.GroupByCompiler.GroupBy;
+ import org.apache.phoenix.compile.OrderByCompiler.OrderBy;
++import org.apache.phoenix.compile.QueryPlan;
+ import org.apache.phoenix.compile.RowProjector;
+ import org.apache.phoenix.compile.StatementContext;
+ import org.apache.phoenix.iterate.ParallelIteratorFactory;
+ import org.apache.phoenix.iterate.ParallelScanGrouper;
+ import org.apache.phoenix.iterate.ResultIterator;
+ import org.apache.phoenix.iterate.SequenceResultIterator;
+ import org.apache.phoenix.parse.FilterableStatement;
+ import org.apache.phoenix.query.KeyRange;
+ import org.apache.phoenix.schema.TableRef;
+ import org.apache.phoenix.schema.tuple.SingleKeyValueTuple;
+ import org.apache.phoenix.schema.tuple.Tuple;
+ 
+ public class LiteralResultIterationPlan extends BaseQueryPlan {
+     protected final Iterator<Tuple> tupleIterator;
+ 
+     public LiteralResultIterationPlan(StatementContext context, 
+             FilterableStatement statement, TableRef tableRef, RowProjector projection, 
+             Integer limit, OrderBy orderBy, ParallelIteratorFactory parallelIteratorFactory) {
+         this(Collections.<Tuple> singletonList(new SingleKeyValueTuple(KeyValue.LOWESTKEY)).iterator(), 
+                 context, statement, tableRef, projection, limit, orderBy, parallelIteratorFactory);
+     }
+ 
+     public LiteralResultIterationPlan(Iterator<Tuple> tupleIterator, StatementContext context, 
+             FilterableStatement statement, TableRef tableRef, RowProjector projection, 
+             Integer limit, OrderBy orderBy, ParallelIteratorFactory parallelIteratorFactory) {
+         super(context, statement, tableRef, projection, context.getBindManager().getParameterMetaData(), limit, orderBy, GroupBy.EMPTY_GROUP_BY, parallelIteratorFactory);
+         this.tupleIterator = tupleIterator;
+     }
+ 
+     @Override
+     public List<KeyRange> getSplits() {
+         return Collections.emptyList();
+     }
+ 
+     @Override
+     public List<List<Scan>> getScans() {
+         return Collections.emptyList();
+     }
+ 
+     @Override
+     public boolean useRoundRobinIterator() throws SQLException {
+         return false;
+     }
+ 
+     @Override
+     protected ResultIterator newIterator(ParallelScanGrouper scanGrouper)
+             throws SQLException {
+         ResultIterator scanner = new ResultIterator() {
+             private boolean closed = false;
+             private int count = 0;
+ 
+             @Override
+             public void close() throws SQLException {
+                 this.closed = true;;
+             }
+ 
+             @Override
+             public Tuple next() throws SQLException {
+                 if (!this.closed 
+                         && (limit == null || count++ < limit)
+                         && tupleIterator.hasNext()) {
+                     return tupleIterator.next();
+                 }
+                 return null;
+             }
+ 
+             @Override
+             public void explain(List<String> planSteps) {
+             }
+             
+         };
+         
+         if (context.getSequenceManager().getSequenceCount() > 0) {
+             scanner = new SequenceResultIterator(scanner, context.getSequenceManager());
+         }
+         
+         return scanner;
+     }
+ 
++    @Override
++    public QueryPlan limit(Integer limit) {
++        if (limit == this.limit || (limit != null && limit.equals(this.limit)))
++            return this;
++        
++        return new LiteralResultIterationPlan(this.tupleIterator, this.context, this.statement, this.tableRef, 
++                this.projection, limit, this.orderBy, this.parallelIteratorFactory);
++    }
++
+ }

http://git-wip-us.apache.org/repos/asf/phoenix/blob/ab97f1cc/phoenix-core/src/test/java/org/apache/phoenix/query/BaseTest.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/phoenix/blob/ab97f1cc/pom.xml
----------------------------------------------------------------------