Fix filtering on non-primary key columns for queries without index patch by Benjamin Lerer; reviewed by Sam Tunnicliffe for CASSANDRA-6377
Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/9c3855b5 Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/9c3855b5 Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/9c3855b5 Branch: refs/heads/trunk Commit: 9c3855b5fd83b9fa9ffb2e5495e43cbea9855dee Parents: e01c6dd Author: Benjamin Lerer <b.le...@gmail.com> Authored: Fri Mar 4 22:09:54 2016 +0100 Committer: Benjamin Lerer <b.le...@gmail.com> Committed: Fri Mar 4 22:09:54 2016 +0100 ---------------------------------------------------------------------- CHANGES.txt | 1 + .../cassandra/cql3/SingleColumnRelation.java | 4 - .../restrictions/StatementRestrictions.java | 8 +- .../cql3/statements/SelectStatement.java | 11 +- .../apache/cassandra/db/filter/RowFilter.java | 51 +- .../index/internal/CassandraIndex.java | 15 + .../entities/FrozenCollectionsTest.java | 3 +- .../validation/entities/SecondaryIndexTest.java | 3 +- .../cql3/validation/operations/DeleteTest.java | 10 +- .../SelectMultiColumnRelationTest.java | 54 +- .../SelectSingleColumnRelationTest.java | 51 +- .../cql3/validation/operations/SelectTest.java | 1071 +++++++++++++++++- .../cql3/validation/operations/UpdateTest.java | 8 +- .../apache/cassandra/index/CustomIndexTest.java | 4 +- .../index/internal/CassandraIndexTest.java | 34 +- 15 files changed, 1205 insertions(+), 123 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cassandra/blob/9c3855b5/CHANGES.txt ---------------------------------------------------------------------- diff --git a/CHANGES.txt b/CHANGES.txt index 520e66e..7204098 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,4 +1,5 @@ 3.0.5 + * Fix filtering on non-primary key columns for queries without index (CASSANDRA-6377) * Fix sstableloader fail when using materialized view (CASSANDRA-11275) Merged from 2.2: * Only log yaml config once, at startup (CASSANDRA-11217) http://git-wip-us.apache.org/repos/asf/cassandra/blob/9c3855b5/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 e2c0b79..05ba42d 100644 --- a/src/java/org/apache/cassandra/cql3/SingleColumnRelation.java +++ b/src/java/org/apache/cassandra/cql3/SingleColumnRelation.java @@ -227,10 +227,6 @@ public final class SingleColumnRelation extends Relation { ColumnSpecification receiver = columnDef; - checkFalse(!columnDef.isPrimaryKeyColumn() && isDense, - "Predicates on the non-primary-key column (%s) of a COMPACT table are not yet supported", - columnDef.name); - if (isIN()) { // We only allow IN on the row key and the clustering key so far, never on non-PK columns, and this even if http://git-wip-us.apache.org/repos/asf/cassandra/blob/9c3855b5/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 1c7db4e..797b8e4 100644 --- a/src/java/org/apache/cassandra/cql3/restrictions/StatementRestrictions.java +++ b/src/java/org/apache/cassandra/cql3/restrictions/StatementRestrictions.java @@ -50,8 +50,10 @@ import static org.apache.cassandra.cql3.statements.RequestValidations.invalidReq */ public final class StatementRestrictions { - public static final String NO_INDEX_FOUND_MESSAGE = - "No supported secondary index found for the non primary key columns restrictions"; + public static final String REQUIRES_ALLOW_FILTERING_MESSAGE = + "Cannot execute this query as it might involve data filtering and " + + "thus may have unpredictable performance. If you want to execute " + + "this query despite the performance unpredictability, use ALLOW FILTERING"; /** * The type of statement @@ -224,7 +226,7 @@ public final class StatementRestrictions if (hasQueriableIndex) usesSecondaryIndexing = true; else if (!useFiltering) - throw invalidRequest(NO_INDEX_FOUND_MESSAGE); + throw invalidRequest(StatementRestrictions.REQUIRES_ALLOW_FILTERING_MESSAGE); indexRestrictions.add(nonPrimaryKeyRestrictions); } http://git-wip-us.apache.org/repos/asf/cassandra/blob/9c3855b5/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java b/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java index 931813a..51d675b 100644 --- a/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java +++ b/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java @@ -46,7 +46,6 @@ import org.apache.cassandra.db.rows.RowIterator; import org.apache.cassandra.db.view.View; import org.apache.cassandra.dht.AbstractBounds; import org.apache.cassandra.exceptions.*; -import org.apache.cassandra.index.Index; import org.apache.cassandra.index.SecondaryIndexManager; import org.apache.cassandra.serializers.MarshalException; import org.apache.cassandra.service.ClientState; @@ -79,11 +78,6 @@ public class SelectStatement implements CQLStatement private static final Logger logger = LoggerFactory.getLogger(SelectStatement.class); private static final int DEFAULT_COUNT_PAGE_SIZE = 10000; - public static final String REQUIRES_ALLOW_FILTERING_MESSAGE = - "Cannot execute this query as it might involve data filtering and " + - "thus may have unpredictable performance. If you want to execute " + - "this query despite the performance unpredictability, use ALLOW FILTERING"; - private final int boundTerms; public final CFMetaData cfm; public final Parameters parameters; @@ -702,7 +696,8 @@ public class SelectStatement implements CQLStatement // we want to include static columns and we're done. if (!partition.hasNext()) { - if (!staticRow.isEmpty() && (!restrictions.usesSecondaryIndexing() || cfm.isStaticCompactTable()) && !restrictions.hasClusteringColumnsRestriction()) + if (!staticRow.isEmpty() && (!restrictions.usesSecondaryIndexing() || cfm.isStaticCompactTable()) + && !restrictions.hasClusteringColumnsRestriction()) { result.newRow(protocolVersion); for (ColumnDefinition def : selection.getColumns()) @@ -1018,7 +1013,7 @@ public class SelectStatement implements CQLStatement // We will potentially filter data if either: // - Have more than one IndexExpression // - Have no index expression and the row filter is not the identity - checkFalse(restrictions.needFiltering(), REQUIRES_ALLOW_FILTERING_MESSAGE); + checkFalse(restrictions.needFiltering(), StatementRestrictions.REQUIRES_ALLOW_FILTERING_MESSAGE); } } http://git-wip-us.apache.org/repos/asf/cassandra/blob/9c3855b5/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 17db323..4960452 100644 --- a/src/java/org/apache/cassandra/db/filter/RowFilter.java +++ b/src/java/org/apache/cassandra/db/filter/RowFilter.java @@ -80,23 +80,29 @@ public abstract class RowFilter implements Iterable<RowFilter.Expression> public void add(ColumnDefinition def, Operator op, ByteBuffer value) { - expressions.add(new SimpleExpression(def, op, value)); + add(new SimpleExpression(def, op, value)); } public void addMapEquality(ColumnDefinition def, ByteBuffer key, Operator op, ByteBuffer value) { - expressions.add(new MapEqualityExpression(def, key, op, value)); + add(new MapEqualityExpression(def, key, op, value)); } public void addThriftExpression(CFMetaData metadata, ByteBuffer name, Operator op, ByteBuffer value) { assert (this instanceof ThriftFilter); - expressions.add(new ThriftExpression(metadata, name, op, value)); + add(new ThriftExpression(metadata, name, op, value)); } public void addCustomIndexExpression(CFMetaData cfm, IndexMetadata targetIndex, ByteBuffer value) { - expressions.add(new CustomExpression(cfm, targetIndex, value)); + add(new CustomExpression(cfm, targetIndex, value)); + } + + private void add(Expression expression) + { + expression.validate(); + expressions.add(expression); } public List<Expression> getExpressions() @@ -223,14 +229,23 @@ 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; class IsSatisfiedFilter extends Transformation<UnfilteredRowIterator> { DecoratedKey pk; public UnfilteredRowIterator applyToPartition(UnfilteredRowIterator partition) { + // The filter might be on static columns, so need to check static row first. + if (filterStaticColumns && applyToRow(partition.staticRow()) == null) + return null; + pk = partition.partitionKey(); - return Transformation.apply(partition, this); + UnfilteredRowIterator iterator = Transformation.apply(partition, this); + + return (filterNonStaticColumns && !iterator.hasNext()) ? null : iterator; } public Row applyToRow(Row row) @@ -365,11 +380,17 @@ public abstract class RowFilter implements Iterable<RowFilter.Expression> return value; } - public void validateForIndexing() throws InvalidRequestException + public void validate() { - checkNotNull(value, "Unsupported null value for indexed column %s", column.name); - checkBindValueSet(value, "Unsupported unset value for indexed column %s", column.name); - checkFalse(value.remaining() > FBUtilities.MAX_UNSIGNED_SHORT, "Index expression values may not be larger than 64K"); + checkNotNull(value, "Unsupported null value for column %s", column.name); + checkBindValueSet(value, "Unsupported unset value for column %s", column.name); + } + + @Deprecated + public void validateForIndexing() + { + checkFalse(value.remaining() > FBUtilities.MAX_UNSIGNED_SHORT, + "Index expression values may not be larger than 64K"); } /** @@ -706,11 +727,12 @@ public abstract class RowFilter implements Iterable<RowFilter.Expression> } @Override - public void validateForIndexing() throws InvalidRequestException + public void validate() throws InvalidRequestException { - super.validateForIndexing(); - checkNotNull(key, "Unsupported null value for key of map column %s", column.name); - checkBindValueSet(key, "Unsupported unset value for key of map column %s", column.name); + checkNotNull(key, "Unsupported null map key for column %s", column.name); + checkBindValueSet(key, "Unsupported unset map key for column %s", column.name); + checkNotNull(value, "Unsupported null map value for column %s", column.name); + checkBindValueSet(value, "Unsupported unset map value for column %s", column.name); } @Override @@ -789,13 +811,10 @@ public abstract class RowFilter implements Iterable<RowFilter.Expression> */ private static class ThriftExpression extends Expression { - private final CFMetaData metadata; - public ThriftExpression(CFMetaData metadata, ByteBuffer name, Operator operator, ByteBuffer value) { super(makeDefinition(metadata, name), operator, value); assert metadata.isCompactTable(); - this.metadata = metadata; } private static ColumnDefinition makeDefinition(CFMetaData metadata, ByteBuffer name) http://git-wip-us.apache.org/repos/asf/cassandra/blob/9c3855b5/src/java/org/apache/cassandra/index/internal/CassandraIndex.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/index/internal/CassandraIndex.java b/src/java/org/apache/cassandra/index/internal/CassandraIndex.java index 7cb4471..74d3f5d 100644 --- a/src/java/org/apache/cassandra/index/internal/CassandraIndex.java +++ b/src/java/org/apache/cassandra/index/internal/CassandraIndex.java @@ -48,6 +48,8 @@ import org.apache.cassandra.utils.Pair; import org.apache.cassandra.utils.concurrent.OpOrder; import org.apache.cassandra.utils.concurrent.Refs; +import static org.apache.cassandra.cql3.statements.RequestValidations.checkFalse; + /** * Index implementation which indexes the values for a single column in the base * table and which stores its index data in a local, hidden table. @@ -192,6 +194,19 @@ public abstract class CassandraIndex implements Index }; } + @Override + public void validate(ReadCommand command) throws InvalidRequestException + { + Optional<RowFilter.Expression> target = getTargetExpression(command.rowFilter().getExpressions()); + + if (target.isPresent()) + { + ByteBuffer indexValue = target.get().getIndexValue(); + checkFalse(indexValue.remaining() > FBUtilities.MAX_UNSIGNED_SHORT, + "Index expression values may not be larger than 64K"); + } + } + private void setMetadata(IndexMetadata indexDef) { metadata = indexDef; http://git-wip-us.apache.org/repos/asf/cassandra/blob/9c3855b5/test/unit/org/apache/cassandra/cql3/validation/entities/FrozenCollectionsTest.java ---------------------------------------------------------------------- diff --git a/test/unit/org/apache/cassandra/cql3/validation/entities/FrozenCollectionsTest.java b/test/unit/org/apache/cassandra/cql3/validation/entities/FrozenCollectionsTest.java index 523a1ed..9df8ea0 100644 --- a/test/unit/org/apache/cassandra/cql3/validation/entities/FrozenCollectionsTest.java +++ b/test/unit/org/apache/cassandra/cql3/validation/entities/FrozenCollectionsTest.java @@ -27,6 +27,7 @@ import org.junit.BeforeClass; import org.junit.Test; import org.apache.cassandra.cql3.CQLTester; +import org.apache.cassandra.cql3.restrictions.StatementRestrictions; import org.apache.cassandra.db.marshal.*; import org.apache.cassandra.dht.ByteOrderedPartitioner; import org.apache.cassandra.exceptions.ConfigurationException; @@ -635,7 +636,7 @@ public class FrozenCollectionsTest extends CQLTester assertInvalidMessage("Cannot restrict clustering columns by a CONTAINS relation without a secondary index", "SELECT * FROM %s WHERE b CONTAINS ? ALLOW FILTERING", 1); - assertInvalidMessage("No supported secondary index found for the non primary key columns restrictions", + assertInvalidMessage(StatementRestrictions.REQUIRES_ALLOW_FILTERING_MESSAGE, "SELECT * FROM %s WHERE d CONTAINS KEY ?", 1); assertInvalidMessage("Cannot restrict clustering columns by a CONTAINS relation without a secondary index", http://git-wip-us.apache.org/repos/asf/cassandra/blob/9c3855b5/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 06f1987..6ad9cc8 100644 --- a/test/unit/org/apache/cassandra/cql3/validation/entities/SecondaryIndexTest.java +++ b/test/unit/org/apache/cassandra/cql3/validation/entities/SecondaryIndexTest.java @@ -31,6 +31,7 @@ import org.apache.cassandra.config.DatabaseDescriptor; import org.apache.cassandra.cql3.CQLTester; import org.apache.cassandra.cql3.ColumnIdentifier; import org.apache.cassandra.cql3.QueryProcessor; +import org.apache.cassandra.cql3.restrictions.StatementRestrictions; import org.apache.cassandra.cql3.statements.IndexTarget; import org.apache.cassandra.db.ColumnFamilyStore; import org.apache.cassandra.db.DeletionTime; @@ -131,7 +132,7 @@ public class SecondaryIndexTest extends CQLTester execute("DROP INDEX " + indexName); } - assertInvalidMessage("No supported secondary index found for the non primary key columns restrictions", + assertInvalidMessage(StatementRestrictions.REQUIRES_ALLOW_FILTERING_MESSAGE, "SELECT * FROM %s where b = ?", 1); dropIndex("DROP INDEX IF EXISTS " + indexName); assertInvalidMessage(String.format("Index '%s' could not be found", http://git-wip-us.apache.org/repos/asf/cassandra/blob/9c3855b5/test/unit/org/apache/cassandra/cql3/validation/operations/DeleteTest.java ---------------------------------------------------------------------- diff --git a/test/unit/org/apache/cassandra/cql3/validation/operations/DeleteTest.java b/test/unit/org/apache/cassandra/cql3/validation/operations/DeleteTest.java index da0bc33..76351ee 100644 --- a/test/unit/org/apache/cassandra/cql3/validation/operations/DeleteTest.java +++ b/test/unit/org/apache/cassandra/cql3/validation/operations/DeleteTest.java @@ -482,10 +482,7 @@ public class DeleteTest extends CQLTester "DELETE FROM %s WHERE partitionKey CONTAINS ? AND clustering = ?", 0, 1); // Non primary key in the where clause - String errorMsg = isEmpty(compactOption) ? "Non PRIMARY KEY columns found in where clause: value" - : "Predicates on the non-primary-key column (value) of a COMPACT table are not yet supported"; - - assertInvalidMessage(errorMsg, + assertInvalidMessage("Non PRIMARY KEY columns found in where clause: value", "DELETE FROM %s WHERE partitionKey = ? AND clustering = ? AND value = ?", 0, 1, 3); } } @@ -615,10 +612,7 @@ public class DeleteTest extends CQLTester "DELETE FROM %s WHERE partitionKey CONTAINS ? AND clustering_1 = ? AND clustering_2 = ?", 0, 1, 1); // Non primary key in the where clause - String errorMsg = isEmpty(compactOption) ? "Non PRIMARY KEY columns found in where clause: value" - : "Predicates on the non-primary-key column (value) of a COMPACT table are not yet supported"; - - assertInvalidMessage(errorMsg, + assertInvalidMessage("Non PRIMARY KEY columns found in where clause: value", "DELETE FROM %s WHERE partitionKey = ? AND clustering_1 = ? AND clustering_2 = ? AND value = ?", 0, 1, 1, 3); } } http://git-wip-us.apache.org/repos/asf/cassandra/blob/9c3855b5/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 b8a1d50..522c8cd 100644 --- a/test/unit/org/apache/cassandra/cql3/validation/operations/SelectMultiColumnRelationTest.java +++ b/test/unit/org/apache/cassandra/cql3/validation/operations/SelectMultiColumnRelationTest.java @@ -19,10 +19,16 @@ package org.apache.cassandra.cql3.validation.operations; import org.junit.Test; +import java.nio.ByteBuffer; + import org.apache.cassandra.cql3.CQLTester; +import org.apache.cassandra.cql3.restrictions.StatementRestrictions; +import org.apache.cassandra.utils.ByteBufferUtil; public class SelectMultiColumnRelationTest extends CQLTester { + private static final ByteBuffer TOO_BIG = ByteBuffer.allocate(1024 * 65); + @Test public void testSingleClusteringInvalidQueries() throws Throwable { @@ -821,7 +827,7 @@ public class SelectMultiColumnRelationTest extends CQLTester row(0, 1, 1, 0, 1), row(0, 1, 1, 1, 2)); - assertInvalidMessage("Cannot execute this query as it might involve data filtering", + assertInvalidMessage(StatementRestrictions.REQUIRES_ALLOW_FILTERING_MESSAGE, "SELECT * FROM %s WHERE (b, c) = (?, ?)", 1, 1); assertRows(execute("SELECT * FROM %s WHERE a = ? AND (b, c) = (?, ?)", 0, 1, 1), row(0, 1, 1, 0, 1), @@ -832,45 +838,63 @@ public class SelectMultiColumnRelationTest extends CQLTester assertRows(execute("SELECT * FROM %s WHERE a = ? AND (b, c) = (?, ?) AND e = ?", 0, 1, 1, 2), row(0, 1, 1, 1, 2)); - assertInvalidMessage("Cannot execute this query as it might involve data filtering", + assertInvalidMessage(StatementRestrictions.REQUIRES_ALLOW_FILTERING_MESSAGE, "SELECT * FROM %s WHERE (b, c) = (?, ?) AND e = ?", 1, 1, 2); assertRows(execute("SELECT * FROM %s WHERE (b, c) = (?, ?) AND e = ? ALLOW FILTERING", 1, 1, 2), row(0, 1, 1, 1, 2)); assertRows(execute("SELECT * FROM %s WHERE a = ? AND (b) IN ((?)) AND e = ? ALLOW FILTERING", 0, 1, 2), row(0, 1, 1, 1, 2)); - assertInvalidMessage("Cannot execute this query as it might involve data filtering", + assertInvalidMessage(StatementRestrictions.REQUIRES_ALLOW_FILTERING_MESSAGE, "SELECT * FROM %s WHERE (b) IN ((?)) AND e = ?", 1, 2); assertRows(execute("SELECT * FROM %s WHERE (b) IN ((?)) AND e = ? ALLOW FILTERING", 1, 2), row(0, 1, 1, 1, 2)); - assertInvalidMessage("Cannot execute this query as it might involve data filtering", + assertInvalidMessage(StatementRestrictions.REQUIRES_ALLOW_FILTERING_MESSAGE, "SELECT * FROM %s WHERE (b) IN ((?), (?)) AND e = ?", 0, 1, 2); assertRows(execute("SELECT * FROM %s WHERE (b) IN ((?), (?)) AND e = ? ALLOW FILTERING", 0, 1, 2), row(0, 0, 1, 1, 2), row(0, 1, 1, 1, 2)); - assertInvalidMessage("Cannot execute this query as it might involve data filtering", + assertInvalidMessage(StatementRestrictions.REQUIRES_ALLOW_FILTERING_MESSAGE, "SELECT * FROM %s WHERE (b, c) IN ((?, ?)) AND e = ?", 0, 1, 2); assertRows(execute("SELECT * FROM %s WHERE (b, c) IN ((?, ?)) AND e = ? ALLOW FILTERING", 0, 1, 2), row(0, 0, 1, 1, 2)); - assertInvalidMessage("Cannot execute this query as it might involve data filtering", + assertInvalidMessage(StatementRestrictions.REQUIRES_ALLOW_FILTERING_MESSAGE, "SELECT * FROM %s WHERE (b, c) IN ((?, ?), (?, ?)) AND e = ?", 0, 1, 1, 1, 2); assertRows(execute("SELECT * FROM %s WHERE (b, c) IN ((?, ?), (?, ?)) AND e = ? ALLOW FILTERING", 0, 1, 1, 1, 2), row(0, 0, 1, 1, 2), row(0, 1, 1, 1, 2)); - assertInvalidMessage("Cannot execute this query as it might involve data filtering", + assertInvalidMessage(StatementRestrictions.REQUIRES_ALLOW_FILTERING_MESSAGE, "SELECT * FROM %s WHERE (b) >= (?) AND e = ?", 1, 2); assertRows(execute("SELECT * FROM %s WHERE (b) >= (?) AND e = ? ALLOW FILTERING", 1, 2), row(0, 1, 1, 1, 2)); - assertInvalidMessage("Cannot execute this query as it might involve data filtering", + assertInvalidMessage(StatementRestrictions.REQUIRES_ALLOW_FILTERING_MESSAGE, "SELECT * FROM %s WHERE (b, c) >= (?, ?) AND e = ?", 1, 1, 2); assertRows(execute("SELECT * FROM %s WHERE (b, c) >= (?, ?) AND e = ? ALLOW FILTERING", 1, 1, 2), row(0, 1, 1, 1, 2)); + assertInvalidMessage("Unsupported null value for column e", + "SELECT * FROM %s WHERE (b, c) >= (?, ?) AND e = ? ALLOW FILTERING", 1, 1, null); + + assertInvalidMessage("Unsupported unset value for column e", + "SELECT * FROM %s WHERE (b, c) >= (?, ?) AND e = ? ALLOW FILTERING", 1, 1, unset()); + } + + @Test + public void testMultipleClusteringWithIndexAndValueOver64K() throws Throwable + { + createTable("CREATE TABLE %s (a int, b blob, c int, d int, PRIMARY KEY (a, b, c))"); + createIndex("CREATE INDEX ON %s (b)"); + + execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 0, ByteBufferUtil.bytes(1), 0, 0); + execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 0, ByteBufferUtil.bytes(2), 1, 0); + + assertInvalidMessage("Index expression values may not be larger than 64K", + "SELECT * FROM %s WHERE (b, c) = (?, ?) AND d = ? ALLOW FILTERING", TOO_BIG, 1, 2); } @Test @@ -890,14 +914,14 @@ public class SelectMultiColumnRelationTest extends CQLTester execute("INSERT INTO %s (a, b, c, d, e, f) VALUES (?, ?, ?, ?, ?, ?)", 0, 0, 2, 0, 0, 5); - assertInvalidMessage("Cannot execute this query as it might involve data filtering", + assertInvalidMessage(StatementRestrictions.REQUIRES_ALLOW_FILTERING_MESSAGE, "SELECT * FROM %s WHERE a = ? AND (c) = (?)"); 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)); - assertInvalidMessage("Cannot execute this query as it might involve data filtering", + assertInvalidMessage(StatementRestrictions.REQUIRES_ALLOW_FILTERING_MESSAGE, "SELECT * FROM %s WHERE a = ? AND (c, d) = (?, ?)", 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), @@ -911,12 +935,12 @@ public class SelectMultiColumnRelationTest extends CQLTester 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)); - assertInvalidMessage("Cannot execute this query as it might involve data filtering", + assertInvalidMessage(StatementRestrictions.REQUIRES_ALLOW_FILTERING_MESSAGE, "SELECT * FROM %s WHERE a = ? AND (c) IN ((?)) AND f = ?", 0, 1, 5); assertRows(execute("SELECT * FROM %s WHERE a = ? AND (c) IN ((?)) AND f = ? ALLOW FILTERING", 0, 1, 5), row(0, 0, 1, 1, 1, 5)); - assertInvalidMessage("Cannot execute this query as it might involve data filtering", + assertInvalidMessage(StatementRestrictions.REQUIRES_ALLOW_FILTERING_MESSAGE, "SELECT * FROM %s WHERE a = ? AND (c) IN ((?), (?)) AND f = ?", 0, 1, 2, 5); assertRows(execute("SELECT * FROM %s WHERE a = ? AND b = ? AND (c) IN ((?), (?)) AND f = ?", 0, 0, 1, 2, 5), @@ -929,12 +953,12 @@ public class SelectMultiColumnRelationTest extends CQLTester assertRows(execute("SELECT * FROM %s WHERE a = ? AND b = ? AND (c, d) IN ((?, ?)) AND f = ?", 0, 0, 1, 0, 3), row(0, 0, 1, 0, 0, 3)); - assertInvalidMessage("Cannot execute this query as it might involve data filtering", + assertInvalidMessage(StatementRestrictions.REQUIRES_ALLOW_FILTERING_MESSAGE, "SELECT * FROM %s WHERE a = ? AND (c, d) IN ((?, ?)) AND f = ?", 0, 1, 0, 3); assertRows(execute("SELECT * FROM %s WHERE a = ? AND (c, d) IN ((?, ?)) AND f = ? ALLOW FILTERING", 0, 1, 0, 3), row(0, 0, 1, 0, 0, 3)); - assertInvalidMessage("Cannot execute this query as it might involve data filtering", + assertInvalidMessage(StatementRestrictions.REQUIRES_ALLOW_FILTERING_MESSAGE, "SELECT * FROM %s WHERE a = ? AND (c) >= (?) AND f = ?", 0, 1, 5); assertRows(execute("SELECT * FROM %s WHERE a = ? AND b = ? AND (c) >= (?) AND f = ?", 0, 0, 1, 5), @@ -948,7 +972,7 @@ public class SelectMultiColumnRelationTest extends CQLTester assertRows(execute("SELECT * FROM %s WHERE a = ? AND b = ? AND (c, d) >= (?, ?) AND f = ?", 0, 0, 1, 1, 5), row(0, 0, 1, 1, 1, 5), row(0, 0, 2, 0, 0, 5)); - assertInvalidMessage("Cannot execute this query as it might involve data filtering", + assertInvalidMessage(StatementRestrictions.REQUIRES_ALLOW_FILTERING_MESSAGE, "SELECT * FROM %s WHERE a = ? AND (c, d) >= (?, ?) AND f = ?", 0, 1, 1, 5); assertRows(execute("SELECT * FROM %s WHERE a = ? AND (c, d) >= (?, ?) AND f = ? ALLOW FILTERING", 0, 1, 1, 5), row(0, 0, 1, 1, 1, 5), http://git-wip-us.apache.org/repos/asf/cassandra/blob/9c3855b5/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 fef34ca..0893903 100644 --- a/test/unit/org/apache/cassandra/cql3/validation/operations/SelectSingleColumnRelationTest.java +++ b/test/unit/org/apache/cassandra/cql3/validation/operations/SelectSingleColumnRelationTest.java @@ -17,14 +17,14 @@ */ package org.apache.cassandra.cql3.validation.operations; -import java.util.Arrays; - -import org.junit.Test; - import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import org.apache.cassandra.cql3.CQLTester; +import org.apache.cassandra.cql3.restrictions.StatementRestrictions; + +import org.junit.Test; public class SelectSingleColumnRelationTest extends CQLTester { @@ -267,9 +267,9 @@ public class SelectSingleColumnRelationTest extends CQLTester assertRows(execute("SELECT * FROM %s WHERE k = ? AND c = ? ALLOW FILTERING", 1, 2), row(1, 2, 1)); // Require filtering, allowed only with ALLOW FILTERING - assertInvalidMessage("Cannot execute this query as it might involve data filtering", + assertInvalidMessage(StatementRestrictions.REQUIRES_ALLOW_FILTERING_MESSAGE, "SELECT * FROM %s WHERE c = ?", 2); - assertInvalidMessage("Cannot execute this query as it might involve data filtering", + assertInvalidMessage(StatementRestrictions.REQUIRES_ALLOW_FILTERING_MESSAGE, "SELECT * FROM %s WHERE c > ? AND c <= ?", 2, 4); assertRows(execute("SELECT * FROM %s WHERE c = ? ALLOW FILTERING", 2), @@ -301,6 +301,25 @@ public class SelectSingleColumnRelationTest extends CQLTester } @Test + public void testAllowFilteringWithIndexedColumnAndStaticColumns() throws Throwable + { + createTable("CREATE TABLE %s (a int, b int, c int, s int static, PRIMARY KEY(a, b))"); + createIndex("CREATE INDEX ON %s(c)"); + + execute("INSERT INTO %s(a, b, c, s) VALUES(?, ?, ?, ?)", 1, 1, 1, 1); + execute("INSERT INTO %s(a, b, c) VALUES(?, ?, ?)", 1, 2, 1); + execute("INSERT INTO %s(a, s) VALUES(?, ?)", 3, 3); + execute("INSERT INTO %s(a, b, c, s) VALUES(?, ?, ?, ?)", 2, 1, 1, 2); + + assertRows(execute("SELECT * FROM %s WHERE c = ? AND s > ? ALLOW FILTERING", 1, 1), + row(2, 1, 2, 1)); + + assertRows(execute("SELECT * FROM %s WHERE c = ? AND s < ? ALLOW FILTERING", 1, 2), + row(1, 1, 1, 1), + row(1, 2, 1, 1)); + } + + @Test public void testIndexQueriesOnComplexPrimaryKey() throws Throwable { createTable("CREATE TABLE %s (pk0 int, pk1 int, ck0 int, ck1 int, ck2 int, value int, PRIMARY KEY ((pk0, pk1), ck0, ck1, ck2))"); @@ -377,7 +396,7 @@ public class SelectSingleColumnRelationTest extends CQLTester assertEmpty(execute("SELECT content FROM %s WHERE time1 = 1 AND time2 = 1 AND author='foo' ALLOW FILTERING")); assertEmpty(execute("SELECT content FROM %s WHERE time1 = 1 AND time2 > 0 AND author='foo' ALLOW FILTERING")); - assertInvalidMessage("Cannot execute this query as it might involve data filtering", + assertInvalidMessage(StatementRestrictions.REQUIRES_ALLOW_FILTERING_MESSAGE, "SELECT content FROM %s WHERE time2 >= 0 AND author='foo'"); } @@ -393,7 +412,7 @@ public class SelectSingleColumnRelationTest extends CQLTester execute(q, 2, 2, 0); execute(q, 3, 3, 0); - assertInvalidMessage("Cannot execute this query as it might involve data filtering", + assertInvalidMessage(StatementRestrictions.REQUIRES_ALLOW_FILTERING_MESSAGE, "SELECT * FROM %s WHERE setid = 0 AND row < 1;"); assertRows(execute("SELECT * FROM %s WHERE setid = 0 AND row < 1 ALLOW FILTERING;"), row(0, 0, 0)); } @@ -462,14 +481,14 @@ public class SelectSingleColumnRelationTest extends CQLTester execute("INSERT INTO %s (a, b, c, d, e, f) VALUES (?, ?, ?, ?, ?, ?)", 0, 0, 2, 0, 0, 5); - assertInvalidMessage("Cannot execute this query as it might involve data filtering", + assertInvalidMessage(StatementRestrictions.REQUIRES_ALLOW_FILTERING_MESSAGE, "SELECT * FROM %s WHERE a = ? AND c = ?", 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)); - assertInvalidMessage("Cannot execute this query as it might involve data filtering", + assertInvalidMessage(StatementRestrictions.REQUIRES_ALLOW_FILTERING_MESSAGE, "SELECT * FROM %s WHERE a = ? AND c = ? AND d = ?", 0, 1, 1); assertRows(execute("SELECT * FROM %s WHERE a = ? AND c = ? AND d = ? ALLOW FILTERING", 0, 1, 1), row(0, 0, 1, 1, 0, 4), @@ -481,18 +500,18 @@ public class SelectSingleColumnRelationTest extends CQLTester 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); - assertInvalidMessage("Cannot execute this query as it might involve data filtering", + assertInvalidMessage(StatementRestrictions.REQUIRES_ALLOW_FILTERING_MESSAGE, "SELECT * FROM %s WHERE a = ? AND c IN (?) AND f = ?", 0, 1, 5); assertRows(execute("SELECT * FROM %s WHERE a = ? AND c IN (?) AND f = ? ALLOW FILTERING", 0, 1, 5), row(0, 0, 1, 1, 1, 5)); - assertInvalidMessage("Cannot execute this query as it might involve data filtering", + assertInvalidMessage(StatementRestrictions.REQUIRES_ALLOW_FILTERING_MESSAGE, "SELECT * FROM %s WHERE a = ? AND c IN (?, ?) AND f = ?", 0, 1, 2, 5); assertRows(execute("SELECT * FROM %s WHERE a = ? AND c IN (?, ?) AND f = ? ALLOW FILTERING", 0, 1, 2, 5), row(0, 0, 1, 1, 1, 5), row(0, 0, 2, 0, 0, 5)); - assertInvalidMessage("Cannot execute this query as it might involve data filtering", + assertInvalidMessage(StatementRestrictions.REQUIRES_ALLOW_FILTERING_MESSAGE, "SELECT * FROM %s WHERE a = ? AND c IN (?) AND d IN (?) AND f = ?", 0, 1, 0, 3); assertRows(execute("SELECT * FROM %s WHERE a = ? AND c IN (?) AND d IN (?) AND f = ? ALLOW FILTERING", 0, 1, 0, 3), row(0, 0, 1, 0, 0, 3)); @@ -500,7 +519,7 @@ public class SelectSingleColumnRelationTest extends CQLTester assertInvalidMessage("Partition key parts: b must be restricted as other parts are", "SELECT * FROM %s WHERE a = ? AND c >= ? ALLOW FILTERING", 0, 1); - assertInvalidMessage("Cannot execute this query as it might involve data filtering", + assertInvalidMessage(StatementRestrictions.REQUIRES_ALLOW_FILTERING_MESSAGE, "SELECT * FROM %s WHERE a = ? AND c >= ? AND f = ?", 0, 1, 5); assertRows(execute("SELECT * FROM %s WHERE a = ? AND b = ? AND c >= ? AND f = ?", 0, 0, 1, 5), row(0, 0, 1, 1, 1, 5), @@ -510,7 +529,7 @@ public class SelectSingleColumnRelationTest extends CQLTester row(0, 0, 1, 1, 1, 5), row(0, 0, 2, 0, 0, 5)); - assertInvalidMessage("Cannot execute this query as it might involve data filtering", + assertInvalidMessage(StatementRestrictions.REQUIRES_ALLOW_FILTERING_MESSAGE, "SELECT * FROM %s WHERE a = ? AND c = ? AND d >= ? AND f = ?", 0, 1, 1, 5); assertRows(execute("SELECT * FROM %s WHERE a = ? AND b = ? AND c = ? AND d >= ? AND f = ?", 0, 0, 1, 1, 5), @@ -560,7 +579,7 @@ public class SelectSingleColumnRelationTest extends CQLTester assertInvalidMessage("Invalid unset value for column i", "SELECT * from %s WHERE k = 1 AND i IN(?,?)", 1, unset()); assertInvalidMessage("Invalid unset value for column i", "SELECT * from %s WHERE i = ? ALLOW FILTERING", unset()); // indexed column - assertInvalidMessage("Unsupported unset value for indexed column s", "SELECT * from %s WHERE s = ?", unset()); + assertInvalidMessage("Unsupported unset value for column s", "SELECT * from %s WHERE s = ?", unset()); // range assertInvalidMessage("Invalid unset value for column i", "SELECT * from %s WHERE k = 1 AND i > ?", unset()); }