Allow filtering on partition key columns for queries without secondary indexes
patch by ZhaoYang and Alex Petrov; reviewed by Benjamin Lerer for CASSANDRA-11031 Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/3f49c328 Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/3f49c328 Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/3f49c328 Branch: refs/heads/trunk Commit: 3f49c328f202e68b67a9caaa63522e333ea5006f Parents: 64f12ab Author: ZhaoYang <zhaoyangsingap...@gmail.com> Authored: Mon Sep 12 11:22:25 2016 +0200 Committer: Benjamin Lerer <b.le...@gmail.com> Committed: Mon Sep 12 11:24:38 2016 +0200 ---------------------------------------------------------------------- CHANGES.txt | 1 + NEWS.txt | 2 + .../cassandra/cql3/SingleColumnRelation.java | 11 - .../restrictions/PartitionKeyRestrictions.java | 17 + .../PartitionKeySingleRestrictionSet.java | 26 + .../cql3/restrictions/RestrictionSet.java | 10 + .../restrictions/RestrictionSetWrapper.java | 5 + .../cql3/restrictions/Restrictions.java | 6 + .../restrictions/StatementRestrictions.java | 65 +- .../cql3/restrictions/TokenFilter.java | 23 +- .../cql3/restrictions/TokenRestriction.java | 25 +- .../apache/cassandra/db/filter/RowFilter.java | 30 +- .../cassandra/cql3/ViewFilteringTest.java | 211 ++- .../org/apache/cassandra/cql3/ViewTest.java | 13 + .../validation/entities/SecondaryIndexTest.java | 95 ++ .../SelectMultiColumnRelationTest.java | 13 +- .../SelectOrderedPartitionerTest.java | 34 +- .../SelectSingleColumnRelationTest.java | 28 +- .../cql3/validation/operations/SelectTest.java | 1495 +++++++++++++++--- .../index/internal/CassandraIndexTest.java | 4 +- 20 files changed, 1832 insertions(+), 282 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cassandra/blob/3f49c328/CHANGES.txt ---------------------------------------------------------------------- diff --git a/CHANGES.txt b/CHANGES.txt index 3ab144e..312713f 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,4 +1,5 @@ 3.10 + * Allow filtering on partition key columns for queries without secondary indexes (CASSANDRA-11031) * Fix Cassandra Stress reporting thread model and precision (CASSANDRA-12585) * Add JMH benchmarks.jar (CASSANDRA-12586) * Add row offset support to SASI (CASSANDRA-11990) http://git-wip-us.apache.org/repos/asf/cassandra/blob/3f49c328/NEWS.txt ---------------------------------------------------------------------- diff --git a/NEWS.txt b/NEWS.txt index ddb1263..1b15f7d 100644 --- a/NEWS.txt +++ b/NEWS.txt @@ -18,6 +18,8 @@ using the provided 'sstableupgrade' tool. New features ------------ + - Filtering on partition key columns is now also supported for queries without + secondary indexes. - A slow query log has been added: slow queries will be logged at DEBUG level. For more details refer to CASSANDRA-12403 and slow_query_log_timeout_in_ms in cassandra.yaml. http://git-wip-us.apache.org/repos/asf/cassandra/blob/3f49c328/src/java/org/apache/cassandra/cql3/SingleColumnRelation.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql3/SingleColumnRelation.java b/src/java/org/apache/cassandra/cql3/SingleColumnRelation.java index 22df6bd..4dbb7da 100644 --- a/src/java/org/apache/cassandra/cql3/SingleColumnRelation.java +++ b/src/java/org/apache/cassandra/cql3/SingleColumnRelation.java @@ -252,17 +252,6 @@ public final class SingleColumnRelation extends Relation checkFalse(!columnDef.isPrimaryKeyColumn() && !canHaveOnlyOneValue(), "IN predicates on non-primary-key columns (%s) is not yet supported", columnDef.name); } - else if (isSlice()) - { - // Non EQ relation is not supported without token(), even if we have a 2ndary index (since even those - // are ordered by partitioner). - // Note: In theory we could allow it for 2ndary index queries with ALLOW FILTERING, but that would - // probably require some special casing - // Note bis: This is also why we don't bother handling the 'tuple' notation of #4851 for keys. If we - // lift the limitation for 2ndary - // index with filtering, we'll need to handle it though. - checkFalse(columnDef.isPartitionKey(), "Only EQ and IN relation are supported on the partition key (unless you use the token() function)"); - } checkFalse(isContainsKey() && !(receiver.type instanceof MapType), "Cannot use CONTAINS KEY on non-map column %s", receiver.name); checkFalse(isContains() && !(receiver.type.isCollection()), "Cannot use CONTAINS on non-collection column %s", receiver.name); http://git-wip-us.apache.org/repos/asf/cassandra/blob/3f49c328/src/java/org/apache/cassandra/cql3/restrictions/PartitionKeyRestrictions.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql3/restrictions/PartitionKeyRestrictions.java b/src/java/org/apache/cassandra/cql3/restrictions/PartitionKeyRestrictions.java index 10efa9f..1ff45d0 100644 --- a/src/java/org/apache/cassandra/cql3/restrictions/PartitionKeyRestrictions.java +++ b/src/java/org/apache/cassandra/cql3/restrictions/PartitionKeyRestrictions.java @@ -20,6 +20,7 @@ package org.apache.cassandra.cql3.restrictions; import java.nio.ByteBuffer; import java.util.List; +import org.apache.cassandra.config.CFMetaData; import org.apache.cassandra.cql3.QueryOptions; import org.apache.cassandra.cql3.statements.Bound; @@ -48,4 +49,20 @@ interface PartitionKeyRestrictions extends Restrictions * @return <code>true</code> if the specified bound is inclusive, <code>false</code> otherwise */ public boolean isInclusive(Bound b); + + /** + * checks if specified restrictions require filtering + * + * @param cfm column family metadata + * @return <code>true</code> if filtering is required, <code>false</code> otherwise + */ + public boolean needFiltering(CFMetaData cfm); + + /** + * Checks if the partition key has unrestricted components. + * + * @param cfm column family metadata + * @return <code>true</code> if the partition key has unrestricted components, <code>false</code> otherwise. + */ + public boolean hasUnrestrictedPartitionKeyComponents(CFMetaData cfm); } http://git-wip-us.apache.org/repos/asf/cassandra/blob/3f49c328/src/java/org/apache/cassandra/cql3/restrictions/PartitionKeySingleRestrictionSet.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql3/restrictions/PartitionKeySingleRestrictionSet.java b/src/java/org/apache/cassandra/cql3/restrictions/PartitionKeySingleRestrictionSet.java index b96f6da..b34ff54 100644 --- a/src/java/org/apache/cassandra/cql3/restrictions/PartitionKeySingleRestrictionSet.java +++ b/src/java/org/apache/cassandra/cql3/restrictions/PartitionKeySingleRestrictionSet.java @@ -129,4 +129,30 @@ final class PartitionKeySingleRestrictionSet extends RestrictionSetWrapper imple restriction.addRowFilterTo(filter, indexManager, options); } } + + @Override + public boolean needFiltering(CFMetaData cfm) + { + if (isEmpty()) + return false; + // slice or has unrestricted key component + return hasUnrestrictedPartitionKeyComponents(cfm) || hasSlice(); + } + + @Override + public boolean hasUnrestrictedPartitionKeyComponents(CFMetaData cfm) + { + return size() < cfm.partitionKeyColumns().size(); + } + + @Override + public boolean hasSlice() + { + for (SingleRestriction restriction : restrictions) + { + if (restriction.isSlice()) + return true; + } + return false; + } } http://git-wip-us.apache.org/repos/asf/cassandra/blob/3f49c328/src/java/org/apache/cassandra/cql3/restrictions/RestrictionSet.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql3/restrictions/RestrictionSet.java b/src/java/org/apache/cassandra/cql3/restrictions/RestrictionSet.java index 0e6c2f7..0876f3e 100644 --- a/src/java/org/apache/cassandra/cql3/restrictions/RestrictionSet.java +++ b/src/java/org/apache/cassandra/cql3/restrictions/RestrictionSet.java @@ -266,6 +266,16 @@ final class RestrictionSet implements Restrictions, Iterable<SingleRestriction> return false; } + public final boolean hasSlice() + { + for (SingleRestriction restriction : this) + { + if (restriction.isSlice()) + return true; + } + return false; + } + /** * Checks if all of the underlying restrictions are EQ or IN restrictions. * http://git-wip-us.apache.org/repos/asf/cassandra/blob/3f49c328/src/java/org/apache/cassandra/cql3/restrictions/RestrictionSetWrapper.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql3/restrictions/RestrictionSetWrapper.java b/src/java/org/apache/cassandra/cql3/restrictions/RestrictionSetWrapper.java index 6b110da..996a1c4 100644 --- a/src/java/org/apache/cassandra/cql3/restrictions/RestrictionSetWrapper.java +++ b/src/java/org/apache/cassandra/cql3/restrictions/RestrictionSetWrapper.java @@ -89,6 +89,11 @@ class RestrictionSetWrapper implements Restrictions return restrictions.hasIN(); } + public boolean hasSlice() + { + return restrictions.hasSlice(); + } + public boolean hasOnlyEqualityRestrictions() { return restrictions.hasOnlyEqualityRestrictions(); http://git-wip-us.apache.org/repos/asf/cassandra/blob/3f49c328/src/java/org/apache/cassandra/cql3/restrictions/Restrictions.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql3/restrictions/Restrictions.java b/src/java/org/apache/cassandra/cql3/restrictions/Restrictions.java index 4cf165f..8a5140a 100644 --- a/src/java/org/apache/cassandra/cql3/restrictions/Restrictions.java +++ b/src/java/org/apache/cassandra/cql3/restrictions/Restrictions.java @@ -55,6 +55,12 @@ public interface Restrictions extends Restriction public boolean hasIN(); /** + * Checks if any of the underlying restrictions is a slice. + * @return <code>true</code> if any of the underlying restrictions is a slice, <code>false</code> otherwise + */ + public boolean hasSlice(); + + /** * Checks if all of the underlying restrictions are EQ or IN restrictions. * * @return <code>true</code> if all of the underlying restrictions are EQ or IN restrictions, http://git-wip-us.apache.org/repos/asf/cassandra/blob/3f49c328/src/java/org/apache/cassandra/cql3/restrictions/StatementRestrictions.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql3/restrictions/StatementRestrictions.java b/src/java/org/apache/cassandra/cql3/restrictions/StatementRestrictions.java index 0b3b37d..53ac68c 100644 --- a/src/java/org/apache/cassandra/cql3/restrictions/StatementRestrictions.java +++ b/src/java/org/apache/cassandra/cql3/restrictions/StatementRestrictions.java @@ -190,11 +190,11 @@ public final class StatementRestrictions } // At this point, the select statement if fully constructed, but we still have a few things to validate - processPartitionKeyRestrictions(hasQueriableIndex); + processPartitionKeyRestrictions(hasQueriableIndex, allowFiltering, forView); // Some but not all of the partition key columns have been specified; // hence we need turn these restrictions into a row filter. - if (usesSecondaryIndexing) + if (usesSecondaryIndexing || partitionKeyRestrictions.needFiltering(cfm)) filterRestrictions.add(partitionKeyRestrictions); if (selectsOnlyStaticColumns && hasClusteringColumnsRestriction()) @@ -385,36 +385,48 @@ public final class StatementRestrictions return this.usesSecondaryIndexing; } - private void processPartitionKeyRestrictions(boolean hasQueriableIndex) + private void processPartitionKeyRestrictions(boolean hasQueriableIndex, boolean allowFiltering, boolean forView) { if (!type.allowPartitionKeyRanges()) { checkFalse(partitionKeyRestrictions.isOnToken(), "The token function cannot be used in WHERE clauses for %s statements", type); - if (hasUnrestrictedPartitionKeyComponents()) + if (partitionKeyRestrictions.hasUnrestrictedPartitionKeyComponents(cfm)) throw invalidRequest("Some partition key parts are missing: %s", Joiner.on(", ").join(getPartitionKeyUnrestrictedComponents())); + + // slice query + checkFalse(partitionKeyRestrictions.hasSlice(), + "Only EQ and IN relation are supported on the partition key (unless you use the token() function)" + + " for %s statements", type); } else { - // If there is a queriable index, no special condition are required on the other restrictions. - // But we still need to know 2 things: - // - If we don't have a queriable index, is the query ok - // - Is it queriable without 2ndary index, which is always more efficient - // If a component of the partition key is restricted by a relation, all preceding - // components must have a EQ. Only the last partition key component can be in IN relation. - if (partitionKeyRestrictions.isOnToken()) - isKeyRange = true; + // If there are no partition restrictions or there's only token restriction, we have to set a key range + if (partitionKeyRestrictions.isOnToken()) + isKeyRange = true; - if (hasUnrestrictedPartitionKeyComponents()) + if (partitionKeyRestrictions.isEmpty() && partitionKeyRestrictions.hasUnrestrictedPartitionKeyComponents(cfm)) { - if (!partitionKeyRestrictions.isEmpty()) - { - if (!hasQueriableIndex) - throw invalidRequest("Partition key parts: %s must be restricted as other parts are", - Joiner.on(", ").join(getPartitionKeyUnrestrictedComponents())); - } + isKeyRange = true; + usesSecondaryIndexing = hasQueriableIndex; + } + + // If there is a queriable index, no special condition is required on the other restrictions. + // But we still need to know 2 things: + // - If we don't have a queriable index, is the query ok + // - Is it queriable without 2ndary index, which is always more efficient + // If a component of the partition key is restricted by a relation, all preceding + // components must have a EQ. Only the last partition key component can be in IN relation. + if (partitionKeyRestrictions.needFiltering(cfm)) + { + if (!allowFiltering && !forView && !hasQueriableIndex + && (partitionKeyRestrictions.hasUnrestrictedPartitionKeyComponents(cfm) || partitionKeyRestrictions.hasSlice())) + throw new InvalidRequestException(REQUIRES_ALLOW_FILTERING_MESSAGE); + + if (partitionKeyRestrictions.hasIN()) + throw new InvalidRequestException("IN restrictions are not supported when the query involves filtering"); isKeyRange = true; usesSecondaryIndexing = hasQueriableIndex; @@ -422,15 +434,6 @@ public final class StatementRestrictions } } - /** - * Checks if the partition key has some unrestricted components. - * @return <code>true</code> if the partition key has some unrestricted components, <code>false</code> otherwise. - */ - private boolean hasUnrestrictedPartitionKeyComponents() - { - return partitionKeyRestrictions.size() < cfm.partitionKeyColumns().size(); - } - public boolean hasPartitionKeyRestrictions() { return !partitionKeyRestrictions.isEmpty(); @@ -622,8 +625,8 @@ public final class StatementRestrictions private ByteBuffer getPartitionKeyBound(Bound b, QueryOptions options) { // Deal with unrestricted partition key components (special-casing is required to deal with 2i queries on the - // first component of a composite partition key). - if (hasUnrestrictedPartitionKeyComponents()) + // first component of a composite partition key) queries that filter on the partition key. + if (partitionKeyRestrictions.needFiltering(cfm)) return ByteBufferUtil.EMPTY_BYTE_BUFFER; // We deal with IN queries for keys in other places, so we know buildBound will return only one result @@ -804,7 +807,7 @@ public final class StatementRestrictions public boolean hasAllPKColumnsRestrictedByEqualities() { return !isPartitionKeyRestrictionsOnToken() - && !hasUnrestrictedPartitionKeyComponents() + && !partitionKeyRestrictions.hasUnrestrictedPartitionKeyComponents(cfm) && (partitionKeyRestrictions.hasOnlyEqualityRestrictions()) && !hasUnrestrictedClusteringColumns() && (clusteringColumnsRestrictions.hasOnlyEqualityRestrictions()); http://git-wip-us.apache.org/repos/asf/cassandra/blob/3f49c328/src/java/org/apache/cassandra/cql3/restrictions/TokenFilter.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql3/restrictions/TokenFilter.java b/src/java/org/apache/cassandra/cql3/restrictions/TokenFilter.java index c27d742..2611d19 100644 --- a/src/java/org/apache/cassandra/cql3/restrictions/TokenFilter.java +++ b/src/java/org/apache/cassandra/cql3/restrictions/TokenFilter.java @@ -25,6 +25,7 @@ import com.google.common.collect.ImmutableRangeSet; import com.google.common.collect.Range; import com.google.common.collect.RangeSet; +import org.apache.cassandra.config.CFMetaData; import org.apache.cassandra.config.ColumnDefinition; import org.apache.cassandra.cql3.QueryOptions; import org.apache.cassandra.cql3.functions.Function; @@ -135,8 +136,8 @@ final class TokenFilter implements PartitionKeyRestrictions */ private List<ByteBuffer> filter(List<ByteBuffer> values, QueryOptions options) throws InvalidRequestException { - RangeSet<Token> rangeSet = tokenRestriction.isSlice() ? toRangeSet(tokenRestriction, options) - : toRangeSet(tokenRestriction.values(options)); + RangeSet<Token> rangeSet = tokenRestriction.hasSlice() ? toRangeSet(tokenRestriction, options) + : toRangeSet(tokenRestriction.values(options)); return filterWithRangeSet(rangeSet, values); } @@ -285,4 +286,22 @@ final class TokenFilter implements PartitionKeyRestrictions { return restrictions.size(); } + + @Override + public boolean needFiltering(CFMetaData cfm) + { + return restrictions.needFiltering(cfm); + } + + @Override + public boolean hasUnrestrictedPartitionKeyComponents(CFMetaData cfm) + { + return restrictions.hasUnrestrictedPartitionKeyComponents(cfm); + } + + @Override + public boolean hasSlice() + { + return restrictions.hasSlice(); + } } http://git-wip-us.apache.org/repos/asf/cassandra/blob/3f49c328/src/java/org/apache/cassandra/cql3/restrictions/TokenRestriction.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql3/restrictions/TokenRestriction.java b/src/java/org/apache/cassandra/cql3/restrictions/TokenRestriction.java index dd31730..e90319d 100644 --- a/src/java/org/apache/cassandra/cql3/restrictions/TokenRestriction.java +++ b/src/java/org/apache/cassandra/cql3/restrictions/TokenRestriction.java @@ -57,11 +57,6 @@ public abstract class TokenRestriction implements PartitionKeyRestrictions this.metadata = metadata; } - public boolean isSlice() - { - return false; - } - public boolean hasIN() { return false; @@ -85,6 +80,24 @@ public abstract class TokenRestriction implements PartitionKeyRestrictions } @Override + public boolean needFiltering(CFMetaData cfm) + { + return false; + } + + @Override + public boolean hasSlice() + { + return false; + } + + @Override + public boolean hasUnrestrictedPartitionKeyComponents(CFMetaData cfm) + { + return false; + } + + @Override public List<ColumnDefinition> getColumnDefs() { return columnDefs; @@ -225,7 +238,7 @@ public abstract class TokenRestriction implements PartitionKeyRestrictions } @Override - public boolean isSlice() + public boolean hasSlice() { return true; } http://git-wip-us.apache.org/repos/asf/cassandra/blob/3f49c328/src/java/org/apache/cassandra/db/filter/RowFilter.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/db/filter/RowFilter.java b/src/java/org/apache/cassandra/db/filter/RowFilter.java index 6626275..4c0608f 100644 --- a/src/java/org/apache/cassandra/db/filter/RowFilter.java +++ b/src/java/org/apache/cassandra/db/filter/RowFilter.java @@ -25,6 +25,7 @@ import java.util.concurrent.ConcurrentMap; import java.util.concurrent.atomic.AtomicInteger; import com.google.common.base.Objects; +import com.google.common.collect.Iterables; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -274,9 +275,19 @@ public abstract class RowFilter implements Iterable<RowFilter.Expression> return iter; final CFMetaData metadata = iter.metadata(); - long numberOfStaticColumnExpressions = expressions.stream().filter(e -> e.column.isStatic()).count(); - final boolean filterStaticColumns = numberOfStaticColumnExpressions != 0; - final boolean filterNonStaticColumns = (expressions.size() - numberOfStaticColumnExpressions) > 0; + + List<Expression> partitionLevelExpressions = new ArrayList<>(); + List<Expression> rowLevelExpressions = new ArrayList<>(); + for (Expression e: expressions) + { + if (e.column.isStatic() || e.column.isPartitionKey()) + partitionLevelExpressions.add(e); + else + rowLevelExpressions.add(e); + } + + long numberOfRegularColumnExpressions = rowLevelExpressions.size(); + final boolean filterNonStaticColumns = numberOfRegularColumnExpressions > 0; class IsSatisfiedFilter extends Transformation<UnfilteredRowIterator> { @@ -285,9 +296,10 @@ public abstract class RowFilter implements Iterable<RowFilter.Expression> { pk = partition.partitionKey(); - // The filter might be on static columns, so need to check static row first. - if (filterStaticColumns && applyToRow(partition.staticRow()) == null) - return null; + // Short-circuit all partitions that won't match based on static and partition keys + for (Expression e : partitionLevelExpressions) + if (!e.isSatisfiedBy(metadata, partition.partitionKey(), partition.staticRow())) + return null; UnfilteredRowIterator iterator = Transformation.apply(partition, this); return (filterNonStaticColumns && !iterator.hasNext()) ? null : iterator; @@ -299,9 +311,10 @@ public abstract class RowFilter implements Iterable<RowFilter.Expression> if (purged == null) return null; - for (Expression e : expressions) + for (Expression e : rowLevelExpressions) if (!e.isSatisfiedBy(metadata, pk, purged)) return null; + return row; } } @@ -669,9 +682,6 @@ public abstract class RowFilter implements Iterable<RowFilter.Expression> // TODO: we should try to merge both code someday. assert value != null; - if (row.isStatic() != column.isStatic()) - return true; - switch (operator) { case EQ: http://git-wip-us.apache.org/repos/asf/cassandra/blob/3f49c328/test/unit/org/apache/cassandra/cql3/ViewFilteringTest.java ---------------------------------------------------------------------- diff --git a/test/unit/org/apache/cassandra/cql3/ViewFilteringTest.java b/test/unit/org/apache/cassandra/cql3/ViewFilteringTest.java index 12cb673..0cecfa2 100644 --- a/test/unit/org/apache/cassandra/cql3/ViewFilteringTest.java +++ b/test/unit/org/apache/cassandra/cql3/ViewFilteringTest.java @@ -148,13 +148,6 @@ public class ViewFilteringTest extends CQLTester throw new RuntimeException("MV alter failed: " + goodStatements.get(i), e); } } - - try - { - createView("mv_foo", "CREATE MATERIALIZED VIEW %s AS SELECT * FROM %%s WHERE a = 1 AND b IS NOT NULL AND c IS NOT NULL AND d is NOT NULL PRIMARY KEY ((a, b), c, d)"); - Assert.fail("Partial partition key restriction should not be allowed"); - } - catch (InvalidQueryException exc) {} } @Test @@ -266,6 +259,210 @@ public class ViewFilteringTest extends CQLTester } @Test + public void testPartitionKeyFilteringUnrestrictedPart() throws Throwable + { + List<String> mvPrimaryKeys = Arrays.asList("((a, b), c)", "((b, a), c)", "(a, b, c)", "(c, b, a)", "((c, a), b)"); + for (int i = 0; i < mvPrimaryKeys.size(); i++) + { + createTable("CREATE TABLE %s (a int, b int, c int, d int, PRIMARY KEY ((a, b), c))"); + + execute("USE " + keyspace()); + executeNet(protocolVersion, "USE " + keyspace()); + + execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 0, 0, 0, 0); + execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 0, 1, 0, 0); + execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 1, 0, 0, 0); + execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 1, 0, 1, 0); + execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 1, 1, 0, 0); + execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 1, 1, 1, 0); + + logger.info("Testing MV primary key: {}", mvPrimaryKeys.get(i)); + + // only accept rows where a = 1 + String viewName= "mv_test" + i; + createView(viewName, "CREATE MATERIALIZED VIEW %s AS SELECT * FROM %%s WHERE a = 1 AND b IS NOT NULL AND c IS NOT NULL PRIMARY KEY " + mvPrimaryKeys.get(i)); + + waitForView(keyspace(), viewName); + + assertRowsIgnoringOrder(execute("SELECT a, b, c, d FROM mv_test" + i), + row(1, 0, 0, 0), + row(1, 0, 1, 0), + row(1, 1, 0, 0), + row(1, 1, 1, 0) + ); + + // insert new rows that do not match the filter + execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 2, 0, 0, 0); + execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 2, 1, 0, 0); + assertRowsIgnoringOrder(execute("SELECT a, b, c, d FROM mv_test" + i), + row(1, 0, 0, 0), + row(1, 0, 1, 0), + row(1, 1, 0, 0), + row(1, 1, 1, 0) + ); + + // insert new row that does match the filter + execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 1, 1, 2, 0); + assertRowsIgnoringOrder(execute("SELECT a, b, c, d FROM mv_test" + i), + row(1, 0, 0, 0), + row(1, 0, 1, 0), + row(1, 1, 0, 0), + row(1, 1, 1, 0), + row(1, 1, 2, 0) + ); + + // update rows that don't match the filter + execute("UPDATE %s SET d = ? WHERE a = ? AND b = ? AND c = ?", 1, 0, 0, 0); + execute("UPDATE %s SET d = ? WHERE a = ? AND b = ? AND c = ?", 1, 0, 1, 0); + assertRowsIgnoringOrder(execute("SELECT a, b, c, d FROM mv_test" + i), + row(1, 0, 0, 0), + row(1, 0, 1, 0), + row(1, 1, 0, 0), + row(1, 1, 1, 0), + row(1, 1, 2, 0) + ); + + // update a row that does match the filter + execute("UPDATE %s SET d = ? WHERE a = ? AND b = ? AND c = ?", 1, 1, 1, 0); + assertRowsIgnoringOrder(execute("SELECT a, b, c, d FROM mv_test" + i), + row(1, 0, 0, 0), + row(1, 0, 1, 0), + row(1, 1, 0, 1), + row(1, 1, 1, 0), + row(1, 1, 2, 0) + ); + + // delete rows that don't match the filter + execute("DELETE FROM %s WHERE a = ? AND b = ? AND c = ?", 0, 0, 0); + execute("DELETE FROM %s WHERE a = ? AND b = ? AND c = ?", 0, 1, 0); + execute("DELETE FROM %s WHERE a = ? AND b = ?", 0, 0); + assertRowsIgnoringOrder(execute("SELECT a, b, c, d FROM mv_test" + i), + row(1, 0, 0, 0), + row(1, 0, 1, 0), + row(1, 1, 0, 1), + row(1, 1, 1, 0), + row(1, 1, 2, 0) + ); + + // delete a row that does match the filter + execute("DELETE FROM %s WHERE a = ? AND b = ? AND c = ?", 1, 1, 0); + assertRowsIgnoringOrder(execute("SELECT a, b, c, d FROM mv_test" + i), + row(1, 0, 0, 0), + row(1, 0, 1, 0), + row(1, 1, 1, 0), + row(1, 1, 2, 0) + ); + + // delete a partition that matches the filter + execute("DELETE FROM %s WHERE a = ? AND b = ?", 1, 0); + assertRowsIgnoringOrder(execute("SELECT a, b, c, d FROM mv_test" + i), + row(1, 1, 1, 0), + row(1, 1, 2, 0)); + execute("DELETE FROM %s WHERE a = ? AND b = ?", 1, 1); + assertEmpty(execute("SELECT * FROM mv_test" + i)); + } + } + + @Test + public void testPartitionKeyFilteringWithSlice() throws Throwable + { + List<String> mvPrimaryKeys = Arrays.asList("((a, b), c)", "((b, a), c)", "(a, b, c)", "(c, b, a)", "((c, a), b)"); + for (int i = 0; i < mvPrimaryKeys.size(); i++) + { + createTable("CREATE TABLE %s (a int, b int, c int, d int, PRIMARY KEY ((a, b), c))"); + + execute("USE " + keyspace()); + executeNet(protocolVersion, "USE " + keyspace()); + + execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 0, 0, 1, 1); + execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 0, 10, 1, 2); + execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 1, 0, 2, 1); + execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 1, 10, 2, 2); + execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 2, 1, 3, 1); + execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 2, 10, 3, 2); + + logger.info("Testing MV primary key: {}", mvPrimaryKeys.get(i)); + + // only accept rows where a = 1 + String viewName= "mv_test" + i; + createView(viewName, "CREATE MATERIALIZED VIEW %s AS SELECT * FROM %%s WHERE a > 0 AND b > 5 AND c IS NOT NULL PRIMARY KEY " + mvPrimaryKeys.get(i)); + + waitForView(keyspace(), viewName); + + assertRowsIgnoringOrder(execute("SELECT a, b, c, d FROM mv_test" + i), + row(1, 10, 2, 2), + row(2, 10, 3, 2) + ); + + // insert new rows that do not match the filter + execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 2, 0, 0, 0); + execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 2, 1, 0, 0); + assertRowsIgnoringOrder(execute("SELECT a, b, c, d FROM mv_test" + i), + row(1, 10, 2, 2), + row(2, 10, 3, 2) + ); + + // insert new row that does match the filter + execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 3, 10, 4, 2); + assertRowsIgnoringOrder(execute("SELECT a, b, c, d FROM mv_test" + i), + row(1, 10, 2, 2), + row(2, 10, 3, 2), + row(3, 10, 4, 2) + ); + + // update rows that don't match the filter + execute("UPDATE %s SET d = ? WHERE a = ? AND b = ? AND c = ?", 1, 0, 0, 0); + execute("UPDATE %s SET d = ? WHERE a = ? AND b = ? AND c = ?", 1, 0, 1, 0); + assertRowsIgnoringOrder(execute("SELECT a, b, c, d FROM mv_test" + i), + row(1, 10, 2, 2), + row(2, 10, 3, 2), + row(3, 10, 4, 2) + ); + + // update a row that does match the filter + execute("UPDATE %s SET d = ? WHERE a = ? AND b = ? AND c = ?", 100, 3, 10, 4); + assertRowsIgnoringOrder(execute("SELECT a, b, c, d FROM mv_test" + i), + row(1, 10, 2, 2), + row(2, 10, 3, 2), + row(3, 10, 4, 100) + ); + + // delete rows that don't match the filter + execute("DELETE FROM %s WHERE a = ? AND b = ? AND c = ?", 0, 0, 0); + execute("DELETE FROM %s WHERE a = ? AND b = ? AND c = ?", 0, 1, 0); + execute("DELETE FROM %s WHERE a = ? AND b = ?", 0, 0); + assertRowsIgnoringOrder(execute("SELECT a, b, c, d FROM mv_test" + i), + row(1, 10, 2, 2), + row(2, 10, 3, 2), + row(3, 10, 4, 100) + ); + + // delete a row that does match the filter + execute("DELETE FROM %s WHERE a = ? AND b = ? AND c = ?", 1, 1, 0); + assertRowsIgnoringOrder(execute("SELECT a, b, c, d FROM mv_test" + i), + row(1, 10, 2, 2), + row(2, 10, 3, 2), + row(3, 10, 4, 100) + ); + + // delete a partition that matches the filter + execute("DELETE FROM %s WHERE a = ? AND b = ?", 1, 10); + assertRowsIgnoringOrder(execute("SELECT a, b, c, d FROM mv_test" + i), + row(2, 10, 3, 2), + row(3, 10, 4, 100)); + } + } + + + + + private static void waitForView(String keyspace, String view) throws InterruptedException + { + while (!SystemKeyspace.isViewBuilt(keyspace, view)) + Thread.sleep(10); + } + + @Test public void testPartitionKeyRestrictions() throws Throwable { List<String> mvPrimaryKeys = Arrays.asList("((a, b), c)", "((b, a), c)", "(a, b, c)", "(c, b, a)", "((c, a), b)"); http://git-wip-us.apache.org/repos/asf/cassandra/blob/3f49c328/test/unit/org/apache/cassandra/cql3/ViewTest.java ---------------------------------------------------------------------- diff --git a/test/unit/org/apache/cassandra/cql3/ViewTest.java b/test/unit/org/apache/cassandra/cql3/ViewTest.java index c9ef401..0945511 100644 --- a/test/unit/org/apache/cassandra/cql3/ViewTest.java +++ b/test/unit/org/apache/cassandra/cql3/ViewTest.java @@ -117,6 +117,19 @@ public class ViewTest extends CQLTester Assert.assertEquals(0, execute("select * from view1").size()); } + + @Test + public void createMvWithUnrestrictedPKParts() throws Throwable + { + createTable("CREATE TABLE %s (k1 int, c1 int , val int, PRIMARY KEY (k1, c1))"); + + execute("USE " + keyspace()); + executeNet(protocolVersion, "USE " + keyspace()); + + createView("view1", "CREATE MATERIALIZED VIEW view1 AS SELECT k1 FROM %%s WHERE k1 IS NOT NULL AND c1 IS NOT NULL AND val IS NOT NULL PRIMARY KEY (val, k1, c1)"); + + } + @Test public void testClusteringKeyTombstone() throws Throwable { http://git-wip-us.apache.org/repos/asf/cassandra/blob/3f49c328/test/unit/org/apache/cassandra/cql3/validation/entities/SecondaryIndexTest.java ---------------------------------------------------------------------- diff --git a/test/unit/org/apache/cassandra/cql3/validation/entities/SecondaryIndexTest.java b/test/unit/org/apache/cassandra/cql3/validation/entities/SecondaryIndexTest.java index 2072bf2..05c11a4 100644 --- a/test/unit/org/apache/cassandra/cql3/validation/entities/SecondaryIndexTest.java +++ b/test/unit/org/apache/cassandra/cql3/validation/entities/SecondaryIndexTest.java @@ -1177,6 +1177,101 @@ public class SecondaryIndexTest extends CQLTester row(bytes("foo124"), EMPTY_BYTE_BUFFER)); } + @Test + public void testPartitionKeyWithIndex() throws Throwable + { + createTable("CREATE TABLE %s (a int, b int, c int, PRIMARY KEY ((a, b)))"); + createIndex("CREATE INDEX ON %s (a);"); + createIndex("CREATE INDEX ON %s (b);"); + + execute("INSERT INTO %s (a, b, c) VALUES (1,2,3)"); + execute("INSERT INTO %s (a, b, c) VALUES (2,3,4)"); + execute("INSERT INTO %s (a, b, c) VALUES (5,6,7)"); + + beforeAndAfterFlush(() -> { + assertRows(execute("SELECT * FROM %s WHERE a = 1"), + row(1, 2, 3)); + assertRows(execute("SELECT * FROM %s WHERE b = 3"), + row(2, 3, 4)); + + }); + } + + @Test + public void testAllowFilteringOnPartitionKeyWithSecondaryIndex() throws Throwable + { + createTable("CREATE TABLE %s (pk1 int, pk2 int, c1 int, c2 int, v int, " + + "PRIMARY KEY ((pk1, pk2), c1, c2))"); + createIndex("CREATE INDEX v_idx_1 ON %s (v);"); + + for (int i = 1; i <= 5; i++) + { + for (int j = 1; j <= 2; j++) + { + execute("INSERT INTO %s (pk1, pk2, c1, c2, v) VALUES (?, ?, ?, ?, ?)", j, 1, 1, 1, i); + execute("INSERT INTO %s (pk1, pk2, c1, c2, v) VALUES (?, ?, ?, ?, ?)", j, 1, 1, i, i); + execute("INSERT INTO %s (pk1, pk2, c1, c2, v) VALUES (?, ?, ?, ?, ?)", j, 1, i, i, i); + execute("INSERT INTO %s (pk1, pk2, c1, c2, v) VALUES (?, ?, ?, ?, ?)", j, i, i, i, i); + } + } + + beforeAndAfterFlush(() -> { + assertEmpty(execute("SELECT * FROM %s WHERE pk1 = 1 AND c1 > 0 AND c1 < 5 AND c2 = 1 AND v = 3 ALLOW FILTERING;")); + + assertRows(execute("SELECT * FROM %s WHERE pk1 = 1 AND c1 > 0 AND c1 < 5 AND c2 = 3 AND v = 3 ALLOW FILTERING;"), + row(1, 3, 3, 3, 3), + row(1, 1, 1, 3, 3), + row(1, 1, 3, 3, 3)); + + assertEmpty(execute("SELECT * FROM %s WHERE pk1 = 1 AND c2 > 1 AND c2 < 5 AND v = 1 ALLOW FILTERING;")); + + assertRows(execute("SELECT * FROM %s WHERE pk1 = 1 AND c1 > 1 AND c2 > 2 AND v = 3 ALLOW FILTERING;"), + row(1, 3, 3, 3, 3), + row(1, 1, 3, 3, 3)); + + assertRows(execute("SELECT * FROM %s WHERE pk1 = 1 AND pk2 > 1 AND c2 > 2 AND v = 3 ALLOW FILTERING;"), + row(1, 3, 3, 3, 3)); + + assertRowsIgnoringOrder(execute("SELECT * FROM %s WHERE pk2 > 1 AND c1 IN(0,1,2) AND v <= 3 ALLOW FILTERING;"), + row(1, 2, 2, 2, 2), + row(2, 2, 2, 2, 2)); + + assertRows(execute("SELECT * FROM %s WHERE pk1 >= 2 AND pk2 <=3 AND c1 IN(0,1,2) AND c2 IN(0,1,2) AND v < 3 ALLOW FILTERING;"), + row(2, 2, 2, 2, 2), + row(2, 1, 1, 2, 2), + row(2, 1, 2, 2, 2)); + + assertInvalidMessage(StatementRestrictions.REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE pk1 >= 1 AND pk2 <=3 AND c1 IN(0,1,2) AND c2 IN(0,1,2) AND v = 3"); + }); + } + + @Test + public void testAllowFilteringOnPartitionKeyWithIndexForContains() throws Throwable + { + createTable("CREATE TABLE %s (k1 int, k2 int, v set<int>, PRIMARY KEY ((k1, k2)))"); + createIndex("CREATE INDEX ON %s(k2)"); + + execute("INSERT INTO %s (k1, k2, v) VALUES (?, ?, ?)", 0, 0, set(1, 2, 3)); + execute("INSERT INTO %s (k1, k2, v) VALUES (?, ?, ?)", 0, 1, set(2, 3, 4)); + execute("INSERT INTO %s (k1, k2, v) VALUES (?, ?, ?)", 1, 0, set(3, 4, 5)); + execute("INSERT INTO %s (k1, k2, v) VALUES (?, ?, ?)", 1, 1, set(4, 5, 6)); + + beforeAndAfterFlush(() -> { + assertInvalidMessage(StatementRestrictions.REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE k2 > ?", 0); + + assertRows(execute("SELECT * FROM %s WHERE k2 > ? ALLOW FILTERING", 0), + row(0, 1, set(2, 3, 4)), + row(1, 1, set(4, 5, 6))); + + assertRows(execute("SELECT * FROM %s WHERE k2 >= ? AND v CONTAINS ? ALLOW FILTERING", 1, 6), + row(1, 1, set(4, 5, 6))); + + assertEmpty(execute("SELECT * FROM %s WHERE k2 < ? AND v CONTAINS ? ALLOW FILTERING", 0, 7)); + }); + } + private ResultMessage.Prepared prepareStatement(String cql, boolean forThrift) { return QueryProcessor.prepare(String.format(cql, KEYSPACE, currentTable()), http://git-wip-us.apache.org/repos/asf/cassandra/blob/3f49c328/test/unit/org/apache/cassandra/cql3/validation/operations/SelectMultiColumnRelationTest.java ---------------------------------------------------------------------- diff --git a/test/unit/org/apache/cassandra/cql3/validation/operations/SelectMultiColumnRelationTest.java b/test/unit/org/apache/cassandra/cql3/validation/operations/SelectMultiColumnRelationTest.java index 19f798f..b91650d 100644 --- a/test/unit/org/apache/cassandra/cql3/validation/operations/SelectMultiColumnRelationTest.java +++ b/test/unit/org/apache/cassandra/cql3/validation/operations/SelectMultiColumnRelationTest.java @@ -958,11 +958,14 @@ public class SelectMultiColumnRelationTest extends CQLTester row(0, 0, 1, 1, 0, 4), row(0, 0, 1, 1, 1, 5)); - assertInvalidMessage("Partition key parts: b must be restricted as other parts are", - "SELECT * FROM %s WHERE a = ? AND (c, d) IN ((?, ?), (?, ?)) ALLOW FILTERING", 0, 1, 1, 2, 1); - - assertInvalidMessage("Partition key parts: b must be restricted as other parts are", - "SELECT * FROM %s WHERE a = ? AND (c, d) >= (?, ?) ALLOW FILTERING", 0, 1, 1); + assertRows(execute("SELECT * FROM %s WHERE a = ? AND (c, d) IN ((?, ?)) ALLOW FILTERING", 0, 1, 1), + row(0, 0, 1, 1, 0, 4), + row(0, 0, 1, 1, 1, 5)); + + assertRows(execute("SELECT * FROM %s WHERE a = ? AND (c, d) >= (?, ?) ALLOW FILTERING", 0, 1, 1), + row(0, 0, 1, 1, 0, 4), + row(0, 0, 1, 1, 1, 5), + row(0, 0, 2, 0, 0, 5)); assertRows(execute("SELECT * FROM %s WHERE a = ? AND b = ? AND (c) IN ((?)) AND f = ?", 0, 0, 1, 5), row(0, 0, 1, 1, 1, 5)); http://git-wip-us.apache.org/repos/asf/cassandra/blob/3f49c328/test/unit/org/apache/cassandra/cql3/validation/operations/SelectOrderedPartitionerTest.java ---------------------------------------------------------------------- diff --git a/test/unit/org/apache/cassandra/cql3/validation/operations/SelectOrderedPartitionerTest.java b/test/unit/org/apache/cassandra/cql3/validation/operations/SelectOrderedPartitionerTest.java index 83e7e47..0e3a342 100644 --- a/test/unit/org/apache/cassandra/cql3/validation/operations/SelectOrderedPartitionerTest.java +++ b/test/unit/org/apache/cassandra/cql3/validation/operations/SelectOrderedPartitionerTest.java @@ -27,8 +27,11 @@ import org.junit.Test; import static junit.framework.Assert.assertNull; import static org.junit.Assert.assertEquals; + import org.apache.cassandra.config.DatabaseDescriptor; import org.apache.cassandra.cql3.CQLTester; +import org.apache.cassandra.cql3.UntypedResultSet; +import org.apache.cassandra.cql3.restrictions.StatementRestrictions; import org.apache.cassandra.dht.ByteOrderedPartitioner; /** @@ -43,6 +46,33 @@ public class SelectOrderedPartitionerTest extends CQLTester } @Test + public void testFilteringOnPartitionKeyWithToken() throws Throwable + { + createTable("CREATE TABLE %s (a int, b int, c int, d int, PRIMARY KEY ((a, b), c))"); + + for (int i = 0; i < 10; i++) + { + execute("INSERT INTO %s (a,b,c,d) VALUES (?, ?, ?, ?)", i, i, i, i); + execute("INSERT INTO %s (a,b,c,d) VALUES (?, ?, ?, ?)", i, i + 10, i + 10, i + 10); + } + + beforeAndAfterFlush(() -> { + assertRowsIgnoringOrder(execute("SELECT * FROM %s WHERE token(a, b) > token(5, 10) AND b < 8 ALLOW FILTERING"), + row(6, 6, 6, 6), + row(7, 7, 7, 7)); + + assertRows(execute("SELECT * FROM %s WHERE token(a, b) > token(8, 10) AND a = 9 ALLOW FILTERING"), + row(9, 9, 9, 9), + row(9, 19, 19, 19)); + + assertRows(execute("SELECT * FROM %s WHERE token(a, b) > token(8, 10) AND a = 9 AND c = 19 ALLOW FILTERING"), + row(9, 19, 19, 19)); + + assertEmpty(execute("SELECT * FROM %s WHERE token(a, b) = token(8, 8) AND b = 9 ALLOW FILTERING")); + }); + } + + @Test public void testTokenFunctionWithSingleColumnPartitionKey() throws Throwable { createTable("CREATE TABLE IF NOT EXISTS %s (a int PRIMARY KEY, b text)"); @@ -130,7 +160,7 @@ public class SelectOrderedPartitionerTest extends CQLTester assertRows(execute("SELECT * FROM %s WHERE token(a) < token(?) AND token(a) >= token(?) AND a IN (?, ?);", 1, 3, 1, 3), row(3, 3)); - assertInvalidMessage("Only EQ and IN relation are supported on the partition key (unless you use the token() function)", + assertInvalidMessage(StatementRestrictions.REQUIRES_ALLOW_FILTERING_MESSAGE, "SELECT * FROM %s WHERE token(a) > token(?) AND token(a) <= token(?) AND a > ?;", 1, 3, 1); assertRows(execute("SELECT * FROM %s WHERE token(a) > token(?) AND token(a) <= token(?) AND a IN ?;", @@ -206,7 +236,7 @@ public class SelectOrderedPartitionerTest extends CQLTester assertEmpty(execute("SELECT * FROM %s WHERE b IN (?, ?) AND token(a, b) = token(?, ?) AND a = ?;", 0, 1, 0, 0, 1)); - assertInvalidMessage("Partition key parts: b must be restricted as other parts are", + assertInvalidMessage(StatementRestrictions.REQUIRES_ALLOW_FILTERING_MESSAGE, "SELECT * FROM %s WHERE token(a, b) > token(?, ?) AND a = ?;", 0, 0, 1); } http://git-wip-us.apache.org/repos/asf/cassandra/blob/3f49c328/test/unit/org/apache/cassandra/cql3/validation/operations/SelectSingleColumnRelationTest.java ---------------------------------------------------------------------- diff --git a/test/unit/org/apache/cassandra/cql3/validation/operations/SelectSingleColumnRelationTest.java b/test/unit/org/apache/cassandra/cql3/validation/operations/SelectSingleColumnRelationTest.java index a52ce66..2ad0427 100644 --- a/test/unit/org/apache/cassandra/cql3/validation/operations/SelectSingleColumnRelationTest.java +++ b/test/unit/org/apache/cassandra/cql3/validation/operations/SelectSingleColumnRelationTest.java @@ -206,9 +206,9 @@ public class SelectSingleColumnRelationTest extends CQLTester row("second", 1, 1, 1), row("second", 4, 4, 4)); - assertInvalidMessage("Partition key parts: b must be restricted as other parts are", + assertInvalidMessage(StatementRestrictions.REQUIRES_ALLOW_FILTERING_MESSAGE, "select * from %s where a in (?, ?)", "first", "second"); - assertInvalidMessage("Partition key parts: b must be restricted as other parts are", + assertInvalidMessage(StatementRestrictions.REQUIRES_ALLOW_FILTERING_MESSAGE, "select * from %s where a = ?", "first"); assertInvalidMessage("b cannot be restricted by more than one relation if it includes a IN", "select * from %s where a = ? AND b IN (?, ?) AND b = ?", "first", 2, 2, 3); @@ -498,11 +498,14 @@ public class SelectSingleColumnRelationTest extends CQLTester row(0, 0, 1, 1, 0, 4), row(0, 0, 1, 1, 1, 5)); - assertInvalidMessage("Partition key parts: b must be restricted as other parts are", - "SELECT * FROM %s WHERE a = ? AND c IN (?, ?) AND d IN (?) ALLOW FILTERING", 0, 0, 1, 1); + assertRows(execute("SELECT * FROM %s WHERE a = ? AND c IN (?) AND d IN (?) ALLOW FILTERING", 0, 1, 1), + row(0, 0, 1, 1, 0, 4), + row(0, 0, 1, 1, 1, 5)); - assertInvalidMessage("Partition key parts: b must be restricted as other parts are", - "SELECT * FROM %s WHERE a = ? AND (c, d) >= (?, ?) ALLOW FILTERING", 0, 1, 1); + assertRows(execute("SELECT * FROM %s WHERE a = ? AND (c, d) >= (?, ?) ALLOW FILTERING", 0, 1, 1), + row(0, 0, 1, 1, 0, 4), + row(0, 0, 1, 1, 1, 5), + row(0, 0, 2, 0, 0, 5)); assertInvalidMessage(StatementRestrictions.REQUIRES_ALLOW_FILTERING_MESSAGE, "SELECT * FROM %s WHERE a = ? AND c IN (?, ?) AND f = ?", 0, 0, 1, 5); @@ -520,8 +523,11 @@ public class SelectSingleColumnRelationTest extends CQLTester assertRows(execute("SELECT * FROM %s WHERE a = ? AND c IN (?, ?) AND d IN (?) AND f = ? ALLOW FILTERING", 0, 1, 3, 0, 3), row(0, 0, 1, 0, 0, 3)); - assertInvalidMessage("Partition key parts: b must be restricted as other parts are", - "SELECT * FROM %s WHERE a = ? AND c >= ? ALLOW FILTERING", 0, 1); + assertRows(execute("SELECT * FROM %s WHERE a = ? AND c >= ? ALLOW FILTERING", 0, 1), + row(0, 0, 1, 0, 0, 3), + row(0, 0, 1, 1, 0, 4), + row(0, 0, 1, 1, 1, 5), + row(0, 0, 2, 0, 0, 5)); assertInvalidMessage(StatementRestrictions.REQUIRES_ALLOW_FILTERING_MESSAGE, "SELECT * FROM %s WHERE a = ? AND c >= ? AND f = ?", 0, 1, 5); @@ -592,7 +598,7 @@ public class SelectSingleColumnRelationTest extends CQLTester public void testInvalidSliceRestrictionOnPartitionKey() throws Throwable { createTable("CREATE TABLE %s (a int PRIMARY KEY, b int, c text)"); - assertInvalidMessage("Only EQ and IN relation are supported on the partition key (unless you use the token() function)", + assertInvalidMessage(StatementRestrictions.REQUIRES_ALLOW_FILTERING_MESSAGE, "SELECT * FROM %s WHERE a >= 1 and a < 4"); assertInvalidMessage("Multi-column relations can only be applied to clustering columns but was applied to: a", "SELECT * FROM %s WHERE (a) >= (1) and (a) < (4)"); @@ -604,9 +610,9 @@ public class SelectSingleColumnRelationTest extends CQLTester createTable("CREATE TABLE %s (a int, b int, c text, PRIMARY KEY ((a, b)))"); assertInvalidMessage("Multi-column relations can only be applied to clustering columns but was applied to: a", "SELECT * FROM %s WHERE (a, b) >= (1, 1) and (a, b) < (4, 1)"); - assertInvalidMessage("Only EQ and IN relation are supported on the partition key (unless you use the token() function)", + assertInvalidMessage("Multi-column relations can only be applied to clustering columns but was applied to: a", "SELECT * FROM %s WHERE a >= 1 and (a, b) < (4, 1)"); - assertInvalidMessage("Only EQ and IN relation are supported on the partition key (unless you use the token() function)", + assertInvalidMessage("Multi-column relations can only be applied to clustering columns but was applied to: a", "SELECT * FROM %s WHERE b >= 1 and (a, b) < (4, 1)"); assertInvalidMessage("Multi-column relations can only be applied to clustering columns but was applied to: a", "SELECT * FROM %s WHERE (a, b) >= (1, 1) and (b) < (4)");