/* * Licensed 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 com.facebook.presto.cassandra; import com.facebook.presto.Session; import com.facebook.presto.spi.type.Type; import com.facebook.presto.testing.MaterializedResult; import com.facebook.presto.testing.MaterializedRow; import com.facebook.presto.tests.AbstractTestIntegrationSmokeTest; import com.google.common.collect.ImmutableList; import org.joda.time.DateTime; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; import java.math.BigInteger; import java.nio.ByteBuffer; import java.sql.Timestamp; import java.util.Date; import java.util.List; import static com.datastax.driver.core.utils.Bytes.toRawHexString; import static com.facebook.presto.cassandra.CassandraQueryRunner.createCassandraSession; import static com.facebook.presto.cassandra.CassandraTestingUtils.TABLE_ALL_TYPES; import static com.facebook.presto.cassandra.CassandraTestingUtils.TABLE_ALL_TYPES_PARTITION_KEY; import static com.facebook.presto.cassandra.CassandraTestingUtils.TABLE_CLUSTERING_KEYS; import static com.facebook.presto.cassandra.CassandraTestingUtils.TABLE_CLUSTERING_KEYS_LARGE; import static com.facebook.presto.cassandra.CassandraTestingUtils.TABLE_MULTI_PARTITION_CLUSTERING_KEYS; import static com.facebook.presto.cassandra.CassandraTestingUtils.createTestTables; import static com.facebook.presto.spi.type.BigintType.BIGINT; import static com.facebook.presto.spi.type.BooleanType.BOOLEAN; import static com.facebook.presto.spi.type.DoubleType.DOUBLE; import static com.facebook.presto.spi.type.IntegerType.INTEGER; import static com.facebook.presto.spi.type.RealType.REAL; import static com.facebook.presto.spi.type.TimestampType.TIMESTAMP; import static com.facebook.presto.spi.type.VarbinaryType.VARBINARY; import static com.facebook.presto.spi.type.VarcharType.createUnboundedVarcharType; import static com.facebook.presto.spi.type.VarcharType.createVarcharType; import static com.facebook.presto.testing.MaterializedResult.DEFAULT_PRECISION; import static com.google.common.primitives.Ints.toByteArray; import static java.util.stream.Collectors.toList; import static org.joda.time.DateTimeZone.UTC; import static org.testng.Assert.assertEquals; @Test(singleThreaded = true) public class TestCassandraIntegrationSmokeTest extends AbstractTestIntegrationSmokeTest { private static final String KEYSPACE = "smoke_test"; private static final Session SESSION = createCassandraSession(KEYSPACE); private static final DateTime DATE_TIME_UTC = new DateTime(1970, 1, 1, 3, 4, 5, UTC); private static final Date DATE_LOCAL = new Date(DATE_TIME_UTC.getMillis()); private static final Timestamp TIMESTAMP_LOCAL = new Timestamp(DATE_TIME_UTC.getMillis()); public TestCassandraIntegrationSmokeTest() throws Exception { super(CassandraQueryRunner::createCassandraQueryRunner); } @BeforeClass public void setUp() throws Exception { createTestTables(EmbeddedCassandra.getSession(), KEYSPACE, DATE_LOCAL); } @Test public void testPartitionKeyPredicate() { String sql = "SELECT *" + " FROM " + TABLE_ALL_TYPES_PARTITION_KEY + " WHERE key = 'key 7'" + " AND typeuuid = '00000000-0000-0000-0000-000000000007'" + " AND typeinteger = 7" + " AND typelong = 1007" + " AND typebytes = from_hex('" + toRawHexString(ByteBuffer.wrap(toByteArray(7))) + "')" + " AND typetimestamp = TIMESTAMP '1970-01-01 03:04:05'" + " AND typeansi = 'ansi 7'" + " AND typeboolean = false" + " AND typedecimal = 128.0" + " AND typedouble = 16384.0" + " AND typefloat = REAL '2097152.0'" + " AND typeinet = '127.0.0.1'" + " AND typevarchar = 'varchar 7'" + " AND typevarint = '10000000'" + " AND typetimeuuid = 'd2177dd0-eaa2-11de-a572-001b779c76e7'" + " AND typelist = '[\"list-value-17\",\"list-value-27\"]'" + " AND typemap = '{7:8,9:10}'" + " AND typeset = '[false,true]'" + ""; MaterializedResult result = execute(sql); assertEquals(result.getRowCount(), 1); } @Test public void testSelect() throws Exception { assertSelect(TABLE_ALL_TYPES, false); assertSelect(TABLE_ALL_TYPES_PARTITION_KEY, false); } @Test public void testCreateTableAs() throws Exception { execute("DROP TABLE IF EXISTS table_all_types_copy"); execute("CREATE TABLE table_all_types_copy AS SELECT * FROM " + TABLE_ALL_TYPES); assertSelect("table_all_types_copy", true); execute("DROP TABLE table_all_types_copy"); } @Test public void testClusteringPredicates() throws Exception { String sql = "SELECT * FROM " + TABLE_CLUSTERING_KEYS + " WHERE key='key_1' AND clust_one='clust_one'"; assertEquals(execute(sql).getRowCount(), 1); sql = "SELECT * FROM " + TABLE_CLUSTERING_KEYS + " WHERE key IN ('key_1','key_2') AND clust_one='clust_one'"; assertEquals(execute(sql).getRowCount(), 2); sql = "SELECT * FROM " + TABLE_CLUSTERING_KEYS + " WHERE key='key_1' AND clust_one!='clust_one'"; assertEquals(execute(sql).getRowCount(), 0); sql = "SELECT * FROM " + TABLE_CLUSTERING_KEYS + " WHERE key IN ('key_1','key_2','key_3','key_4') AND clust_one='clust_one' AND clust_two>'clust_two_1'"; assertEquals(execute(sql).getRowCount(), 3); sql = "SELECT * FROM " + TABLE_CLUSTERING_KEYS + " WHERE key IN ('key_1','key_2') AND clust_one='clust_one' AND " + "((clust_two='clust_two_1') OR (clust_two='clust_two_2'))"; assertEquals(execute(sql).getRowCount(), 2); sql = "SELECT * FROM " + TABLE_CLUSTERING_KEYS + " WHERE key IN ('key_1','key_2') AND clust_one='clust_one' AND " + "((clust_two='clust_two_1' AND clust_three='clust_three_1') OR (clust_two='clust_two_2' AND clust_three='clust_three_2'))"; assertEquals(execute(sql).getRowCount(), 2); sql = "SELECT * FROM " + TABLE_CLUSTERING_KEYS + " WHERE key IN ('key_1','key_2') AND clust_one='clust_one' AND clust_three='clust_three_1'"; assertEquals(execute(sql).getRowCount(), 1); sql = "SELECT * FROM " + TABLE_CLUSTERING_KEYS + " WHERE key IN ('key_1','key_2') AND clust_one='clust_one' AND clust_two IN ('clust_two_1','clust_two_2')"; assertEquals(execute(sql).getRowCount(), 2); } @Test public void testMultiplePartitionClusteringPredicates() throws Exception { String partitionInPredicates = " partition_one IN ('partition_one_1','partition_one_2') AND partition_two IN ('partition_two_1','partition_two_2') "; String sql = "SELECT * FROM " + TABLE_MULTI_PARTITION_CLUSTERING_KEYS + " WHERE partition_one='partition_one_1' AND partition_two='partition_two_1' AND clust_one='clust_one'"; assertEquals(execute(sql).getRowCount(), 1); sql = "SELECT * FROM " + TABLE_MULTI_PARTITION_CLUSTERING_KEYS + " WHERE " + partitionInPredicates + " AND clust_one='clust_one'"; assertEquals(execute(sql).getRowCount(), 2); sql = "SELECT * FROM " + TABLE_MULTI_PARTITION_CLUSTERING_KEYS + " WHERE partition_one='partition_one_1' AND partition_two='partition_two_1' AND clust_one!='clust_one'"; assertEquals(execute(sql).getRowCount(), 0); sql = "SELECT * FROM " + TABLE_MULTI_PARTITION_CLUSTERING_KEYS + " WHERE " + "partition_one IN ('partition_one_1','partition_one_2','partition_one_3','partition_one_4') AND " + "partition_two IN ('partition_two_1','partition_two_2','partition_two_3','partition_two_4') AND " + "clust_one='clust_one' AND clust_two>'clust_two_1'"; assertEquals(execute(sql).getRowCount(), 3); sql = "SELECT * FROM " + TABLE_MULTI_PARTITION_CLUSTERING_KEYS + " WHERE " + partitionInPredicates + " AND clust_one='clust_one' AND " + "((clust_two='clust_two_1') OR (clust_two='clust_two_2'))"; assertEquals(execute(sql).getRowCount(), 2); sql = "SELECT * FROM " + TABLE_MULTI_PARTITION_CLUSTERING_KEYS + " WHERE " + partitionInPredicates + " AND clust_one='clust_one' AND " + "((clust_two='clust_two_1' AND clust_three='clust_three_1') OR (clust_two='clust_two_2' AND clust_three='clust_three_2'))"; assertEquals(execute(sql).getRowCount(), 2); sql = "SELECT * FROM " + TABLE_MULTI_PARTITION_CLUSTERING_KEYS + " WHERE " + partitionInPredicates + " AND clust_one='clust_one' AND clust_three='clust_three_1'"; assertEquals(execute(sql).getRowCount(), 1); sql = "SELECT * FROM " + TABLE_MULTI_PARTITION_CLUSTERING_KEYS + " WHERE " + partitionInPredicates + " AND clust_one='clust_one' AND clust_two IN ('clust_two_1','clust_two_2')"; assertEquals(execute(sql).getRowCount(), 2); } @Test public void testClusteringKeyOnlyPushdown() throws Exception { String sql = "SELECT * FROM " + TABLE_CLUSTERING_KEYS + " WHERE clust_one='clust_one'"; assertEquals(execute(sql).getRowCount(), 9); sql = "SELECT * FROM " + TABLE_CLUSTERING_KEYS + " WHERE clust_one='clust_one' AND clust_two='clust_two_2'"; assertEquals(execute(sql).getRowCount(), 1); sql = "SELECT * FROM " + TABLE_CLUSTERING_KEYS + " WHERE clust_one='clust_one' AND clust_two='clust_two_2' AND clust_three='clust_three_2'"; assertEquals(execute(sql).getRowCount(), 1); // below test cases are needed to verify clustering key pushdown with unpartitioned table // for the smaller table (<200 partitions by default) connector fetches all the partitions id // and the partitioned patch is being followed sql = "SELECT * FROM " + TABLE_CLUSTERING_KEYS_LARGE + " WHERE clust_one='clust_one' AND clust_two='clust_two_2'"; assertEquals(execute(sql).getRowCount(), 1); sql = "SELECT * FROM " + TABLE_CLUSTERING_KEYS_LARGE + " WHERE clust_one='clust_one' AND clust_two='clust_two_2' AND clust_three='clust_three_2'"; assertEquals(execute(sql).getRowCount(), 1); } private void assertSelect(String tableName, boolean createdByPresto) { Type uuidType = createdByPresto ? createUnboundedVarcharType() : createVarcharType(36); Type inetType = createdByPresto ? createUnboundedVarcharType() : createVarcharType(45); String sql = "SELECT " + " key, " + " typeuuid, " + " typeinteger, " + " typelong, " + " typebytes, " + " typetimestamp, " + " typeansi, " + " typeboolean, " + " typedecimal, " + " typedouble, " + " typefloat, " + " typeinet, " + " typevarchar, " + " typevarint, " + " typetimeuuid, " + " typelist, " + " typemap, " + " typeset " + " FROM " + tableName; MaterializedResult result = execute(sql); int rowCount = result.getRowCount(); assertEquals(rowCount, 9); assertEquals(result.getTypes(), ImmutableList.of( createUnboundedVarcharType(), uuidType, INTEGER, BIGINT, VARBINARY, TIMESTAMP, createUnboundedVarcharType(), BOOLEAN, DOUBLE, DOUBLE, REAL, inetType, createUnboundedVarcharType(), createUnboundedVarcharType(), uuidType, createUnboundedVarcharType(), createUnboundedVarcharType(), createUnboundedVarcharType() )); List<MaterializedRow> sortedRows = result.getMaterializedRows().stream() .sorted((o1, o2) -> o1.getField(1).toString().compareTo(o2.getField(1).toString())) .collect(toList()); for (int rowNumber = 1; rowNumber <= rowCount; rowNumber++) { assertEquals(sortedRows.get(rowNumber - 1), new MaterializedRow(DEFAULT_PRECISION, "key " + rowNumber, String.format("00000000-0000-0000-0000-%012d", rowNumber), rowNumber, rowNumber + 1000L, ByteBuffer.wrap(toByteArray(rowNumber)), TIMESTAMP_LOCAL, "ansi " + rowNumber, rowNumber % 2 == 0, Math.pow(2, rowNumber), Math.pow(4, rowNumber), (float) Math.pow(8, rowNumber), "127.0.0.1", "varchar " + rowNumber, BigInteger.TEN.pow(rowNumber).toString(), String.format("d2177dd0-eaa2-11de-a572-001b779c76e%d", rowNumber), String.format("[\"list-value-1%1$d\",\"list-value-2%1$d\"]", rowNumber), String.format("{%d:%d,%d:%d}", rowNumber, rowNumber + 1L, rowNumber + 2, rowNumber + 3L), "[false,true]" )); } } private MaterializedResult execute(String sql) { return getQueryRunner().execute(SESSION, sql); } }