/* * 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.raptor.systemtables; import com.facebook.presto.raptor.RaptorMetadata; import com.facebook.presto.raptor.metadata.ColumnInfo; import com.facebook.presto.raptor.metadata.MetadataDao; import com.facebook.presto.raptor.metadata.ShardInfo; import com.facebook.presto.raptor.metadata.ShardManager; import com.facebook.presto.spi.ColumnMetadata; import com.facebook.presto.spi.RecordCursor; import com.facebook.presto.spi.SchemaTableName; import com.facebook.presto.spi.connector.ConnectorMetadata; import com.facebook.presto.spi.predicate.Domain; import com.facebook.presto.spi.predicate.TupleDomain; import com.facebook.presto.spi.predicate.ValueSet; import com.facebook.presto.spi.type.Type; import com.facebook.presto.testing.MaterializedRow; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import io.airlift.slice.Slice; import org.joda.time.DateTime; import org.skife.jdbi.v2.DBI; import org.skife.jdbi.v2.Handle; import org.skife.jdbi.v2.IDBI; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; import java.util.ArrayList; import java.util.List; import java.util.Optional; import java.util.OptionalInt; import java.util.Set; import java.util.UUID; import static com.facebook.presto.metadata.MetadataUtil.TableMetadataBuilder.tableMetadataBuilder; import static com.facebook.presto.raptor.metadata.SchemaDaoUtil.createTablesWithRetry; import static com.facebook.presto.raptor.metadata.TestDatabaseShardManager.createShardManager; import static com.facebook.presto.raptor.systemtables.ShardMetadataRecordCursor.SHARD_METADATA; import static com.facebook.presto.spi.predicate.Range.greaterThan; import static com.facebook.presto.spi.predicate.Range.lessThanOrEqual; import static com.facebook.presto.spi.type.BigintType.BIGINT; import static com.facebook.presto.spi.type.DateType.DATE; import static com.facebook.presto.spi.type.VarcharType.createVarcharType; import static com.facebook.presto.testing.MaterializedResult.DEFAULT_PRECISION; import static com.facebook.presto.testing.TestingConnectorSession.SESSION; import static io.airlift.slice.Slices.utf8Slice; import static java.util.stream.Collectors.toList; import static org.testng.Assert.assertEquals; @Test(singleThreaded = true) public class TestShardMetadataRecordCursor { private static final SchemaTableName DEFAULT_TEST_ORDERS = new SchemaTableName("test", "orders"); private Handle dummyHandle; private ConnectorMetadata metadata; private IDBI dbi; @BeforeMethod public void setup() { this.dbi = new DBI("jdbc:h2:mem:test" + System.nanoTime()); this.dummyHandle = dbi.open(); createTablesWithRetry(dbi); this.metadata = new RaptorMetadata("raptor", dbi, createShardManager(dbi)); // Create table metadata.createTable(SESSION, tableMetadataBuilder(DEFAULT_TEST_ORDERS) .column("orderkey", BIGINT) .column("orderdate", DATE) .property("temporal_column", "orderdate") .build()); } @AfterMethod(alwaysRun = true) public void teardown() { dummyHandle.close(); } @Test public void testSimple() throws Exception { ShardManager shardManager = createShardManager(dbi); // Add shards to the table long tableId = 1; OptionalInt bucketNumber = OptionalInt.empty(); UUID uuid1 = UUID.randomUUID(); UUID uuid2 = UUID.randomUUID(); UUID uuid3 = UUID.randomUUID(); ShardInfo shardInfo1 = new ShardInfo(uuid1, bucketNumber, ImmutableSet.of("node1"), ImmutableList.of(), 1, 10, 100); ShardInfo shardInfo2 = new ShardInfo(uuid2, bucketNumber, ImmutableSet.of("node2"), ImmutableList.of(), 2, 20, 200); ShardInfo shardInfo3 = new ShardInfo(uuid3, bucketNumber, ImmutableSet.of("node3"), ImmutableList.of(), 3, 30, 300); List<ShardInfo> shards = ImmutableList.of(shardInfo1, shardInfo2, shardInfo3); long transactionId = shardManager.beginTransaction(); shardManager.commitShards( transactionId, tableId, ImmutableList.of( new ColumnInfo(1, BIGINT), new ColumnInfo(2, DATE)), shards, Optional.empty(), 0); Slice schema = utf8Slice(DEFAULT_TEST_ORDERS.getSchemaName()); Slice table = utf8Slice(DEFAULT_TEST_ORDERS.getTableName()); DateTime date1 = DateTime.parse("2015-01-01T00:00"); DateTime date2 = DateTime.parse("2015-01-02T00:00"); TupleDomain<Integer> tupleDomain = TupleDomain.withColumnDomains( ImmutableMap.<Integer, Domain>builder() .put(0, Domain.singleValue(createVarcharType(10), schema)) .put(1, Domain.create(ValueSet.ofRanges(lessThanOrEqual(createVarcharType(10), table)), true)) .put(6, Domain.create(ValueSet.ofRanges(lessThanOrEqual(BIGINT, date1.getMillis()), greaterThan(BIGINT, date2.getMillis())), true)) .put(7, Domain.create(ValueSet.ofRanges(lessThanOrEqual(BIGINT, date1.getMillis()), greaterThan(BIGINT, date2.getMillis())), true)) .build()); List<MaterializedRow> actual; try (RecordCursor cursor = new ShardMetadataSystemTable(dbi).cursor(null, SESSION, tupleDomain)) { actual = getMaterializedResults(cursor, SHARD_METADATA.getColumns()); } assertEquals(actual.size(), 3); List<MaterializedRow> expected = ImmutableList.of( new MaterializedRow(DEFAULT_PRECISION, schema, table, utf8Slice(uuid1.toString()), null, 100L, 10L, 1L, null, null), new MaterializedRow(DEFAULT_PRECISION, schema, table, utf8Slice(uuid2.toString()), null, 200L, 20L, 2L, null, null), new MaterializedRow(DEFAULT_PRECISION, schema, table, utf8Slice(uuid3.toString()), null, 300L, 30L, 3L, null, null)); assertEquals(actual, expected); } @Test public void testNoSchemaFilter() throws Exception { // Create "orders" table in a different schema metadata.createTable(SESSION, tableMetadataBuilder(new SchemaTableName("other", "orders")) .column("orderkey", BIGINT) .build()); // Create another table that should not be selected metadata.createTable(SESSION, tableMetadataBuilder(new SchemaTableName("schema1", "foo")) .column("orderkey", BIGINT) .build()); TupleDomain<Integer> tupleDomain = TupleDomain.withColumnDomains( ImmutableMap.<Integer, Domain>builder() .put(1, Domain.singleValue(createVarcharType(10), utf8Slice("orders"))) .build()); MetadataDao metadataDao = dummyHandle.attach(MetadataDao.class); Set<Long> actual = ImmutableSet.copyOf(ShardMetadataRecordCursor.getTableIds(dbi, tupleDomain)); Set<Long> expected = ImmutableSet.of( metadataDao.getTableInformation("other", "orders").getTableId(), metadataDao.getTableInformation("test", "orders").getTableId()); assertEquals(actual, expected); } @Test public void testNoTableFilter() throws Exception { // Create "orders" table in a different schema metadata.createTable(SESSION, tableMetadataBuilder(new SchemaTableName("test", "orders2")) .column("orderkey", BIGINT) .build()); // Create another table that should not be selected metadata.createTable(SESSION, tableMetadataBuilder(new SchemaTableName("schema1", "foo")) .column("orderkey", BIGINT) .build()); TupleDomain<Integer> tupleDomain = TupleDomain.withColumnDomains( ImmutableMap.<Integer, Domain>builder() .put(0, Domain.singleValue(createVarcharType(10), utf8Slice("test"))) .build()); MetadataDao metadataDao = dummyHandle.attach(MetadataDao.class); Set<Long> actual = ImmutableSet.copyOf(ShardMetadataRecordCursor.getTableIds(dbi, tupleDomain)); Set<Long> expected = ImmutableSet.of( metadataDao.getTableInformation("test", "orders").getTableId(), metadataDao.getTableInformation("test", "orders2").getTableId()); assertEquals(actual, expected); } private static List<MaterializedRow> getMaterializedResults(RecordCursor cursor, List<ColumnMetadata> columns) { List<Type> types = columns.stream().map(ColumnMetadata::getType).collect(toList()); ImmutableList.Builder<MaterializedRow> rowBuilder = ImmutableList.builder(); for (int i = 0; i < types.size(); i++) { assertEquals(cursor.getType(i), types.get(i)); } while (cursor.advanceNextPosition()) { List<Object> values = new ArrayList<>(); for (int i = 0; i < columns.size(); i++) { Type type = columns.get(i).getType(); Class<?> javaType = type.getJavaType(); if (cursor.isNull(i)) { values.add(null); } else if (javaType == boolean.class) { values.add(cursor.getBoolean(i)); } else if (javaType == long.class) { values.add(cursor.getLong(i)); } else if (javaType == double.class) { values.add(cursor.getDouble(i)); } else if (javaType == Slice.class) { values.add(cursor.getSlice(i)); } } rowBuilder.add(new MaterializedRow(DEFAULT_PRECISION, values)); } return rowBuilder.build(); } }