Merge branch cassandra-2.2 into cassandra-3.0
Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/9244531a Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/9244531a Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/9244531a Branch: refs/heads/cassandra-3.0 Commit: 9244531ab7bb0f4d07cf9996a9bb89d5e4370f54 Parents: db61372 e06dae8 Author: Benjamin Lerer <b.le...@gmail.com> Authored: Mon Jul 4 14:30:55 2016 +0200 Committer: Benjamin Lerer <b.le...@gmail.com> Committed: Mon Jul 4 14:31:46 2016 +0200 ---------------------------------------------------------------------- CHANGES.txt | 3 + .../restrictions/MultiColumnRestriction.java | 2 +- .../restrictions/PrimaryKeyRestrictionSet.java | 82 ++++---------------- .../restrictions/StatementRestrictions.java | 41 ++++++++-- .../SelectMultiColumnRelationTest.java | 33 +++++++- .../cql3/validation/operations/SelectTest.java | 61 +++++++++++++++ 6 files changed, 144 insertions(+), 78 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cassandra/blob/9244531a/CHANGES.txt ---------------------------------------------------------------------- diff --cc CHANGES.txt index f12d704,451575c..2df77e1 --- a/CHANGES.txt +++ b/CHANGES.txt @@@ -1,17 -1,11 +1,20 @@@ -2.2.8 +3.0.9 + * Avoid digest mismatch with empty but static rows (CASSANDRA-12090) + * Fix EOF exception when altering column type (CASSANDRA-11820) +Merged from 2.2: * MemoryUtil.getShort() should return an unsigned short also for architectures not supporting unaligned memory accesses (CASSANDRA-11973) + Merged from 2.1: + * Fix filtering on clustering columns when 2i is used (CASSANDRA-11907) - * Account for partition deletions in tombstone histogram (CASSANDRA-12112) + -2.2.7 +3.0.8 + * Fix potential race in schema during new table creation (CASSANDRA-12083) + * cqlsh: fix error handling in rare COPY FROM failure scenario (CASSANDRA-12070) + * Disable autocompaction during drain (CASSANDRA-11878) + * Add a metrics timer to MemtablePool and use it to track time spent blocked on memory in MemtableAllocator (CASSANDRA-11327) + * Fix upgrading schema with super columns with non-text subcomparators (CASSANDRA-12023) + * Add TimeWindowCompactionStrategy (CASSANDRA-9666) +Merged from 2.2: * Allow nodetool info to run with readonly JMX access (CASSANDRA-11755) * Validate bloom_filter_fp_chance against lowest supported value when the table is created (CASSANDRA-11920) http://git-wip-us.apache.org/repos/asf/cassandra/blob/9244531a/src/java/org/apache/cassandra/cql3/restrictions/MultiColumnRestriction.java ---------------------------------------------------------------------- diff --cc src/java/org/apache/cassandra/cql3/restrictions/MultiColumnRestriction.java index 4329b6e,51e2ce4..9d33bb1 --- a/src/java/org/apache/cassandra/cql3/restrictions/MultiColumnRestriction.java +++ b/src/java/org/apache/cassandra/cql3/restrictions/MultiColumnRestriction.java @@@ -473,11 -471,11 +473,11 @@@ public abstract class MultiColumnRestri } @Override - public final void addIndexExpressionTo(List<IndexExpression> expressions, - SecondaryIndexManager indexManager, - QueryOptions options) throws InvalidRequestException + public final void addRowFilterTo(RowFilter filter, + SecondaryIndexManager indexManager, + QueryOptions options) throws InvalidRequestException { - throw invalidRequest("Slice restrictions are not supported on indexed columns"); + throw invalidRequest("Multi-column slice restrictions cannot be used for filtering."); } @Override http://git-wip-us.apache.org/repos/asf/cassandra/blob/9244531a/src/java/org/apache/cassandra/cql3/restrictions/PrimaryKeyRestrictionSet.java ---------------------------------------------------------------------- diff --cc src/java/org/apache/cassandra/cql3/restrictions/PrimaryKeyRestrictionSet.java index 061284b,e1cbc29..a5f4a24 --- a/src/java/org/apache/cassandra/cql3/restrictions/PrimaryKeyRestrictionSet.java +++ b/src/java/org/apache/cassandra/cql3/restrictions/PrimaryKeyRestrictionSet.java @@@ -25,14 -26,11 +25,13 @@@ import org.apache.cassandra.config.Colu import org.apache.cassandra.cql3.QueryOptions; import org.apache.cassandra.cql3.functions.Function; import org.apache.cassandra.cql3.statements.Bound; -import org.apache.cassandra.db.IndexExpression; -import org.apache.cassandra.db.composites.*; -import org.apache.cassandra.db.composites.Composite.EOC; -import org.apache.cassandra.db.index.SecondaryIndexManager; +import org.apache.cassandra.db.*; +import org.apache.cassandra.db.filter.RowFilter; import org.apache.cassandra.exceptions.InvalidRequestException; +import org.apache.cassandra.index.SecondaryIndexManager; +import org.apache.cassandra.utils.btree.BTreeSet; + - import static org.apache.cassandra.cql3.statements.RequestValidations.checkFalse; +import static org.apache.cassandra.cql3.statements.RequestValidations.invalidRequest; /** * A set of single column restrictions on a primary key part (partition key or clustering key). @@@ -64,72 -62,18 +63,26 @@@ final class PrimaryKeyRestrictionSet ex */ private boolean contains; - public PrimaryKeyRestrictionSet(CType ctype) + /** + * <code>true</code> if the restrictions corresponding to a partition key, <code>false</code> if it's clustering columns. + */ + private boolean isPartitionKey; + - /** - * If restrictions apply to clustering columns, we need to check whether they can be satisfied by an index lookup - * as this affects which other restrictions can legally be specified (if an index is present, we are more lenient - * about what additional filtering can be performed on the results of a lookup - see CASSANDRA-11510). - * - * We don't hold a reference to the SecondaryIndexManager itself as this is not strictly a singleton (although - * we often treat is as one), the field would also require annotation with @Unmetered to avoid blowing up the - * object size (used when calculating the size of prepared statements for caching). Instead, we refer to the - * CFMetaData and retrieve the index manager when necessary. - * - * There are a couple of scenarios where the CFM can be null (and we make sure and test for null when we use it): - * * where an empty set of restrictions are created for use in processing query results - see - * SelectStatement.forSelection - * * where the restrictions apply to partition keys and not clustering columns e.g. - * StatementRestrictions.partitionKeyRestrictions - * * in unit tests (in particular PrimaryKeyRestrictionSetTest which is primarily concerned with the correct - * generation of bounds when secondary indexes are not used). - */ - private final CFMetaData cfm; - + public PrimaryKeyRestrictionSet(ClusteringComparator comparator, boolean isPartitionKey) { - this(comparator, isPartitionKey, null); - } - - public PrimaryKeyRestrictionSet(ClusteringComparator comparator, boolean isPartitionKey, CFMetaData cfm) - { - super(ctype); + super(comparator); + - if (cfm != null) - assert !isPartitionKey; - - this.cfm = cfm; this.restrictions = new RestrictionSet(); this.eq = true; + this.isPartitionKey = isPartitionKey; } private PrimaryKeyRestrictionSet(PrimaryKeyRestrictionSet primaryKeyRestrictions, Restriction restriction) throws InvalidRequestException { - super(primaryKeyRestrictions.ctype); + super(primaryKeyRestrictions.comparator); this.restrictions = primaryKeyRestrictions.restrictions.addRestriction(restriction); + this.isPartitionKey = primaryKeyRestrictions.isPartitionKey; - this.cfm = primaryKeyRestrictions.cfm; - - if (!primaryKeyRestrictions.isEmpty() && !hasSupportingIndex(restriction)) - { - ColumnDefinition lastRestrictionStart = primaryKeyRestrictions.restrictions.lastRestriction().getFirstColumn(); - ColumnDefinition newRestrictionStart = restriction.getFirstColumn(); - - checkFalse(primaryKeyRestrictions.isSlice() && newRestrictionStart.position() > lastRestrictionStart.position(), - "Clustering column \"%s\" cannot be restricted (preceding column \"%s\" is restricted by a non-EQ relation)", - newRestrictionStart.name, - lastRestrictionStart.name); - - if (newRestrictionStart.position() < lastRestrictionStart.position() && restriction.isSlice()) - throw invalidRequest("PRIMARY KEY column \"%s\" cannot be restricted (preceding column \"%s\" is restricted by a non-EQ relation)", - restrictions.nextColumn(newRestrictionStart).name, - newRestrictionStart.name); - } if (restriction.isSlice() || primaryKeyRestrictions.isSlice()) this.slice = true; @@@ -141,22 -85,6 +94,15 @@@ this.eq = true; } + private List<ByteBuffer> toByteBuffers(SortedSet<? extends ClusteringPrefix> clusterings) + { + // It's currently a tad hard to follow that this is only called for partition key so we should fix that + List<ByteBuffer> l = new ArrayList<>(clusterings.size()); + for (ClusteringPrefix clustering : clusterings) + l.add(CFMetaData.serializePartitionKey(clustering)); + return l; + } + - private boolean hasSupportingIndex(Restriction restriction) - { - return cfm != null - && restriction.hasSupportingIndex(Keyspace.openAndGetStore(cfm).indexManager); - - } - @Override public boolean isSlice() { @@@ -319,16 -338,22 +265,15 @@@ for (Restriction restriction : restrictions) { -- ColumnDefinition columnDef = restriction.getFirstColumn(); - - // PrimaryKeyRestrictionSet contains only one kind of column, either partition key or clustering columns. - // Therefore we only need to check the column kind once. All the other columns will be of the same kind. - if (clusteringColumns == null) - clusteringColumns = columnDef.isClusteringColumn() ? Boolean.TRUE : Boolean.FALSE; -- // We ignore all the clustering columns that can be handled by slices. - if (!isPartitionKey && !restriction.isContains()&& position == columnDef.position()) - if (!clusteringColumns || handleInFilter(restriction, position) || restriction.hasSupportingIndex(indexManager)) ++ if (isPartitionKey || handleInFilter(restriction, position) || restriction.hasSupportingIndex(indexManager)) { - position = restriction.getLastColumn().position() + 1; - if (!restriction.hasSupportingIndex(indexManager)) - continue; - restriction.addIndexExpressionTo(expressions, indexManager, options); ++ restriction.addRowFilterTo(filter, indexManager, options); + continue; } - restriction.addRowFilterTo(filter, indexManager, options); + + if (!restriction.isSlice()) + position = restriction.getLastColumn().position() + 1; } } http://git-wip-us.apache.org/repos/asf/cassandra/blob/9244531a/src/java/org/apache/cassandra/cql3/restrictions/StatementRestrictions.java ---------------------------------------------------------------------- diff --cc src/java/org/apache/cassandra/cql3/restrictions/StatementRestrictions.java index ae0c9c4,1547210..647d22f --- a/src/java/org/apache/cassandra/cql3/restrictions/StatementRestrictions.java +++ b/src/java/org/apache/cassandra/cql3/restrictions/StatementRestrictions.java @@@ -27,22 -28,17 +27,20 @@@ import org.apache.cassandra.config.Colu import org.apache.cassandra.cql3.*; import org.apache.cassandra.cql3.functions.Function; import org.apache.cassandra.cql3.statements.Bound; +import org.apache.cassandra.cql3.statements.StatementType; import org.apache.cassandra.db.*; -import org.apache.cassandra.db.composites.Composite; -import org.apache.cassandra.db.index.SecondaryIndexManager; +import org.apache.cassandra.db.filter.RowFilter; +import org.apache.cassandra.db.marshal.AbstractType; import org.apache.cassandra.dht.*; import org.apache.cassandra.exceptions.InvalidRequestException; -import org.apache.cassandra.service.StorageService; +import org.apache.cassandra.index.Index; +import org.apache.cassandra.index.SecondaryIndexManager; +import org.apache.cassandra.net.MessagingService; import org.apache.cassandra.utils.ByteBufferUtil; +import org.apache.cassandra.utils.btree.BTreeSet; -import static org.apache.cassandra.config.ColumnDefinition.toIdentifiers; import static org.apache.cassandra.cql3.statements.RequestValidations.checkFalse; import static org.apache.cassandra.cql3.statements.RequestValidations.checkNotNull; - import static org.apache.cassandra.cql3.statements.RequestValidations.checkTrue; import static org.apache.cassandra.cql3.statements.RequestValidations.invalidRequest; /** @@@ -125,58 -110,28 +123,58 @@@ public final class StatementRestriction VariableSpecifications boundNames, boolean selectsOnlyStaticColumns, boolean selectACollection, - boolean useFiltering, - boolean allowFiltering) ++ boolean allowFiltering, + boolean forView) throws InvalidRequestException { + this.type = type; this.cfm = cfm; - this.partitionKeyRestrictions = new PrimaryKeyRestrictionSet(cfm.getKeyValidatorAsCType()); - this.clusteringColumnsRestrictions = new PrimaryKeyRestrictionSet(cfm.comparator); + this.partitionKeyRestrictions = new PrimaryKeyRestrictionSet(cfm.getKeyValidatorAsClusteringComparator(), true); - this.clusteringColumnsRestrictions = new PrimaryKeyRestrictionSet(cfm.comparator, false, cfm); ++ this.clusteringColumnsRestrictions = new PrimaryKeyRestrictionSet(cfm.comparator, false); this.nonPrimaryKeyRestrictions = new RestrictionSet(); + this.notNullColumns = new HashSet<>(); /* - * WHERE clause. For a given entity, rules are: - EQ relation conflicts with anything else (including a 2nd EQ) - * - Can't have more than one LT(E) relation (resp. GT(E) relation) - IN relation are restricted to row keys - * (for now) and conflicts with anything else (we could allow two IN for the same entity but that doesn't seem - * very useful) - The value_alias cannot be restricted in any way (we don't support wide rows with indexed value - * in CQL so far) + * WHERE clause. For a given entity, rules are: + * - EQ relation conflicts with anything else (including a 2nd EQ) + * - Can't have more than one LT(E) relation (resp. GT(E) relation) + * - IN relation are restricted to row keys (for now) and conflicts with anything else (we could + * allow two IN for the same entity but that doesn't seem very useful) + * - The value_alias cannot be restricted in any way (we don't support wide rows with indexed value + * in CQL so far) */ - for (Relation relation : whereClause) - addRestriction(relation.toRestriction(cfm, boundNames)); + for (Relation relation : whereClause.relations) + { + if (relation.operator() == Operator.IS_NOT) + { + if (!forView) + throw new InvalidRequestException("Unsupported restriction: " + relation); + + for (ColumnDefinition def : relation.toRestriction(cfm, boundNames).getColumnDefs()) + this.notNullColumns.add(def); + } + else + { + addRestriction(relation.toRestriction(cfm, boundNames)); + } + } + + boolean hasQueriableClusteringColumnIndex = false; + boolean hasQueriableIndex = false; - SecondaryIndexManager secondaryIndexManager = Keyspace.open(cfm.ksName).getColumnFamilyStore(cfm.cfName).indexManager; - boolean hasQueriableClusteringColumnIndex = clusteringColumnsRestrictions.hasSupportingIndex(secondaryIndexManager); - boolean hasQueriableIndex = hasQueriableClusteringColumnIndex - || partitionKeyRestrictions.hasSupportingIndex(secondaryIndexManager) - || nonPrimaryKeyRestrictions.hasSupportingIndex(secondaryIndexManager); + if (type.allowUseOfSecondaryIndices()) + { + ColumnFamilyStore cfs = Keyspace.open(cfm.ksName).getColumnFamilyStore(cfm.cfName); + SecondaryIndexManager secondaryIndexManager = cfs.indexManager; + + if (whereClause.containsCustomExpressions()) + processCustomIndexExpressions(whereClause.expressions, boundNames, secondaryIndexManager); + + hasQueriableClusteringColumnIndex = clusteringColumnsRestrictions.hasSupportingIndex(secondaryIndexManager); + hasQueriableIndex = !indexRestrictions.getCustomIndexExpressions().isEmpty() + || hasQueriableClusteringColumnIndex + || partitionKeyRestrictions.hasSupportingIndex(secondaryIndexManager) + || nonPrimaryKeyRestrictions.hasSupportingIndex(secondaryIndexManager); + } // At this point, the select statement if fully constructed, but we still have a few things to validate processPartitionKeyRestrictions(hasQueriableIndex); @@@ -220,19 -159,17 +218,19 @@@ // there is restrictions not covered by the PK. if (!nonPrimaryKeyRestrictions.isEmpty()) { - if (!hasQueriableIndex) + if (!type.allowNonPrimaryKeyInWhereClause()) { - // Filtering for non-index query is only supported for thrift static CFs - if (cfm.comparator.isDense() || cfm.comparator.isCompound()) - throw invalidRequest("Predicates on non-primary-key columns (%s) are not yet supported for non secondary index queries", - Joiner.on(", ").join(toIdentifiers(nonPrimaryKeyRestrictions.getColumnDefs()))); + Collection<ColumnIdentifier> nonPrimaryKeyColumns = + ColumnDefinition.toIdentifiers(nonPrimaryKeyRestrictions.getColumnDefs()); - if (!allowFiltering) - throw invalidRequest(REQUIRES_ALLOW_FILTERING_MESSAGE); + throw invalidRequest("Non PRIMARY KEY columns found in where clause: %s ", + Joiner.on(", ").join(nonPrimaryKeyColumns)); } - usesSecondaryIndexing = true; + if (hasQueriableIndex) + usesSecondaryIndexing = true; - else if (!useFiltering) ++ else if (!allowFiltering) + throw invalidRequest(StatementRestrictions.REQUIRES_ALLOW_FILTERING_MESSAGE); + indexRestrictions.add(nonPrimaryKeyRestrictions); } @@@ -435,60 -299,78 +433,93 @@@ * Processes the clustering column restrictions. * * @param hasQueriableIndex <code>true</code> if some of the queried data are indexed, <code>false</code> otherwise + * @param selectsOnlyStaticColumns <code>true</code> if the selected or modified columns are all statics, + * <code>false</code> otherwise. * @param selectACollection <code>true</code> if the query should return a collection column - * @throws InvalidRequestException if the request is invalid */ private void processClusteringColumnsRestrictions(boolean hasQueriableIndex, - boolean selectACollection) throws InvalidRequestException + boolean selectsOnlyStaticColumns, + boolean selectACollection, + boolean forView) throws InvalidRequestException { + validateClusteringRestrictions(hasQueriableIndex); + - checkFalse(clusteringColumnsRestrictions.isIN() && selectACollection, - "Cannot restrict clustering columns by IN relations when a collection is selected by the query"); - checkFalse(clusteringColumnsRestrictions.isContains() && !hasQueriableIndex, - "Cannot restrict clustering columns by a CONTAINS relation without a secondary index"); + checkFalse(!type.allowClusteringColumnSlices() && clusteringColumnsRestrictions.isSlice(), + "Slice restrictions are not supported on the clustering columns in %s statements", type); - if (hasClusteringColumnsRestriction() && clusteringRestrictionsNeedFiltering()) + if (!type.allowClusteringColumnSlices() + && (!cfm.isCompactTable() || (cfm.isCompactTable() && !hasClusteringColumnsRestriction()))) { - if (hasQueriableIndex) - { - usesSecondaryIndexing = true; - return; - } - - List<ColumnDefinition> clusteringColumns = cfm.clusteringColumns(); - List<ColumnDefinition> restrictedColumns = new LinkedList<>(clusteringColumnsRestrictions.getColumnDefs()); + if (!selectsOnlyStaticColumns && hasUnrestrictedClusteringColumns()) + throw invalidRequest("Some clustering keys are missing: %s", + Joiner.on(", ").join(getUnrestrictedClusteringColumns())); + } + else + { + checkFalse(clusteringColumnsRestrictions.isIN() && selectACollection, + "Cannot restrict clustering columns by IN relations when a collection is selected by the query"); + checkFalse(clusteringColumnsRestrictions.isContains() && !hasQueriableIndex, + "Cannot restrict clustering columns by a CONTAINS relation without a secondary index"); - for (int i = 0, m = restrictedColumns.size(); i < m; i++) + if (hasClusteringColumnsRestriction() && clusteringRestrictionsNeedFiltering()) { - ColumnDefinition clusteringColumn = clusteringColumns.get(i); - ColumnDefinition restrictedColumn = restrictedColumns.get(i); + if (hasQueriableIndex || forView) + { + usesSecondaryIndexing = true; + return; + } - if (!clusteringColumn.equals(restrictedColumn)) + List<ColumnDefinition> clusteringColumns = cfm.clusteringColumns(); + List<ColumnDefinition> restrictedColumns = new LinkedList<>(clusteringColumnsRestrictions.getColumnDefs()); + + for (int i = 0, m = restrictedColumns.size(); i < m; i++) { - throw invalidRequest( - "PRIMARY KEY column \"%s\" cannot be restricted as preceding column \"%s\" is not restricted", - restrictedColumn.name, - clusteringColumn.name); + ColumnDefinition clusteringColumn = clusteringColumns.get(i); + ColumnDefinition restrictedColumn = restrictedColumns.get(i); + + if (!clusteringColumn.equals(restrictedColumn)) + { + throw invalidRequest( + "PRIMARY KEY column \"%s\" cannot be restricted as preceding column \"%s\" is not restricted", + restrictedColumn.name, + clusteringColumn.name); + } } } } } + /** + * Validates whether or not restrictions are allowed for execution when secondary index is not used. + */ + public final void validateClusteringRestrictions(boolean hasQueriableIndex) + { + assert clusteringColumnsRestrictions instanceof PrimaryKeyRestrictionSet; + + // If there's a queriable index, filtering will take care of clustering restrictions + if (hasQueriableIndex) + return; + - Iterator<Restriction> iter = ((PrimaryKeyRestrictionSet)clusteringColumnsRestrictions).iterator(); ++ Iterator<Restriction> iter = ((PrimaryKeyRestrictionSet) clusteringColumnsRestrictions).iterator(); + Restriction previousRestriction = null; - + while (iter.hasNext()) + { + Restriction restriction = iter.next(); + + if (previousRestriction != null) + { + ColumnDefinition lastRestrictionStart = previousRestriction.getFirstColumn(); + ColumnDefinition newRestrictionStart = restriction.getFirstColumn(); + + if (previousRestriction.isSlice() && newRestrictionStart.position() > lastRestrictionStart.position()) + throw invalidRequest("Clustering column \"%s\" cannot be restricted (preceding column \"%s\" is restricted by a non-EQ relation)", + newRestrictionStart.name, + lastRestrictionStart.name); + } + previousRestriction = restriction; + } + } + public final boolean clusteringRestrictionsNeedFiltering() { assert clusteringColumnsRestrictions instanceof PrimaryKeyRestrictionSet; http://git-wip-us.apache.org/repos/asf/cassandra/blob/9244531a/test/unit/org/apache/cassandra/cql3/validation/operations/SelectMultiColumnRelationTest.java ---------------------------------------------------------------------- diff --cc test/unit/org/apache/cassandra/cql3/validation/operations/SelectMultiColumnRelationTest.java index 0db0039,0975662..ce74fe2 --- a/test/unit/org/apache/cassandra/cql3/validation/operations/SelectMultiColumnRelationTest.java +++ b/test/unit/org/apache/cassandra/cql3/validation/operations/SelectMultiColumnRelationTest.java @@@ -885,19 -874,33 +885,46 @@@ public class SelectMultiColumnRelationT } @Test + public void testMultiColumnRestrictionsWithIndex() throws Throwable + { + createTable("CREATE TABLE %s (a int, b int, c int, d int, e int, v int, PRIMARY KEY (a, b, c, d, e))"); + createIndex("CREATE INDEX ON %s (v)"); + for (int i = 1; i <= 5; i++) + { + execute("INSERT INTO %s (a,b,c,d,e,v) VALUES (?,?,?,?,?,?)", 0, i, 0, 0, 0, 0); + execute("INSERT INTO %s (a,b,c,d,e,v) VALUES (?,?,?,?,?,?)", 0, i, i, 0, 0, 0); + execute("INSERT INTO %s (a,b,c,d,e,v) VALUES (?,?,?,?,?,?)", 0, i, i, i, 0, 0); + execute("INSERT INTO %s (a,b,c,d,e,v) VALUES (?,?,?,?,?,?)", 0, i, i, i, i, 0); + execute("INSERT INTO %s (a,b,c,d,e,v) VALUES (?,?,?,?,?,?)", 0, i, i, i, i, i); + } + + String errorMsg = "Multi-column slice restrictions cannot be used for filtering."; + assertInvalidMessage(errorMsg, + "SELECT * FROM %s WHERE a = 0 AND (c,d) < (2,2) AND v = 0 ALLOW FILTERING"); + assertInvalidMessage(errorMsg, + "SELECT * FROM %s WHERE a = 0 AND (d,e) < (2,2) AND b = 1 AND v = 0 ALLOW FILTERING"); + assertInvalidMessage(errorMsg, + "SELECT * FROM %s WHERE a = 0 AND b = 1 AND (d,e) < (2,2) AND v = 0 ALLOW FILTERING"); + assertInvalidMessage(errorMsg, + "SELECT * FROM %s WHERE a = 0 AND b > 1 AND (d,e) < (2,2) AND v = 0 ALLOW FILTERING"); + assertInvalidMessage(errorMsg, + "SELECT * FROM %s WHERE a = 0 AND (b,c) > (1,0) AND (d,e) < (2,2) AND v = 0 ALLOW FILTERING"); + } + + @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 public void testMultiplePartitionKeyAndMultiClusteringWithIndex() throws Throwable { createTable("CREATE TABLE %s (a int, b int, c int, d int, e int, f int, PRIMARY KEY ((a, b), c, d, e))"); http://git-wip-us.apache.org/repos/asf/cassandra/blob/9244531a/test/unit/org/apache/cassandra/cql3/validation/operations/SelectTest.java ---------------------------------------------------------------------- diff --cc test/unit/org/apache/cassandra/cql3/validation/operations/SelectTest.java index 65bfb32,c8df4c3..1b6fe9b --- a/test/unit/org/apache/cassandra/cql3/validation/operations/SelectTest.java +++ b/test/unit/org/apache/cassandra/cql3/validation/operations/SelectTest.java @@@ -1534,6 -1450,32 +1534,24 @@@ public class SelectTest extends CQLTest } @Test - public void testFilteringOnStaticColumnWithoutIndices() throws Throwable ++ public void testIndexQueryWithCompositePartitionKey() throws Throwable + { - createTable("CREATE TABLE %s (a int, b int, s int static, c int, PRIMARY KEY (a, b))"); ++ createTable("CREATE TABLE %s (p1 int, p2 int, v int, PRIMARY KEY ((p1, p2)))"); ++ assertInvalidMessage("Partition key parts: p2 must be restricted as other parts are", ++ "SELECT * FROM %s WHERE p1 = 1 AND v = 3 ALLOW FILTERING"); + - // Checks filtering - assertInvalidMessage("Predicates on non-primary-key columns (c, s) are not yet supported for non secondary index queries", - "SELECT * FROM %s WHERE c = 1 AND s = 2 ALLOW FILTERING"); - assertInvalidMessage("Predicates on non-primary-key columns (s) are not yet supported for non secondary index queries", - "SELECT * FROM %s WHERE a = 1 AND b = 1 AND s = 2 ALLOW FILTERING"); - assertInvalidMessage("Predicates on non-primary-key columns (s) are not yet supported for non secondary index queries", - "SELECT * FROM %s WHERE s > 2 ALLOW FILTERING"); ++ createIndex("CREATE INDEX ON %s(v)"); + - // Checks filtering with null - assertInvalidMessage("Predicates on non-primary-key columns (s) are not yet supported for non secondary index queries", - "SELECT * FROM %s WHERE s = null ALLOW FILTERING"); - assertInvalidMessage("Predicates on non-primary-key columns (s) are not yet supported for non secondary index queries", - "SELECT * FROM %s WHERE s > null ALLOW FILTERING"); ++ execute("INSERT INTO %s(p1, p2, v) values (?, ?, ?)", 1, 1, 3); ++ execute("INSERT INTO %s(p1, p2, v) values (?, ?, ?)", 1, 2, 3); ++ execute("INSERT INTO %s(p1, p2, v) values (?, ?, ?)", 2, 1, 3); + - // Checks filtering with unset - assertInvalidMessage("Predicates on non-primary-key columns (s) are not yet supported for non secondary index queries", - "SELECT * FROM %s WHERE s = ? ALLOW FILTERING", unset()); - assertInvalidMessage("Predicates on non-primary-key columns (s) are not yet supported for non secondary index queries", - "SELECT * FROM %s WHERE s > ? ALLOW FILTERING", unset()); ++ assertRows(execute("SELECT * FROM %s WHERE p1 = 1 AND v = 3 ALLOW FILTERING"), ++ row(1, 2, 3), ++ row(1, 1, 3)); + } + + @Test public void testFilteringOnCompactTablesWithoutIndices() throws Throwable { //---------------------------------------------- @@@ -2515,4 -2250,93 +2533,47 @@@ row("a", 3, 5)); } } + + @Test - public void testOverlyLargeSelectPK() throws Throwable - { - createTable("CREATE TABLE %s (a text, b text, PRIMARY KEY ((a), b))"); - - assertInvalidThrow(InvalidRequestException.class, - "SELECT * FROM %s WHERE a = ?", new String(TOO_BIG.array())); - } - - @Test - public void testOverlyLargeSelectCK() throws Throwable - { - createTable("CREATE TABLE %s (a text, b text, PRIMARY KEY ((a), b))"); - - assertInvalidThrow(InvalidRequestException.class, - "SELECT * FROM %s WHERE a = 'foo' AND b = ?", new String(TOO_BIG.array())); - } - - @Test - public void testOverlyLargeSelectKeyIn() throws Throwable - { - createTable("CREATE TABLE %s (a text, b text, c text, d text, PRIMARY KEY ((a, b, c), d))"); - - assertInvalidThrow(InvalidRequestException.class, - "SELECT * FROM %s WHERE a = 'foo' AND b= 'bar' AND c IN (?, ?)", - new String(TOO_BIG.array()), new String(TOO_BIG.array())); - } - - @Test + public void testFilteringWithSecondaryIndex() throws Throwable + { + createTable("CREATE TABLE %s (pk int, " + + "c1 int, " + + "c2 int, " + + "c3 int, " + + "v int, " + + "PRIMARY KEY (pk, c1, c2, c3))"); + createIndex("CREATE INDEX v_idx_1 ON %s (v);"); + + for (int i = 1; i <= 5; i++) + { + execute("INSERT INTO %s (pk, c1, c2, c3, v) VALUES (?, ?, ?, ?, ?)", 1, 1, 1, 1, i); + execute("INSERT INTO %s (pk, c1, c2, c3, v) VALUES (?, ?, ?, ?, ?)", 1, 1, 1, i, i); + execute("INSERT INTO %s (pk, c1, c2, c3, v) VALUES (?, ?, ?, ?, ?)", 1, 1, i, i, i); + execute("INSERT INTO %s (pk, c1, c2, c3, v) VALUES (?, ?, ?, ?, ?)", 1, i, i, i, i); + } + + assertRows(execute("SELECT * FROM %s WHERE pk = 1 AND c1 > 0 AND c1 < 5 AND c2 = 1 AND v = 3 ALLOW FILTERING;"), + row(1, 1, 1, 3, 3)); + + assertEmpty(execute("SELECT * FROM %s WHERE pk = 1 AND c1 > 1 AND c1 < 5 AND c2 = 1 AND v = 3 ALLOW FILTERING;")); + + assertRows(execute("SELECT * FROM %s WHERE pk = 1 AND c1 > 1 AND c2 > 2 AND c3 > 2 AND v = 3 ALLOW FILTERING;"), + row(1, 3, 3, 3, 3)); + + assertRows(execute("SELECT * FROM %s WHERE pk = 1 AND c1 > 1 AND c2 > 2 AND c3 = 3 AND v = 3 ALLOW FILTERING;"), + row(1, 3, 3, 3, 3)); + + assertRows(execute("SELECT * FROM %s WHERE pk = 1 AND c1 IN(0,1,2) AND c2 = 1 AND v = 3 ALLOW FILTERING;"), + row(1, 1, 1, 3, 3)); + + assertRows(execute("SELECT * FROM %s WHERE pk = 1 AND c1 IN(0,1,2) AND c2 = 1 AND v = 3"), + row(1, 1, 1, 3, 3)); + + assertInvalidMessage("Clustering column \"c2\" cannot be restricted (preceding column \"c1\" is restricted by a non-EQ relation)", + "SELECT * FROM %s WHERE pk = 1 AND c1 > 0 AND c1 < 5 AND c2 = 1 ALLOW FILTERING;"); + + assertInvalidMessage("PRIMARY KEY column \"c2\" cannot be restricted as preceding column \"c1\" is not restricted", + "SELECT * FROM %s WHERE pk = 1 AND c2 = 1 ALLOW FILTERING;"); + } - - @Test - public void testIndexQueryWithCompositePartitionKey() throws Throwable - { - createTable("CREATE TABLE %s (p1 int, p2 int, v int, PRIMARY KEY ((p1, p2)))"); - assertInvalidMessage("Partition key parts: p2 must be restricted as other parts are", - "SELECT * FROM %s WHERE p1 = 1 AND v = 3 ALLOW FILTERING"); - - createIndex("CREATE INDEX ON %s(v)"); - - execute("INSERT INTO %s(p1, p2, v) values (?, ?, ?)", 1, 1, 3); - execute("INSERT INTO %s(p1, p2, v) values (?, ?, ?)", 1, 2, 3); - execute("INSERT INTO %s(p1, p2, v) values (?, ?, ?)", 2, 1, 3); - - assertRows(execute("SELECT * FROM %s WHERE p1 = 1 AND v = 3 ALLOW FILTERING"), - row(1, 2, 3), - row(1, 1, 3)); - } }