http://git-wip-us.apache.org/repos/asf/phoenix/blob/faad4ad3/phoenix-core/src/it/java/org/apache/phoenix/end2end/BaseViewIT.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/BaseViewIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/BaseViewIT.java index d9a59a9..a3c36fa 100644 --- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/BaseViewIT.java +++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/BaseViewIT.java @@ -69,7 +69,6 @@ public abstract class BaseViewIT extends BaseOwnClusterHBaseManagedTimeIT { public static void doSetup() throws Exception { Map<String,String> props = Maps.newHashMapWithExpectedSize(3); props.put(QueryServices.STATS_GUIDEPOST_WIDTH_BYTES_ATTRIB, Integer.toString(20)); - props.put(QueryServices.QUEUE_SIZE_ATTRIB, Integer.toString(1024)); props.put(QueryServices.TRANSACTIONS_ENABLED, Boolean.toString(true)); setUpTestDriver(new ReadOnlyProps(props.entrySet().iterator())); }
http://git-wip-us.apache.org/repos/asf/phoenix/blob/faad4ad3/phoenix-core/src/it/java/org/apache/phoenix/end2end/CsvBulkLoadToolIT.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/CsvBulkLoadToolIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/CsvBulkLoadToolIT.java index 8968555..4971fc3 100644 --- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/CsvBulkLoadToolIT.java +++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/CsvBulkLoadToolIT.java @@ -40,7 +40,9 @@ import org.apache.phoenix.mapreduce.CsvBulkLoadTool; import org.apache.phoenix.query.QueryServices; import org.apache.phoenix.query.QueryServicesOptions; import org.apache.phoenix.util.DateUtil; +import org.apache.phoenix.util.PhoenixRuntime; import org.apache.phoenix.util.ReadOnlyProps; +import org.apache.phoenix.util.TestUtil; import org.junit.BeforeClass; import org.junit.Test; @@ -57,8 +59,8 @@ public class CsvBulkLoadToolIT extends BaseOwnClusterHBaseManagedTimeIT { serverProps.put(QueryServices.EXTRA_JDBC_ARGUMENTS_ATTRIB, QueryServicesOptions.DEFAULT_EXTRA_JDBC_ARGUMENTS); Map<String, String> clientProps = Maps.newHashMapWithExpectedSize(1); clientProps.put(QueryServices.TRANSACTIONS_ENABLED, "true"); - setUpRealDriver(new ReadOnlyProps(serverProps.entrySet().iterator()), new ReadOnlyProps(clientProps.entrySet().iterator())); - zkQuorum = "localhost:" + getUtility().getZkCluster().getClientPort(); + setUpTestDriver(new ReadOnlyProps(serverProps.entrySet().iterator()), new ReadOnlyProps(clientProps.entrySet().iterator())); + zkQuorum = TestUtil.LOCALHOST + PhoenixRuntime.JDBC_PROTOCOL_SEPARATOR + getUtility().getZkCluster().getClientPort(); conn = DriverManager.getConnection(getUrl()); } http://git-wip-us.apache.org/repos/asf/phoenix/blob/faad4ad3/phoenix-core/src/it/java/org/apache/phoenix/end2end/IndexExtendedIT.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/IndexExtendedIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/IndexExtendedIT.java new file mode 100644 index 0000000..140888b --- /dev/null +++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/IndexExtendedIT.java @@ -0,0 +1,591 @@ +/* + * 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.end2end; + +import static org.apache.phoenix.util.TestUtil.TEST_PROPERTIES; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.UUID; + +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.hbase.HRegionInfo; +import org.apache.hadoop.hbase.TableName; +import org.apache.hadoop.hbase.catalog.CatalogTracker; +import org.apache.hadoop.hbase.catalog.MetaReader; +import org.apache.hadoop.hbase.client.HBaseAdmin; +import org.apache.hadoop.hbase.util.Bytes; +import org.apache.phoenix.jdbc.PhoenixConnection; +import org.apache.phoenix.mapreduce.index.IndexTool; +import org.apache.phoenix.query.QueryServices; +import org.apache.phoenix.query.QueryServicesOptions; +import org.apache.phoenix.util.ByteUtil; +import org.apache.phoenix.util.PropertiesUtil; +import org.apache.phoenix.util.QueryUtil; +import org.apache.phoenix.util.ReadOnlyProps; +import org.apache.phoenix.util.SchemaUtil; +import org.apache.phoenix.util.TestUtil; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; + +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; + +/** + * Tests for the {@link IndexTool} + */ +@RunWith(Parameterized.class) +public class IndexExtendedIT extends BaseOwnClusterHBaseManagedTimeIT { + private final boolean localIndex; + private final boolean transactional; + private final boolean directApi; + private final String tableDDLOptions; + private final boolean mutable; + + public IndexExtendedIT(boolean transactional, boolean mutable, boolean localIndex, boolean directApi) { + this.localIndex = localIndex; + this.transactional = transactional; + this.directApi = directApi; + this.mutable = mutable; + StringBuilder optionBuilder = new StringBuilder(); + if (!mutable) { + optionBuilder.append(" IMMUTABLE_ROWS=true "); + } + if (transactional) { + if (!(optionBuilder.length()==0)) { + optionBuilder.append(","); + } + optionBuilder.append(" TRANSACTIONAL=true "); + } + optionBuilder.append(" SPLIT ON(1,2)"); + this.tableDDLOptions = optionBuilder.toString(); + } + + @BeforeClass + public static void doSetup() throws Exception { + Map<String, String> serverProps = Maps.newHashMapWithExpectedSize(1); + serverProps.put(QueryServices.EXTRA_JDBC_ARGUMENTS_ATTRIB, QueryServicesOptions.DEFAULT_EXTRA_JDBC_ARGUMENTS); + Map<String, String> clientProps = Maps.newHashMapWithExpectedSize(1); + clientProps.put(QueryServices.TRANSACTIONS_ENABLED, Boolean.TRUE.toString()); + setUpTestDriver(new ReadOnlyProps(serverProps.entrySet().iterator()), new ReadOnlyProps(clientProps.entrySet() + .iterator())); + } + + @Parameters(name="transactional = {0} , mutable = {1} , localIndex = {2}, directApi = {3}") + public static Collection<Boolean[]> data() { + return Arrays.asList(new Boolean[][] { + { false, false, false, false }, { false, false, false, true }, { false, false, true, false }, { false, false, true, true }, + { false, true, false, false }, { false, true, false, true }, { false, true, true, false }, { false, true, true, true }, + { true, false, false, false }, { true, false, false, true }, { true, false, true, false }, { true, false, true, true }, + { true, true, false, false }, { true, true, false, true }, { true, true, true, false }, { true, true, true, true } + }); + } + + /** + * This test is to assert that updates that happen to rows of a mutable table after an index is created in ASYNC mode and before + * the MR job runs, do show up in the index table . + * @throws Exception + */ + @Test + public void testMutableIndexWithUpdates() throws Exception { + if (!mutable || transactional) { + return; + } + String schemaName = generateRandomString(); + String dataTableName = generateRandomString(); + String dataTableFullName = SchemaUtil.getTableName(schemaName, dataTableName); + String indexTableName = generateRandomString(); + String indexTableFullName = SchemaUtil.getTableName(schemaName, indexTableName); + Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES); + Connection conn = DriverManager.getConnection(getUrl(), props); + Statement stmt = conn.createStatement(); + try { + stmt.execute(String.format("CREATE TABLE %s (ID INTEGER NOT NULL PRIMARY KEY, NAME VARCHAR, ZIP INTEGER)",dataTableFullName)); + String upsertQuery = String.format("UPSERT INTO %s VALUES(?, ?, ?)",dataTableFullName); + PreparedStatement stmt1 = conn.prepareStatement(upsertQuery); + + int id = 1; + // insert two rows + IndexExtendedIT.upsertRow(stmt1, id++); + IndexExtendedIT.upsertRow(stmt1, id++); + conn.commit(); + + stmt.execute(String.format("CREATE " + (localIndex ? "LOCAL" : "") + " INDEX %s ON %s (UPPER(NAME)) ASYNC ", indexTableName,dataTableFullName)); + + //update a row + stmt1.setInt(1, 1); + stmt1.setString(2, "uname" + String.valueOf(10)); + stmt1.setInt(3, 95050 + 1); + stmt1.executeUpdate(); + conn.commit(); + + //verify rows are fetched from data table. + String selectSql = String.format("SELECT ID FROM %s WHERE UPPER(NAME) ='UNAME2'",dataTableFullName); + ResultSet rs = conn.createStatement().executeQuery("EXPLAIN " + selectSql); + String actualExplainPlan = QueryUtil.getExplainPlan(rs); + + //assert we are pulling from data table. + assertEquals(String.format("CLIENT PARALLEL 1-WAY FULL SCAN OVER %s\n" + + " SERVER FILTER BY UPPER(NAME) = 'UNAME2'",dataTableFullName),actualExplainPlan); + + rs = stmt1.executeQuery(selectSql); + assertTrue(rs.next()); + assertEquals(2, rs.getInt(1)); + assertFalse(rs.next()); + + //run the index MR job. + runIndexTool(schemaName, dataTableName, indexTableName); + + //assert we are pulling from index table. + rs = conn.createStatement().executeQuery("EXPLAIN " + selectSql); + actualExplainPlan = QueryUtil.getExplainPlan(rs); + // TODO: why is it a 1-WAY parallel scan only for !transactional && mutable && localIndex + assertExplainPlan(actualExplainPlan, dataTableFullName, indexTableFullName); + + rs = stmt.executeQuery(selectSql); + assertTrue(rs.next()); + assertEquals(2, rs.getInt(1)); + assertFalse(rs.next()); + } finally { + conn.close(); + } + } + + private void runIndexTool(String schemaName, String dataTableName, String indexTableName) throws Exception { + IndexTool indexingTool = new IndexTool(); + Configuration conf = new Configuration(getUtility().getConfiguration()); + conf.set(QueryServices.TRANSACTIONS_ENABLED, Boolean.TRUE.toString()); + indexingTool.setConf(conf); + final String[] cmdArgs = getArgValues(schemaName, dataTableName, indexTableName); + int status = indexingTool.run(cmdArgs); + assertEquals(0, status); + } + + @Test + public void testSecondaryIndex() throws Exception { + String schemaName = generateRandomString(); + String dataTableName = generateRandomString(); + String dataTableFullName = SchemaUtil.getTableName(schemaName, dataTableName); + String indexTableName = generateRandomString(); + String indexTableFullName = SchemaUtil.getTableName(schemaName, indexTableName); + Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES); + Connection conn = DriverManager.getConnection(getUrl(), props); + try { + String stmString1 = "CREATE TABLE " + dataTableFullName + " (ID INTEGER NOT NULL PRIMARY KEY, NAME VARCHAR, ZIP INTEGER) " + tableDDLOptions; + conn.createStatement().execute(stmString1); + String upsertQuery = String.format("UPSERT INTO %s VALUES(?, ?, ?)", dataTableFullName); + PreparedStatement stmt1 = conn.prepareStatement(upsertQuery); + + // insert two rows + upsertRow(stmt1, 1); + upsertRow(stmt1, 2); + conn.commit(); + + if (transactional) { + // insert two rows in another connection without committing so that they are not visible to other transactions + try (Connection conn2 = DriverManager.getConnection(getUrl(), props)) { + conn2.setAutoCommit(false); + PreparedStatement stmt2 = conn2.prepareStatement(upsertQuery); + upsertRow(stmt2, 5); + upsertRow(stmt2, 6); + ResultSet rs = conn.createStatement().executeQuery("SELECT count(*) from "+dataTableFullName); + assertTrue(rs.next()); + assertEquals("Unexpected row count ", 2, rs.getInt(1)); + assertFalse(rs.next()); + rs = conn2.createStatement().executeQuery("SELECT count(*) from "+dataTableFullName); + assertTrue(rs.next()); + assertEquals("Unexpected row count ", 4, rs.getInt(1)); + assertFalse(rs.next()); + } + } + + String stmtString2 = String.format("CREATE %s INDEX %s ON %s (LPAD(UPPER(NAME),8,'x')||'_xyz') ASYNC ", (localIndex ? "LOCAL" : ""), indexTableName, dataTableFullName); + conn.createStatement().execute(stmtString2); + + //verify rows are fetched from data table. + String selectSql = String.format("SELECT ID FROM %s WHERE LPAD(UPPER(NAME),8,'x')||'_xyz' = 'xxUNAME2_xyz'", dataTableFullName); + ResultSet rs = conn.createStatement().executeQuery("EXPLAIN " + selectSql); + String actualExplainPlan = QueryUtil.getExplainPlan(rs); + + //assert we are pulling from data table. + assertEquals( + String.format("CLIENT PARALLEL 1-WAY FULL SCAN OVER %s\n" + + " SERVER FILTER BY (LPAD(UPPER(NAME), 8, 'x') || '_xyz') = 'xxUNAME2_xyz'", dataTableFullName), actualExplainPlan); + + rs = stmt1.executeQuery(selectSql); + assertTrue(rs.next()); + assertEquals(2, rs.getInt(1)); + assertFalse(rs.next()); + conn.commit(); + + //run the index MR job. + runIndexTool(schemaName, dataTableName, indexTableName); + + // insert two more rows + upsertRow(stmt1, 3); + upsertRow(stmt1, 4); + conn.commit(); + + //assert we are pulling from index table. + rs = conn.createStatement().executeQuery("EXPLAIN " + selectSql); + actualExplainPlan = QueryUtil.getExplainPlan(rs); + assertExplainPlan(actualExplainPlan, dataTableFullName, indexTableFullName); + + rs = conn.createStatement().executeQuery(selectSql); + assertTrue(rs.next()); + assertEquals(2, rs.getInt(1)); + assertFalse(rs.next()); + } finally { + conn.close(); + } + } + + private void assertExplainPlan(final String actualExplainPlan, String dataTableFullName, String indexTableFullName) { + String expectedExplainPlan; + if(localIndex) { + expectedExplainPlan = String.format(" RANGE SCAN OVER %s [1,", + dataTableFullName); + } else { + expectedExplainPlan = String.format(" RANGE SCAN OVER %s", + indexTableFullName); + } + assertTrue(actualExplainPlan + "\n expected to contain \n" + expectedExplainPlan, actualExplainPlan.contains(expectedExplainPlan)); + } + + private String[] getArgValues(String schemaName, String dataTable, String indxTable) { + final List<String> args = Lists.newArrayList(); + if (schemaName!=null) { + args.add("-s"); + args.add(schemaName); + } + args.add("-dt"); + args.add(dataTable); + args.add("-it"); + args.add(indxTable); + if(directApi) { + args.add("-direct"); + // Need to run this job in foreground for the test to be deterministic + args.add("-runfg"); + } + + args.add("-op"); + args.add("/tmp/"+UUID.randomUUID().toString()); + return args.toArray(new String[0]); + } + + private static void upsertRow(PreparedStatement stmt, int i) throws SQLException { + // insert row + stmt.setInt(1, i); + stmt.setString(2, "uname" + String.valueOf(i)); + stmt.setInt(3, 95050 + i); + stmt.executeUpdate(); + } + + @Test + public void testDeleteFromImmutable() throws Exception { + if (transactional || mutable) { + return; + } + if (localIndex) { // TODO: remove this return once PHOENIX-3292 is fixed + return; + } + String schemaName = generateRandomString(); + String dataTableName = generateRandomString(); + String dataTableFullName = SchemaUtil.getTableName(schemaName, dataTableName); + String indexTableName = generateRandomString(); + String indexTableFullName = SchemaUtil.getTableName(schemaName, indexTableName); + Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES); + try (Connection conn = DriverManager.getConnection(getUrl(), props)) { + conn.createStatement().execute("CREATE TABLE " + dataTableFullName + " (\n" + + " pk1 VARCHAR NOT NULL,\n" + + " pk2 VARCHAR NOT NULL,\n" + + " pk3 VARCHAR\n" + + " CONSTRAINT PK PRIMARY KEY \n" + + " (\n" + + " pk1,\n" + + " pk2,\n" + + " pk3\n" + + " )\n" + + " ) IMMUTABLE_ROWS=true"); + conn.createStatement().execute("upsert into " + dataTableFullName + " (pk1, pk2, pk3) values ('a', '1', '1')"); + conn.createStatement().execute("upsert into " + dataTableFullName + " (pk1, pk2, pk3) values ('b', '2', '2')"); + conn.commit(); + conn.createStatement().execute("CREATE " + (localIndex ? "LOCAL" : "") + " INDEX " + indexTableName + " ON " + dataTableFullName + " (pk3, pk2) ASYNC"); + + // this delete will be issued at a timestamp later than the above timestamp of the index table + conn.createStatement().execute("delete from " + dataTableFullName + " where pk1 = 'a'"); + conn.commit(); + + //run the index MR job. + runIndexTool(schemaName, dataTableName, indexTableName); + + // upsert two more rows + conn.createStatement().execute( + "upsert into " + dataTableFullName + " (pk1, pk2, pk3) values ('a', '3', '3')"); + conn.createStatement().execute( + "upsert into " + dataTableFullName + " (pk1, pk2, pk3) values ('b', '4', '4')"); + conn.commit(); + + // validate that delete markers were issued correctly and only ('a', '1', 'value1') was + // deleted + String query = "SELECT pk3 from " + dataTableFullName + " ORDER BY pk3"; + ResultSet rs = conn.createStatement().executeQuery("EXPLAIN " + query); + String expectedPlan = + "CLIENT PARALLEL 1-WAY FULL SCAN OVER " + indexTableFullName + "\n" + + " SERVER FILTER BY FIRST KEY ONLY"; + assertEquals("Wrong plan ", expectedPlan, QueryUtil.getExplainPlan(rs)); + rs = conn.createStatement().executeQuery(query); + assertTrue(rs.next()); + assertEquals("2", rs.getString(1)); + assertTrue(rs.next()); + assertEquals("3", rs.getString(1)); + assertTrue(rs.next()); + assertEquals("4", rs.getString(1)); + assertFalse(rs.next()); + } + } + + private Connection getConnectionForLocalIndexTest() throws SQLException{ + Properties props = PropertiesUtil.deepCopy(TestUtil.TEST_PROPERTIES); + props.put(QueryServices.FORCE_ROW_KEY_ORDER_ATTRIB, Boolean.TRUE.toString()); + return DriverManager.getConnection(getUrl(),props); + } + + private void createBaseTable(String tableName, String splits) throws SQLException { + Connection conn = getConnectionForLocalIndexTest(); + String ddl = "CREATE TABLE " + tableName + " (t_id VARCHAR NOT NULL,\n" + + "k1 INTEGER NOT NULL,\n" + + "k2 INTEGER NOT NULL,\n" + + "k3 INTEGER,\n" + + "v1 VARCHAR,\n" + + "CONSTRAINT pk PRIMARY KEY (t_id, k1, k2))\n" + + (splits != null ? (" split on " + splits) : ""); + conn.createStatement().execute(ddl); + conn.close(); + } + + // Moved from LocalIndexIT because it was causing parallel runs to hang + @Test + public void testLocalIndexScanAfterRegionSplit() throws Exception { + // This test just needs be run once + if (!localIndex || transactional || mutable || directApi) { + return; + } + String schemaName = generateRandomString(); + String tableName = schemaName + "." + generateRandomString(); + String indexName = "IDX_" + generateRandomString(); + TableName physicalTableName = SchemaUtil.getPhysicalTableName(tableName.getBytes(), false); + String indexPhysicalTableName = physicalTableName.getNameAsString(); + + createBaseTable(tableName, "('e','j','o')"); + Connection conn1 = getConnectionForLocalIndexTest(); + try{ + String[] strings = {"a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"}; + for (int i = 0; i < 26; i++) { + conn1.createStatement().execute( + "UPSERT INTO " + tableName + " values('"+strings[i]+"'," + i + "," + + (i + 1) + "," + (i + 2) + ",'" + strings[25 - i] + "')"); + } + conn1.commit(); + conn1.createStatement().execute("CREATE LOCAL INDEX " + indexName + " ON " + tableName + "(v1)"); + conn1.createStatement().execute("CREATE LOCAL INDEX " + indexName + "_2 ON " + tableName + "(k3)"); + + ResultSet rs = conn1.createStatement().executeQuery("SELECT * FROM " + tableName); + assertTrue(rs.next()); + + HBaseAdmin admin = conn1.unwrap(PhoenixConnection.class).getQueryServices().getAdmin(); + for (int i = 1; i < 5; i++) { + CatalogTracker ct = new CatalogTracker(admin.getConfiguration()); + admin.split(physicalTableName.getName(), ByteUtil.concat(Bytes.toBytes(strings[3*i]))); + List<HRegionInfo> regionsOfUserTable = + MetaReader.getTableRegions(ct, physicalTableName, false); + + while (regionsOfUserTable.size() != (4+i)) { + Thread.sleep(100); + regionsOfUserTable = MetaReader.getTableRegions(ct, physicalTableName, false); + } + assertEquals(4+i, regionsOfUserTable.size()); + String[] tIdColumnValues = new String[26]; + String[] v1ColumnValues = new String[26]; + int[] k1ColumnValue = new int[26]; + String query = "SELECT t_id,k1,v1 FROM " + tableName; + rs = conn1.createStatement().executeQuery(query); + Thread.sleep(1000); + for (int j = 0; j < 26; j++) { + assertTrue(rs.next()); + tIdColumnValues[j] = rs.getString("t_id"); + k1ColumnValue[j] = rs.getInt("k1"); + v1ColumnValues[j] = rs.getString("V1"); + } + Arrays.sort(tIdColumnValues); + Arrays.sort(v1ColumnValues); + Arrays.sort(k1ColumnValue); + assertTrue(Arrays.equals(strings, tIdColumnValues)); + assertTrue(Arrays.equals(strings, v1ColumnValues)); + for(int m=0;m<26;m++) { + assertEquals(m, k1ColumnValue[m]); + } + + rs = conn1.createStatement().executeQuery("EXPLAIN " + query); + assertEquals( + "CLIENT PARALLEL " + (4 + i) + "-WAY RANGE SCAN OVER " + + indexPhysicalTableName + " [1]\n" + + " SERVER FILTER BY FIRST KEY ONLY\n" + + "CLIENT MERGE SORT", QueryUtil.getExplainPlan(rs)); + + query = "SELECT t_id,k1,k3 FROM " + tableName; + rs = conn1.createStatement().executeQuery("EXPLAIN "+query); + assertEquals( + "CLIENT PARALLEL " + + ((strings[3 * i].compareTo("j") < 0) ? (4 + i) : (4 + i - 1)) + + "-WAY RANGE SCAN OVER " + + indexPhysicalTableName + " [2]\n" + + " SERVER FILTER BY FIRST KEY ONLY\n" + + "CLIENT MERGE SORT", QueryUtil.getExplainPlan(rs)); + rs = conn1.createStatement().executeQuery(query); + Thread.sleep(1000); + int[] k3ColumnValue = new int[26]; + for (int j = 0; j < 26; j++) { + assertTrue(rs.next()); + tIdColumnValues[j] = rs.getString("t_id"); + k1ColumnValue[j] = rs.getInt("k1"); + k3ColumnValue[j] = rs.getInt("k3"); + } + Arrays.sort(tIdColumnValues); + Arrays.sort(k1ColumnValue); + Arrays.sort(k3ColumnValue); + assertTrue(Arrays.equals(strings, tIdColumnValues)); + for(int m=0;m<26;m++) { + assertEquals(m, k1ColumnValue[m]); + assertEquals(m+2, k3ColumnValue[m]); + } + } + } finally { + conn1.close(); + } + } + + // Moved from LocalIndexIT because it was causing parallel runs to hang + @Test + public void testLocalIndexScanAfterRegionsMerge() throws Exception { + // This test just needs be run once + if (!localIndex || transactional || mutable || directApi) { + return; + } + String schemaName = generateRandomString(); + String tableName = schemaName + "." + generateRandomString(); + String indexName = "IDX_" + generateRandomString(); + TableName physicalTableName = SchemaUtil.getPhysicalTableName(tableName.getBytes(), false); + String indexPhysicalTableName = physicalTableName.getNameAsString(); + + createBaseTable(tableName, "('e','j','o')"); + Connection conn1 = getConnectionForLocalIndexTest(); + try{ + String[] strings = {"a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"}; + for (int i = 0; i < 26; i++) { + conn1.createStatement().execute( + "UPSERT INTO " + tableName + " values('"+strings[i]+"'," + i + "," + + (i + 1) + "," + (i + 2) + ",'" + strings[25 - i] + "')"); + } + conn1.commit(); + conn1.createStatement().execute("CREATE LOCAL INDEX " + indexName + " ON " + tableName + "(v1)"); + conn1.createStatement().execute("CREATE LOCAL INDEX " + indexName + "_2 ON " + tableName + "(k3)"); + + ResultSet rs = conn1.createStatement().executeQuery("SELECT * FROM " + tableName); + assertTrue(rs.next()); + + HBaseAdmin admin = conn1.unwrap(PhoenixConnection.class).getQueryServices().getAdmin(); + CatalogTracker ct = new CatalogTracker(admin.getConfiguration()); + List<HRegionInfo> regionsOfUserTable = + MetaReader.getTableRegions(ct, + physicalTableName, false); + admin.mergeRegions(regionsOfUserTable.get(0).getEncodedNameAsBytes(), + regionsOfUserTable.get(1).getEncodedNameAsBytes(), false); + regionsOfUserTable = + MetaReader.getTableRegions(ct, + physicalTableName, false); + + while (regionsOfUserTable.size() != 3) { + Thread.sleep(100); + regionsOfUserTable = + MetaReader.getTableRegions(ct, + physicalTableName, false); + } + assertEquals(3, regionsOfUserTable.size()); + TableName indexTable = + TableName.valueOf(indexPhysicalTableName); + List<HRegionInfo> regionsOfIndexTable = + MetaReader.getTableRegions(ct, indexTable, false); + + while (regionsOfIndexTable.size() != 3) { + Thread.sleep(100); + regionsOfIndexTable = MetaReader.getTableRegions(ct, indexTable, false); + } + assertEquals(3, regionsOfIndexTable.size()); + String query = "SELECT t_id,k1,v1 FROM " + tableName; + rs = conn1.createStatement().executeQuery(query); + Thread.sleep(1000); + for (int j = 0; j < 26; j++) { + assertTrue(rs.next()); + assertEquals(strings[25 - j], rs.getString("t_id")); + assertEquals(25 - j, rs.getInt("k1")); + assertEquals(strings[j], rs.getString("V1")); + } + rs = conn1.createStatement().executeQuery("EXPLAIN " + query); + assertEquals( + "CLIENT PARALLEL " + 3 + "-WAY RANGE SCAN OVER " + + indexPhysicalTableName + + " [1]\n" + " SERVER FILTER BY FIRST KEY ONLY\n" + + "CLIENT MERGE SORT", QueryUtil.getExplainPlan(rs)); + + query = "SELECT t_id,k1,k3 FROM " + tableName; + rs = conn1.createStatement().executeQuery("EXPLAIN " + query); + assertEquals( + "CLIENT PARALLEL " + 3 + "-WAY RANGE SCAN OVER " + + indexPhysicalTableName + + " [2]\n" + " SERVER FILTER BY FIRST KEY ONLY\n" + + "CLIENT MERGE SORT", QueryUtil.getExplainPlan(rs)); + + rs = conn1.createStatement().executeQuery(query); + Thread.sleep(1000); + for (int j = 0; j < 26; j++) { + assertTrue(rs.next()); + assertEquals(strings[j], rs.getString("t_id")); + assertEquals(j, rs.getInt("k1")); + assertEquals(j + 2, rs.getInt("k3")); + } + } finally { + conn1.close(); + } + } +} http://git-wip-us.apache.org/repos/asf/phoenix/blob/faad4ad3/phoenix-core/src/it/java/org/apache/phoenix/end2end/IndexToolIT.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/IndexToolIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/IndexToolIT.java deleted file mode 100644 index 16db876..0000000 --- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/IndexToolIT.java +++ /dev/null @@ -1,257 +0,0 @@ -/* - * 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.end2end; - -import static org.apache.phoenix.util.TestUtil.TEST_PROPERTIES; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import java.sql.Connection; -import java.sql.DriverManager; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.Properties; -import java.util.UUID; - -import org.apache.hadoop.conf.Configuration; -import org.apache.phoenix.mapreduce.index.IndexTool; -import org.apache.phoenix.query.QueryServices; -import org.apache.phoenix.query.QueryServicesOptions; -import org.apache.phoenix.util.PropertiesUtil; -import org.apache.phoenix.util.QueryUtil; -import org.apache.phoenix.util.ReadOnlyProps; -import org.apache.phoenix.util.SchemaUtil; -import org.junit.BeforeClass; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameters; - -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; - -/** - * Tests for the {@link IndexTool} - */ -@RunWith(Parameterized.class) -public class IndexToolIT extends BaseOwnClusterHBaseManagedTimeIT { - - private final String schemaName; - private final String dataTable; - - private final boolean localIndex; - private final boolean transactional; - private final boolean directApi; - private final String tableDDLOptions; - - public IndexToolIT(boolean transactional, boolean localIndex, boolean mutable, boolean directApi) { - this.schemaName = "S"; - this.dataTable = "T" + (transactional ? "_TXN" : ""); - this.localIndex = localIndex; - this.transactional = transactional; - this.directApi = directApi; - StringBuilder optionBuilder = new StringBuilder(); - if (!mutable) - optionBuilder.append(" IMMUTABLE_ROWS=true "); - if (transactional) { - if (!(optionBuilder.length()==0)) - optionBuilder.append(","); - optionBuilder.append(" TRANSACTIONAL=true "); - } - optionBuilder.append(" SPLIT ON(1,2)"); - this.tableDDLOptions = optionBuilder.toString(); - } - - @BeforeClass - public static void doSetup() throws Exception { - Map<String, String> serverProps = Maps.newHashMapWithExpectedSize(1); - serverProps.put(QueryServices.EXTRA_JDBC_ARGUMENTS_ATTRIB, QueryServicesOptions.DEFAULT_EXTRA_JDBC_ARGUMENTS); - Map<String, String> clientProps = Maps.newHashMapWithExpectedSize(1); - clientProps.put(QueryServices.TRANSACTIONS_ENABLED, "true"); - setUpRealDriver(new ReadOnlyProps(serverProps.entrySet().iterator()), new ReadOnlyProps(clientProps.entrySet().iterator())); - } - - @Parameters(name="transactional = {0} , mutable = {1} , localIndex = {2}, directApi = {3}") - public static Collection<Boolean[]> data() { - return Arrays.asList(new Boolean[][] { - { false, false, false, false }, { false, false, false, true }, { false, false, true, false }, { false, false, true, true }, - { false, true, false, false }, { false, true, false, true }, { false, true, true, false }, { false, true, true, true }, - { true, false, false, false }, { true, false, false, true }, { true, false, true, false }, { true, false, true, true }, - { true, true, false, false }, { true, true, false, true }, { true, true, true, false }, { true, true, true, true } - }); - } - - @Test - public void testSecondaryIndex() throws Exception { - final String fullTableName = SchemaUtil.getTableName(schemaName, dataTable); - final String indxTable = String.format("%s_%s", dataTable, "INDX"); - Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES); - props.setProperty(QueryServices.TRANSACTIONS_ENABLED, Boolean.TRUE.toString()); - props.setProperty(QueryServices.EXPLAIN_ROW_COUNT_ATTRIB, Boolean.FALSE.toString()); - Connection conn = DriverManager.getConnection(getUrl(), props); - Statement stmt = conn.createStatement(); - try { - - stmt.execute(String.format("CREATE TABLE %s (ID INTEGER NOT NULL PRIMARY KEY, NAME VARCHAR, ZIP INTEGER) %s", fullTableName, tableDDLOptions)); - String upsertQuery = String.format("UPSERT INTO %s VALUES(?, ?, ?)", fullTableName); - PreparedStatement stmt1 = conn.prepareStatement(upsertQuery); - - // insert two rows - upsertRow(stmt1, 1); - upsertRow(stmt1, 2); - conn.commit(); - - if (transactional) { - // insert two rows in another connection without committing so that they are not visible to other transactions - try (Connection conn2 = DriverManager.getConnection(getUrl(), props)) { - conn2.setAutoCommit(false); - PreparedStatement stmt2 = conn2.prepareStatement(upsertQuery); - upsertRow(stmt2, 5); - upsertRow(stmt2, 6); - ResultSet rs = conn.createStatement().executeQuery("SELECT count(*) from "+fullTableName); - assertTrue(rs.next()); - assertEquals("Unexpected row count ", 2, rs.getInt(1)); - assertFalse(rs.next()); - rs = conn2.createStatement().executeQuery("SELECT count(*) from "+fullTableName); - assertTrue(rs.next()); - assertEquals("Unexpected row count ", 4, rs.getInt(1)); - assertFalse(rs.next()); - } - } - - stmt.execute(String.format("CREATE %s INDEX %s ON %s (LPAD(UPPER(NAME),8,'x')||'_xyz') ASYNC ", (localIndex ? "LOCAL" : ""), indxTable, fullTableName)); - - //verify rows are fetched from data table. - String selectSql = String.format("SELECT LPAD(UPPER(NAME),8,'x')||'_xyz',ID FROM %s", fullTableName); - ResultSet rs = conn.createStatement().executeQuery("EXPLAIN " + selectSql); - String actualExplainPlan = QueryUtil.getExplainPlan(rs); - - //assert we are pulling from data table. - assertEquals(String.format("CLIENT 3-CHUNK PARALLEL 1-WAY ROUND ROBIN FULL SCAN OVER %s", fullTableName), actualExplainPlan); - - rs = stmt1.executeQuery(selectSql); - assertTrue(rs.next()); - assertEquals("xxUNAME1_xyz", rs.getString(1)); - assertTrue(rs.next()); - assertEquals("xxUNAME2_xyz", rs.getString(1)); - assertFalse(rs.next()); - conn.commit(); - - //run the index MR job. - final IndexTool indexingTool = new IndexTool(); - Configuration conf = new Configuration(getUtility().getConfiguration()); - conf.set(QueryServices.TRANSACTIONS_ENABLED, Boolean.TRUE.toString()); - indexingTool.setConf(conf); - - final String[] cmdArgs = getArgValues(schemaName, dataTable, indxTable, directApi); - int status = indexingTool.run(cmdArgs); - assertEquals(0, status); - - // insert two more rows - upsertRow(stmt1, 3); - upsertRow(stmt1, 4); - conn.commit(); - - rs = stmt1.executeQuery("SELECT LPAD(UPPER(NAME),8,'x')||'_xyz',ID FROM "+fullTableName); - - //assert we are pulling from index table. - rs = conn.createStatement().executeQuery("EXPLAIN " + selectSql); - actualExplainPlan = QueryUtil.getExplainPlan(rs); - assertExplainPlan(actualExplainPlan, schemaName, dataTable, indxTable, localIndex); - - rs = stmt.executeQuery(selectSql); - assertTrue(rs.next()); - assertEquals("xxUNAME1_xyz", rs.getString(1)); - assertEquals(1, rs.getInt(2)); - - assertTrue(rs.next()); - assertEquals("xxUNAME2_xyz", rs.getString(1)); - assertEquals(2, rs.getInt(2)); - - assertTrue(rs.next()); - assertEquals("xxUNAME3_xyz", rs.getString(1)); - assertEquals(3, rs.getInt(2)); - - assertTrue(rs.next()); - assertEquals("xxUNAME4_xyz", rs.getString(1)); - assertEquals(4, rs.getInt(2)); - - assertFalse(rs.next()); - - conn.createStatement().execute(String.format("DROP INDEX %s ON %s",indxTable , fullTableName)); - } finally { - conn.close(); - } - } - - public static void assertExplainPlan(final String actualExplainPlan, String schemaName, String dataTable, - String indxTable, boolean isLocal) { - - String expectedExplainPlan = ""; - if(isLocal) { - final String localIndexName = SchemaUtil.getTableName(schemaName, dataTable); - expectedExplainPlan = String.format("CLIENT 3-CHUNK PARALLEL 3-WAY ROUND ROBIN RANGE SCAN OVER %s [1]" - + "\n SERVER FILTER BY FIRST KEY ONLY", localIndexName); - } else { - expectedExplainPlan = String.format("CLIENT 1-CHUNK PARALLEL 1-WAY ROUND ROBIN FULL SCAN OVER %s" - + "\n SERVER FILTER BY FIRST KEY ONLY",SchemaUtil.getTableName(schemaName, indxTable)); - } - assertEquals(expectedExplainPlan,actualExplainPlan); - } - - public static String[] getArgValues(String schemaName, String dataTable, String indxTable) { - return getArgValues(schemaName, dataTable, indxTable, false); - } - - public static String[] getArgValues(String schemaName, String dataTable, String indxTable, boolean directApi) { - final List<String> args = Lists.newArrayList(); - if (schemaName!=null) { - args.add("-s"); - args.add(schemaName); - } - args.add("-dt"); - args.add(dataTable); - args.add("-it"); - args.add(indxTable); - if(directApi) { - args.add("-direct"); - // Need to run this job in foreground for the test to be deterministic - args.add("-runfg"); - } - - args.add("-op"); - args.add("/tmp/"+UUID.randomUUID().toString()); - return args.toArray(new String[0]); - } - - public static void upsertRow(PreparedStatement stmt, int i) throws SQLException { - // insert row - stmt.setInt(1, i); - stmt.setString(2, "uname" + String.valueOf(i)); - stmt.setInt(3, 95050 + i); - stmt.executeUpdate(); - } - -} http://git-wip-us.apache.org/repos/asf/phoenix/blob/faad4ad3/phoenix-core/src/it/java/org/apache/phoenix/end2end/KeyOnlyIT.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/KeyOnlyIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/KeyOnlyIT.java index 4497c49..50e0709 100644 --- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/KeyOnlyIT.java +++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/KeyOnlyIT.java @@ -52,8 +52,7 @@ public class KeyOnlyIT extends BaseOwnClusterClientManagedTimeIT { public static void doSetup() throws Exception { Map<String,String> props = Maps.newHashMapWithExpectedSize(3); // Must update config before starting server - props.put(QueryServices.STATS_GUIDEPOST_WIDTH_BYTES_ATTRIB, Long.toString(50)); - props.put(QueryServices.QUEUE_SIZE_ATTRIB, Integer.toString(100)); + props.put(QueryServices.STATS_GUIDEPOST_WIDTH_BYTES_ATTRIB, Long.toString(20)); setUpTestDriver(new ReadOnlyProps(props.entrySet().iterator())); } @@ -81,7 +80,7 @@ public class KeyOnlyIT extends BaseOwnClusterClientManagedTimeIT { assertEquals(4, rs.getInt(2)); assertFalse(rs.next()); List<KeyRange> splits = getAllSplits(conn5, "KEYONLY"); - assertEquals(2, splits.size()); + assertEquals(3, splits.size()); conn5.close(); props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts+60)); http://git-wip-us.apache.org/repos/asf/phoenix/blob/faad4ad3/phoenix-core/src/it/java/org/apache/phoenix/end2end/MultiCfQueryExecIT.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/MultiCfQueryExecIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/MultiCfQueryExecIT.java index 15fc01d..b9d27ca 100644 --- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/MultiCfQueryExecIT.java +++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/MultiCfQueryExecIT.java @@ -52,7 +52,6 @@ public class MultiCfQueryExecIT extends BaseOwnClusterClientManagedTimeIT { Map<String,String> props = Maps.newHashMapWithExpectedSize(3); // Must update config before starting server props.put(QueryServices.STATS_GUIDEPOST_WIDTH_BYTES_ATTRIB, Long.toString(20)); - props.put(QueryServices.QUEUE_SIZE_ATTRIB, Long.toString(200)); setUpTestDriver(new ReadOnlyProps(props.entrySet().iterator())); } http://git-wip-us.apache.org/repos/asf/phoenix/blob/faad4ad3/phoenix-core/src/it/java/org/apache/phoenix/end2end/MutableIndexToolIT.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/MutableIndexToolIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/MutableIndexToolIT.java deleted file mode 100644 index c335ff8..0000000 --- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/MutableIndexToolIT.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - * 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.end2end; - -import static org.apache.phoenix.util.TestUtil.TEST_PROPERTIES; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -import java.sql.Connection; -import java.sql.DriverManager; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.Statement; -import java.util.Map; -import java.util.Properties; - -import org.apache.hadoop.conf.Configuration; -import org.apache.phoenix.mapreduce.index.IndexTool; -import org.apache.phoenix.query.QueryServices; -import org.apache.phoenix.query.QueryServicesOptions; -import org.apache.phoenix.util.PropertiesUtil; -import org.apache.phoenix.util.QueryUtil; -import org.apache.phoenix.util.ReadOnlyProps; -import org.junit.BeforeClass; -import org.junit.Test; - -import com.google.common.collect.Maps; - -public class MutableIndexToolIT extends BaseOwnClusterHBaseManagedTimeIT { - - @BeforeClass - public static void doSetup() throws Exception { - Map<String, String> serverProps = Maps.newHashMapWithExpectedSize(1); - serverProps.put(QueryServices.EXTRA_JDBC_ARGUMENTS_ATTRIB, QueryServicesOptions.DEFAULT_EXTRA_JDBC_ARGUMENTS); - setUpRealDriver(new ReadOnlyProps(serverProps.entrySet().iterator()), ReadOnlyProps.EMPTY_PROPS); - } - - /** - * This test is to assert that updates that happen to rows of a mutable table after an index is created in ASYNC mode and before - * the MR job runs, do show up in the index table . - * @throws Exception - */ - @Test - public void testMutableIndexWithUpdates() throws Exception { - - final String dataTable = "DATA_TABLE5"; - final String indxTable = String.format("%s_%s",dataTable,"INDX"); - Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES); - props.setProperty(QueryServices.EXPLAIN_ROW_COUNT_ATTRIB, Boolean.FALSE.toString()); - Connection conn = DriverManager.getConnection(getUrl(), props); - Statement stmt = conn.createStatement(); - try { - - stmt.execute(String.format("CREATE TABLE %s (ID INTEGER NOT NULL PRIMARY KEY, NAME VARCHAR, ZIP INTEGER)",dataTable)); - String upsertQuery = String.format("UPSERT INTO %s VALUES(?, ?, ?)",dataTable); - PreparedStatement stmt1 = conn.prepareStatement(upsertQuery); - - int id = 1; - // insert two rows - IndexToolIT.upsertRow(stmt1, id++); - IndexToolIT.upsertRow(stmt1, id++); - conn.commit(); - - stmt.execute(String.format("CREATE INDEX %s ON %s (UPPER(NAME)) ASYNC ", indxTable,dataTable)); - - //update a row - stmt1.setInt(1, 1); - stmt1.setString(2, "uname" + String.valueOf(10)); - stmt1.setInt(3, 95050 + 1); - stmt1.executeUpdate(); - conn.commit(); - - //verify rows are fetched from data table. - String selectSql = String.format("SELECT UPPER(NAME),ID FROM %s",dataTable); - ResultSet rs = conn.createStatement().executeQuery("EXPLAIN " + selectSql); - String actualExplainPlan = QueryUtil.getExplainPlan(rs); - - //assert we are pulling from data table. - assertEquals(String.format("CLIENT 1-CHUNK PARALLEL 1-WAY ROUND ROBIN FULL SCAN OVER %s",dataTable),actualExplainPlan); - - rs = stmt1.executeQuery(selectSql); - assertTrue(rs.next()); - assertEquals("UNAME10", rs.getString(1)); - assertTrue(rs.next()); - assertEquals("UNAME2", rs.getString(1)); - - //run the index MR job. - final IndexTool indexingTool = new IndexTool(); - indexingTool.setConf(new Configuration(getUtility().getConfiguration())); - - final String[] cmdArgs = IndexToolIT.getArgValues(null, dataTable,indxTable); - int status = indexingTool.run(cmdArgs); - assertEquals(0, status); - - //assert we are pulling from index table. - rs = conn.createStatement().executeQuery("EXPLAIN " + selectSql); - actualExplainPlan = QueryUtil.getExplainPlan(rs); - IndexToolIT.assertExplainPlan(actualExplainPlan,null,dataTable,indxTable,false); - - rs = stmt.executeQuery(selectSql); - assertTrue(rs.next()); - assertEquals("UNAME10", rs.getString(1)); - assertEquals(1, rs.getInt(2)); - - assertTrue(rs.next()); - assertEquals("UNAME2", rs.getString(1)); - assertEquals(2, rs.getInt(2)); - conn.createStatement().execute(String.format("DROP INDEX %s ON %s",indxTable , dataTable)); - } finally { - conn.close(); - } - } - -} http://git-wip-us.apache.org/repos/asf/phoenix/blob/faad4ad3/phoenix-core/src/it/java/org/apache/phoenix/end2end/RoundFloorCeilFuncIT.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/RoundFloorCeilFuncIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/RoundFloorCeilFuncIT.java new file mode 100644 index 0000000..a5251a9 --- /dev/null +++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/RoundFloorCeilFuncIT.java @@ -0,0 +1,683 @@ +/* + * 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.end2end; + +import static org.apache.phoenix.util.TestUtil.TEST_PROPERTIES; +import static org.apache.phoenix.util.TestUtil.closeStmtAndConn; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.math.BigDecimal; +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.Time; +import java.sql.Timestamp; +import java.util.Properties; + +import org.apache.phoenix.expression.function.CeilFunction; +import org.apache.phoenix.expression.function.FloorFunction; +import org.apache.phoenix.expression.function.RoundFunction; +import org.apache.phoenix.query.QueryServices; +import org.apache.phoenix.util.DateUtil; +import org.apache.phoenix.util.PhoenixRuntime; +import org.apache.phoenix.util.PropertiesUtil; +import org.junit.Before; +import org.junit.Test; + +import com.google.common.primitives.Doubles; +import com.google.common.primitives.Floats; + +/** + * + * End to end tests for {@link RoundFunction}, {@link FloorFunction}, {@link CeilFunction} + * + */ +public class RoundFloorCeilFuncIT extends BaseHBaseManagedTimeTableReuseIT { + private static final long millisPart = 660; + private static final int nanosPart = 500100; + private static final BigDecimal decimalUpserted = BigDecimal.valueOf(1.264); + private static final double doubleUpserted = 1.264d; + private static final double unsignedDoubleUpserted = 1.264d; + private static final float floatUpserted = 1.264f; + private static final float unsignedFloatUpserted = 1.264f; + + private String tableName; + + @Before + public void initTable() throws Exception { + tableName = generateRandomString(); + String testString = "abc"; + Connection conn = null; + PreparedStatement stmt = null; + try { + conn = DriverManager.getConnection(getUrl()); + String ddl = "CREATE TABLE IF NOT EXISTS " + tableName + + " (s VARCHAR NOT NULL PRIMARY KEY, dt DATE, t TIME, ts TIMESTAMP, dec DECIMAL, doub DOUBLE, undoub UNSIGNED_DOUBLE, fl FLOAT, unfl UNSIGNED_FLOAT)"; + conn.createStatement().execute(ddl); + + Date dateUpserted = DateUtil.parseDate("2012-01-01 14:25:28"); + dateUpserted = new Date(dateUpserted.getTime() + millisPart); // this makes the dateUpserted equivalent to 2012-01-01 14:25:28.660 + long millis = dateUpserted.getTime(); + + Time timeUpserted = new Time(millis); + Timestamp tsUpserted = DateUtil.getTimestamp(millis, nanosPart); + + stmt = conn.prepareStatement( + "UPSERT INTO " + tableName + " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"); + stmt.setString(1, testString); + stmt.setDate(2, dateUpserted); + stmt.setTime(3, timeUpserted); + stmt.setTimestamp(4, tsUpserted); + stmt.setBigDecimal(5, decimalUpserted); + stmt.setDouble(6, doubleUpserted); + stmt.setDouble(7, unsignedDoubleUpserted); + stmt.setFloat(8, floatUpserted); + stmt.setFloat(9, unsignedFloatUpserted); + stmt.executeUpdate(); + conn.commit(); + } finally { + closeStmtAndConn(stmt, conn); + } + } + + @Test + public void testRoundingUpDate() throws Exception { + Connection conn = DriverManager.getConnection(getUrl()); + ResultSet rs = conn.createStatement().executeQuery("SELECT ROUND(dt, 'day'), ROUND(dt, 'hour', 1), ROUND(dt, 'minute', 1), ROUND(dt, 'second', 1), " + + " ROUND(dt,'week'), ROUND(dt,'month') , ROUND(dt,'year') FROM " + tableName); + assertTrue(rs.next()); + Date expectedDate = DateUtil.parseDate("2012-01-02 00:00:00"); + assertEquals(expectedDate, rs.getDate(1)); + expectedDate = DateUtil.parseDate("2012-01-01 14:00:00"); + assertEquals(expectedDate, rs.getDate(2)); + expectedDate = DateUtil.parseDate("2012-01-01 14:25:00"); + assertEquals(expectedDate, rs.getDate(3)); + expectedDate = DateUtil.parseDate("2012-01-01 14:25:29"); + assertEquals(expectedDate, rs.getDate(4)); + expectedDate = DateUtil.parseDate("2012-01-02 00:00:00"); + assertEquals(expectedDate, rs.getDate(5)); + expectedDate = DateUtil.parseDate("2012-01-01 00:00:00"); + assertEquals(expectedDate, rs.getDate(6)); + expectedDate = DateUtil.parseDate("2012-01-01 00:00:00"); + assertEquals(expectedDate, rs.getDate(7)); + } + + @Test + public void testRoundingUpDateInWhere() throws Exception { + Connection conn = DriverManager.getConnection(getUrl()); + ResultSet rs = conn.createStatement().executeQuery("SELECT * FROM " + tableName + + " WHERE ROUND(dt, 'day') = to_date('2012-01-02 00:00:00')"); + assertTrue(rs.next()); + } + + @Test + public void testFloorDate() throws Exception { + Connection conn = DriverManager.getConnection(getUrl()); + ResultSet rs = conn.createStatement().executeQuery("SELECT FLOOR(dt, 'day', 1), FLOOR(dt, 'hour', 1), FLOOR(dt, 'minute', 1), FLOOR(dt, 'second', 1)," + + " FLOOR(dt,'week'), FLOOR(dt,'month'), FLOOR(dt,'year') FROM " + tableName); + assertTrue(rs.next()); + Date expectedDate = DateUtil.parseDate("2012-01-01 00:00:00"); + assertEquals(expectedDate, rs.getDate(1)); + expectedDate = DateUtil.parseDate("2012-01-01 14:00:00"); + assertEquals(expectedDate, rs.getDate(2)); + expectedDate = DateUtil.parseDate("2012-01-01 14:25:00"); + assertEquals(expectedDate, rs.getDate(3)); + expectedDate = DateUtil.parseDate("2012-01-01 14:25:28"); + assertEquals(expectedDate, rs.getDate(4)); + expectedDate = DateUtil.parseDate("2011-12-26 00:00:00"); + assertEquals(expectedDate, rs.getDate(5)); + expectedDate = DateUtil.parseDate("2012-01-01 00:00:00"); + assertEquals(expectedDate, rs.getDate(6)); + expectedDate = DateUtil.parseDate("2012-01-01 00:00:00"); + assertEquals(expectedDate, rs.getDate(7)); + } + + @Test + public void testFloorDateInWhere() throws Exception { + Connection conn = DriverManager.getConnection(getUrl()); + ResultSet rs = conn.createStatement().executeQuery("SELECT * FROM " + tableName + + " WHERE FLOOR(dt, 'hour') = to_date('2012-01-01 14:00:00')"); + assertTrue(rs.next()); + } + + @Test + public void testCeilDate() throws Exception { + Connection conn = DriverManager.getConnection(getUrl()); + ResultSet rs = conn.createStatement().executeQuery("SELECT CEIL(dt, 'day', 1), CEIL(dt, 'hour', 1), CEIL(dt, 'minute', 1), CEIL(dt, 'second', 1), " + + " CEIL(dt,'week') , CEIL(dt,'month') , CEIL(dt,'year') FROM " + tableName); + assertTrue(rs.next()); + //Date upserted is 2012-01-01 14:25:28.660. So we will end up bumping up in every case. + Date expectedDate = DateUtil.parseDate("2012-01-02 00:00:00"); + assertEquals(expectedDate, rs.getDate(1)); + expectedDate = DateUtil.parseDate("2012-01-01 15:00:00"); + assertEquals(expectedDate, rs.getDate(2)); + expectedDate = DateUtil.parseDate("2012-01-01 14:26:00"); + assertEquals(expectedDate, rs.getDate(3)); + expectedDate = DateUtil.parseDate("2012-01-01 14:25:29"); + assertEquals(expectedDate, rs.getDate(4)); + expectedDate = DateUtil.parseDate("2012-01-02 00:00:00"); + System.out.println(String.format(" the expected time is [%s] and the actual time is [%s]",expectedDate.getTime(),rs.getDate(5).getTime())); + assertEquals(expectedDate, rs.getDate(5)); + expectedDate = DateUtil.parseDate("2012-02-01 00:00:00"); + assertEquals(expectedDate, rs.getDate(6)); + expectedDate = DateUtil.parseDate("2013-01-01 00:00:00"); + assertEquals(expectedDate, rs.getDate(7)); + } + + @Test + public void testCeilDateInWhere() throws Exception { + Connection conn = DriverManager.getConnection(getUrl()); + ResultSet rs = conn.createStatement().executeQuery("SELECT * FROM " + tableName + + " WHERE CEIL(dt, 'second') = to_date('2012-01-01 14:25:29')"); + assertTrue(rs.next()); + } + + @Test + public void testRoundingUpTimestamp() throws Exception { + Connection conn = DriverManager.getConnection(getUrl()); + ResultSet rs = conn.createStatement().executeQuery( + "SELECT ROUND(ts, 'day'), ROUND(ts, 'hour', 1), ROUND(ts, 'minute', 1), ROUND(ts, 'second', 1), ROUND(ts, 'millisecond', 1) FROM " + + tableName); + assertTrue(rs.next()); + Timestamp expectedTimestamp; + expectedTimestamp = new Timestamp(DateUtil.parseDate("2012-01-02 00:00:00").getTime()); + assertEquals(expectedTimestamp, rs.getTimestamp(1)); + expectedTimestamp = new Timestamp(DateUtil.parseDate("2012-01-01 14:00:00").getTime()); + assertEquals(expectedTimestamp, rs.getTimestamp(2)); + expectedTimestamp = new Timestamp(DateUtil.parseDate("2012-01-01 14:25:00").getTime()); + assertEquals(expectedTimestamp, rs.getTimestamp(3)); + expectedTimestamp = new Timestamp(DateUtil.parseDate("2012-01-01 14:25:29").getTime()); + assertEquals(expectedTimestamp, rs.getTimestamp(4)); + + // Rounding of "2012-01-01 14:25:28.660" + nanosPart will end up bumping up the millisecond part of date. + // That is, it should be evaluated as "2012-01-01 14:25:28.661". + expectedTimestamp = new Timestamp(DateUtil.parseDate("2012-01-01 14:25:28").getTime() + millisPart + 1); + assertEquals(expectedTimestamp, rs.getTimestamp(5)); + } + + @Test + public void testRoundingUpTimestampInWhere() throws Exception { + Connection conn = DriverManager.getConnection(getUrl()); + ResultSet rs = conn.createStatement().executeQuery("SELECT * FROM " + tableName + + " WHERE ROUND(ts, 'second') = to_date('2012-01-01 14:25:29')"); + assertTrue(rs.next()); + } + + @Test + public void testFloorTimestamp() throws Exception { + Connection conn = DriverManager.getConnection(getUrl()); + ResultSet rs = conn.createStatement().executeQuery("SELECT FLOOR(ts, 'day'), FLOOR(ts, 'hour', 1), FLOOR(ts, 'minute', 1), FLOOR(ts, 'second', 1), " + + " FLOOR(ts, 'millisecond', 1) , FLOOR(ts,'week') , FLOOR(ts,'month') FROM " + + tableName); + assertTrue(rs.next()); + Timestamp expectedTimestamp; + expectedTimestamp = new Timestamp(DateUtil.parseDate("2012-01-01 00:00:00").getTime()); + assertEquals(expectedTimestamp, rs.getTimestamp(1)); + expectedTimestamp = new Timestamp(DateUtil.parseDate("2012-01-01 14:00:00").getTime()); + assertEquals(expectedTimestamp, rs.getTimestamp(2)); + expectedTimestamp = new Timestamp(DateUtil.parseDate("2012-01-01 14:25:00").getTime()); + assertEquals(expectedTimestamp, rs.getTimestamp(3)); + expectedTimestamp = new Timestamp(DateUtil.parseDate("2012-01-01 14:25:28").getTime()); + assertEquals(expectedTimestamp, rs.getTimestamp(4)); + + // FLOOR of "2012-01-01 14:25:28.660" + nanosPart will end up removing the nanos part. + expectedTimestamp = new Timestamp(DateUtil.parseDate("2012-01-01 14:25:28").getTime() + millisPart); + assertEquals(expectedTimestamp, rs.getTimestamp(5)); + expectedTimestamp = new Timestamp(DateUtil.parseDate("2011-12-26 00:00:00").getTime()); + assertEquals(expectedTimestamp, rs.getTimestamp(6)); + expectedTimestamp = new Timestamp(DateUtil.parseDate("2012-01-01 00:00:00").getTime()); + assertEquals(expectedTimestamp, rs.getTimestamp(7)); + } + + @Test + public void testFloorTimestampInWhere() throws Exception { + Connection conn = DriverManager.getConnection(getUrl()); + ResultSet rs = conn.createStatement().executeQuery("SELECT * FROM " + tableName + + " WHERE FLOOR(ts, 'second') = to_date('2012-01-01 14:25:28')"); + assertTrue(rs.next()); + } + + @Test + public void testWeekFloorTimestampInWhere() throws Exception { + Connection conn = DriverManager.getConnection(getUrl()); + ResultSet rs = conn.createStatement().executeQuery("SELECT * FROM " + tableName + + " WHERE FLOOR(ts, 'week') = to_date('2011-12-26 00:00:00')"); + assertTrue(rs.next()); + } + + @Test + public void testCeilTimestamp() throws Exception { + Connection conn = DriverManager.getConnection(getUrl()); + ResultSet rs = conn.createStatement().executeQuery("SELECT CEIL(ts, 'day'), CEIL(ts, 'hour', 1), CEIL(ts, 'minute', 1), CEIL(ts, 'second', 1), CEIL(ts, 'millisecond', 1)," + + " CEIL(ts,'week'), CEIL(ts,'month') , CEIL(ts,'year') FROM " + tableName); + assertTrue(rs.next()); + Timestamp expectedTimestamp; + expectedTimestamp = new Timestamp(DateUtil.parseDate("2012-01-02 00:00:00").getTime()); + assertEquals(expectedTimestamp, rs.getTimestamp(1)); + expectedTimestamp = new Timestamp(DateUtil.parseDate("2012-01-01 15:00:00").getTime()); + assertEquals(expectedTimestamp, rs.getTimestamp(2)); + expectedTimestamp = new Timestamp(DateUtil.parseDate("2012-01-01 14:26:00").getTime()); + assertEquals(expectedTimestamp, rs.getTimestamp(3)); + expectedTimestamp = new Timestamp(DateUtil.parseDate("2012-01-01 14:25:29").getTime()); + assertEquals(expectedTimestamp, rs.getTimestamp(4)); + + // CEIL of "2012-01-01 14:25:28.660" + nanosPart will end up bumping up the millisecond part of date. + // That is, it should be evaluated as "2012-01-01 14:25:28.661". + expectedTimestamp = new Timestamp(DateUtil.parseDate("2012-01-01 14:25:28").getTime() + millisPart + 1); + assertEquals(expectedTimestamp, rs.getTimestamp(5)); + expectedTimestamp = new Timestamp(DateUtil.parseDate("2012-01-02 00:00:00").getTime()); + assertEquals(expectedTimestamp, rs.getTimestamp(6)); + expectedTimestamp = new Timestamp(DateUtil.parseDate("2012-02-01 00:00:00").getTime()); + assertEquals(expectedTimestamp, rs.getTimestamp(7)); + expectedTimestamp = new Timestamp(DateUtil.parseDate("2013-01-01 00:00:00").getTime()); + assertEquals(expectedTimestamp, rs.getTimestamp(8)); + } + + @Test + public void testCeilTimestampInWhere() throws Exception { + Connection conn = DriverManager.getConnection(getUrl()); + ResultSet rs = conn.createStatement().executeQuery("SELECT * FROM " + tableName + + " WHERE CEIL(ts, 'second') = to_date('2012-01-01 14:25:29')"); + assertTrue(rs.next()); + } + + @Test + public void testRoundingUpTime() throws Exception { + Connection conn = DriverManager.getConnection(getUrl()); + ResultSet rs = conn.createStatement().executeQuery("SELECT ROUND(t, 'day', 1), ROUND(t, 'hour', 1), ROUND(t, 'minute', 1), ROUND(t, 'second', 1)," + + " ROUND(t,'week') , ROUND(t,'month') , ROUND(t,'year') FROM " + tableName); + assertTrue(rs.next()); + Time expectedTime = new Time(DateUtil.parseDate("2012-01-02 00:00:00").getTime()); + assertEquals(expectedTime, rs.getTime(1)); + expectedTime = new Time(DateUtil.parseDate("2012-01-01 14:00:00").getTime()); + assertEquals(expectedTime, rs.getTime(2)); + expectedTime = new Time(DateUtil.parseDate("2012-01-01 14:25:00").getTime()); + assertEquals(expectedTime, rs.getTime(3)); + expectedTime = new Time(DateUtil.parseDate("2012-01-01 14:25:29").getTime()); + assertEquals(expectedTime, rs.getTime(4)); + expectedTime = new Time(DateUtil.parseDate("2012-01-02 00:00:00").getTime()); + assertEquals(expectedTime, rs.getTime(5)); + expectedTime = new Time(DateUtil.parseDate("2012-01-01 00:00:00").getTime()); + assertEquals(expectedTime, rs.getTime(6)); + expectedTime = new Time(DateUtil.parseDate("2012-01-01 00:00:00").getTime()); + assertEquals(expectedTime, rs.getTime(7)); + } + + @Test + public void testFloorTime() throws Exception { + Connection conn = DriverManager.getConnection(getUrl()); + ResultSet rs = conn.createStatement().executeQuery("SELECT FLOOR(t, 'day', 1), FLOOR(t, 'hour', 1), FLOOR(t, 'minute', 1), FLOOR(t, 'second', 1), " + + " FLOOR(t, 'week'), FLOOR(t, 'month'), FLOOR(t, 'year') FROM " + tableName); + assertTrue(rs.next()); + Time expectedTime = new Time(DateUtil.parseDate("2012-01-01 00:00:00").getTime()); + assertEquals(expectedTime, rs.getTime(1)); + expectedTime = new Time(DateUtil.parseDate("2012-01-01 14:00:00").getTime()); + assertEquals(expectedTime, rs.getTime(2)); + expectedTime = new Time(DateUtil.parseDate("2012-01-01 14:25:00").getTime()); + assertEquals(expectedTime, rs.getTime(3)); + expectedTime = new Time(DateUtil.parseDate("2012-01-01 14:25:28").getTime()); + assertEquals(expectedTime, rs.getTime(4)); + expectedTime = new Time(DateUtil.parseDate("2011-12-26 00:00:00").getTime()); + assertEquals(expectedTime, rs.getTime(5)); + expectedTime = new Time(DateUtil.parseDate("2012-01-01 00:00:00").getTime()); + assertEquals(expectedTime, rs.getTime(6)); + expectedTime = new Time(DateUtil.parseDate("2012-01-01 00:00:00").getTime()); + assertEquals(expectedTime, rs.getTime(7)); + } + + @Test + public void testCeilTime() throws Exception { + Connection conn = DriverManager.getConnection(getUrl()); + ResultSet rs = conn.createStatement().executeQuery("SELECT CEIL(t, 'day', 1), CEIL(t, 'hour', 1), CEIL(t, 'minute', 1), CEIL(t, 'second', 1)," + + " CEIL(t,'week') , CEIL(t,'month') , CEIL(t,'year') FROM " + tableName); + assertTrue(rs.next()); + Time expectedTime = new Time(DateUtil.parseDate("2012-01-02 00:00:00").getTime()); + assertEquals(expectedTime, rs.getTime(1)); + expectedTime = new Time(DateUtil.parseDate("2012-01-01 15:00:00").getTime()); + assertEquals(expectedTime, rs.getTime(2)); + expectedTime = new Time(DateUtil.parseDate("2012-01-01 14:26:00").getTime()); + assertEquals(expectedTime, rs.getTime(3)); + expectedTime = new Time(DateUtil.parseDate("2012-01-01 14:25:29").getTime()); + assertEquals(expectedTime, rs.getTime(4)); + expectedTime = new Time(DateUtil.parseDate("2012-01-02 00:00:00").getTime()); + assertEquals(expectedTime, rs.getTime(5)); + expectedTime = new Time(DateUtil.parseDate("2012-02-01 00:00:00").getTime()); + assertEquals(expectedTime, rs.getTime(6)); + expectedTime = new Time(DateUtil.parseDate("2013-01-01 00:00:00").getTime()); + assertEquals(expectedTime, rs.getTime(7)); + } + + @Test + public void testRoundingUpDecimal() throws Exception { + Connection conn = DriverManager.getConnection(getUrl()); + ResultSet rs = conn.createStatement().executeQuery( + "SELECT ROUND(dec), ROUND(dec, 1), ROUND(dec, 2), ROUND(dec, 3) FROM " + tableName); + assertTrue(rs.next()); + BigDecimal expectedBd = BigDecimal.valueOf(1); + assertEquals(expectedBd, rs.getBigDecimal(1)); + expectedBd = BigDecimal.valueOf(1.3); + assertEquals(expectedBd, rs.getBigDecimal(2)); + expectedBd = BigDecimal.valueOf(1.26); + assertEquals(expectedBd, rs.getBigDecimal(3)); + expectedBd = BigDecimal.valueOf(1.264); + assertEquals(expectedBd, rs.getBigDecimal(4)); + } + + @Test + public void testRoundingUpDecimalInWhere() throws Exception { + Connection conn = DriverManager.getConnection(getUrl()); + ResultSet rs = conn.createStatement().executeQuery( + "SELECT * FROM " + tableName + " WHERE ROUND(dec, 2) = 1.26"); + assertTrue(rs.next()); + } + + @Test + public void testFloorDecimal() throws Exception { + Connection conn = DriverManager.getConnection(getUrl()); + ResultSet rs = conn.createStatement().executeQuery( + "SELECT FLOOR(dec), FLOOR(dec, 1), FLOOR(dec, 2), FLOOR(dec, 3) FROM " + tableName); + assertTrue(rs.next()); + BigDecimal expectedBd = BigDecimal.valueOf(1); + assertEquals(expectedBd, rs.getBigDecimal(1)); + expectedBd = BigDecimal.valueOf(1.2); + assertEquals(expectedBd, rs.getBigDecimal(2)); + expectedBd = BigDecimal.valueOf(1.26); + assertEquals(expectedBd, rs.getBigDecimal(3)); + expectedBd = BigDecimal.valueOf(1.264); + assertEquals(expectedBd, rs.getBigDecimal(4)); + } + + @Test + public void testFloorDecimalInWhere() throws Exception { + Connection conn = DriverManager.getConnection(getUrl()); + ResultSet rs = conn.createStatement().executeQuery( + "SELECT * FROM " + tableName + " WHERE FLOOR(dec, 2) = 1.26"); + assertTrue(rs.next()); + } + + @Test + public void testCeilDecimal() throws Exception { + Connection conn = DriverManager.getConnection(getUrl()); + ResultSet rs = conn.createStatement().executeQuery( + "SELECT CEIL(dec), CEIL(dec, 1), CEIL(dec, 2), CEIL(dec, 3) FROM " + tableName); + assertTrue(rs.next()); + BigDecimal expectedBd = BigDecimal.valueOf(2); + assertEquals(expectedBd, rs.getBigDecimal(1)); + expectedBd = BigDecimal.valueOf(1.3); + assertEquals(expectedBd, rs.getBigDecimal(2)); + expectedBd = BigDecimal.valueOf(1.27); + assertEquals(expectedBd, rs.getBigDecimal(3)); + expectedBd = BigDecimal.valueOf(1.264); + assertEquals(expectedBd, rs.getBigDecimal(4)); + } + + @Test + public void testCeilDecimalInWhere() throws Exception { + Connection conn = DriverManager.getConnection(getUrl()); + ResultSet rs = conn.createStatement().executeQuery( + "SELECT * FROM " + tableName + " WHERE CEIL(dec, 2) = 1.27"); + assertTrue(rs.next()); + } + @Test + public void testRoundingUpDouble() throws Exception { + Connection conn = DriverManager.getConnection(getUrl()); + ResultSet rs = conn.createStatement().executeQuery( + "SELECT ROUND(doub), ROUND(doub, 1), ROUND(doub, 2), ROUND(doub, 3) FROM " + tableName); + assertTrue(rs.next()); + assertEquals(0, Doubles.compare(1, rs.getDouble(1))); + assertEquals(0, Doubles.compare(1.3, rs.getDouble(2))); + assertEquals(0, Doubles.compare(1.26, rs.getDouble(3))); + assertEquals(0, Doubles.compare(1.264, rs.getDouble(4))); + } + + @Test + public void testRoundingUpDoubleInWhere() throws Exception { + Connection conn = DriverManager.getConnection(getUrl()); + ResultSet rs = conn.createStatement().executeQuery( + "SELECT * FROM " + tableName + " WHERE ROUND(dec, 2) = 1.26"); + assertTrue(rs.next()); + } + + @Test + public void testCeilDouble() throws Exception { + Connection conn = DriverManager.getConnection(getUrl()); + ResultSet rs = conn.createStatement().executeQuery( + "SELECT CEIL(doub), CEIL(doub, 1), CEIL(doub, 2), CEIL(doub, 3) FROM " + tableName); + assertTrue(rs.next()); + assertEquals(0, Doubles.compare(2, rs.getDouble(1))); + assertEquals(0, Doubles.compare(1.3, rs.getDouble(2))); + assertEquals(0, Doubles.compare(1.27, rs.getDouble(3))); + assertEquals(0, Doubles.compare(1.264, rs.getDouble(4))); + } + + @Test + public void testCeilDoubleInWhere() throws Exception { + Connection conn = DriverManager.getConnection(getUrl()); + ResultSet rs = conn.createStatement().executeQuery( + "SELECT * FROM " + tableName + " WHERE CEIL(doub, 2) = 1.27"); + assertTrue(rs.next()); + } + + @Test + public void testFloorDouble() throws Exception { + Connection conn = DriverManager.getConnection(getUrl()); + ResultSet rs = conn.createStatement().executeQuery( + "SELECT FLOOR(doub), FLOOR(doub, 1), FLOOR(doub, 2), FLOOR(doub, 3) FROM " + tableName); + assertTrue(rs.next()); + assertEquals(0, Doubles.compare(1, rs.getDouble(1))); + assertEquals(0, Doubles.compare(1.2, rs.getDouble(2))); + assertEquals(0, Doubles.compare(1.26, rs.getDouble(3))); + assertEquals(0, Doubles.compare(1.264, rs.getDouble(4))); + } + + @Test + public void testFloorDoubleInWhere() throws Exception { + Connection conn = DriverManager.getConnection(getUrl()); + ResultSet rs = conn.createStatement().executeQuery( + "SELECT * FROM " + tableName + " WHERE FLOOR(doub, 2) = 1.26"); + assertTrue(rs.next()); + } + + @Test + public void testRoundFloat() throws Exception { + Connection conn = DriverManager.getConnection(getUrl()); + ResultSet rs = conn.createStatement().executeQuery( + "SELECT ROUND(fl), ROUND(fl, 1), ROUND(fl, 2), ROUND(fl, 3) FROM " + tableName); + assertTrue(rs.next()); + assertEquals(0, Floats.compare(1, rs.getFloat(1))); + assertEquals(0, Floats.compare(1.3f, rs.getFloat(2))); + assertEquals(0, Floats.compare(1.26f, rs.getFloat(3))); + assertEquals(0, Floats.compare(1.264f, rs.getFloat(4))); + } + + @Test + public void testRoundUnsignedFloat() throws Exception { + Connection conn = DriverManager.getConnection(getUrl()); + ResultSet rs = conn.createStatement().executeQuery( + "SELECT ROUND(unfl), ROUND(unfl, 1), ROUND(unfl, 2), ROUND(unfl, 3) FROM " + tableName); + assertTrue(rs.next()); + assertEquals(0, Floats.compare(1, rs.getFloat(1))); + assertEquals(0, Floats.compare(1.3f, rs.getFloat(2))); + assertEquals(0, Floats.compare(1.26f, rs.getFloat(3))); + assertEquals(0, Floats.compare(1.264f, rs.getFloat(4))); + } + + @Test + public void testRoundUnsignedDouble() throws Exception { + Connection conn = DriverManager.getConnection(getUrl()); + ResultSet rs = conn.createStatement().executeQuery( + "SELECT ROUND(undoub), ROUND(undoub, 1), ROUND(undoub, 2), ROUND(undoub, 3) FROM " + + tableName); + assertTrue(rs.next()); + assertEquals(0, Floats.compare(1, rs.getFloat(1))); + assertEquals(0, Floats.compare(1.3f, rs.getFloat(2))); + assertEquals(0, Floats.compare(1.26f, rs.getFloat(3))); + assertEquals(0, Floats.compare(1.264f, rs.getFloat(4))); + } + + @Test + public void testTimestampAggregateFunctions() throws Exception { + String dateString = "2015-03-08 09:09:11.665"; + Properties props = new Properties(); + props.setProperty(QueryServices.DATE_FORMAT_TIMEZONE_ATTRIB, "GMT+1"); + Connection conn = DriverManager.getConnection(getUrl(), props); + try { + conn.prepareStatement( + "create table TIME_AGG_TABLE(" + + "ID unsigned_int NOT NULL, " + + "THE_DATE TIMESTAMP, " + + "constraint PK primary key (ID))").execute(); + PreparedStatement stmt = conn.prepareStatement("upsert into " + + "TIME_AGG_TABLE(" + " ID, " + " THE_DATE)" + + "VALUES (?, ?)"); + stmt.setInt(1, 1); + stmt.setTimestamp(2, DateUtil.parseTimestamp(dateString)); + stmt.execute(); + conn.commit(); + + ResultSet rs = conn.prepareStatement( + "SELECT THE_DATE ,TRUNC(THE_DATE,'DAY') AS day_from_dt " + + ",TRUNC(THE_DATE,'HOUR') AS hour_from_dt " + + ",TRUNC(THE_DATE,'MINUTE') AS min_from_dt " + + ",TRUNC(THE_DATE,'SECOND') AS sec_from_dt " + + ",TRUNC(THE_DATE,'MILLISECOND') AS mil_from_dt " + + "FROM TIME_AGG_TABLE").executeQuery(); + assertTrue(rs.next()); + assertEquals(DateUtil.parseTimestamp("2015-03-08 09:09:11.665"), + rs.getTimestamp("THE_DATE")); + assertEquals(DateUtil.parseTimestamp("2015-03-08 00:00:00.0"), + rs.getTimestamp("day_from_dt")); + assertEquals(DateUtil.parseTimestamp("2015-03-08 09:00:00.0"), + rs.getTimestamp("hour_from_dt")); + assertEquals(DateUtil.parseTimestamp("2015-03-08 09:09:00.0"), + rs.getTimestamp("min_from_dt")); + assertEquals(DateUtil.parseTimestamp("2015-03-08 09:09:11.0"), + rs.getTimestamp("sec_from_dt")); + assertEquals(DateUtil.parseTimestamp("2015-03-08 09:09:11.665"), + rs.getTimestamp("mil_from_dt")); + rs.close(); + + rs = conn.prepareStatement( + "SELECT THE_DATE ,ROUND(THE_DATE,'DAY') AS day_from_dt " + + ",ROUND(THE_DATE,'HOUR') AS hour_from_dt " + + ",ROUND(THE_DATE,'MINUTE') AS min_from_dt " + + ",ROUND(THE_DATE,'SECOND') AS sec_from_dt " + + ",ROUND(THE_DATE,'MILLISECOND') AS mil_from_dt " + + "FROM TIME_AGG_TABLE").executeQuery(); + assertTrue(rs.next()); + assertEquals(DateUtil.parseTimestamp("2015-03-08 09:09:11.665"), + rs.getTimestamp("THE_DATE")); + assertEquals(DateUtil.parseTimestamp("2015-03-08 00:00:00.0"), + rs.getTimestamp("day_from_dt")); + assertEquals(DateUtil.parseTimestamp("2015-03-08 09:00:00.0"), + rs.getTimestamp("hour_from_dt")); + assertEquals(DateUtil.parseTimestamp("2015-03-08 09:09:00.0"), + rs.getTimestamp("min_from_dt")); + assertEquals(DateUtil.parseTimestamp("2015-03-08 09:09:12.0"), + rs.getTimestamp("sec_from_dt")); + assertEquals(DateUtil.parseTimestamp("2015-03-08 09:09:11.665"), + rs.getTimestamp("mil_from_dt")); + rs.close(); + + rs = conn.prepareStatement( + "SELECT THE_DATE ,FLOOR(THE_DATE,'DAY') AS day_from_dt " + + ",FLOOR(THE_DATE,'HOUR') AS hour_from_dt " + + ",FLOOR(THE_DATE,'MINUTE') AS min_from_dt " + + ",FLOOR(THE_DATE,'SECOND') AS sec_from_dt " + + ",FLOOR(THE_DATE,'MILLISECOND') AS mil_from_dt " + + "FROM TIME_AGG_TABLE").executeQuery(); + assertTrue(rs.next()); + assertEquals(DateUtil.parseTimestamp("2015-03-08 09:09:11.665"), + rs.getTimestamp("THE_DATE")); + assertEquals(DateUtil.parseTimestamp("2015-03-08 00:00:00.0"), + rs.getTimestamp("day_from_dt")); + assertEquals(DateUtil.parseTimestamp("2015-03-08 09:00:00.0"), + rs.getTimestamp("hour_from_dt")); + assertEquals(DateUtil.parseTimestamp("2015-03-08 09:09:00.0"), + rs.getTimestamp("min_from_dt")); + assertEquals(DateUtil.parseTimestamp("2015-03-08 09:09:11.0"), + rs.getTimestamp("sec_from_dt")); + assertEquals(DateUtil.parseTimestamp("2015-03-08 09:09:11.665"), + rs.getTimestamp("mil_from_dt")); + rs.close(); + + rs = conn.prepareStatement( + "SELECT THE_DATE ,CEIL(THE_DATE,'DAY') AS day_from_dt " + + ",CEIL(THE_DATE,'HOUR') AS hour_from_dt " + + ",CEIL(THE_DATE,'MINUTE') AS min_from_dt " + + ",CEIL(THE_DATE,'SECOND') AS sec_from_dt " + + ",CEIL(THE_DATE,'MILLISECOND') AS mil_from_dt " + + "FROM TIME_AGG_TABLE").executeQuery(); + assertTrue(rs.next()); + assertEquals(DateUtil.parseTimestamp("2015-03-08 09:09:11.665"), + rs.getTimestamp("THE_DATE")); + assertEquals(DateUtil.parseTimestamp("2015-03-09 00:00:00.0"), + rs.getTimestamp("day_from_dt")); + assertEquals(DateUtil.parseTimestamp("2015-03-08 10:00:00.0"), + rs.getTimestamp("hour_from_dt")); + assertEquals(DateUtil.parseTimestamp("2015-03-08 09:10:00.0"), + rs.getTimestamp("min_from_dt")); + assertEquals(DateUtil.parseTimestamp("2015-03-08 09:09:12.0"), + rs.getTimestamp("sec_from_dt")); + assertEquals(DateUtil.parseTimestamp("2015-03-08 09:09:11.665"), + rs.getTimestamp("mil_from_dt")); + rs.close(); + } finally { + conn.close(); + } + } + + @Test + public void testRoundOffFunction() throws SQLException { + long ts = nextTimestamp(); + Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES); + props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts + 10)); + Connection conn = DriverManager.getConnection(getUrl(), props); + String ddl = "create table round_test(k bigint primary key)"; + conn.createStatement().execute(ddl); + conn.close(); + + props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts + 30)); + conn = DriverManager.getConnection(getUrl(), props); + PreparedStatement stmt = conn.prepareStatement("upsert into round_test values(1380603308885)"); + stmt.execute(); + conn.commit(); + conn.close(); + + + props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts + 40)); + conn = DriverManager.getConnection(getUrl(), props); + ResultSet rs; + stmt = conn.prepareStatement("select round(k/1000000,0) from round_test"); + rs = stmt.executeQuery(); + assertTrue(rs.next()); + assertEquals(1380603, rs.getLong(1)); + + props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts + 40)); + conn = DriverManager.getConnection(getUrl(), props); + stmt = conn.prepareStatement("select round(k/1000000,0) x from round_test group by x"); + rs = stmt.executeQuery(); + assertTrue(rs.next()); + assertEquals(1380603, rs.getLong(1)); + } + +}