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 2017/03/16 21:12:12 UTC

[50/50] [abbrv] phoenix git commit: Fix merge conflicts; fix compilation errors; fix test failures

Fix merge conflicts; fix compilation errors; fix test failures


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

Branch: refs/heads/calcite
Commit: db78bd6fd9c4661c550024e35f82a2b812b548df
Parents: 5e47b46 bc814f1
Author: maryannxue <ma...@gmail.com>
Authored: Thu Mar 16 14:11:10 2017 -0700
Committer: maryannxue <ma...@gmail.com>
Committed: Thu Mar 16 14:11:10 2017 -0700

----------------------------------------------------------------------
 LICENSE                                         |   10 -
 phoenix-assembly/pom.xml                        |    6 +-
 .../src/build/components/all-common-jars.xml    |    8 +
 phoenix-client/pom.xml                          |    2 +-
 phoenix-core/pom.xml                            |    2 +-
 .../apache/phoenix/calcite/BaseCalciteIT.java   |   27 +-
 .../phoenix/calcite/BaseCalciteIndexIT.java     |    2 +-
 .../phoenix/calcite/CalciteGlobalIndexIT.java   |   14 +-
 .../org/apache/phoenix/calcite/CalciteIT.java   |  151 +-
 .../phoenix/calcite/CalciteLocalIndexIT.java    |   16 +-
 .../phoenix/end2end/AggregateQueryIT.java       |   74 +-
 .../AlterMultiTenantTableWithViewsIT.java       |   25 +-
 .../apache/phoenix/end2end/AlterTableIT.java    |  491 +-
 .../phoenix/end2end/AlterTableWithViewsIT.java  |  133 +-
 .../org/apache/phoenix/end2end/ArrayIT.java     |   28 +
 .../org/apache/phoenix/end2end/BaseJoinIT.java  |    4 +-
 .../org/apache/phoenix/end2end/BaseQueryIT.java |   98 +-
 .../apache/phoenix/end2end/CaseStatementIT.java |   54 +-
 .../apache/phoenix/end2end/CastAndCoerceIT.java |   34 +-
 .../end2end/ClientTimeArithmeticQueryIT.java    |   76 +-
 .../end2end/ColumnEncodedBytesPropIT.java       |  112 +
 .../end2end/CountDistinctCompressionIT.java     |    2 +-
 .../apache/phoenix/end2end/CreateTableIT.java   |  136 +
 .../phoenix/end2end/CsvBulkLoadToolIT.java      |   36 +
 .../org/apache/phoenix/end2end/DateTimeIT.java  |    2 +-
 .../phoenix/end2end/DefaultColumnValueIT.java   |    1 +
 .../apache/phoenix/end2end/DerivedTableIT.java  |    2 +-
 .../apache/phoenix/end2end/DistinctCountIT.java |    4 +-
 .../apache/phoenix/end2end/DropSchemaIT.java    |   11 +
 .../apache/phoenix/end2end/DynamicColumnIT.java |   63 +
 .../phoenix/end2end/ExtendedQueryExecIT.java    |    8 +-
 .../apache/phoenix/end2end/FunkyNamesIT.java    |    2 +-
 .../apache/phoenix/end2end/GroupByCaseIT.java   |   66 +-
 .../org/apache/phoenix/end2end/GroupByIT.java   |  162 +-
 .../phoenix/end2end/ImmutableTablePropIT.java   |  130 -
 .../end2end/ImmutableTablePropertiesIT.java     |  189 +
 .../apache/phoenix/end2end/MutableQueryIT.java  |  424 ++
 .../phoenix/end2end/NativeHBaseTypesIT.java     |    2 +-
 .../org/apache/phoenix/end2end/NotQueryIT.java  |   28 +-
 .../org/apache/phoenix/end2end/OrderByIT.java   |    2 -
 .../apache/phoenix/end2end/PercentileIT.java    |    4 +-
 .../phoenix/end2end/PhoenixRuntimeIT.java       |    4 +-
 .../phoenix/end2end/PointInTimeQueryIT.java     |   78 +-
 .../phoenix/end2end/ProductMetricsIT.java       |    2 +-
 .../end2end/QueryDatabaseMetaDataIT.java        |   16 +-
 .../org/apache/phoenix/end2end/QueryIT.java     |  112 +-
 .../phoenix/end2end/ReadIsolationLevelIT.java   |    2 +-
 .../phoenix/end2end/RegexBulkLoadToolIT.java    |  371 ++
 .../apache/phoenix/end2end/RenewLeaseIT.java    |    7 +-
 .../phoenix/end2end/RowValueConstructorIT.java  |   36 +-
 .../org/apache/phoenix/end2end/ScanQueryIT.java |   93 +-
 .../phoenix/end2end/StatsCollectorIT.java       |  124 +-
 .../apache/phoenix/end2end/StoreNullsIT.java    |  310 +-
 .../phoenix/end2end/StoreNullsPropIT.java       |   51 +
 ...SysTableNamespaceMappedStatsCollectorIT.java |    4 +-
 .../java/org/apache/phoenix/end2end/TopNIT.java |    6 +-
 .../phoenix/end2end/UpperLowerFunctionIT.java   |  119 +
 .../apache/phoenix/end2end/UpsertSelectIT.java  |   10 +-
 .../apache/phoenix/end2end/UpsertValuesIT.java  |   51 +-
 .../phoenix/end2end/UserDefinedFunctionsIT.java |    3 +-
 .../phoenix/end2end/VariableLengthPKIT.java     |   38 +-
 .../phoenix/end2end/index/DropColumnIT.java     |  517 ++
 .../phoenix/end2end/index/DropMetadataIT.java   |  215 -
 .../phoenix/end2end/index/ImmutableIndexIT.java |   20 +-
 .../end2end/index/IndexExpressionIT.java        |   28 +-
 .../apache/phoenix/end2end/index/IndexIT.java   |   58 +-
 .../phoenix/end2end/index/IndexTestUtil.java    |   11 +-
 .../phoenix/end2end/index/LocalIndexIT.java     |   79 +
 .../end2end/index/MutableIndexFailureIT.java    |    2 +
 .../phoenix/end2end/index/MutableIndexIT.java   |   96 +-
 .../phoenix/end2end/salted/SaltedTableIT.java   |    2 +-
 .../EndToEndCoveredColumnsIndexBuilderIT.java   |    2 +-
 .../iterate/RenewLeaseOnlyTableIterator.java    |   17 +-
 .../phoenix/monitoring/PhoenixMetricsIT.java    |   39 +-
 .../SystemCatalogWALEntryFilterIT.java          |  185 +
 .../phoenix/trace/PhoenixTracingEndToEndIT.java |    6 +-
 .../phoenix/tx/ParameterizedTransactionIT.java  |  518 ++
 .../org/apache/phoenix/tx/TransactionIT.java    |  589 +-
 .../org/apache/phoenix/tx/TxCheckpointIT.java   |   42 +-
 .../calcite/jdbc/PhoenixCalciteFactory.java     |   28 -
 .../DataTableLocalIndexRegionScanner.java       |   86 +
 .../IndexHalfStoreFileReaderGenerator.java      |   72 +-
 .../regionserver/wal/IndexedWALEditCodec.java   |   20 +-
 .../apache/phoenix/cache/ServerCacheClient.java |    2 +
 .../org/apache/phoenix/cache/TenantCache.java   |    2 +-
 .../apache/phoenix/cache/TenantCacheImpl.java   |    4 +-
 .../apache/phoenix/calcite/PhoenixSchema.java   |    2 +-
 .../apache/phoenix/calcite/TableMapping.java    |   21 +-
 .../calcite/rel/PhoenixRelImplementorImpl.java  |   10 +-
 .../phoenix/calcite/rel/PhoenixTableModify.java |   10 +-
 .../phoenix/calcite/rel/PhoenixTableScan.java   |    2 +-
 .../phoenix/compile/CreateTableCompiler.java    |   10 +-
 .../apache/phoenix/compile/DeleteCompiler.java  |    2 +-
 .../phoenix/compile/ExpressionCompiler.java     |   18 +-
 .../apache/phoenix/compile/FromCompiler.java    |   54 +-
 .../apache/phoenix/compile/JoinCompiler.java    |   15 +-
 .../phoenix/compile/ListJarsQueryPlan.java      |    6 +-
 .../apache/phoenix/compile/PostDDLCompiler.java |   11 +-
 .../compile/PostLocalIndexDDLCompiler.java      |    9 +-
 .../phoenix/compile/ProjectionCompiler.java     |   35 +-
 .../apache/phoenix/compile/TraceQueryPlan.java  |    4 +-
 .../compile/TupleProjectionCompiler.java        |   43 +-
 .../apache/phoenix/compile/UnionCompiler.java   |    7 +-
 .../apache/phoenix/compile/UpsertCompiler.java  |   32 +-
 .../apache/phoenix/compile/WhereCompiler.java   |   24 +-
 .../coprocessor/BaseScannerRegionObserver.java  |   54 +-
 .../GroupedAggregateRegionObserver.java         |   42 +-
 .../coprocessor/HashJoinRegionScanner.java      |   25 +-
 .../coprocessor/MetaDataEndpointImpl.java       |  273 +-
 .../phoenix/coprocessor/MetaDataProtocol.java   |    6 +-
 .../coprocessor/MetaDataRegionObserver.java     |   34 +-
 .../phoenix/coprocessor/ScanRegionObserver.java |   33 +-
 .../coprocessor/ServerCachingEndpointImpl.java  |    2 +-
 .../coprocessor/ServerCachingProtocol.java      |    2 +-
 .../UngroupedAggregateRegionObserver.java       |  147 +-
 .../coprocessor/generated/PTableProtos.java     | 1474 ++++-
 .../generated/ServerCachingProtos.java          | 5125 +++++++++++++++++-
 .../phoenix/exception/SQLExceptionCode.java     |    9 +-
 .../apache/phoenix/execute/BaseQueryPlan.java   |   27 +-
 .../apache/phoenix/execute/CorrelatePlan.java   |    2 +-
 .../apache/phoenix/execute/MutationState.java   |   16 +-
 .../phoenix/execute/SortMergeJoinPlan.java      |    2 +-
 .../apache/phoenix/execute/TupleProjector.java  |   72 +-
 .../apache/phoenix/execute/UnnestArrayPlan.java |    3 +-
 .../expression/ArrayConstructorExpression.java  |   82 +-
 .../phoenix/expression/CoerceExpression.java    |    7 +-
 .../phoenix/expression/ExpressionType.java      |    5 +-
 .../expression/KeyValueColumnExpression.java    |   32 +-
 .../phoenix/expression/LiteralExpression.java   |   11 +-
 .../expression/ProjectedColumnExpression.java   |    1 +
 .../expression/SingleCellColumnExpression.java  |  182 +
 .../SingleCellConstructorExpression.java        |  102 +
 .../function/ArrayElemRefExpression.java        |    4 +-
 .../expression/function/ArrayIndexFunction.java |    4 +-
 .../expression/util/regex/JONIPattern.java      |   18 +-
 .../visitor/BaseExpressionVisitor.java          |    6 +
 .../visitor/CloneExpressionVisitor.java         |   12 +
 .../CloneNonDeterministicExpressionVisitor.java |    1 +
 .../expression/visitor/ExpressionVisitor.java   |    6 +
 .../StatelessTraverseAllExpressionVisitor.java  |   12 +
 .../StatelessTraverseNoExpressionVisitor.java   |   12 +
 .../phoenix/filter/ColumnProjectionFilter.java  |   24 +-
 ...EncodedQualifiersColumnProjectionFilter.java |  151 +
 .../MultiEncodedCQKeyValueComparisonFilter.java |  369 ++
 .../filter/MultiKeyValueComparisonFilter.java   |    6 +-
 .../SingleCQKeyValueComparisonFilter.java       |    3 +-
 .../filter/SingleKeyValueComparisonFilter.java  |    4 +-
 .../apache/phoenix/filter/SkipScanFilter.java   |   15 +-
 .../org/apache/phoenix/hbase/index/Indexer.java |    7 +-
 .../apache/phoenix/hbase/index/ValueGetter.java |    1 +
 .../hbase/index/covered/LocalTableState.java    |   14 +-
 .../phoenix/hbase/index/covered/TableState.java |    4 +-
 .../example/CoveredColumnIndexCodec.java        |    4 +-
 .../hbase/index/scanner/ScannerBuilder.java     |    8 +-
 .../hbase/index/util/IndexManagementUtil.java   |    2 +-
 .../hbase/index/util/KeyValueBuilder.java       |    1 +
 .../apache/phoenix/index/IndexMaintainer.java   |  538 +-
 .../phoenix/index/IndexMetaDataCacheClient.java |    1 +
 .../index/IndexMetaDataCacheFactory.java        |    4 +-
 .../phoenix/index/PhoenixIndexBuilder.java      |    2 +-
 .../apache/phoenix/index/PhoenixIndexCodec.java |   26 +-
 .../index/PhoenixIndexFailurePolicy.java        |    2 +-
 .../phoenix/index/PhoenixIndexMetaData.java     |    9 +-
 .../index/PhoenixTransactionalIndexer.java      |   18 +-
 .../phoenix/iterate/BaseResultIterators.java    |  111 +-
 .../iterate/LookAheadResultIterator.java        |    2 +-
 .../phoenix/iterate/MappedByteBufferQueue.java  |    1 +
 .../phoenix/iterate/OrderedResultIterator.java  |    3 +-
 .../iterate/RegionScannerResultIterator.java    |   19 +-
 .../phoenix/iterate/TableResultIterator.java    |  186 +-
 .../apache/phoenix/jdbc/PhoenixConnection.java  |    2 +
 .../phoenix/jdbc/PhoenixDatabaseMetaData.java   |   14 +-
 .../org/apache/phoenix/jdbc/PhoenixDriver.java  |    3 -
 .../phoenix/jdbc/PhoenixEmbeddedDriver.java     |   39 +-
 .../apache/phoenix/jdbc/PhoenixResultSet.java   |    2 +-
 .../apache/phoenix/join/HashCacheFactory.java   |    2 +-
 .../phoenix/mapreduce/AbstractBulkLoadTool.java |    2 +-
 .../mapreduce/FormatToBytesWritableMapper.java  |   54 +-
 .../mapreduce/FormatToKeyValueReducer.java      |   58 +-
 .../mapreduce/MultiHfileOutputFormat.java       |    2 +-
 .../phoenix/mapreduce/PhoenixInputFormat.java   |   69 +-
 .../phoenix/mapreduce/PhoenixInputSplit.java    |   23 +-
 .../phoenix/mapreduce/RegexBulkLoadTool.java    |   74 +
 .../mapreduce/RegexToKeyValueMapper.java        |  135 +
 .../phoenix/mapreduce/index/IndexTool.java      |   12 +-
 .../index/PhoenixIndexPartialBuildMapper.java   |    4 +-
 .../util/PhoenixConfigurationUtil.java          |   11 +
 .../phoenix/monitoring/GlobalClientMetrics.java |    8 +-
 .../apache/phoenix/monitoring/MetricType.java   |    5 +-
 .../query/ConnectionQueryServicesImpl.java      |  184 +-
 .../query/ConnectionlessQueryServicesImpl.java  |    1 -
 .../java/org/apache/phoenix/query/KeyRange.java |   72 +-
 .../apache/phoenix/query/QueryConstants.java    |   59 +-
 .../org/apache/phoenix/query/QueryServices.java |   12 +-
 .../phoenix/query/QueryServicesOptions.java     |   10 +-
 .../SystemCatalogWALEntryFilter.java            |   69 +
 .../org/apache/phoenix/schema/ColumnRef.java    |   16 +-
 .../phoenix/schema/ColumnValueDecoder.java      |   31 +
 .../phoenix/schema/ColumnValueEncoder.java      |   45 +
 .../apache/phoenix/schema/DelegateColumn.java   |    4 +
 .../apache/phoenix/schema/DelegateTable.java    |   24 +-
 .../apache/phoenix/schema/MetaDataClient.java   |  594 +-
 .../java/org/apache/phoenix/schema/PColumn.java |    4 +-
 .../apache/phoenix/schema/PColumnFamily.java    |   14 +-
 .../phoenix/schema/PColumnFamilyImpl.java       |   49 +-
 .../org/apache/phoenix/schema/PColumnImpl.java  |   29 +-
 .../apache/phoenix/schema/PMetaDataImpl.java    |    4 +-
 .../java/org/apache/phoenix/schema/PTable.java  |  435 +-
 .../org/apache/phoenix/schema/PTableImpl.java   |  480 +-
 .../org/apache/phoenix/schema/PTableKey.java    |    6 +-
 .../apache/phoenix/schema/ProjectedColumn.java  |   12 +-
 .../org/apache/phoenix/schema/RowKeySchema.java |   10 +-
 .../org/apache/phoenix/schema/SaltingUtil.java  |    2 +-
 .../apache/phoenix/schema/TableProperty.java    |   42 +
 .../apache/phoenix/schema/tuple/BaseTuple.java  |   39 +
 .../phoenix/schema/tuple/DelegateTuple.java     |    7 +
 .../tuple/EncodedColumnQualiferCellsList.java   |  581 ++
 .../schema/tuple/MultiKeyValueTuple.java        |    1 +
 .../tuple/PositionBasedMultiKeyValueTuple.java  |   90 +
 .../schema/tuple/PositionBasedResultTuple.java  |  125 +
 .../phoenix/schema/tuple/ResultTuple.java       |   20 +-
 .../org/apache/phoenix/schema/tuple/Tuple.java  |    4 +
 .../phoenix/schema/types/PArrayDataType.java    |  340 +-
 .../schema/types/PArrayDataTypeDecoder.java     |  102 +
 .../schema/types/PArrayDataTypeEncoder.java     |  170 +
 .../apache/phoenix/util/EncodedColumnsUtil.java |  205 +
 .../java/org/apache/phoenix/util/IndexUtil.java |  105 +-
 .../org/apache/phoenix/util/KeyValueUtil.java   |    2 -
 .../org/apache/phoenix/util/MetaDataUtil.java   |   10 +
 .../org/apache/phoenix/util/PhoenixRuntime.java |   12 +-
 .../org/apache/phoenix/util/RepairUtil.java     |   40 +
 .../org/apache/phoenix/util/ResultUtil.java     |   60 -
 .../java/org/apache/phoenix/util/ScanUtil.java  |   29 +-
 .../org/apache/phoenix/util/SchemaUtil.java     |   31 +-
 .../phoenix/util/regex/RegexUpsertExecutor.java |   80 +
 .../wal/IndexedWALEditCodecTest.java            |   32 +
 .../apache/phoenix/cache/TenantCacheTest.java   |    6 +-
 .../phoenix/compile/HavingCompilerTest.java     |    2 +-
 .../phoenix/compile/QueryCompilerTest.java      |   70 +-
 .../phoenix/compile/QueryOptimizerTest.java     |   51 +
 .../compile/SelectStatementRewriterTest.java    |   11 +-
 .../phoenix/compile/WhereCompilerTest.java      |   44 +-
 .../phoenix/execute/CorrelatePlanTest.java      |   12 +-
 .../execute/LiteralResultIteratorPlanTest.java  |   12 +-
 .../phoenix/execute/MutationStateTest.java      |    4 +-
 .../phoenix/execute/UnnestArrayPlanTest.java    |    8 +-
 .../ArrayConstructorExpressionTest.java         |   20 +-
 .../expression/ColumnExpressionTest.java        |   27 +-
 .../phoenix/filter/SkipScanFilterTest.java      |  229 +-
 .../index/covered/TestLocalTableState.java      |   10 +-
 .../phoenix/index/IndexMaintainerTest.java      |    7 +-
 .../iterate/AggregateResultScannerTest.java     |    2 +-
 .../phoenix/jdbc/PhoenixEmbeddedDriverTest.java |   14 +
 .../phoenix/jdbc/SecureUserConnectionsTest.java |   66 +-
 .../query/BaseConnectionlessQueryTest.java      |   18 +-
 .../java/org/apache/phoenix/query/BaseTest.java |   61 +-
 .../phoenix/query/ConnectionlessTest.java       |   18 +-
 .../EncodedColumnQualifierCellsListTest.java    |  608 +++
 .../apache/phoenix/query/KeyRangeMoreTest.java  |  263 +
 .../phoenix/query/ScannerLeaseRenewalTest.java  |   21 +-
 .../schema/ImmutableStorageSchemeTest.java      |  182 +
 .../schema/types/PDataTypeForArraysTest.java    |   38 +-
 .../apache/phoenix/util/PhoenixRuntimeTest.java |    7 +-
 .../util/QualifierEncodingSchemeTest.java       |  119 +
 .../java/org/apache/phoenix/util/TestUtil.java  |   89 +-
 phoenix-flume/pom.xml                           |   12 +-
 .../phoenix/flume/CsvEventSerializerIT.java     |  416 ++
 .../org/apache/phoenix/flume/PhoenixSinkIT.java |    2 +-
 .../apache/phoenix/flume/FlumeConstants.java    |   14 +-
 .../flume/serializer/CsvEventSerializer.java    |  196 +
 .../flume/serializer/EventSerializers.java      |    4 +-
 phoenix-hive/pom.xml                            |   15 +-
 .../phoenix/hive/BaseHivePhoenixStoreIT.java    |  165 +
 .../apache/phoenix/hive/HiveMapReduceIT.java    |   34 +
 .../apache/phoenix/hive/HivePhoenixStoreIT.java |  330 +-
 .../org/apache/phoenix/hive/HiveTestUtil.java   |   22 +-
 .../java/org/apache/phoenix/hive/HiveTezIT.java |   34 +
 .../apache/phoenix/hive/PhoenixMetaHook.java    |   37 +-
 .../org/apache/phoenix/hive/PhoenixSerDe.java   |    9 +-
 .../apache/phoenix/hive/PhoenixSerializer.java  |    4 +
 .../phoenix/hive/PhoenixStorageHandler.java     |    5 +
 .../hive/mapreduce/PhoenixInputFormat.java      |   56 +-
 .../hive/mapreduce/PhoenixRecordReader.java     |    1 +
 .../hive/mapreduce/PhoenixResultWritable.java   |   12 +-
 .../phoenix/hive/query/PhoenixQueryBuilder.java |  370 +-
 .../phoenix/hive/util/ColumnMappingUtils.java   |   76 +
 .../hive/util/PhoenixConnectionUtil.java        |   19 +
 .../hive/util/PhoenixStorageHandlerUtil.java    |   46 +-
 .../hive/query/PhoenixQueryBuilderTest.java     |   97 +-
 phoenix-kafka/pom.xml                           |  435 ++
 .../apache/phoenix/kafka/PhoenixConsumerIT.java |  276 +
 phoenix-kafka/src/it/resources/consumer.props   |   32 +
 phoenix-kafka/src/it/resources/producer.props   |   24 +
 .../apache/phoenix/kafka/KafkaConstants.java    |   52 +
 .../phoenix/kafka/consumer/PhoenixConsumer.java |  276 +
 .../kafka/consumer/PhoenixConsumerTool.java     |  107 +
 phoenix-pherf/pom.xml                           |    2 +-
 phoenix-pig/pom.xml                             |    2 +-
 phoenix-protocol/src/main/PTable.proto          |    9 +
 .../src/main/ServerCachingService.proto         |   35 +
 phoenix-queryserver-client/pom.xml              |    2 +-
 .../queryserver/client/SqllineWrapper.java      |   18 +-
 phoenix-queryserver/pom.xml                     |    2 +-
 .../phoenix/queryserver/server/QueryServer.java |    5 +-
 phoenix-server/pom.xml                          |    2 +-
 phoenix-spark/pom.xml                           |    2 +-
 .../org/apache/phoenix/spark/PhoenixRDD.scala   |    4 +
 phoenix-tracing-webapp/pom.xml                  |    2 +-
 pom.xml                                         |   13 +-
 309 files changed, 22228 insertions(+), 4292 deletions(-)
----------------------------------------------------------------------


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

http://git-wip-us.apache.org/repos/asf/phoenix/blob/db78bd6f/phoenix-core/src/it/java/org/apache/phoenix/calcite/BaseCalciteIT.java
----------------------------------------------------------------------
diff --cc phoenix-core/src/it/java/org/apache/phoenix/calcite/BaseCalciteIT.java
index 4c89f8d,0000000..e8f6cd6
mode 100644,000000..100644
--- a/phoenix-core/src/it/java/org/apache/phoenix/calcite/BaseCalciteIT.java
+++ b/phoenix-core/src/it/java/org/apache/phoenix/calcite/BaseCalciteIT.java
@@@ -1,758 -1,0 +1,777 @@@
 +/*
 + * 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.calcite;
 +
 +import static org.apache.phoenix.util.PhoenixRuntime.PHOENIX_TEST_DRIVER_URL_PARAM;
 +import static org.apache.phoenix.util.TestUtil.TEST_PROPERTIES;
 +import static org.junit.Assert.assertFalse;
 +import static org.junit.Assert.assertTrue;
 +import static org.junit.Assert.fail;
 +
 +import java.io.File;
 +import java.io.FileWriter;
 +import java.io.PrintWriter;
 +import java.sql.Connection;
 +import java.sql.Date;
 +import java.sql.DriverManager;
 +import java.sql.PreparedStatement;
 +import java.sql.ResultSet;
 +import java.sql.SQLException;
 +import java.sql.Statement;
 +import java.sql.Time;
 +import java.sql.Timestamp;
 +import java.text.DecimalFormat;
 +import java.util.List;
 +import java.util.Map;
 +import java.util.Properties;
 +
 +import org.apache.calcite.avatica.util.ArrayImpl;
 +import org.apache.calcite.config.CalciteConnectionProperty;
 +import org.apache.phoenix.calcite.rel.PhoenixRel;
 +import org.apache.phoenix.end2end.BaseHBaseManagedTimeIT;
 +import org.apache.phoenix.end2end.BaseJoinIT;
 +import org.apache.phoenix.query.QueryServices;
 +import org.apache.phoenix.schema.TableAlreadyExistsException;
 +import org.apache.phoenix.util.PhoenixRuntime;
 +import org.apache.phoenix.util.PropertiesUtil;
 +import org.apache.phoenix.util.QueryUtil;
 +import org.apache.phoenix.util.ReadOnlyProps;
 +import org.junit.Assert;
 +import org.junit.BeforeClass;
 +
 +import com.google.common.collect.Lists;
 +import com.google.common.collect.Maps;
 +
 +public class BaseCalciteIT extends BaseHBaseManagedTimeIT {
 +    
 +    @BeforeClass
 +    public static void doSetup() throws Exception {
 +        Map<String,String> props = Maps.newHashMapWithExpectedSize(5);
 +        props.put(QueryServices.STATS_USE_CURRENT_TIME_ATTRIB, Boolean.FALSE.toString());
 +        props.put(QueryServices.RUN_UPDATE_STATS_ASYNC, Boolean.FALSE.toString());
 +        props.put(QueryServices.STATS_GUIDEPOST_WIDTH_BYTES_ATTRIB, Long.toString(1000));
 +        props.put(QueryServices.THREAD_POOL_SIZE_ATTRIB, Integer.toString(200));
 +        setUpTestDriver(new ReadOnlyProps(props.entrySet().iterator()));
 +    }
 +    
 +    public static Start start(boolean materializationEnabled, float rowCountFactor) {
 +        return new Start(getConnectionProps(materializationEnabled, rowCountFactor));
 +    }
 +    
 +    public static Start start(Properties props) {
 +        return new Start(props);
 +    }
 +    
 +    public static Start startPhoenixStandalone(Properties props) {
 +        return new Start(props) {
 +            Connection createConnection() throws Exception {
 +                return DriverManager.getConnection(
 +                        getOldUrl(), 
 +                        props);
 +            }
 +            
 +            String getExplainPlanString() {
 +                return "explain";
 +            }
 +        };
 +    }
 +
 +    public static class Start {
 +        protected final Properties props;
 +        private Connection connection;
 +        
 +        Start(Properties props) {
 +            this.props = props;
 +        }
 +
 +        Connection createConnection() throws Exception {
 +        	// FIXME Cannot get correct stats with 'test=true' property
 +        	final String testProp = PhoenixRuntime.JDBC_PROTOCOL_TERMINATOR + PHOENIX_TEST_DRIVER_URL_PARAM;
 +        	final String url = getUrl().replaceAll(testProp, "");
 +            return DriverManager.getConnection(url, props);
 +        }
 +        
 +        String getExplainPlanString() {
 +            return "explain plan for";
 +        }
 +
 +        public Sql sql(String sql) {
 +            return new Sql(this, sql);
 +        }
 +
 +        public Connection getConnection() {
 +            if (connection == null) {
 +                try {
 +                    connection = createConnection();
 +                } catch (Exception e) {
 +                    throw new RuntimeException(e);
 +                }
 +            }
 +            return connection;
 +        }
 +
 +        public void commit() {
 +            if (connection != null) {
 +                try {
 +                    connection.commit();
 +                } catch (SQLException e) {
 +                    throw new RuntimeException(e);
 +                }
 +            }
 +        }
 +
 +        public void close() {
 +            if (connection != null) {
 +                try {
 +                    connection.commit();
 +                    connection.close();
 +                } catch (SQLException e) {
 +                    throw new RuntimeException(e);
 +                }
 +            }
 +        }
 +    }
 +
 +    /** Fluid class for a test that has specified a SQL query. */
 +    static class Sql {
 +        private final Start start;
 +        private final String sql;
 +
 +        public Sql(Start start, String sql) {
 +            this.start = start;
 +            this.sql = sql;
 +        }
 +
 +        private static void populateResult(ResultSet resultSet, List<Object[]> list) throws SQLException {
 +            final int columnCount = resultSet.getMetaData().getColumnCount();
 +            while (resultSet.next()) {
 +                Object[] row = new Object[columnCount];
 +                for (int i = 0; i < columnCount; i++) {
 +                    row[i] = resultSet.getObject(i + 1);
 +                }
 +                list.add(row);
 +            }
 +        }
 +
 +        public Sql explainIs(String expected) throws SQLException {
-             return checkExplain(expected, true);
++            return checkExplain(expected, false);
 +        }
 +
 +        public Sql explainMatches(String expected) throws SQLException {
-             return checkExplain(expected, false);
++            return checkExplain(expected, true);
 +        }
 +
-         private Sql checkExplain(String expected, boolean exact) throws SQLException {
++        private Sql checkExplain(String expected, boolean regex) throws SQLException {
 +            final Statement statement = start.getConnection().createStatement();
 +            final ResultSet resultSet = statement.executeQuery(start.getExplainPlanString() + " " + sql);
 +            String explain = QueryUtil.getExplainPlan(resultSet);
 +            resultSet.close();
 +            statement.close();
-             if (exact) {
++            if (!regex) {
 +                Assert.assertEquals(explain, expected);
 +            } else {
 +                Assert.assertTrue(
 +                        "Explain plan \"" + explain
 +                        + "\" does not match \"" + expected + "\"",
 +                        explain.matches(expected));
 +            }
 +            return this;
 +        }
 +
++        public Sql explainIsAny(List<String> expected, boolean regex) throws SQLException {
++            final Statement statement = start.getConnection().createStatement();
++            final ResultSet resultSet = statement.executeQuery(start.getExplainPlanString() + " " + sql);
++            String explain = QueryUtil.getExplainPlan(resultSet);
++            resultSet.close();
++            statement.close();
++            boolean match = false;
++            for (String s : expected) {
++                if ((!regex && explain.equals(s))
++                        || (regex && explain.matches(s))) {
++                    match = true;
++                }
++            }
++            if (!match) {
++                Assert.fail(explain + " did not match any of the expected plans: " + expected);
++            }
++            return this;
++        }
++
 +        public List<Object[]> getResult() throws SQLException {
 +            final Statement statement = start.getConnection().createStatement();
 +            final ResultSet resultSet = statement.executeQuery(sql);
 +            final List<Object[]> list = Lists.newArrayList();
 +            populateResult(resultSet, list);
 +            resultSet.close();
 +            statement.close();
 +            return list;
 +        }
 +
 +        public Sql execute() throws SQLException {
 +            final Statement statement = start.getConnection().createStatement();
 +            statement.execute(sql);
 +            statement.close();
 +            return this;
 +        }
 +        
 +        public Sql executeUpdate() throws SQLException {
 +            final Statement statement = start.getConnection().createStatement();
 +            statement.executeUpdate(sql);
 +            statement.close();
 +            return this;
 +        }
 +        
 +        public PreparedStatement prepareStatement() throws SQLException {
 +            return start.getConnection().prepareStatement(sql);
 +        }
 +
 +        public void commit() {
 +            start.commit();
 +        }
 +
 +        public void close() {
 +            start.close();
 +        }
 +
 +        public Sql resultIs(Object[][] expected) throws SQLException {
 +            final Statement statement = start.getConnection().createStatement();
 +            final ResultSet resultSet = statement.executeQuery(sql);
 +            checkResultOrdered(resultSet, expected);
 +            resultSet.close();
 +            statement.close();
 +            return this;
 +        }
 +
 +        public Sql resultIs(int orderedCount, Object[][] expected) throws SQLException {
 +            final Statement statement = start.getConnection().createStatement();
 +            final ResultSet resultSet = statement.executeQuery(sql);
 +            checkResultUnordered(resultSet, expected, orderedCount, null);
 +            resultSet.close();
 +            statement.close();
 +            return this;
 +        }
 +
 +        public Sql resultIsSomeOf(int count, Object[][] expected) throws SQLException {
 +            final Statement statement = start.getConnection().createStatement();
 +            final ResultSet resultSet = statement.executeQuery(sql);
 +            checkResultUnordered(resultSet, expected, 0, count);
 +            resultSet.close();
 +            statement.close();
 +            return this;
 +        }
 +        
 +        public Sql sameResultAsPhoenixStandalone() throws SQLException {
 +            Start phoenixStart = startPhoenixStandalone(this.start.props);
 +            List<Object[]> result = phoenixStart.sql(this.sql).getResult();
 +            phoenixStart.close();
 +            return resultIs(result.toArray(new Object[result.size()][]));
 +        }
 +        
 +        public Sql sameResultAsPhoenixStandalone(int orderedCount) throws SQLException {
 +            Start phoenixStart = startPhoenixStandalone(this.start.props);
 +            List<Object[]> result = phoenixStart.sql(this.sql).getResult();
 +            phoenixStart.close();
 +            return resultIs(orderedCount, result.toArray(new Object[result.size()][]));
 +        }
 +        
 +        private void checkResultOrdered(ResultSet resultSet, Object[][] expected) throws SQLException {
 +            int expectedCount = expected.length;
 +            int count = 0;
 +            for (int i = 0; i < expectedCount; i++) {
 +                assertTrue(
 +                        "Expected " + expectedCount + " rows, but got " + count + " rows.",
 +                        resultSet.next());
 +                count++;
 +                Object[] row = expected[i];
 +                for (int j = 0; j < row.length; j++) {
 +                    Object obj = resultSet.getObject(j + 1);
 +                    Assert.assertEquals(canonicalize(row[j]), canonicalize(obj));
 +                }
 +            }
 +            assertFalse("Got more rows than expected.", resultSet.next());            
 +        }
 +        
 +        private void checkResultUnordered(ResultSet resultSet, Object[][] expected, int orderedCount, Integer checkContains) throws SQLException {
 +            List<List<Object>> expectedResults = Lists.newArrayList();
 +            List<List<Object>> actualResults = Lists.newArrayList();
 +            List<List<Object>> errorResults = Lists.newArrayList();
 +            int columnCount = expected.length > 0 ? expected[0].length : 0;
 +            for (Object[] e : expected) {
 +                List<Object> row = Lists.newArrayList();
 +                for (int i = orderedCount; i < e.length; i++) {
 +                    row.add(canonicalize(e[i]));
 +                }
 +                expectedResults.add(row);
 +            }
 +            while (resultSet.next()) {
 +                if (actualResults.size() >= expected.length) {
 +                    fail("Got more rows than expected after getting results: " + actualResults);
 +                }
 +                // check the ordered part
 +                Object[] row = expected[actualResults.size()];
 +                for (int i = 0; i < orderedCount; i++) {
 +                    Object obj = resultSet.getObject(i + 1);
 +                    Assert.assertEquals(canonicalize(row[i]), canonicalize(obj));
 +                }
 +                // check the unordered part
 +                List<Object> result = Lists.newArrayList();
 +                for (int i = orderedCount; i < columnCount; i++) {
 +                    result.add(canonicalize(resultSet.getObject(i+1)));
 +                }
 +                if (!expectedResults.remove(result)) {
 +                    errorResults.add(result);
 +                }
 +                actualResults.add(result);
 +            }
 +            boolean allContainedInExpected = errorResults.isEmpty();
 +            boolean allExpectedFound = checkContains == null ? expectedResults.isEmpty() : checkContains == actualResults.size();
 +            assertTrue(
 +                    (allContainedInExpected ? "" : "Could not find " + errorResults + " in expected results.\n") +
 +                    (allExpectedFound ? "" : 
 +                        (checkContains == null
 +                              ? ("Count not find " + expectedResults + " in actual results: " + actualResults + ".\n")
 +                              : ("Expected " + checkContains + " rows, but got " + actualResults.size() + " rows."))),
 +                    allContainedInExpected && allExpectedFound);
 +        }
 +        
 +        private Object canonicalize(Object obj) {
 +            if (obj == null) {
 +                return obj;
 +            }
 +            
 +            if (obj instanceof ArrayImpl) {
 +                return obj.toString();
 +            }
 +            
 +            if (obj.getClass().isArray()) {
 +                final StringBuilder buf = new StringBuilder("[");
 +                for (Object o : (Object[]) obj) {
 +                    if (buf.length() > 1) {
 +                        buf.append(", ");
 +                    }
 +                    String s = o.toString();
 +                    // Remove nano suffix
 +                    if (o instanceof Timestamp) {
 +                        s = s.substring(0, s.lastIndexOf('.'));
 +                    }
 +                    buf.append(s);
 +                }
 +                return buf.append("]").toString();
 +            }
 +            
 +            return obj;
 +        }
 +    }
 +
 +    private static final String FOODMART_SCHEMA = "     {\n"
 +            + "       type: 'jdbc',\n"
 +            + "       name: 'foodmart',\n"
 +            + "       jdbcDriver: 'org.hsqldb.jdbcDriver',\n"
 +            + "       jdbcUser: 'FOODMART',\n"
 +            + "       jdbcPassword: 'FOODMART',\n"
 +            + "       jdbcUrl: 'jdbc:hsqldb:res:foodmart',\n"
 +            + "       jdbcCatalog: null,\n"
 +            + "       jdbcSchema: 'foodmart'\n"
 +            + "     }";
 +    
 +    private static final String getPhoenixSchema() {
 +        return "    {\n"
 +            + "      name: 'phoenix',\n"
 +            + "      type: 'custom',\n"
 +            + "      factory: 'org.apache.phoenix.calcite.PhoenixSchema$Factory',\n"
 +            + "      operand: {\n"
 +            + "        url: \"" + getOldUrl() + "\"\n"
 +            + "      }\n"
 +            + "    }";
 +    }
 +
 +    protected static Connection connectUsingModel(Properties props) throws Exception {
 +        final File file = File.createTempFile("model", ".json");
 +        final String url = getOldUrl();
 +        final PrintWriter pw = new PrintWriter(new FileWriter(file));
 +        pw.print(
 +            "{\n"
 +                + "  version: '1.0',\n"
 +                + "  defaultSchema: 'HR',\n"
 +                + "  schemas: [\n"
 +                + "    {\n"
 +                + "      name: 'HR',\n"
 +                + "      type: 'custom',\n"
 +                + "      factory: 'org.apache.phoenix.calcite.PhoenixSchema$Factory',\n"
 +                + "      operand: {\n"
 +                + "        url: \"" + url + "\",\n"
 +                + "        user: \"scott\",\n"
 +                + "        password: \"tiger\"\n"
 +                + "      }\n"
 +                + "    }\n"
 +                + "  ]\n"
 +                + "}\n");
 +        pw.close();
 +        final Connection connection =
 +            DriverManager.getConnection("jdbc:phoenixcalcite:model=" + file.getAbsolutePath(), props);
 +        return connection;
 +    }
 +
 +    protected static Connection connectWithHsqldbUsingModel(Properties props) throws Exception {
 +        final File file = File.createTempFile("model", ".json");
 +        final PrintWriter pw = new PrintWriter(new FileWriter(file));
 +        pw.print(
 +            "{\n"
 +                + "  version: '1.0',\n"
 +                + "  defaultSchema: 'phoenix',\n"
 +                + "  schemas: [\n"
 +                + getPhoenixSchema() + ",\n"
 +                + FOODMART_SCHEMA + "\n"
 +                + "  ]\n"
 +                + "}\n");
 +        pw.close();
 +        final Connection connection =
 +            DriverManager.getConnection("jdbc:phoenixcalcite:model=" + file.getAbsolutePath(), props);
 +        return connection;
 +    }
 +
 +    protected static Properties getConnectionProps(boolean enableMaterialization, float rowCountFactor) {
 +        Properties props = new Properties();
 +        if (!enableMaterialization) {
 +            props.setProperty(
 +                    CalciteConnectionProperty.MATERIALIZATIONS_ENABLED.camelName(),
 +                    Boolean.toString(enableMaterialization));
 +        }
 +        props.setProperty(
 +                CalciteConnectionProperty.CREATE_MATERIALIZATIONS.camelName(),
 +                Boolean.toString(false));
 +        props.setProperty(PhoenixRel.ROW_COUNT_FACTOR, Float.toString(rowCountFactor));
 +        return props;
 +    }
 +    
 +    protected static final String SCORES_TABLE_NAME = "scores";
 +    
 +    protected void initJoinTableValues(String url) throws Exception {
 +        Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);
 +        Connection conn = DriverManager.getConnection(url, props);
 +        try {
 +            for (String tableName : new String[] {
 +                    BaseJoinIT.JOIN_CUSTOMER_TABLE_FULL_NAME,
 +                    BaseJoinIT.JOIN_ITEM_TABLE_FULL_NAME,
 +                    BaseJoinIT.JOIN_ORDER_TABLE_FULL_NAME,
 +                    BaseJoinIT.JOIN_SUPPLIER_TABLE_FULL_NAME}) {
 +                try {
 +                    BaseJoinIT.createTable(conn, tableName, tableName);
 +                } catch (TableAlreadyExistsException e) {
 +                }
 +                BaseJoinIT.initValues(conn, tableName, tableName);
 +            }
 +        } finally {
 +            conn.close();
 +        }
 +    }
 +    
 +    protected void initArrayTable(String url) throws Exception {
 +        Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);
 +        Connection conn = DriverManager.getConnection(url, props);
 +        try {
 +            conn.createStatement().execute(
 +                    "CREATE TABLE " + SCORES_TABLE_NAME
 +                    + "(student_id INTEGER NOT NULL, subject_id INTEGER NOT NULL, scores INTEGER[], exam_date DATE[], exam_time TIME[], exam_timestamp TIMESTAMP[] CONSTRAINT pk PRIMARY KEY (student_id, subject_id))");
 +            PreparedStatement stmt = conn.prepareStatement(
 +                    "UPSERT INTO " + SCORES_TABLE_NAME
 +                    + " VALUES(?, ?, ?, ?, ?, ?)");
 +            stmt.setInt(1, 1);
 +            stmt.setInt(2, 1);
 +            stmt.setArray(3, conn.createArrayOf("INTEGER", new Integer[] {85, 80, 82}));
 +            stmt.setArray(4, conn.createArrayOf("DATE", new Date[] {Date.valueOf("2016-3-22"), Date.valueOf("2016-5-23"), Date.valueOf("2016-7-24")}));
 +            stmt.setArray(5, conn.createArrayOf("TIME", new Time[] {Time.valueOf("15:30:28"), Time.valueOf("13:26:50"), Time.valueOf("16:20:00")}));
 +            stmt.setArray(6, conn.createArrayOf("TIMESTAMP", new Timestamp[] {Timestamp.valueOf("2016-3-22 15:30:28"), Timestamp.valueOf("2016-5-23 13:26:50"), Timestamp.valueOf("2016-7-24 16:20:00")}));
 +            stmt.execute();
 +            stmt.setInt(1, 2);
 +            stmt.setInt(2, 1);
 +            stmt.setArray(3, null);
 +            stmt.setArray(4, null);
 +            stmt.setArray(5, null);
 +            stmt.setArray(6, null);
 +            stmt.execute();
 +            stmt.setInt(1, 3);
 +            stmt.setInt(2, 2);
 +            stmt.setArray(3, conn.createArrayOf("INTEGER", new Integer[] {87, 88, 80}));
 +            stmt.setArray(4, conn.createArrayOf("DATE", new Date[] {Date.valueOf("2016-3-22"), Date.valueOf("2016-5-23"), Date.valueOf("2016-7-24")}));
 +            stmt.setArray(5, conn.createArrayOf("TIME", new Time[] {Time.valueOf("15:30:16"), Time.valueOf("13:26:52"), Time.valueOf("16:20:40")}));
 +            stmt.setArray(6, conn.createArrayOf("TIMESTAMP", new Timestamp[] {Timestamp.valueOf("2016-3-22 15:30:16"), Timestamp.valueOf("2016-5-23 13:26:52"), Timestamp.valueOf("2016-7-24 16:20:40")}));
 +            stmt.execute();
 +            conn.commit();
 +        } catch (TableAlreadyExistsException e) {
 +        }
 +        conn.close();        
 +    }
 +    
 +    protected static final String NOSALT_TABLE_NAME = "nosalt_test_table";
 +    protected static final String NOSALT_TABLE_SALTED_INDEX_NAME = "idxsalted_nosalt_test_table";
 +    protected static final String SALTED_TABLE_NAME = "salted_test_table";
 +    protected static final String SALTED_TABLE_NOSALT_INDEX_NAME = "idx_salted_test_table";
 +    protected static final String SALTED_TABLE_SALTED_INDEX_NAME = "idxsalted_salted_test_table";
 +    
 +    protected void initSaltedTables(String url, String index) throws SQLException {
 +        Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);
 +        Connection conn = DriverManager.getConnection(url, props);
 +        try {
 +            conn.createStatement().execute(
 +                    "CREATE TABLE " + NOSALT_TABLE_NAME + " (mypk0 INTEGER NOT NULL, mypk1 INTEGER NOT NULL, col0 INTEGER, col1 INTEGER CONSTRAINT pk PRIMARY KEY (mypk0, mypk1))");
 +            PreparedStatement stmt = conn.prepareStatement(
 +                    "UPSERT INTO " + NOSALT_TABLE_NAME
 +                    + " VALUES(?, ?, ?, ?)");
 +            for (int i = 0; i < 1000; i++) {
 +                stmt.setInt(1, i + 1);
 +                stmt.setInt(2, i + 2);
 +                stmt.setInt(3, i + 3);
 +                stmt.setInt(4, i + 4);
 +                stmt.execute();
 +            }
 +            conn.commit();
 +            
 +            if (index != null) {
 +                conn.createStatement().execute(
 +                        "CREATE " + index + " " + NOSALT_TABLE_SALTED_INDEX_NAME + " ON " + NOSALT_TABLE_NAME + " (col0)"
 +                        + (index.toUpperCase().startsWith("LOCAL") ? "" : " SALT_BUCKETS=4"));
 +                conn.commit();
 +            }
 +            
 +            conn.createStatement().execute(
 +                    "CREATE TABLE " + SALTED_TABLE_NAME + " (mypk0 INTEGER NOT NULL, mypk1 INTEGER NOT NULL, col0 INTEGER, col1 INTEGER CONSTRAINT pk PRIMARY KEY (mypk0, mypk1)) SALT_BUCKETS=4");
 +            stmt = conn.prepareStatement(
 +                    "UPSERT INTO " + SALTED_TABLE_NAME
 +                    + " VALUES(?, ?, ?, ?)");
 +            for (int i = 0; i < 1000; i++) {
 +                stmt.setInt(1, i + 1);
 +                stmt.setInt(2, i + 2);
 +                stmt.setInt(3, i + 3);
 +                stmt.setInt(4, i + 4);
 +                stmt.execute();
 +            }
 +            conn.commit();
 +            
 +            if (index != null) {
 +                conn.createStatement().execute("CREATE " + index + " " + SALTED_TABLE_NOSALT_INDEX_NAME + " ON " + SALTED_TABLE_NAME + " (col0)");
 +                conn.createStatement().execute(
 +                        "CREATE " + index + " " + SALTED_TABLE_SALTED_INDEX_NAME + " ON " + SALTED_TABLE_NAME + " (col1) INCLUDE (col0)"
 +                        + (index.toUpperCase().startsWith("LOCAL") ? "" : " SALT_BUCKETS=4"));
 +                conn.commit();
 +            }
 +        } catch (TableAlreadyExistsException e) {
 +        }
 +        conn.close();        
 +    }
 +    
 +    protected static final String KEY_ORDERING_TABLE_1_NAME = "key_ordering_test_table_1";
 +    protected static final String KEY_ORDERING_TABLE_2_NAME = "key_ordering_test_table_2";
 +    
 +    protected void initKeyOrderingTable(String url) throws Exception {
 +        Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);
 +        Connection conn = DriverManager.getConnection(url, props);
 +        try {
 +            conn.createStatement().execute(
 +                    "CREATE TABLE " + KEY_ORDERING_TABLE_1_NAME
 +                    + "(k0 BIGINT NOT NULL, k1 INTEGER NOT NULL, v0 INTEGER, v1 BIGINT CONSTRAINT pk PRIMARY KEY (k0 DESC, k1))");
 +            conn.createStatement().execute(
 +                    "CREATE TABLE " + KEY_ORDERING_TABLE_2_NAME
 +                    + "(k0 BIGINT NOT NULL, k1 BIGINT NOT NULL, v0 INTEGER, v1 BIGINT CONSTRAINT pk PRIMARY KEY (k0 DESC, k1 DESC))");
 +            PreparedStatement stmt = conn.prepareStatement(
 +                    "UPSERT INTO " + KEY_ORDERING_TABLE_1_NAME
 +                    + " VALUES(?, ?, ?, ?)");
 +            stmt.setInt(1, 1);
 +            stmt.setInt(2, 2);
 +            stmt.setInt(3, 1);
 +            stmt.setInt(4, 2);
 +            stmt.execute();
 +            stmt.setInt(1, 1);
 +            stmt.setInt(2, 3);
 +            stmt.setInt(3, 1);
 +            stmt.setInt(4, 3);
 +            stmt.execute();
 +            stmt.setInt(1, 1);
 +            stmt.setInt(2, 4);
 +            stmt.setInt(3, 1);
 +            stmt.setInt(4, 4);
 +            stmt.execute();
 +            stmt.setInt(1, 1);
 +            stmt.setInt(2, 5);
 +            stmt.setInt(3, 1);
 +            stmt.setInt(4, 5);
 +            stmt.execute();
 +            stmt.setInt(1, 2);
 +            stmt.setInt(2, 3);
 +            stmt.setInt(3, 2);
 +            stmt.setInt(4, 3);
 +            stmt.execute();
 +            stmt.setInt(1, 2);
 +            stmt.setInt(2, 5);
 +            stmt.setInt(3, 2);
 +            stmt.setInt(4, 5);
 +            stmt.execute();
 +            stmt.setInt(1, 3);
 +            stmt.setInt(2, 2);
 +            stmt.setInt(3, 3);
 +            stmt.setInt(4, 2);
 +            stmt.execute();
 +            stmt.setInt(1, 5);
 +            stmt.setInt(2, 2);
 +            stmt.setInt(3, 5);
 +            stmt.setInt(4, 2);
 +            stmt.execute();
 +            stmt.setInt(1, 5);
 +            stmt.setInt(2, 5);
 +            stmt.setInt(3, 5);
 +            stmt.setInt(4, 5);
 +            stmt.execute();
 +            conn.commit();
 +            stmt = conn.prepareStatement(
 +                    "UPSERT INTO " + KEY_ORDERING_TABLE_2_NAME
 +                    + " VALUES(?, ?, ?, ?)");
 +            stmt.setInt(1, 1);
 +            stmt.setInt(2, 2);
 +            stmt.setInt(3, 1);
 +            stmt.setInt(4, 2);
 +            stmt.execute();
 +            stmt.setInt(1, 1);
 +            stmt.setInt(2, 5);
 +            stmt.setInt(3, 1);
 +            stmt.setInt(4, 5);
 +            stmt.execute();
 +            stmt.setInt(1, 2);
 +            stmt.setInt(2, 2);
 +            stmt.setInt(3, 2);
 +            stmt.setInt(4, 2);
 +            stmt.execute();
 +            stmt.setInt(1, 2);
 +            stmt.setInt(2, 3);
 +            stmt.setInt(3, 2);
 +            stmt.setInt(4, 3);
 +            stmt.execute();
 +            stmt.setInt(1, 2);
 +            stmt.setInt(2, 4);
 +            stmt.setInt(3, 2);
 +            stmt.setInt(4, 4);
 +            stmt.execute();
 +            stmt.setInt(1, 2);
 +            stmt.setInt(2, 5);
 +            stmt.setInt(3, 2);
 +            stmt.setInt(4, 5);
 +            stmt.execute();
 +            stmt.setInt(1, 4);
 +            stmt.setInt(2, 3);
 +            stmt.setInt(3, 4);
 +            stmt.setInt(4, 3);
 +            stmt.execute();
 +            stmt.setInt(1, 5);
 +            stmt.setInt(2, 4);
 +            stmt.setInt(3, 5);
 +            stmt.setInt(4, 4);
 +            stmt.execute();
 +            stmt.setInt(1, 5);
 +            stmt.setInt(2, 5);
 +            stmt.setInt(3, 5);
 +            stmt.setInt(4, 5);
 +            stmt.execute();
 +            conn.commit();
 +        } catch (TableAlreadyExistsException e) {
 +        }
 +        conn.close();        
 +    }
 +    
 +    protected static final String MULTI_TENANT_TABLE = "multitenant_test_table";
 +    protected static final String MULTI_TENANT_TABLE_INDEX = "idx_multitenant_test_table";
 +    protected static final String MULTI_TENANT_VIEW1 = "s1.multitenant_test_view1";
 +    protected static final String MULTI_TENANT_VIEW1_INDEX = "idx_multitenant_test_view1";
 +    protected static final String MULTI_TENANT_VIEW2 = "s2.multitenant_test_view2";
 +    protected static final String MULTI_TENANT_VIEW2_INDEX = "idx_multitenant_test_view2";
 +    
 +    protected void initMultiTenantTables(String url, String index) throws SQLException {
 +        Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);
 +        Connection conn = DriverManager.getConnection(url, props);
 +        try {
 +            conn.createStatement().execute(
 +                    "CREATE TABLE " + MULTI_TENANT_TABLE + " (tenant_id VARCHAR NOT NULL, id VARCHAR NOT NULL, col0 INTEGER, col1 INTEGER, col2 INTEGER CONSTRAINT pk PRIMARY KEY (tenant_id, id)) MULTI_TENANT=true");
 +            PreparedStatement stmt = conn.prepareStatement(
 +                    "UPSERT INTO " + MULTI_TENANT_TABLE
 +                    + " VALUES(?, ?, ?, ?, ?)");
 +            DecimalFormat formatter = new DecimalFormat("0000");
 +            for (int i = 0; i < 1000; i++) {
 +                stmt.setString(1, "10");
 +                stmt.setString(2, formatter.format(2 + i));
 +                stmt.setInt(3, 3 + i);
 +                stmt.setInt(4, 4 + i);
 +                stmt.setInt(5, 5 + i);
 +                stmt.execute();
 +            }
 +            for (int i = 0; i < 1000; i++) {
 +                stmt.setString(1, "15");
 +                stmt.setString(2, formatter.format(3 + i));
 +                stmt.setInt(3, 4 + i);
 +                stmt.setInt(4, 5 + i);
 +                stmt.setInt(5, 6 + i);
 +                stmt.execute();
 +            }
 +            for (int i = 0; i < 1000; i++) {
 +                stmt.setString(1, "20");
 +                stmt.setString(2, formatter.format(4 + i));
 +                stmt.setInt(3, 5 + i);
 +                stmt.setInt(4, 6 + i);
 +                stmt.setInt(5, 7 + i);
 +                stmt.execute();
 +            }
 +            conn.commit();
 +            
 +            if (index != null) {
 +                conn.createStatement().execute(
 +                        "CREATE " + index + " " + MULTI_TENANT_TABLE_INDEX
 +                        + " ON " + MULTI_TENANT_TABLE + "(col1) INCLUDE (col0, col2)");
 +                conn.commit();
 +            }
 +            
 +            conn.close();
 +            props.setProperty("TenantId", "10");
 +            conn = DriverManager.getConnection(getOldUrl(), props);
 +            conn.createStatement().execute("CREATE VIEW " + MULTI_TENANT_VIEW1
 +                    + " AS select * from " + MULTI_TENANT_TABLE);
 +            conn.commit();
 +            
 +            if (index != null) {
 +                conn.createStatement().execute(
 +                        "CREATE " + index + " " + MULTI_TENANT_VIEW1_INDEX
 +                        + " ON " + MULTI_TENANT_VIEW1 + "(col0)");
 +                conn.commit();
 +            }
 +            
 +            conn.close();
 +            props.setProperty("TenantId", "20");
 +            conn = DriverManager.getConnection(getOldUrl(), props);
 +            conn.createStatement().execute("CREATE VIEW " + MULTI_TENANT_VIEW2
 +                    + " AS select * from " + MULTI_TENANT_TABLE + " where col2 > 7");
 +            conn.commit();
 +            
 +            if (index != null) {
 +                conn.createStatement().execute(
 +                        "CREATE " + index + " " + MULTI_TENANT_VIEW2_INDEX
 +                        + " ON " + MULTI_TENANT_VIEW2 + "(col0)");
 +                conn.commit();
 +            }
 +        } catch (TableAlreadyExistsException e) {
 +        } finally {
 +            conn.close();
 +        }
 +    }
 +
 +}

http://git-wip-us.apache.org/repos/asf/phoenix/blob/db78bd6f/phoenix-core/src/it/java/org/apache/phoenix/calcite/BaseCalciteIndexIT.java
----------------------------------------------------------------------
diff --cc phoenix-core/src/it/java/org/apache/phoenix/calcite/BaseCalciteIndexIT.java
index b7e5955,0000000..bef3335
mode 100644,000000..100644
--- a/phoenix-core/src/it/java/org/apache/phoenix/calcite/BaseCalciteIndexIT.java
+++ b/phoenix-core/src/it/java/org/apache/phoenix/calcite/BaseCalciteIndexIT.java
@@@ -1,64 -1,0 +1,64 @@@
 +/*
 + * 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.calcite;
 +
 +import java.sql.Connection;
 +import java.sql.DriverManager;
 +import java.util.Properties;
 +
 +import org.apache.phoenix.util.TestUtil;
 +import org.junit.Before;
 +
 +public class BaseCalciteIndexIT extends BaseCalciteIT {
 +    
 +    private final boolean localIndex;
 +    
 +    public BaseCalciteIndexIT(boolean localIndex) {
 +        this.localIndex = localIndex;
 +    }
 +    
 +    @Before
 +    public void initTable() throws Exception {
 +        final String url = getOldUrl();
 +        final String index = localIndex ? "LOCAL INDEX" : "INDEX";
-         initATableValues(TestUtil.ATABLE_NAME, getOrganizationId(), null, null, null, url);
++        initATableValues(TestUtil.ATABLE_NAME, getOrganizationId(), null, null, null, url, null);
 +        initSaltedTables(url, index);
 +        initMultiTenantTables(url, index);
 +        Connection connection = DriverManager.getConnection(url);
 +        connection.createStatement().execute("CREATE " + index + " IF NOT EXISTS IDX1 ON aTable (a_string) INCLUDE (b_string, x_integer)");
 +        connection.createStatement().execute("CREATE " + index + " IF NOT EXISTS IDX2 ON aTable (b_string) INCLUDE (a_string, y_integer)");
 +        connection.createStatement().execute("CREATE " + index + " IF NOT EXISTS IDX_FULL ON aTable (b_string) INCLUDE (a_string, a_integer, a_date, a_time, a_timestamp, x_decimal, x_long, x_integer, y_integer, a_byte, a_short, a_float, a_double, a_unsigned_float, a_unsigned_double)");
 +        connection.createStatement().execute("UPDATE STATISTICS ATABLE");
 +        connection.createStatement().execute("UPDATE STATISTICS " + NOSALT_TABLE_NAME);
 +        connection.createStatement().execute("UPDATE STATISTICS " + SALTED_TABLE_NAME);
 +        connection.createStatement().execute("UPDATE STATISTICS " + MULTI_TENANT_TABLE);
 +        connection.close();
 +        
 +        Properties props = new Properties();
 +        props.setProperty("TenantId", "10");
 +        connection = DriverManager.getConnection(url, props);
 +        connection.createStatement().execute("UPDATE STATISTICS " + MULTI_TENANT_VIEW1);
 +        connection.close();
 +        
 +        props.setProperty("TenantId", "20");
 +        connection = DriverManager.getConnection(url, props);
 +        connection.createStatement().execute("UPDATE STATISTICS " + MULTI_TENANT_VIEW2);
 +        connection.close();
 +    }
 +
 +}

http://git-wip-us.apache.org/repos/asf/phoenix/blob/db78bd6f/phoenix-core/src/it/java/org/apache/phoenix/calcite/CalciteGlobalIndexIT.java
----------------------------------------------------------------------
diff --cc phoenix-core/src/it/java/org/apache/phoenix/calcite/CalciteGlobalIndexIT.java
index d5a95ff,0000000..21eef12
mode 100644,000000..100644
--- a/phoenix-core/src/it/java/org/apache/phoenix/calcite/CalciteGlobalIndexIT.java
+++ b/phoenix-core/src/it/java/org/apache/phoenix/calcite/CalciteGlobalIndexIT.java
@@@ -1,259 -1,0 +1,259 @@@
 +/*
 + * 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.calcite;
 +
 +import static org.junit.Assert.fail;
 +
 +import java.sql.SQLException;
 +import java.util.Properties;
 +
 +import org.junit.Test;
 +
 +public class CalciteGlobalIndexIT extends BaseCalciteIndexIT {
 +    
 +    public CalciteGlobalIndexIT() {
 +        super(false);
 +    }
 +    
 +    @Test public void testIndex() throws Exception {
 +        start(true, 1000f).sql("select * from aTable where b_string = 'b'")
 +            .explainIs("PhoenixToEnumerableConverter\n" +
 +                       "  PhoenixServerProject(ORGANIZATION_ID=[$1], ENTITY_ID=[$2], A_STRING=[$3], B_STRING=[$0], A_INTEGER=[$4], A_DATE=[$5], A_TIME=[$6], A_TIMESTAMP=[$7], X_DECIMAL=[$8], X_LONG=[$9], X_INTEGER=[$10], Y_INTEGER=[$11], A_BYTE=[$12], A_SHORT=[$13], A_FLOAT=[$14], A_DOUBLE=[$15], A_UNSIGNED_FLOAT=[$16], A_UNSIGNED_DOUBLE=[$17])\n" +
 +                       "    PhoenixTableScan(table=[[phoenix, IDX_FULL]], filter=[=($0, 'b')])\n")
 +            .close();
 +        start(true, 1000f).sql("select x_integer from aTable")
 +            .explainIs("PhoenixToEnumerableConverter\n" +
 +                       "  PhoenixServerProject(0:X_INTEGER=[$4])\n" +
 +                       "    PhoenixTableScan(table=[[phoenix, IDX1]])\n")
 +            .close();
 +        start(true, 1000f).sql("select a_string from aTable order by a_string")
 +            .explainIs("PhoenixToEnumerableConverter\n" +
 +                       "  PhoenixServerProject(0:A_STRING=[$0])\n" +
 +                       "    PhoenixTableScan(table=[[phoenix, IDX1]], scanOrder=[FORWARD])\n")
 +            .close();
 +        start(true, 1000000f).sql("select a_string from aTable order by organization_id")
 +            .explainIs("PhoenixToEnumerableConverter\n" +
 +                       "  PhoenixServerProject(A_STRING=[$2], ORGANIZATION_ID=[$0])\n" +
 +                       "    PhoenixTableScan(table=[[phoenix, ATABLE]], scanOrder=[FORWARD])\n")
 +            .close();
 +        start(true, 1000f).sql("select a_integer from aTable order by a_string")
 +            .explainIs("PhoenixToEnumerableConverter\n" +
 +                       "  PhoenixServerSort(sort0=[$1], dir0=[ASC])\n" +
-                        "    PhoenixServerProject(A_INTEGER=[$4], A_STRING=[$3])\n" +
-                        "      PhoenixTableScan(table=[[phoenix, IDX_FULL]])\n")
++                       "    PhoenixServerProject(A_INTEGER=[$4], A_STRING=[$2])\n" +
++                       "      PhoenixTableScan(table=[[phoenix, ATABLE]])\n")
 +            .close();
 +        start(true, 1000f).sql("select a_string, b_string from aTable where a_string = 'a'")
 +            .explainIs("PhoenixToEnumerableConverter\n" +
 +                       "  PhoenixServerProject(0:A_STRING=[$0], 0:B_STRING=[$3])\n" +
 +                       "    PhoenixTableScan(table=[[phoenix, IDX1]], filter=[=($0, 'a')])\n")
 +            .close();
 +        start(true, 1000f).sql("select a_string, b_string from aTable where b_string = 'b'")
 +            .explainIs("PhoenixToEnumerableConverter\n" +
 +                       "  PhoenixServerProject(A_STRING=[$3], B_STRING=[$0])\n" +
 +                       "    PhoenixTableScan(table=[[phoenix, IDX2]], filter=[=($0, 'b')])\n")
 +            .close();
 +        start(true, 1000f).sql("select a_string, b_string, x_integer, y_integer from aTable where b_string = 'b'")
 +            .explainIs("PhoenixToEnumerableConverter\n" +
 +                       "  PhoenixServerProject(A_STRING=[$3], B_STRING=[$0], X_INTEGER=[$10], Y_INTEGER=[$11])\n" +
 +                       "    PhoenixTableScan(table=[[phoenix, IDX_FULL]], filter=[=($0, 'b')])\n")
 +            .close();
 +        start(true, 1000f).sql("select a_string, count(*) from aTable group by a_string")
 +            .explainIs("PhoenixToEnumerableConverter\n" +
 +                       "  PhoenixServerAggregate(group=[{0}], EXPR$1=[COUNT()], isOrdered=[true])\n" +
 +                       "    PhoenixTableScan(table=[[phoenix, IDX1]], scanOrder=[FORWARD])\n")
 +            .close();
 +    }
 +    
 +    @Test public void testSaltedIndex() throws Exception {
 +        start(true, 1f).sql("select count(*) from " + NOSALT_TABLE_NAME + " where col0 > 3")
 +                .explainIs("PhoenixToEnumerableConverter\n" +
 +                           "  PhoenixServerAggregate(group=[{}], EXPR$0=[COUNT()])\n" +
 +                           "    PhoenixTableScan(table=[[phoenix, IDXSALTED_NOSALT_TEST_TABLE]], filter=[>(CAST($0):INTEGER, 3)])\n")
 +                .resultIs(0, new Object[][]{{999L}})
 +                .close();
 +        start(true, 1f).sql("select mypk0, mypk1, col0 from " + NOSALT_TABLE_NAME + " where col0 <= 4")
 +                .explainIs("PhoenixToEnumerableConverter\n" +
 +                           "  PhoenixServerProject(MYPK0=[$1], MYPK1=[$2], COL0=[CAST($0):INTEGER])\n" +
 +                           "    PhoenixTableScan(table=[[phoenix, IDXSALTED_NOSALT_TEST_TABLE]], filter=[<=(CAST($0):INTEGER, 4)])\n")
 +                .resultIs(0, new Object[][] {
 +                        {2, 3, 4},
 +                        {1, 2, 3}})
 +                .close();
 +        start(true, 1f).sql("select * from " + SALTED_TABLE_NAME + " where mypk0 < 3")
 +                .explainIs("PhoenixToEnumerableConverter\n" +
 +                           "  PhoenixTableScan(table=[[phoenix, SALTED_TEST_TABLE]], filter=[<($0, 3)])\n")
 +                .resultIs(0, new Object[][] {
 +                        {1, 2, 3, 4},
 +                        {2, 3, 4, 5}})
 +                .close();
 +        start(true, 1f).sql("select count(*) from " + SALTED_TABLE_NAME + " where col0 > 3")
 +                .explainIs("PhoenixToEnumerableConverter\n" +
 +                           "  PhoenixServerAggregate(group=[{}], EXPR$0=[COUNT()])\n" +
 +                           "    PhoenixTableScan(table=[[phoenix, IDX_SALTED_TEST_TABLE]], filter=[>(CAST($0):INTEGER, 3)])\n")
 +                .resultIs(0, new Object[][]{{999L}})
 +                .close();
 +        start(true, 1f).sql("select mypk0, mypk1, col0 from " + SALTED_TABLE_NAME + " where col0 <= 4")
 +                .explainIs("PhoenixToEnumerableConverter\n" +
 +                           "  PhoenixServerProject(MYPK0=[$1], MYPK1=[$2], COL0=[CAST($0):INTEGER])\n" +
 +                           "    PhoenixTableScan(table=[[phoenix, IDX_SALTED_TEST_TABLE]], filter=[<=(CAST($0):INTEGER, 4)])\n")
 +                .resultIs(0, new Object[][] {
 +                        {2, 3, 4},
 +                        {1, 2, 3}})
 +                .close();
 +        start(true, 1f).sql("select count(*) from " + SALTED_TABLE_NAME + " where col1 > 4")
 +                .explainIs("PhoenixToEnumerableConverter\n" +
 +                           "  PhoenixServerAggregate(group=[{}], EXPR$0=[COUNT()])\n" +
 +                           "    PhoenixTableScan(table=[[phoenix, IDXSALTED_SALTED_TEST_TABLE]], filter=[>(CAST($0):INTEGER, 4)])\n")
 +                .resultIs(0, new Object[][]{{999L}})
 +                .close();
 +        start(true, 1f).sql("select * from " + SALTED_TABLE_NAME + " where col1 <= 5 order by col1")
 +                .explainIs("PhoenixToEnumerableConverter\n" +
 +                           "  PhoenixServerProject(MYPK0=[$1], MYPK1=[$2], COL0=[$3], COL1=[CAST($0):INTEGER])\n" +
 +                           "    PhoenixTableScan(table=[[phoenix, IDXSALTED_SALTED_TEST_TABLE]], filter=[<=(CAST($0):INTEGER, 5)], scanOrder=[FORWARD])\n")
 +                .resultIs(new Object[][] {
 +                        {1, 2, 3, 4},
 +                        {2, 3, 4, 5}})
 +                .close();
 +        start(true, 1f).sql("select * from " + SALTED_TABLE_NAME + " s1, " + SALTED_TABLE_NAME + " s2 where s1.mypk1 = s2.mypk1 and s1.mypk0 > 500 and s2.col1 < 505")
 +                .explainIs("PhoenixToEnumerableConverter\n" +
 +                           "  PhoenixServerJoin(condition=[=($1, $5)], joinType=[inner])\n" +
 +                           "    PhoenixTableScan(table=[[phoenix, SALTED_TEST_TABLE]], filter=[>($0, 500)])\n" +
 +                           "    PhoenixServerProject(MYPK0=[$1], MYPK1=[$2], COL0=[$3], COL1=[CAST($0):INTEGER])\n" +
 +                           "      PhoenixTableScan(table=[[phoenix, IDXSALTED_SALTED_TEST_TABLE]], filter=[<(CAST($0):INTEGER, 505)])\n")
 +                .resultIs(0, new Object[][] {
 +                        {501, 502, 503, 504, 501, 502, 503, 504}})
 +                .close();
 +    }
 +    
 +    @Test public void testMultiTenant() throws Exception {
 +        Properties props = getConnectionProps(true, 1f);
 +        start(props).sql("select * from " + MULTI_TENANT_TABLE + " where tenant_id = '10' and id <= '0004'")
 +                .explainIs("PhoenixToEnumerableConverter\n" +
-                            "  PhoenixTableScan(table=[[phoenix, MULTITENANT_TEST_TABLE]], filter=[AND(=(CAST($0):VARCHAR(2) CHARACTER SET \"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\" NOT NULL, '10'), <=($1, '0004'))])\n")
++                           "  PhoenixTableScan(table=[[phoenix, MULTITENANT_TEST_TABLE]], filter=[AND(=($0, CAST('10'):VARCHAR CHARACTER SET \"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\" NOT NULL), <=($1, '0004'))])\n")
 +                .resultIs(0, new Object[][] {
 +                        {"10", "0002", 3, 4, 5},
 +                        {"10", "0003", 4, 5, 6},
 +                        {"10", "0004", 5, 6, 7}})
 +                .close();
 +        
 +        start(props).sql("select * from " + MULTI_TENANT_TABLE + " where tenant_id = '20' and col1 < 8")
 +                .explainIs("PhoenixToEnumerableConverter\n" +
 +                           "  PhoenixServerProject(TENANT_ID=[$0], ID=[$2], COL0=[$3], COL1=[CAST($1):INTEGER], COL2=[$4])\n" +
-                            "    PhoenixTableScan(table=[[phoenix, IDX_MULTITENANT_TEST_TABLE]], filter=[AND(=(CAST($0):VARCHAR(2) CHARACTER SET \"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\" NOT NULL, '20'), <(CAST($1):INTEGER, 8))])\n")
++                           "    PhoenixTableScan(table=[[phoenix, IDX_MULTITENANT_TEST_TABLE]], filter=[AND(=($0, CAST('20'):VARCHAR CHARACTER SET \"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\" NOT NULL), <(CAST($1):INTEGER, 8))])\n")
 +                .resultIs(0, new Object[][] {
 +                        {"20", "0004", 5, 6, 7},
 +                        {"20", "0005", 6, 7, 8}})
 +                .close();
 +        
 +        try {
 +            start(props).sql("select * from " + MULTI_TENANT_VIEW1)
 +                .explainIs("")
 +                .close();
 +            fail("Should have got SQLException.");
 +        } catch (SQLException e) {
 +        }
 +        
 +        props.setProperty("TenantId", "15");
 +        start(props).sql("select * from " + MULTI_TENANT_TABLE + " where id = '0284'")
 +                .explainIs("PhoenixToEnumerableConverter\n" +
-                            "  PhoenixTableScan(table=[[phoenix, MULTITENANT_TEST_TABLE]], filter=[=(CAST($0):VARCHAR(4) CHARACTER SET \"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\" NOT NULL, '0284')])\n")
++                           "  PhoenixTableScan(table=[[phoenix, MULTITENANT_TEST_TABLE]], filter=[=($0, CAST('0284'):VARCHAR CHARACTER SET \"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\" NOT NULL)])\n")
 +                .resultIs(0, new Object[][] {
 +                        {"0284", 285, 286, 287}})
 +                .close();
 +        
 +        start(props).sql("select * from " + MULTI_TENANT_TABLE + " where col1 > 1000")
 +                .explainIs("PhoenixToEnumerableConverter\n" +
 +                           "  PhoenixServerProject(ID=[$1], COL0=[$2], COL1=[CAST($0):INTEGER], COL2=[$3])\n" +
 +                           "    PhoenixTableScan(table=[[phoenix, IDX_MULTITENANT_TEST_TABLE]], filter=[>(CAST($0):INTEGER, 1000)])\n")
 +                .resultIs(0, new Object[][] {
 +                        {"0999", 1000, 1001, 1002},
 +                        {"1000", 1001, 1002, 1003},
 +                        {"1001", 1002, 1003, 1004},
 +                        {"1002", 1003, 1004, 1005}})
 +                .close();
 +        
 +        try {
 +            start(props).sql("select * from " + MULTI_TENANT_VIEW1)
 +                .explainIs("")
 +                .close();
 +            fail("Should have got SQLException.");
 +        } catch (SQLException e) {
 +        }
 +
 +        props.setProperty("TenantId", "10");
 +        start(props).sql("select * from " + MULTI_TENANT_VIEW1 + " where id = '0512'")
 +                .explainIs("PhoenixToEnumerableConverter\n" +
-                            "  PhoenixTableScan(table=[[phoenix, MULTITENANT_TEST_TABLE]], filter=[=(CAST($0):VARCHAR(4) CHARACTER SET \"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\" NOT NULL, '0512')])\n")
++                           "  PhoenixTableScan(table=[[phoenix, MULTITENANT_TEST_TABLE]], filter=[=($0, CAST('0512'):VARCHAR CHARACTER SET \"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\" NOT NULL)])\n")
 +                .resultIs(0, new Object[][] {
 +                        {"0512", 513, 514, 515}})
 +                .close();
 +        
 +        start(props).sql("select * from " + MULTI_TENANT_TABLE + " where col1 <= 6")
 +                .explainIs("PhoenixToEnumerableConverter\n" +
 +                           "  PhoenixServerProject(ID=[$1], COL0=[$2], COL1=[CAST($0):INTEGER], COL2=[$3])\n" +
 +                           "    PhoenixTableScan(table=[[phoenix, IDX_MULTITENANT_TEST_TABLE]], filter=[<=(CAST($0):INTEGER, 6)])\n")
 +                .resultIs(0, new Object[][] {
 +                        {"0002", 3, 4, 5},
 +                        {"0003", 4, 5, 6},
 +                        {"0004", 5, 6, 7}})
 +                .close();
 +        
 +        start(props).sql("select id, col0 from " + MULTI_TENANT_VIEW1 + " where col0 >= 1000")
 +                .explainIs("PhoenixToEnumerableConverter\n" +
 +                           "  PhoenixServerProject(ID=[$1], COL0=[CAST($0):INTEGER])\n" +
 +                           "    PhoenixTableScan(table=[[phoenix, S1, IDX_MULTITENANT_TEST_VIEW1]], filter=[>=(CAST($0):INTEGER, 1000)])\n")
 +                .resultIs(0, new Object[][] {
 +                        {"0999", 1000},
 +                        {"1000", 1001},
 +                        {"1001", 1002}})
 +                .close();
 +
 +        props.setProperty("TenantId", "20");
 +        start(props).sql("select * from " + MULTI_TENANT_VIEW2 + " where id = '0765'")
 +                .explainIs("PhoenixToEnumerableConverter\n" +
-                            "  PhoenixTableScan(table=[[phoenix, MULTITENANT_TEST_TABLE]], filter=[AND(>($3, 7), =(CAST($0):VARCHAR(4) CHARACTER SET \"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\" NOT NULL, '0765'))])\n")
++                           "  PhoenixTableScan(table=[[phoenix, MULTITENANT_TEST_TABLE]], filter=[AND(>($3, 7), =($0, CAST('0765'):VARCHAR CHARACTER SET \"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\" NOT NULL))])\n")
 +                .resultIs(0, new Object[][] {
 +                        {"0765", 766, 767, 768}})
 +                .close();
 +        
 +        start(props).sql("select id, col0 from " + MULTI_TENANT_VIEW2 + " where col0 between 272 and 275")
 +                .explainIs("PhoenixToEnumerableConverter\n" +
 +                           "  PhoenixServerProject(ID=[$1], COL0=[CAST($0):INTEGER])\n" +
 +                           "    PhoenixTableScan(table=[[phoenix, S2, IDX_MULTITENANT_TEST_VIEW2]], filter=[AND(>=(CAST($0):INTEGER, 272), <=(CAST($0):INTEGER, 275))])\n")
 +                .resultIs(0, new Object[][] {
 +                        {"0271", 272},
 +                        {"0272", 273},
 +                        {"0273", 274},
 +                        {"0274", 275}})
 +                .close();
 +        
 +        start(props).sql("select id, col0 from " + MULTI_TENANT_VIEW2 + " order by col0 limit 5")
 +                .explainIs("PhoenixToEnumerableConverter\n" +
 +                           "  PhoenixLimit(fetch=[5])\n" +
 +                           "    PhoenixServerProject(ID=[$1], COL0=[CAST($0):INTEGER])\n" +
 +                           "      PhoenixTableScan(table=[[phoenix, S2, IDX_MULTITENANT_TEST_VIEW2]], scanOrder=[FORWARD])\n")
 +                .resultIs(new Object[][] {
 +                        {"0005", 6},
 +                        {"0006", 7},
 +                        {"0007", 8},
 +                        {"0008", 9},
 +                        {"0009", 10}})
 +                .close();
 +    }
 +
 +}