@Test public void testGetPartitionSplitsTableOfflinePartition() throws Exception { ConnectorTableHandle tableHandle = getTableHandle(tableOfflinePartition); assertNotNull(tableHandle); ConnectorColumnHandle dsColumn = metadata.getColumnHandle(tableHandle, "ds"); assertNotNull(dsColumn); Domain domain = Domain.singleValue(utf8Slice("2012-12-30")); TupleDomain<ConnectorColumnHandle> tupleDomain = TupleDomain.withColumnDomains(ImmutableMap.of(dsColumn, domain)); ConnectorPartitionResult partitionResult = splitManager.getPartitions(tableHandle, tupleDomain); for (ConnectorPartition partition : partitionResult.getPartitions()) { if (domain.equals(partition.getTupleDomain().getDomains().get(dsColumn))) { try { getSplitCount(splitManager.getPartitionSplits(tableHandle, ImmutableList.of(partition))); fail("Expected PartitionOfflineException"); } catch (PartitionOfflineException e) { assertEquals(e.getTableName(), tableOfflinePartition); assertEquals(e.getPartition(), "ds=2012-12-30"); } } else { getSplitCount(splitManager.getPartitionSplits(tableHandle, ImmutableList.of(partition))); } } }
private static Set<List<Comparable<?>>> getPartitionKeysSet( CassandraTable table, TupleDomain<ColumnHandle> tupleDomain) { ImmutableList.Builder<Set<Comparable<?>>> partitionColumnValues = ImmutableList.builder(); for (CassandraColumnHandle columnHandle : table.getPartitionKeyColumns()) { Domain domain = tupleDomain.getDomains().get(columnHandle); // if there is no constraint on a partition key, return an empty set if (domain == null) { return ImmutableSet.of(); } // todo does cassandra allow null partition keys? if (domain.isNullAllowed()) { return ImmutableSet.of(); } ImmutableSet.Builder<Comparable<?>> columnValues = ImmutableSet.builder(); for (Range range : domain.getRanges()) { // if the range is not a single value, we can not perform partition pruning if (!range.isSingleValue()) { return ImmutableSet.of(); } Comparable<?> value = range.getSingleValue(); CassandraType valueType = columnHandle.getCassandraType(); columnValues.add(valueType.getValueForPartitionKey(value)); } partitionColumnValues.add(columnValues.build()); } return Sets.cartesianProduct(partitionColumnValues.build()); }
@Test public void testGetPartitionsWithBindings() throws Exception { ConnectorTableHandle tableHandle = getTableHandle(table); ConnectorPartitionResult partitionResult = splitManager.getPartitions( tableHandle, TupleDomain.withColumnDomains( ImmutableMap.<ConnectorColumnHandle, Domain>of(intColumn, Domain.singleValue(5L)))); assertExpectedPartitions(partitionResult.getPartitions()); }
@Override public ConnectorPartitionResult getPartitions( ConnectorSession session, ConnectorTableHandle tableHandle, TupleDomain<ColumnHandle> tupleDomain) { CassandraTableHandle cassandraTableHandle = checkType(tableHandle, CassandraTableHandle.class, "tableHandle"); checkNotNull(tupleDomain, "tupleDomain is null"); CassandraTable table = schemaProvider.getTable(cassandraTableHandle); List<CassandraColumnHandle> partitionKeys = table.getPartitionKeyColumns(); // fetch the partitions List<CassandraPartition> allPartitions = getCassandraPartitions(table, tupleDomain); log.debug( "%s.%s #partitions: %d", cassandraTableHandle.getSchemaName(), cassandraTableHandle.getTableName(), allPartitions.size()); // do a final pass to filter based on fields that could not be used to build the prefix List<ConnectorPartition> partitions = allPartitions .stream() .filter(partition -> tupleDomain.overlaps(partition.getTupleDomain())) .collect(toList()); // All partition key domains will be fully evaluated, so we don't need to include those TupleDomain<ColumnHandle> remainingTupleDomain = TupleDomain.none(); if (!tupleDomain.isNone()) { if (partitions.size() == 1 && ((CassandraPartition) partitions.get(0)).isUnpartitioned()) { remainingTupleDomain = tupleDomain; } else { @SuppressWarnings({"rawtypes", "unchecked"}) List<ColumnHandle> partitionColumns = (List) partitionKeys; remainingTupleDomain = TupleDomain.withColumnDomains( Maps.filterKeys(tupleDomain.getDomains(), not(in(partitionColumns)))); } } // push down indexed column fixed value predicates only for unpartitioned partition which uses // token range query if (partitions.size() == 1 && ((CassandraPartition) partitions.get(0)).isUnpartitioned()) { Map<ColumnHandle, Domain> domains = tupleDomain.getDomains(); List<ColumnHandle> indexedColumns = new ArrayList<>(); // compose partitionId by using indexed column StringBuilder sb = new StringBuilder(); for (Map.Entry<ColumnHandle, Domain> entry : domains.entrySet()) { CassandraColumnHandle column = (CassandraColumnHandle) entry.getKey(); Domain domain = entry.getValue(); if (column.isIndexed() && domain.isSingleValue()) { sb.append(CassandraCqlUtils.validColumnName(column.getName())) .append(" = ") .append( CassandraCqlUtils.cqlValue( toCQLCompatibleString(entry.getValue().getSingleValue()), column.getCassandraType())); indexedColumns.add(column); // Only one indexed column predicate can be pushed down. break; } } if (sb.length() > 0) { CassandraPartition partition = (CassandraPartition) partitions.get(0); TupleDomain<ColumnHandle> filterIndexedColumn = TupleDomain.withColumnDomains( Maps.filterKeys(remainingTupleDomain.getDomains(), not(in(indexedColumns)))); partitions = new ArrayList<>(); partitions.add( new CassandraPartition(partition.getKey(), sb.toString(), filterIndexedColumn, true)); return new ConnectorPartitionResult(partitions, filterIndexedColumn); } } return new ConnectorPartitionResult(partitions, remainingTupleDomain); }