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 <wei....@intel.com> Authored: Sun Aug 23 13:14:46 2015 -0400 Committer: maryannxue <wei....@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 ----------------------------------------------------------------------