Fix merge conflicts
Project: http://git-wip-us.apache.org/repos/asf/phoenix/repo Commit: http://git-wip-us.apache.org/repos/asf/phoenix/commit/7ca8e4b3 Tree: http://git-wip-us.apache.org/repos/asf/phoenix/tree/7ca8e4b3 Diff: http://git-wip-us.apache.org/repos/asf/phoenix/diff/7ca8e4b3 Branch: refs/heads/calcite Commit: 7ca8e4b39647a056d91b627689d9d496b6136f18 Parents: ac544b4 34ba28e Author: maryannxue <[email protected]> Authored: Fri Oct 7 10:37:45 2016 -0700 Committer: maryannxue <[email protected]> Committed: Fri Oct 7 10:37:45 2016 -0700 ---------------------------------------------------------------------- ...ritesAndUncompressedWALInHBase_094_9_IT.java | 45 -- .../apache/phoenix/calcite/BaseCalciteIT.java | 21 + .../org/apache/phoenix/calcite/CalciteIT.java | 12 +- .../StatisticsCollectionRunTrackerIT.java | 38 +- .../phoenix/end2end/AbsFunctionEnd2EndIT.java | 2 +- .../AlterMultiTenantTableWithViewsIT.java | 16 +- .../apache/phoenix/end2end/AlterSessionIT.java | 59 +- .../apache/phoenix/end2end/AlterTableIT.java | 68 +- .../phoenix/end2end/AlterTableWithViewsIT.java | 30 +- .../phoenix/end2end/AppendOnlySchemaIT.java | 24 +- .../phoenix/end2end/ArithmeticQueryIT.java | 36 +- .../phoenix/end2end/ArrayAppendFunctionIT.java | 18 +- .../phoenix/end2end/ArrayConcatFunctionIT.java | 16 +- .../phoenix/end2end/ArrayFillFunctionIT.java | 76 +- .../phoenix/end2end/ArrayPrependFunctionIT.java | 68 +- .../end2end/ArrayToStringFunctionIT.java | 22 +- .../phoenix/end2end/ArraysWithNullsIT.java | 32 +- .../apache/phoenix/end2end/AutoCommitIT.java | 2 +- .../phoenix/end2end/AutoPartitionViewsIT.java | 18 +- .../org/apache/phoenix/end2end/BaseJoinIT.java | 456 +++++++++++ .../BaseOwnClusterClientManagedTimeIT.java | 29 - .../BaseOwnClusterHBaseManagedTimeIT.java | 29 - .../phoenix/end2end/BaseOwnClusterIT.java | 7 + .../apache/phoenix/end2end/BaseParallelIT.java | 69 -- .../end2end/BaseTenantSpecificTablesIT.java | 87 +- .../end2end/BaseTenantSpecificViewIndexIT.java | 12 +- .../org/apache/phoenix/end2end/BaseViewIT.java | 92 +-- .../apache/phoenix/end2end/BinaryRowKeyIT.java | 6 +- .../phoenix/end2end/CSVCommonsLoaderIT.java | 20 +- .../phoenix/end2end/CbrtFunctionEnd2EndIT.java | 27 +- .../phoenix/end2end/CoalesceFunctionIT.java | 20 +- .../end2end/ConvertTimezoneFunctionIT.java | 14 +- .../end2end/CountDistinctCompressionIT.java | 2 +- .../phoenix/end2end/CsvBulkLoadToolIT.java | 2 +- .../org/apache/phoenix/end2end/DateTimeIT.java | 68 +- .../phoenix/end2end/DecodeFunctionIT.java | 12 +- .../org/apache/phoenix/end2end/DeleteIT.java | 26 +- .../phoenix/end2end/DisableLocalIndexIT.java | 26 +- .../phoenix/end2end/DistinctPrefixFilterIT.java | 26 +- .../apache/phoenix/end2end/DynamicColumnIT.java | 19 +- .../apache/phoenix/end2end/DynamicFamilyIT.java | 4 +- .../apache/phoenix/end2end/DynamicUpsertIT.java | 2 +- .../phoenix/end2end/EncodeFunctionIT.java | 8 +- .../phoenix/end2end/EvaluationOfORIT.java | 2 +- .../phoenix/end2end/ExecuteStatementsIT.java | 6 +- .../phoenix/end2end/ExpFunctionEnd2EndIT.java | 4 +- .../phoenix/end2end/FirstValueFunctionIT.java | 14 +- .../phoenix/end2end/FlappingAlterTableIT.java | 97 +++ .../phoenix/end2end/FlappingLocalIndexIT.java | 300 +++++++ .../end2end/GetSetByteBitFunctionEnd2EndIT.java | 8 +- .../apache/phoenix/end2end/GroupByCaseIT.java | 59 +- .../org/apache/phoenix/end2end/HashJoinIT.java | 808 +++++++++---------- .../phoenix/end2end/HashJoinLocalIndexIT.java | 70 +- .../apache/phoenix/end2end/HashJoinMoreIT.java | 28 +- .../org/apache/phoenix/end2end/InListIT.java | 10 +- .../phoenix/end2end/InMemoryOrderByIT.java | 42 - .../apache/phoenix/end2end/IndexExtendedIT.java | 36 +- .../apache/phoenix/end2end/InstrFunctionIT.java | 16 +- .../org/apache/phoenix/end2end/IsNullIT.java | 6 +- .../org/apache/phoenix/end2end/KeyOnlyIT.java | 127 +-- .../phoenix/end2end/LastValueFunctionIT.java | 22 +- .../phoenix/end2end/LikeExpressionIT.java | 26 +- .../phoenix/end2end/LnLogFunctionEnd2EndIT.java | 4 +- .../apache/phoenix/end2end/MD5FunctionIT.java | 6 +- .../org/apache/phoenix/end2end/MapReduceIT.java | 8 +- .../phoenix/end2end/MappingTableDataTypeIT.java | 2 +- .../end2end/MinMaxAggregateFunctionIT.java | 2 +- .../phoenix/end2end/ModulusExpressionIT.java | 10 +- .../phoenix/end2end/MultiCfQueryExecIT.java | 306 +++---- .../end2end/NamespaceSchemaMappingIT.java | 2 +- .../phoenix/end2end/NthValueFunctionIT.java | 22 +- .../end2end/OctetLengthFunctionEnd2EndIT.java | 2 +- .../org/apache/phoenix/end2end/OrderByIT.java | 16 +- .../phoenix/end2end/ParallelIteratorsIT.java | 112 +-- .../phoenix/end2end/ParallelRunListener.java | 42 + .../end2end/ParallelStatsDisabledIT.java | 14 +- .../phoenix/end2end/ParallelStatsEnabledIT.java | 24 +- .../apache/phoenix/end2end/PercentileIT.java | 15 +- .../phoenix/end2end/PhoenixRuntimeIT.java | 18 +- .../phoenix/end2end/PowerFunctionEnd2EndIT.java | 19 +- .../apache/phoenix/end2end/PrimitiveTypeIT.java | 18 +- .../org/apache/phoenix/end2end/QueryMoreIT.java | 8 +- .../apache/phoenix/end2end/QueryTimeoutIT.java | 2 +- .../phoenix/end2end/QueryWithLimitIT.java | 11 +- .../phoenix/end2end/QueryWithOffsetIT.java | 78 +- .../apache/phoenix/end2end/RTrimFunctionIT.java | 2 +- .../org/apache/phoenix/end2end/ReadOnlyIT.java | 2 +- .../end2end/RegexpReplaceFunctionIT.java | 2 +- .../phoenix/end2end/RegexpSplitFunctionIT.java | 2 +- .../phoenix/end2end/RegexpSubstrFunctionIT.java | 2 +- .../apache/phoenix/end2end/RenewLeaseIT.java | 2 +- .../phoenix/end2end/ReverseFunctionIT.java | 2 +- .../apache/phoenix/end2end/ReverseScanIT.java | 4 +- .../phoenix/end2end/RoundFloorCeilFuncIT.java | 2 +- .../phoenix/end2end/SerialIteratorsIT.java | 21 +- .../phoenix/end2end/ServerExceptionIT.java | 2 +- .../phoenix/end2end/SignFunctionEnd2EndIT.java | 27 +- .../end2end/SkipScanAfterManualSplitIT.java | 39 +- .../apache/phoenix/end2end/SkipScanQueryIT.java | 22 +- .../apache/phoenix/end2end/SortMergeJoinIT.java | 471 +++++------ .../phoenix/end2end/SortMergeJoinMoreIT.java | 36 +- .../org/apache/phoenix/end2end/SortOrderIT.java | 88 +- .../phoenix/end2end/SpillableGroupByIT.java | 127 ++- .../phoenix/end2end/SpooledOrderByIT.java | 40 - .../phoenix/end2end/SpooledSortMergeJoinIT.java | 45 -- .../phoenix/end2end/SpooledTmpFileDeleteIT.java | 64 +- .../phoenix/end2end/SqrtFunctionEnd2EndIT.java | 4 +- .../phoenix/end2end/StatementHintsIT.java | 2 +- .../end2end/StatsCollectionDisabledIT.java | 79 -- .../end2end/StatsCollectorAbstractIT.java | 77 -- .../phoenix/end2end/StatsCollectorIT.java | 239 ++++-- .../StatsCollectorWithSplitsAndMultiCFIT.java | 186 ----- .../apache/phoenix/end2end/StoreNullsIT.java | 76 +- .../org/apache/phoenix/end2end/StringIT.java | 10 +- .../end2end/StringToArrayFunctionIT.java | 99 +-- .../org/apache/phoenix/end2end/SubqueryIT.java | 297 +++---- .../end2end/SubqueryUsingSortMergeJoinIT.java | 456 ++--------- .../apache/phoenix/end2end/TenantIdTypeIT.java | 2 +- .../end2end/TenantSpecificTablesDDLIT.java | 272 +++---- .../end2end/TenantSpecificTablesDMLIT.java | 269 ++---- .../end2end/TenantSpecificViewIndexIT.java | 20 +- .../end2end/TimezoneOffsetFunctionIT.java | 14 +- .../phoenix/end2end/ToCharFunctionIT.java | 6 +- .../phoenix/end2end/ToDateFunctionIT.java | 2 +- .../phoenix/end2end/TransactionalViewIT.java | 57 +- .../org/apache/phoenix/end2end/UnionAllIT.java | 80 +- .../org/apache/phoenix/end2end/UpgradeIT.java | 181 +++-- .../phoenix/end2end/UpsertBigValuesIT.java | 8 +- .../end2end/UpsertSelectAutoCommitIT.java | 10 +- .../apache/phoenix/end2end/UpsertValuesIT.java | 2 +- .../org/apache/phoenix/end2end/UseSchemaIT.java | 16 +- .../phoenix/end2end/UserDefinedFunctionsIT.java | 155 +++- .../java/org/apache/phoenix/end2end/ViewIT.java | 249 +++--- .../end2end/index/AsyncIndexDisabledIT.java | 17 +- .../phoenix/end2end/index/BaseLocalIndexIT.java | 80 ++ .../index/ChildViewsUseParentViewIndexIT.java | 20 +- .../phoenix/end2end/index/DropMetadataIT.java | 64 +- .../index/GlobalIndexOptimizationIT.java | 48 +- .../phoenix/end2end/index/ImmutableIndexIT.java | 31 +- .../index/ImmutableIndexWithStatsIT.java | 26 +- .../end2end/index/IndexExpressionIT.java | 87 +- .../apache/phoenix/end2end/index/IndexIT.java | 111 ++- .../phoenix/end2end/index/IndexMetadataIT.java | 35 +- .../phoenix/end2end/index/LocalIndexIT.java | 356 +------- .../end2end/index/MutableIndexFailureIT.java | 6 +- .../phoenix/end2end/index/MutableIndexIT.java | 93 +-- .../end2end/index/ReadOnlyIndexFailureIT.java | 4 +- .../phoenix/end2end/index/SaltedIndexIT.java | 43 +- .../phoenix/end2end/index/ViewIndexIT.java | 33 +- .../end2end/index/txn/MutableRollbackIT.java | 58 +- .../phoenix/end2end/index/txn/RollbackIT.java | 33 +- .../end2end/index/txn/TxWriteFailureIT.java | 4 +- .../salted/SaltedTableUpsertSelectIT.java | 22 +- .../salted/SaltedTableVarLengthRowKeyIT.java | 2 +- .../apache/phoenix/execute/PartialCommitIT.java | 5 + .../phoenix/iterate/PhoenixQueryTimeoutIT.java | 52 +- .../iterate/RoundRobinResultIteratorIT.java | 48 +- .../RoundRobinResultIteratorWithStatsIT.java | 4 +- .../phoenix/monitoring/PhoenixMetricsIT.java | 4 +- .../apache/phoenix/rpc/PhoenixClientRpcIT.java | 4 +- .../apache/phoenix/rpc/PhoenixServerRpcIT.java | 4 +- .../org/apache/phoenix/rpc/UpdateCacheIT.java | 41 +- .../phoenix/rpc/UpdateCacheWithScnIT.java | 3 +- .../apache/phoenix/trace/BaseTracingTestIT.java | 14 - .../trace/PhoenixTableMetricsWriterIT.java | 4 +- .../phoenix/trace/PhoenixTraceReaderIT.java | 4 +- .../phoenix/trace/PhoenixTracingEndToEndIT.java | 24 +- .../apache/phoenix/trace/TracingTestUtil.java | 8 +- .../phoenix/tx/FlappingTransactionIT.java | 328 ++++++++ .../org/apache/phoenix/tx/TransactionIT.java | 363 +-------- .../org/apache/phoenix/tx/TxCheckpointIT.java | 51 +- .../phoenix/calcite/PhoenixPrepareImpl.java | 10 +- .../phoenix/compile/StatementContext.java | 2 +- .../coprocessor/MetaDataEndpointImpl.java | 53 ++ .../phoenix/coprocessor/MetaDataProtocol.java | 17 + .../coprocessor/generated/MetaDataProtos.java | 353 ++++++-- .../coprocessor/generated/PTableProtos.java | 779 +++++++----------- .../exception/RetriableUpgradeException.java | 31 + .../exception/UpgradeInProgressException.java | 3 +- .../exception/UpgradeNotRequiredException.java | 3 +- .../exception/UpgradeRequiredException.java | 3 +- .../hbase/index/table/CachingHTableFactory.java | 104 ++- .../index/table/CoprocessorHTableFactory.java | 6 + .../hbase/index/table/HTableFactory.java | 4 +- .../hbase/index/write/IndexWriterUtils.java | 3 + .../write/ParallelWriterIndexCommitter.java | 21 +- .../TrackingParallelWriterIndexCommitter.java | 18 +- .../index/PhoenixIndexFailurePolicy.java | 2 +- .../apache/phoenix/parse/ParseNodeRewriter.java | 16 +- .../phoenix/query/ConnectionQueryServices.java | 2 +- .../query/ConnectionQueryServicesImpl.java | 32 +- .../query/ConnectionlessQueryServicesImpl.java | 8 +- .../query/DelegateConnectionQueryServices.java | 4 +- .../phoenix/query/QueryServicesOptions.java | 8 +- .../apache/phoenix/schema/MetaDataClient.java | 88 +- .../org/apache/phoenix/schema/PTableImpl.java | 13 +- .../java/org/apache/phoenix/util/DateUtil.java | 2 +- .../org/apache/phoenix/util/MetaDataUtil.java | 4 + .../java/org/apache/phoenix/util/QueryUtil.java | 2 +- .../phoenix/compile/JoinQueryCompilerTest.java | 35 + .../TenantSpecificViewIndexCompileTest.java | 4 +- .../hbase/index/write/FakeTableFactory.java | 9 +- .../index/write/TestCachingHTableFactory.java | 37 +- .../hbase/index/write/TestIndexWriter.java | 24 +- .../index/write/TestParalleIndexWriter.java | 16 +- .../write/TestParalleWriterIndexCommitter.java | 15 +- .../apache/phoenix/jdbc/PhoenixDriverTest.java | 2 + .../phoenix/jdbc/SecureUserConnectionsTest.java | 27 +- .../query/BaseConnectionlessQueryTest.java | 28 +- .../java/org/apache/phoenix/query/BaseTest.java | 413 ++-------- .../phoenix/query/QueryServicesTestImpl.java | 2 + .../java/org/apache/phoenix/util/TestUtil.java | 101 ++- .../org/apache/phoenix/flume/PhoenixSinkIT.java | 31 +- .../phoenix/flume/RegexEventSerializerIT.java | 16 +- .../apache/phoenix/pherf/ResultBaseTestIT.java | 12 +- .../apache/phoenix/pherf/SchemaReaderIT.java | 4 +- .../java/org/apache/phoenix/pig/BasePigIT.java | 6 +- phoenix-protocol/src/main/MetaDataService.proto | 3 + phoenix-protocol/src/main/PTable.proto | 2 + .../phoenix/end2end/QueryServerBasicsIT.java | 2 +- pom.xml | 101 ++- 221 files changed, 6018 insertions(+), 6555 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/phoenix/blob/7ca8e4b3/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 75bce4c,0000000..4c89f8d 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,737 -1,0 +1,758 @@@ +/* + * 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); + } + + public Sql explainMatches(String expected) throws SQLException { + return checkExplain(expected, false); + } + + private Sql checkExplain(String expected, boolean exact) 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) { + Assert.assertEquals(explain, expected); + } else { + Assert.assertTrue( + "Explain plan \"" + explain + + "\" does not match \"" + expected + "\"", + explain.matches(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(); + } + } + +}
