You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cassandra.apache.org by ty...@apache.org on 2015/02/10 22:09:57 UTC
[1/2] cassandra git commit: Fix multicolumn relations with indexes on
some clustering cols
Repository: cassandra
Updated Branches:
refs/heads/cassandra-2.1 ad91d4162 -> 07ffe1b12
Fix multicolumn relations with indexes on some clustering cols
Patch by Benjamin Lerer; reviewed by Tyler Hobbs for CASSANDRA-8275
Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo
Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/9649594c
Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/9649594c
Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/9649594c
Branch: refs/heads/cassandra-2.1
Commit: 9649594c761dbb72e58ddd71a10f0794378337ca
Parents: 28c380c
Author: blerer <b_...@hotmail.com>
Authored: Tue Feb 10 15:07:02 2015 -0600
Committer: Tyler Hobbs <ty...@apache.org>
Committed: Tue Feb 10 15:07:02 2015 -0600
----------------------------------------------------------------------
CHANGES.txt | 2 +
.../cql3/statements/SelectStatement.java | 46 ++++--
.../cassandra/cql3/MultiColumnRelationTest.java | 122 ++++++++++++++++
.../cql3/SingleColumnRelationTest.java | 145 +++++++++++++++++++
4 files changed, 303 insertions(+), 12 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cassandra/blob/9649594c/CHANGES.txt
----------------------------------------------------------------------
diff --git a/CHANGES.txt b/CHANGES.txt
index fa9c77d..861730f 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,4 +1,6 @@
2.0.13:
+ * Fix some multi-column relations with indexes on some clustering
+ columns (CASSANDRA-8275)
* Fix IllegalArgumentException in dynamic snitch (CASSANDRA-8448)
* Add support for UPDATE ... IF EXISTS (CASSANDRA-8610)
* Fix reversal of list prepends (CASSANDRA-8733)
http://git-wip-us.apache.org/repos/asf/cassandra/blob/9649594c/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 19615b6..2fa57b9 100644
--- a/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java
@@ -35,7 +35,6 @@ import org.apache.cassandra.cql3.CFDefinition.Name.Kind;
import org.apache.cassandra.transport.messages.ResultMessage;
import org.apache.cassandra.config.CFMetaData;
import org.apache.cassandra.db.*;
-import org.apache.cassandra.db.context.CounterContext;
import org.apache.cassandra.db.filter.*;
import org.apache.cassandra.db.marshal.*;
import org.apache.cassandra.dht.*;
@@ -83,8 +82,10 @@ public class SelectStatement implements CQLStatement, MeasurableForPreparedCache
/** Restrictions on non-primary key columns (i.e. secondary index restrictions) */
private final Map<CFDefinition.Name, Restriction> metadataRestrictions = new HashMap<CFDefinition.Name, Restriction>();
- // The name of all restricted names not covered by the key or index filter
- private final Set<CFDefinition.Name> restrictedNames = new HashSet<CFDefinition.Name>();
+ // The map keys are the name of the columns that must be converted into IndexExpressions if a secondary index need
+ // to be used. The value specify if the column has an index that can be used to for the relation in which the column
+ // is specified.
+ private final Map<CFDefinition.Name, Boolean> restrictedNames = new HashMap<CFDefinition.Name, Boolean>();
private Restriction.Slice sliceRestriction;
private boolean isReversed;
@@ -1027,7 +1028,7 @@ public class SelectStatement implements CQLStatement, MeasurableForPreparedCache
return Collections.emptyList();
List<IndexExpression> expressions = new ArrayList<IndexExpression>();
- for (CFDefinition.Name name : restrictedNames)
+ for (CFDefinition.Name name : restrictedNames.keySet())
{
Restriction restriction;
switch (name.kind)
@@ -1068,12 +1069,21 @@ public class SelectStatement implements CQLStatement, MeasurableForPreparedCache
}
else
{
- List<ByteBuffer> values = restriction.values(variables);
+ ByteBuffer value;
+ if (restriction.isMultiColumn())
+ {
+ List<ByteBuffer> values = restriction.values(variables);
+ value = values.get(name.position);
+ }
+ else
+ {
+ List<ByteBuffer> values = restriction.values(variables);
+ if (values.size() != 1)
+ throw new InvalidRequestException("IN restrictions are not supported on indexed columns");
- if (values.size() != 1)
- throw new InvalidRequestException("IN restrictions are not supported on indexed columns");
+ value = values.get(0);
+ }
- ByteBuffer value = values.get(0);
validateIndexExpressionValue(value, name);
expressions.add(new IndexExpression(name.name.key, IndexOperator.EQ, value));
}
@@ -1496,7 +1506,7 @@ public class SelectStatement implements CQLStatement, MeasurableForPreparedCache
// All (or none) of the partition key columns have been specified;
// hence there is no need to turn these restrictions into index expressions.
if (!stmt.usesSecondaryIndexing)
- stmt.restrictedNames.removeAll(cfDef.partitionKeys());
+ stmt.restrictedNames.keySet().removeAll(cfDef.partitionKeys());
if (stmt.selectsOnlyStaticColumns && stmt.hasClusteringColumnsRestriction())
throw new InvalidRequestException("Cannot restrict clustering columns when selecting only static columns");
@@ -1507,8 +1517,17 @@ public class SelectStatement implements CQLStatement, MeasurableForPreparedCache
if (stmt.isKeyRange && hasQueriableClusteringColumnIndex)
stmt.usesSecondaryIndexing = true;
- if (!stmt.usesSecondaryIndexing)
- stmt.restrictedNames.removeAll(cfDef.clusteringColumns());
+ // The clustering columns that can be used to perform a slice filtering on the secondary index do not
+ // need to be converted into IndexExpressions. Therefore, if they are not indexed by an index that support
+ // the relation in which they have been specified, we can removes them from the restrictedNames map.
+ for (Name clusteringColumn : cfDef.clusteringColumns())
+ {
+ Boolean indexed = stmt.restrictedNames.get(clusteringColumn);
+ if (indexed == null)
+ break;
+ if (!indexed)
+ stmt.restrictedNames.remove(clusteringColumn);
+ }
// Even if usesSecondaryIndexing is false at this point, we'll still have to use one if
// there is restrictions not covered by the PK.
@@ -1540,9 +1559,12 @@ public class SelectStatement implements CQLStatement, MeasurableForPreparedCache
if (name == null)
handleUnrecognizedEntity(entity, relation);
- stmt.restrictedNames.add(name);
if (cfDef.cfm.getColumnDefinition(name.name.key).isIndexed() && relation.operator() == Relation.Type.EQ)
+ {
+ stmt.restrictedNames.put(name, Boolean.TRUE);
return new boolean[]{true, name.kind == CFDefinition.Name.Kind.COLUMN_ALIAS};
+ }
+ stmt.restrictedNames.put(name, Boolean.FALSE);
return new boolean[]{false, false};
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/9649594c/test/unit/org/apache/cassandra/cql3/MultiColumnRelationTest.java
----------------------------------------------------------------------
diff --git a/test/unit/org/apache/cassandra/cql3/MultiColumnRelationTest.java b/test/unit/org/apache/cassandra/cql3/MultiColumnRelationTest.java
index ea4f1a6..30a9226 100644
--- a/test/unit/org/apache/cassandra/cql3/MultiColumnRelationTest.java
+++ b/test/unit/org/apache/cassandra/cql3/MultiColumnRelationTest.java
@@ -76,6 +76,15 @@ public class MultiColumnRelationTest
"CREATE TABLE IF NOT EXISTS %s.multiple_clustering_reversed" + tableSuffix +
"(a int, b int, c int, d int, PRIMARY KEY (a, b, c, d)) WITH " + compactOption + " CLUSTERING ORDER BY (b DESC, c ASC, d DESC)");
}
+
+ executeSchemaChange("CREATE TABLE IF NOT EXISTS %s.multiple_clustering_with_indices (a int, b int, c int, d int, e int, PRIMARY KEY (a, b, c, d))");
+ executeSchemaChange("CREATE INDEX ON %s.multiple_clustering_with_indices (b)");
+ executeSchemaChange("CREATE INDEX ON %s.multiple_clustering_with_indices (e)");
+
+ executeSchemaChange("CREATE TABLE IF NOT EXISTS %s.partition_with_indices (a int, b int, c int, d int, e int, f int, PRIMARY KEY ((a, b), c, d, e))");
+ executeSchemaChange("CREATE INDEX ON %s.partition_with_indices (c)");
+ executeSchemaChange("CREATE INDEX ON %s.partition_with_indices (f)");
+
clientState = ClientState.forInternalCalls();
}
@@ -1178,6 +1187,119 @@ public class MultiColumnRelationTest
}
}
+ @Test
+ public void testMultipleClusteringWithIndex() throws Throwable
+ {
+ execute("INSERT INTO %s.multiple_clustering_with_indices (a, b, c, d, e) VALUES (0, 0, 0, 0, 0)");
+ execute("INSERT INTO %s.multiple_clustering_with_indices (a, b, c, d, e) VALUES (0, 0, 1, 0, 1)");
+ execute("INSERT INTO %s.multiple_clustering_with_indices (a, b, c, d, e) VALUES (0, 0, 1, 1, 2)");
+ execute("INSERT INTO %s.multiple_clustering_with_indices (a, b, c, d, e) VALUES (0, 1, 0, 0, 0)");
+ execute("INSERT INTO %s.multiple_clustering_with_indices (a, b, c, d, e) VALUES (0, 1, 1, 0, 1)");
+ execute("INSERT INTO %s.multiple_clustering_with_indices (a, b, c, d, e) VALUES (0, 1, 1, 1, 2)");
+ execute("INSERT INTO %s.multiple_clustering_with_indices (a, b, c, d, e) VALUES (0, 2, 0, 0, 0)");
+
+ UntypedResultSet results = execute("SELECT * FROM %s.multiple_clustering_with_indices WHERE (b) = (1)");
+ assertEquals(3, results.size());
+ checkRow(0, results, 0, 1, 0, 0, 0);
+ checkRow(1, results, 0, 1, 1, 0, 1);
+ checkRow(2, results, 0, 1, 1, 1, 2);
+
+ results = execute("SELECT * FROM %s.multiple_clustering_with_indices WHERE (b, c) = (1, 1) ALLOW FILTERING");
+ assertEquals(2, results.size());
+ checkRow(0, results, 0, 1, 1, 0, 1);
+ checkRow(1, results, 0, 1, 1, 1, 2);
+
+ results = execute("SELECT * FROM %s.multiple_clustering_with_indices WHERE (b, c) = (1, 1) AND e = 2 ALLOW FILTERING");
+ assertEquals(1, results.size());
+ checkRow(0, results, 0, 1, 1, 1, 2);
+
+ results = execute("SELECT * FROM %s.multiple_clustering_with_indices WHERE (b) IN ((1)) AND e = 2 ALLOW FILTERING");
+ assertEquals(1, results.size());
+ checkRow(0, results, 0, 1, 1, 1, 2);
+
+ results = execute("SELECT * FROM %s.multiple_clustering_with_indices WHERE (b) IN ((0), (1)) AND e = 2 ALLOW FILTERING");
+ assertEquals(2, results.size());
+ checkRow(0, results, 0, 0, 1, 1, 2);
+ checkRow(1, results, 0, 1, 1, 1, 2);
+
+ results = execute("SELECT * FROM %s.multiple_clustering_with_indices WHERE (b, c) IN ((0, 1)) AND e = 2 ALLOW FILTERING");
+ assertEquals(1, results.size());
+ checkRow(0, results, 0, 0, 1, 1, 2);
+
+ results = execute("SELECT * FROM %s.multiple_clustering_with_indices WHERE (b, c) IN ((0, 1), (1, 1)) AND e = 2 ALLOW FILTERING");
+ assertEquals(2, results.size());
+ checkRow(0, results, 0, 0, 1, 1, 2);
+ checkRow(1, results, 0, 1, 1, 1, 2);
+
+ results = execute("SELECT * FROM %s.multiple_clustering_with_indices WHERE (b) >= (1) AND e = 2 ALLOW FILTERING");
+ assertEquals(1, results.size());
+ checkRow(0, results, 0, 1, 1, 1, 2);
+
+ results = execute("SELECT * FROM %s.multiple_clustering_with_indices WHERE (b, c) >= (1, 1) AND e = 2 ALLOW FILTERING");
+ assertEquals(1, results.size());
+ checkRow(0, results, 0, 1, 1, 1, 2);
+ }
+
+ @Test
+ public void testPartitionWithIndex() throws Throwable
+ {
+ execute("INSERT INTO %s.partition_with_indices (a, b, c, d, e, f) VALUES (0, 0, 0, 0, 0, 0)");
+ execute("INSERT INTO %s.partition_with_indices (a, b, c, d, e, f) VALUES (0, 0, 0, 1, 0, 1)");
+ execute("INSERT INTO %s.partition_with_indices (a, b, c, d, e, f) VALUES (0, 0, 0, 1, 1, 2)");
+
+ execute("INSERT INTO %s.partition_with_indices (a, b, c, d, e, f) VALUES (0, 0, 1, 0, 0, 3)");
+ execute("INSERT INTO %s.partition_with_indices (a, b, c, d, e, f) VALUES (0, 0, 1, 1, 0, 4)");
+ execute("INSERT INTO %s.partition_with_indices (a, b, c, d, e, f) VALUES (0, 0, 1, 1, 1, 5)");
+
+ execute("INSERT INTO %s.partition_with_indices (a, b, c, d, e, f) VALUES (0, 0, 2, 0, 0, 5)");
+
+ UntypedResultSet results = execute("SELECT * FROM %s.partition_with_indices WHERE a = 0 AND (c) = (1) ALLOW FILTERING");
+ assertEquals(3, results.size());
+ checkRow(0, results, 0, 0, 1, 0, 0, 3);
+ checkRow(1, results, 0, 0, 1, 1, 0, 4);
+ checkRow(2, results, 0, 0, 1, 1, 1, 5);
+
+ results = execute("SELECT * FROM %s.partition_with_indices WHERE a = 0 AND (c, d) = (1, 1) ALLOW FILTERING");
+ assertEquals(2, results.size());
+ checkRow(0, results, 0, 0, 1, 1, 0, 4);
+ checkRow(1, results, 0, 0, 1, 1, 1, 5);
+
+ results = execute("SELECT * FROM %s.partition_with_indices WHERE a = 0 AND (c) IN ((1)) AND f = 5 ALLOW FILTERING");
+ assertEquals(1, results.size());
+ checkRow(0, results, 0, 0, 1, 1, 1, 5);
+
+ results = execute("SELECT * FROM %s.partition_with_indices WHERE a = 0 AND (c) IN ((1), (2)) AND f = 5 ALLOW FILTERING");
+ assertEquals(2, results.size());
+ checkRow(0, results, 0, 0, 1, 1, 1, 5);
+ checkRow(1, results, 0, 0, 2, 0, 0, 5);
+
+ results = execute("SELECT * FROM %s.partition_with_indices WHERE a = 0 AND (c, d) IN ((1, 0)) AND f = 3 ALLOW FILTERING");
+ assertEquals(1, results.size());
+ checkRow(0, results, 0, 0, 1, 0, 0, 3);
+
+ results = execute("SELECT * FROM %s.partition_with_indices WHERE a = 0 AND (c) >= (1) AND f = 5 ALLOW FILTERING");
+ assertEquals(2, results.size());
+ checkRow(0, results, 0, 0, 1, 1, 1, 5);
+ checkRow(1, results, 0, 0, 2, 0, 0, 5);
+
+ results = execute("SELECT * FROM %s.partition_with_indices WHERE a = 0 AND (c, d) >= (1, 1) AND f = 5 ALLOW FILTERING");
+ assertEquals(2, results.size());
+ checkRow(0, results, 0, 0, 1, 1, 1, 5);
+ checkRow(1, results, 0, 0, 2, 0, 0, 5);
+ }
+
+ @Test(expected=InvalidRequestException.class)
+ public void testMissingPartitionComponentWithInRestrictionOnIndexedColumn() throws Throwable
+ {
+ execute("SELECT * FROM %s.partition_with_indices WHERE a = 0 AND (c, d) IN ((1, 1)) ALLOW FILTERING");
+ }
+
+ @Test(expected=InvalidRequestException.class)
+ public void testMissingPartitionComponentWithSliceRestrictionOnIndexedColumn() throws Throwable
+ {
+ execute("SELECT * FROM %s.partition_with_indices WHERE a = 0 AND (c, d) >= (1, 1) ALLOW FILTERING");
+ }
+
@Test(expected=InvalidRequestException.class)
public void testPrepareLiteralInWithShortTuple() throws Throwable
{
http://git-wip-us.apache.org/repos/asf/cassandra/blob/9649594c/test/unit/org/apache/cassandra/cql3/SingleColumnRelationTest.java
----------------------------------------------------------------------
diff --git a/test/unit/org/apache/cassandra/cql3/SingleColumnRelationTest.java b/test/unit/org/apache/cassandra/cql3/SingleColumnRelationTest.java
new file mode 100644
index 0000000..34d3bf1
--- /dev/null
+++ b/test/unit/org/apache/cassandra/cql3/SingleColumnRelationTest.java
@@ -0,0 +1,145 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.cassandra.cql3;
+
+import java.util.Iterator;
+import java.util.List;
+
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import org.apache.cassandra.SchemaLoader;
+import org.apache.cassandra.db.ConsistencyLevel;
+import org.apache.cassandra.exceptions.InvalidRequestException;
+import org.apache.cassandra.gms.Gossiper;
+import org.apache.cassandra.service.ClientState;
+
+import static com.google.common.collect.Lists.newArrayList;
+import static org.apache.cassandra.cql3.QueryProcessor.process;
+import static org.apache.cassandra.cql3.QueryProcessor.processInternal;
+import static org.junit.Assert.assertEquals;
+
+public class SingleColumnRelationTest
+{
+ static ClientState clientState;
+ static String keyspace = "single_column_relation_test";
+
+ @BeforeClass
+ public static void setUpClass() throws Throwable
+ {
+ SchemaLoader.loadSchema();
+ executeSchemaChange("CREATE KEYSPACE IF NOT EXISTS %s WITH replication = {'class': 'SimpleStrategy', 'replication_factor': '1'}");
+
+ executeSchemaChange("CREATE TABLE IF NOT EXISTS %s.partition_with_indices (a int, b int, c int, d int, e int, f int, PRIMARY KEY ((a, b), c, d, e))");
+ executeSchemaChange("CREATE INDEX ON %s.partition_with_indices (c)");
+ executeSchemaChange("CREATE INDEX ON %s.partition_with_indices (f)");
+
+ clientState = ClientState.forInternalCalls();
+ }
+
+ @AfterClass
+ public static void stopGossiper()
+ {
+ Gossiper.instance.stop();
+ }
+
+ private static void executeSchemaChange(String query) throws Throwable
+ {
+ try
+ {
+ process(String.format(query, keyspace), ConsistencyLevel.ONE);
+ } catch (RuntimeException exc)
+ {
+ throw exc.getCause();
+ }
+ }
+
+ private static UntypedResultSet execute(String query) throws Throwable
+ {
+ try
+ {
+ return processInternal(String.format(query, keyspace));
+ } catch (RuntimeException exc)
+ {
+ if (exc.getCause() != null)
+ throw exc.getCause();
+ throw exc;
+ }
+ }
+
+ @Test
+ public void testPartitionWithIndex() throws Throwable
+ {
+ execute("INSERT INTO %s.partition_with_indices (a, b, c, d, e, f) VALUES (0, 0, 0, 0, 0, 0)");
+ execute("INSERT INTO %s.partition_with_indices (a, b, c, d, e, f) VALUES (0, 0, 0, 1, 0, 1)");
+ execute("INSERT INTO %s.partition_with_indices (a, b, c, d, e, f) VALUES (0, 0, 0, 1, 1, 2)");
+
+ execute("INSERT INTO %s.partition_with_indices (a, b, c, d, e, f) VALUES (0, 0, 1, 0, 0, 3)");
+ execute("INSERT INTO %s.partition_with_indices (a, b, c, d, e, f) VALUES (0, 0, 1, 1, 0, 4)");
+ execute("INSERT INTO %s.partition_with_indices (a, b, c, d, e, f) VALUES (0, 0, 1, 1, 1, 5)");
+
+ execute("INSERT INTO %s.partition_with_indices (a, b, c, d, e, f) VALUES (0, 0, 2, 0, 0, 5)");
+
+ UntypedResultSet results = execute("SELECT * FROM %s.partition_with_indices WHERE a = 0 AND c = 1 ALLOW FILTERING");
+ assertEquals(3, results.size());
+ checkRow(0, results, 0, 0, 1, 0, 0, 3);
+ checkRow(1, results, 0, 0, 1, 1, 0, 4);
+ checkRow(2, results, 0, 0, 1, 1, 1, 5);
+
+ results = execute("SELECT * FROM %s.partition_with_indices WHERE a = 0 AND c = 1 AND d = 1 ALLOW FILTERING");
+ assertEquals(2, results.size());
+ checkRow(0, results, 0, 0, 1, 1, 0, 4);
+ checkRow(1, results, 0, 0, 1, 1, 1, 5);
+
+ results = execute("SELECT * FROM %s.partition_with_indices WHERE a = 0 AND c >= 1 AND f = 5 ALLOW FILTERING");
+ assertEquals(2, results.size());
+ checkRow(0, results, 0, 0, 1, 1, 1, 5);
+ checkRow(1, results, 0, 0, 2, 0, 0, 5);
+
+ results = execute("SELECT * FROM %s.partition_with_indices WHERE a = 0 AND c = 1 AND d >= 1 AND f = 5 ALLOW FILTERING");
+ assertEquals(1, results.size());
+ checkRow(0, results, 0, 0, 1, 1, 1, 5);
+ }
+
+ @Test(expected=InvalidRequestException.class)
+ public void testMissingPartitionComponentAndFileringOnTheSecondClusteringColumnWithoutAllowFiltering() throws Throwable
+ {
+ execute("SELECT * FROM %s.partition_with_indices WHERE d >= 1 AND f = 5");
+ }
+
+ @Test(expected=InvalidRequestException.class)
+ public void testMissingPartitionComponentWithSliceRestrictionOnIndexedColumn() throws Throwable
+ {
+ execute("SELECT * FROM %s.partition_with_indices WHERE a = 0 AND c >= 1 ALLOW FILTERING");
+ }
+
+ private static void checkRow(int rowIndex, UntypedResultSet results, Integer... expectedValues)
+ {
+ List<UntypedResultSet.Row> rows = newArrayList(results.iterator());
+ UntypedResultSet.Row row = rows.get(rowIndex);
+ Iterator<ColumnSpecification> columns = row.getColumns().iterator();
+ for (Integer expected : expectedValues)
+ {
+ String columnName = columns.next().name.toString();
+ int actual = row.getInt(columnName);
+ assertEquals(String.format("Expected value %d for column %s in row %d, but got %s", actual, columnName, rowIndex, expected),
+ (long) expected, actual);
+ }
+ }
+}
[2/2] cassandra git commit: Merge branch 'cassandra-2.0' into
cassandra-2.1
Posted by ty...@apache.org.
Merge branch 'cassandra-2.0' into cassandra-2.1
Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo
Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/07ffe1b1
Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/07ffe1b1
Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/07ffe1b1
Branch: refs/heads/cassandra-2.1
Commit: 07ffe1b12eb68cd51fdfc8715ffa7df14381df3a
Parents: ad91d41 9649594
Author: Tyler Hobbs <ty...@apache.org>
Authored: Tue Feb 10 15:09:39 2015 -0600
Committer: Tyler Hobbs <ty...@apache.org>
Committed: Tue Feb 10 15:09:39 2015 -0600
----------------------------------------------------------------------
CHANGES.txt | 3 +
.../cql3/statements/SelectStatement.java | 58 ++++++------
.../cassandra/cql3/MultiColumnRelationTest.java | 94 ++++++++++++++++++++
.../cql3/SingleColumnRelationTest.java | 40 +++++++++
4 files changed, 170 insertions(+), 25 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cassandra/blob/07ffe1b1/CHANGES.txt
----------------------------------------------------------------------
diff --cc CHANGES.txt
index 92ee5d1,861730f..2113349
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@@ -1,96 -1,6 +1,99 @@@
-2.0.13:
+2.1.4
+ * Write partition size estimates into a system table (CASSANDRA-7688)
+ * cqlsh: Fix keys() and full() collection indexes in DESCRIBE output
+ (CASSANDRA-8154)
++Merged from 2.0:
+ * Fix some multi-column relations with indexes on some clustering
+ columns (CASSANDRA-8275)
+
+
+2.1.3
+ * Upgrade libthrift to 0.9.2 (CASSANDRA-8685)
+ * Don't use the shared ref in sstableloader (CASSANDRA-8704)
+ * Purge internal prepared statements if related tables or
+ keyspaces are dropped (CASSANDRA-8693)
+ * (cqlsh) Handle unicode BOM at start of files (CASSANDRA-8638)
+ * Stop compactions before exiting offline tools (CASSANDRA-8623)
+ * Update tools/stress/README.txt to match current behaviour (CASSANDRA-7933)
+ * Fix schema from Thrift conversion with empty metadata (CASSANDRA-8695)
+ * Safer Resource Management (CASSANDRA-7705)
+ * Make sure we compact highly overlapping cold sstables with
+ STCS (CASSANDRA-8635)
+ * rpc_interface and listen_interface generate NPE on startup when specified
+ interface doesn't exist (CASSANDRA-8677)
+ * Fix ArrayIndexOutOfBoundsException in nodetool cfhistograms (CASSANDRA-8514)
+ * Switch from yammer metrics for nodetool cf/proxy histograms (CASSANDRA-8662)
+ * Make sure we don't add tmplink files to the compaction
+ strategy (CASSANDRA-8580)
+ * (cqlsh) Handle maps with blob keys (CASSANDRA-8372)
+ * (cqlsh) Handle DynamicCompositeType schemas correctly (CASSANDRA-8563)
+ * Duplicate rows returned when in clause has repeated values (CASSANDRA-6706)
+ * Add tooling to detect hot partitions (CASSANDRA-7974)
+ * Fix cassandra-stress user-mode truncation of partition generation (CASSANDRA-8608)
+ * Only stream from unrepaired sstables during inc repair (CASSANDRA-8267)
+ * Don't allow starting multiple inc repairs on the same sstables (CASSANDRA-8316)
+ * Invalidate prepared BATCH statements when related tables
+ or keyspaces are dropped (CASSANDRA-8652)
+ * Fix missing results in secondary index queries on collections
+ with ALLOW FILTERING (CASSANDRA-8421)
+ * Expose EstimatedHistogram metrics for range slices (CASSANDRA-8627)
+ * (cqlsh) Escape clqshrc passwords properly (CASSANDRA-8618)
+ * Fix NPE when passing wrong argument in ALTER TABLE statement (CASSANDRA-8355)
+ * Pig: Refactor and deprecate CqlStorage (CASSANDRA-8599)
+ * Don't reuse the same cleanup strategy for all sstables (CASSANDRA-8537)
+ * Fix case-sensitivity of index name on CREATE and DROP INDEX
+ statements (CASSANDRA-8365)
+ * Better detection/logging for corruption in compressed sstables (CASSANDRA-8192)
+ * Use the correct repairedAt value when closing writer (CASSANDRA-8570)
+ * (cqlsh) Handle a schema mismatch being detected on startup (CASSANDRA-8512)
+ * Properly calculate expected write size during compaction (CASSANDRA-8532)
+ * Invalidate affected prepared statements when a table's columns
+ are altered (CASSANDRA-7910)
+ * Stress - user defined writes should populate sequentally (CASSANDRA-8524)
+ * Fix regression in SSTableRewriter causing some rows to become unreadable
+ during compaction (CASSANDRA-8429)
+ * Run major compactions for repaired/unrepaired in parallel (CASSANDRA-8510)
+ * (cqlsh) Fix compression options in DESCRIBE TABLE output when compression
+ is disabled (CASSANDRA-8288)
+ * (cqlsh) Fix DESCRIBE output after keyspaces are altered (CASSANDRA-7623)
+ * Make sure we set lastCompactedKey correctly (CASSANDRA-8463)
+ * (cqlsh) Fix output of CONSISTENCY command (CASSANDRA-8507)
+ * (cqlsh) Fixed the handling of LIST statements (CASSANDRA-8370)
+ * Make sstablescrub check leveled manifest again (CASSANDRA-8432)
+ * Check first/last keys in sstable when giving out positions (CASSANDRA-8458)
+ * Disable mmap on Windows (CASSANDRA-6993)
+ * Add missing ConsistencyLevels to cassandra-stress (CASSANDRA-8253)
+ * Add auth support to cassandra-stress (CASSANDRA-7985)
+ * Fix ArrayIndexOutOfBoundsException when generating error message
+ for some CQL syntax errors (CASSANDRA-8455)
+ * Scale memtable slab allocation logarithmically (CASSANDRA-7882)
+ * cassandra-stress simultaneous inserts over same seed (CASSANDRA-7964)
+ * Reduce cassandra-stress sampling memory requirements (CASSANDRA-7926)
+ * Ensure memtable flush cannot expire commit log entries from its future (CASSANDRA-8383)
+ * Make read "defrag" async to reclaim memtables (CASSANDRA-8459)
+ * Remove tmplink files for offline compactions (CASSANDRA-8321)
+ * Reduce maxHintsInProgress (CASSANDRA-8415)
+ * BTree updates may call provided update function twice (CASSANDRA-8018)
+ * Release sstable references after anticompaction (CASSANDRA-8386)
+ * Handle abort() in SSTableRewriter properly (CASSANDRA-8320)
+ * Fix high size calculations for prepared statements (CASSANDRA-8231)
+ * Centralize shared executors (CASSANDRA-8055)
+ * Fix filtering for CONTAINS (KEY) relations on frozen collection
+ clustering columns when the query is restricted to a single
+ partition (CASSANDRA-8203)
+ * Do more aggressive entire-sstable TTL expiry checks (CASSANDRA-8243)
+ * Add more log info if readMeter is null (CASSANDRA-8238)
+ * add check of the system wall clock time at startup (CASSANDRA-8305)
+ * Support for frozen collections (CASSANDRA-7859)
+ * Fix overflow on histogram computation (CASSANDRA-8028)
+ * Have paxos reuse the timestamp generation of normal queries (CASSANDRA-7801)
+ * Fix incremental repair not remove parent session on remote (CASSANDRA-8291)
+ * Improve JBOD disk utilization (CASSANDRA-7386)
+ * Log failed host when preparing incremental repair (CASSANDRA-8228)
+ * Force config client mode in CQLSSTableWriter (CASSANDRA-8281)
+ * Fix sstableupgrade throws exception (CASSANDRA-8688)
+ * Fix hang when repairing empty keyspace (CASSANDRA-8694)
+Merged from 2.0:
* Fix IllegalArgumentException in dynamic snitch (CASSANDRA-8448)
* Add support for UPDATE ... IF EXISTS (CASSANDRA-8610)
* Fix reversal of list prepends (CASSANDRA-8733)
http://git-wip-us.apache.org/repos/asf/cassandra/blob/07ffe1b1/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/cql3/statements/SelectStatement.java
index 633d43c,2fa57b9..08777c7
--- a/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java
@@@ -85,10 -80,12 +85,12 @@@ public class SelectStatement implement
private final Restriction[] columnRestrictions;
/** Restrictions on non-primary key columns (i.e. secondary index restrictions) */
- private final Map<CFDefinition.Name, Restriction> metadataRestrictions = new HashMap<CFDefinition.Name, Restriction>();
+ private final Map<ColumnIdentifier, Restriction> metadataRestrictions = new HashMap<ColumnIdentifier, Restriction>();
- // All restricted columns not covered by the key or index filter
- private final Set<ColumnDefinition> restrictedColumns = new HashSet<ColumnDefinition>();
+ // The map keys are the name of the columns that must be converted into IndexExpressions if a secondary index need
+ // to be used. The value specify if the column has an index that can be used to for the relation in which the column
+ // is specified.
- private final Map<CFDefinition.Name, Boolean> restrictedNames = new HashMap<CFDefinition.Name, Boolean>();
++ private final Map<ColumnDefinition, Boolean> restrictedColumns = new HashMap<ColumnDefinition, Boolean>();
private Restriction.Slice sliceRestriction;
private boolean isReversed;
@@@ -1059,23 -1028,23 +1061,23 @@@
return Collections.emptyList();
List<IndexExpression> expressions = new ArrayList<IndexExpression>();
- for (ColumnDefinition def : restrictedColumns)
- for (CFDefinition.Name name : restrictedNames.keySet())
++ for (ColumnDefinition def : restrictedColumns.keySet())
{
Restriction restriction;
- switch (name.kind)
+ switch (def.kind)
{
- case KEY_ALIAS:
- restriction = keyRestrictions[name.position];
+ case PARTITION_KEY:
+ restriction = keyRestrictions[def.position()];
break;
- case COLUMN_ALIAS:
- restriction = columnRestrictions[name.position];
+ case CLUSTERING_COLUMN:
+ restriction = columnRestrictions[def.position()];
break;
- case COLUMN_METADATA:
+ case REGULAR:
case STATIC:
- restriction = metadataRestrictions.get(name);
+ restriction = metadataRestrictions.get(def.name);
break;
default:
- // We don't allow restricting a VALUE_ALIAS for now in prepare.
+ // We don't allow restricting a COMPACT_VALUE for now in prepare.
throw new AssertionError();
}
@@@ -1097,39 -1067,27 +1099,49 @@@
}
}
}
+ else if (restriction.isContains())
+ {
+ SingleColumnRestriction.Contains contains = (SingleColumnRestriction.Contains)restriction;
+ for (ByteBuffer value : contains.values(options))
+ {
+ validateIndexedValue(def, value);
+ expressions.add(new IndexExpression(def.name.bytes, Operator.CONTAINS, value));
+ }
+ for (ByteBuffer key : contains.keys(options))
+ {
+ validateIndexedValue(def, key);
+ expressions.add(new IndexExpression(def.name.bytes, Operator.CONTAINS_KEY, key));
+ }
+ }
else
{
- List<ByteBuffer> values = restriction.values(options);
+ ByteBuffer value;
+ if (restriction.isMultiColumn())
+ {
- List<ByteBuffer> values = restriction.values(variables);
- value = values.get(name.position);
++ List<ByteBuffer> values = restriction.values(options);
++ value = values.get(def.position());
+ }
+ else
+ {
- List<ByteBuffer> values = restriction.values(variables);
++ List<ByteBuffer> values = restriction.values(options);
+ if (values.size() != 1)
+ throw new InvalidRequestException("IN restrictions are not supported on indexed columns");
- if (values.size() != 1)
- throw new InvalidRequestException("IN restrictions are not supported on indexed columns");
+ value = values.get(0);
+ }
- ByteBuffer value = validateIndexedValue(def, values.get(0));
- validateIndexExpressionValue(value, name);
- expressions.add(new IndexExpression(name.name.key, IndexOperator.EQ, value));
++ validateIndexedValue(def, value);
+ expressions.add(new IndexExpression(def.name.bytes, Operator.EQ, value));
}
}
+
+ if (usesSecondaryIndexing)
+ {
+ ColumnFamilyStore cfs = Keyspace.open(keyspace()).getColumnFamilyStore(columnFamily());
+ SecondaryIndexManager secondaryIndexManager = cfs.indexManager;
+ secondaryIndexManager.validateIndexSearchersForQuery(expressions);
+ }
+
return expressions;
}
@@@ -1503,7 -1506,7 +1515,7 @@@
// All (or none) of the partition key columns have been specified;
// hence there is no need to turn these restrictions into index expressions.
if (!stmt.usesSecondaryIndexing)
- stmt.restrictedColumns.removeAll(cfm.partitionKeyColumns());
- stmt.restrictedNames.keySet().removeAll(cfDef.partitionKeys());
++ stmt.restrictedColumns.keySet().removeAll(cfm.partitionKeyColumns());
if (stmt.selectsOnlyStaticColumns && stmt.hasClusteringColumnsRestriction())
throw new InvalidRequestException("Cannot restrict clustering columns when selecting only static columns");
@@@ -1514,21 -1517,16 +1526,15 @@@
if (stmt.isKeyRange && hasQueriableClusteringColumnIndex)
stmt.usesSecondaryIndexing = true;
- if (!stmt.usesSecondaryIndexing)
- // The clustering columns that can be used to perform a slice filtering on the secondary index do not
- // need to be converted into IndexExpressions. Therefore, if they are not indexed by an index that support
- // the relation in which they have been specified, we can removes them from the restrictedNames map.
- for (Name clusteringColumn : cfDef.clusteringColumns())
++ for (ColumnDefinition def : cfm.clusteringColumns())
{
- for (ColumnDefinition def : cfm.clusteringColumns())
- {
- // Remove clustering column restrictions that can be handled by slices; the remainder will be
- // handled by filters (which may require a secondary index).
- Restriction restriction = stmt.columnRestrictions[def.position()];
- if (restriction != null)
- {
- if (restriction.canEvaluateWithSlices())
- stmt.restrictedColumns.remove(def);
- else
- stmt.usesSecondaryIndexing = true;
- }
- }
- Boolean indexed = stmt.restrictedNames.get(clusteringColumn);
++ // Remove clustering column restrictions that can be handled by slices; the remainder will be
++ // handled by filters (which may require a secondary index).
++ Boolean indexed = stmt.restrictedColumns.get(def);
+ if (indexed == null)
+ break;
- if (!indexed)
- stmt.restrictedNames.remove(clusteringColumn);
++ if (!indexed && stmt.columnRestrictions[def.position()].canEvaluateWithSlices())
++ stmt.restrictedColumns.remove(def);
}
// Even if usesSecondaryIndexing is false at this point, we'll still have to use one if
@@@ -1551,21 -1553,18 +1557,23 @@@
}
/** Returns a pair of (hasQueriableIndex, hasQueriableClusteringColumnIndex) */
- private boolean[] processRelationEntity(SelectStatement stmt, Relation relation, ColumnIdentifier entity, CFDefinition cfDef) throws InvalidRequestException
+ private boolean[] processRelationEntity(SelectStatement stmt,
+ SecondaryIndexManager indexManager,
+ Relation relation,
+ ColumnIdentifier entity,
+ ColumnDefinition def) throws InvalidRequestException
{
- CFDefinition.Name name = cfDef.get(entity);
- if (name == null)
+ if (def == null)
handleUnrecognizedEntity(entity, relation);
- stmt.restrictedColumns.add(def);
-
- if (cfDef.cfm.getColumnDefinition(name.name.key).isIndexed() && relation.operator() == Relation.Type.EQ)
+ SecondaryIndex index = indexManager.getIndexForColumn(def.name.bytes);
+ if (index != null && index.supportsOperator(relation.operator()))
+ {
- stmt.restrictedNames.put(name, Boolean.TRUE);
- return new boolean[]{true, name.kind == CFDefinition.Name.Kind.COLUMN_ALIAS};
++ stmt.restrictedColumns.put(def, Boolean.TRUE);
+ return new boolean[]{true, def.kind == ColumnDefinition.Kind.CLUSTERING_COLUMN};
+ }
- stmt.restrictedNames.put(name, Boolean.FALSE);
+
++ stmt.restrictedColumns.put(def, Boolean.FALSE);
return new boolean[]{false, false};
}
@@@ -2134,38 -2126,7 +2142,38 @@@
}
}
- private SingleColumnRelation findInclusiveClusteringRelationForCompact(CFDefinition cfDef)
+ /**
+ * Checks if the specified statement will need to filter the data.
+ *
+ * @param stmt the statement to test.
+ * @return <code>true</code> if the specified statement will need to filter the data, <code>false</code>
+ * otherwise.
+ */
+ private static boolean needFiltering(SelectStatement stmt)
+ {
+ return stmt.restrictedColumns.size() > 1
+ || (stmt.restrictedColumns.isEmpty() && !stmt.columnFilterIsIdentity())
+ || (!stmt.restrictedColumns.isEmpty()
- && stmt.isRestrictedByMultipleContains(Iterables.getOnlyElement(stmt.restrictedColumns)));
++ && stmt.isRestrictedByMultipleContains(Iterables.getOnlyElement(stmt.restrictedColumns.keySet())));
+ }
+
+ private int indexOf(ColumnDefinition def, Selection selection)
+ {
+ return indexOf(def, selection.getColumns().iterator());
+ }
+
+ private int indexOf(final ColumnDefinition def, Iterator<ColumnDefinition> defs)
+ {
+ return Iterators.indexOf(defs, new Predicate<ColumnDefinition>()
+ {
+ public boolean apply(ColumnDefinition n)
+ {
+ return def.name.equals(n.name);
+ }
+ });
+ }
+
+ private SingleColumnRelation findInclusiveClusteringRelationForCompact(CFMetaData cfm)
{
for (Relation r : whereClause)
{
http://git-wip-us.apache.org/repos/asf/cassandra/blob/07ffe1b1/test/unit/org/apache/cassandra/cql3/MultiColumnRelationTest.java
----------------------------------------------------------------------
diff --cc test/unit/org/apache/cassandra/cql3/MultiColumnRelationTest.java
index 4c3ba2a,30a9226..25df030
--- a/test/unit/org/apache/cassandra/cql3/MultiColumnRelationTest.java
+++ b/test/unit/org/apache/cassandra/cql3/MultiColumnRelationTest.java
@@@ -469,90 -1140,233 +469,184 @@@ public class MultiColumnRelationTest ex
}
@Test
- public void testPrepareInOneMarker() throws Throwable
+ public void testMultipleClusteringReversedComponents() throws Throwable
{
- for (String tableSuffix : new String[]{"", "_compact"})
+ for (String compactOption : new String[]{"", " COMPACT STORAGE AND"})
{
- execute("INSERT INTO %s.multiple_clustering" + tableSuffix + " (a, b, c, d) VALUES (0, 0, 0, 0)");
- execute("INSERT INTO %s.multiple_clustering" + tableSuffix + " (a, b, c, d) VALUES (0, 0, 1, 0)");
- execute("INSERT INTO %s.multiple_clustering" + tableSuffix + " (a, b, c, d) VALUES (0, 0, 1, 1)");
+ createTable("CREATE TABLE %s (a int, b int, c int, d int, PRIMARY KEY (a, b, c, d)) WITH" + compactOption + " CLUSTERING ORDER BY (b DESC, c ASC, d DESC)");
- UntypedResultSet results = executePrepared(prepare(
- "SELECT * FROM %s.multiple_clustering" + tableSuffix + " WHERE a=0 AND (b, c, d) IN ?"),
- options(list(tuple(0, 1, 0), tuple(0, 1, 1))));
- assertEquals(2, results.size());
- checkRow(0, results, 0, 0, 1, 0);
- checkRow(1, results, 0, 0, 1, 1);
+ // b and d are reversed in the clustering order
+ execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 0, 1, 0, 0);
+ execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 0, 1, 1, 1);
+ execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 0, 1, 1, 0);
+
+ execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 0, 0, 0, 0);
+ execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 0, 0, 1, 1);
+ execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 0, 0, 1, 0);
+
+
+ assertRows(execute("SELECT * FROM %s WHERE a = ? AND (b) > (?)", 0, 0),
+ row(0, 1, 0, 0),
+ row(0, 1, 1, 1),
+ row(0, 1, 1, 0)
+ );
+
+ assertRows(execute("SELECT * FROM %s WHERE a = ? AND (b) >= (?)", 0, 0),
+ row(0, 1, 0, 0),
+ row(0, 1, 1, 1),
+ row(0, 1, 1, 0),
+ row(0, 0, 0, 0),
+ row(0, 0, 1, 1),
+ row(0, 0, 1, 0)
+ );
+
+ assertRows(execute("SELECT * FROM %s WHERE a = ? AND (b) < (?)", 0, 1),
+ row(0, 0, 0, 0),
+ row(0, 0, 1, 1),
+ row(0, 0, 1, 0)
+ );
+
+ assertRows(execute("SELECT * FROM %s WHERE a = ? AND (b) <= (?)", 0, 1),
+ row(0, 1, 0, 0),
+ row(0, 1, 1, 1),
+ row(0, 1, 1, 0),
+ row(0, 0, 0, 0),
+ row(0, 0, 1, 1),
+ row(0, 0, 1, 0)
+ );
+
+ assertRows(execute("SELECT * FROM %s WHERE a=? AND (b, c, d) IN ((?, ?, ?), (?, ?, ?))", 0, 1, 1, 1, 0, 1, 1),
+ row(0, 1, 1, 1),
+ row(0, 0, 1, 1)
+ );
// same query, but reversed order for the IN values
- results = executePrepared(prepare(
- "SELECT * FROM %s.multiple_clustering" + tableSuffix + " WHERE a=0 AND (b, c, d) IN ?"),
- options(list(tuple(0, 1, 1), tuple(0, 1, 0))));
- assertEquals(2, results.size());
- checkRow(0, results, 0, 0, 1, 0);
- checkRow(1, results, 0, 0, 1, 1);
-
- results = executePrepared(prepare(
- "SELECT * FROM %s.multiple_clustering" + tableSuffix + " WHERE a=0 AND (b, c, d) IN ?"),
- options(list()));
- assertTrue(results.isEmpty());
-
- results = executePrepared(prepare("SELECT * FROM %s.multiple_clustering" + tableSuffix + " WHERE a=0 and (b, c) IN ?"),
- options(list(tuple(0, 1))));
- assertEquals(2, results.size());
- checkRow(0, results, 0, 0, 1, 0);
- checkRow(1, results, 0, 0, 1, 1);
-
- results = executePrepared(prepare("SELECT * FROM %s.multiple_clustering" + tableSuffix + " WHERE a=0 and (b) IN ?"),
- options(list(tuple(0))));
- assertEquals(3, results.size());
- checkRow(0, results, 0, 0, 0, 0);
- checkRow(1, results, 0, 0, 1, 0);
- checkRow(2, results, 0, 0, 1, 1);
-
- results = executePrepared(prepare("SELECT * FROM %s.multiple_clustering" + tableSuffix + " WHERE a=0 and (b) IN ?"),
- options(list()));
- assertTrue(results.isEmpty());
+ assertRows(execute("SELECT * FROM %s WHERE a=? AND (b, c, d) IN ((?, ?, ?), (?, ?, ?))", 0, 0, 1, 1, 1, 1, 1),
+ row(0, 1, 1, 1),
+ row(0, 0, 1, 1)
+ );
+
+ assertRows(execute("SELECT * FROM %s WHERE a = ? AND (b, c, d) IN (?, ?, ?, ?, ?, ?)",
+ 0, tuple(1, 0, 0), tuple(1, 1, 1), tuple(1, 1, 0), tuple(0, 0, 0), tuple(0, 1, 1), tuple(0, 1, 0)),
+ row(0, 1, 0, 0),
+ row(0, 1, 1, 1),
+ row(0, 1, 1, 0),
+ row(0, 0, 0, 0),
+ row(0, 0, 1, 1),
+ row(0, 0, 1, 0)
+ );
+
+ assertRows(execute("SELECT * FROM %s WHERE a = ? AND (b, c) IN (?)", 0, tuple(0, 1)),
+ row(0, 0, 1, 1),
+ row(0, 0, 1, 0)
+ );
+
+ assertRows(execute("SELECT * FROM %s WHERE a = ? AND (b, c) IN (?)", 0, tuple(0, 0)),
+ row(0, 0, 0, 0)
+ );
+
+ assertRows(execute("SELECT * FROM %s WHERE a = ? AND (b) IN ((?))", 0, 0),
+ row(0, 0, 0, 0),
+ row(0, 0, 1, 1),
+ row(0, 0, 1, 0)
+ );
+
+ // preserve pre-6875 behavior (even though the query result is technically incorrect)
+ assertEmpty(execute("SELECT * FROM %s WHERE a = ? AND (b, c) > (?, ?)", 0, 1, 0));
}
}
+
+ @Test
+ public void testMultipleClusteringWithIndex() throws Throwable
+ {
- execute("INSERT INTO %s.multiple_clustering_with_indices (a, b, c, d, e) VALUES (0, 0, 0, 0, 0)");
- execute("INSERT INTO %s.multiple_clustering_with_indices (a, b, c, d, e) VALUES (0, 0, 1, 0, 1)");
- execute("INSERT INTO %s.multiple_clustering_with_indices (a, b, c, d, e) VALUES (0, 0, 1, 1, 2)");
- execute("INSERT INTO %s.multiple_clustering_with_indices (a, b, c, d, e) VALUES (0, 1, 0, 0, 0)");
- execute("INSERT INTO %s.multiple_clustering_with_indices (a, b, c, d, e) VALUES (0, 1, 1, 0, 1)");
- execute("INSERT INTO %s.multiple_clustering_with_indices (a, b, c, d, e) VALUES (0, 1, 1, 1, 2)");
- execute("INSERT INTO %s.multiple_clustering_with_indices (a, b, c, d, e) VALUES (0, 2, 0, 0, 0)");
-
- UntypedResultSet results = execute("SELECT * FROM %s.multiple_clustering_with_indices WHERE (b) = (1)");
- assertEquals(3, results.size());
- checkRow(0, results, 0, 1, 0, 0, 0);
- checkRow(1, results, 0, 1, 1, 0, 1);
- checkRow(2, results, 0, 1, 1, 1, 2);
-
- results = execute("SELECT * FROM %s.multiple_clustering_with_indices WHERE (b, c) = (1, 1) ALLOW FILTERING");
- assertEquals(2, results.size());
- checkRow(0, results, 0, 1, 1, 0, 1);
- checkRow(1, results, 0, 1, 1, 1, 2);
-
- results = execute("SELECT * FROM %s.multiple_clustering_with_indices WHERE (b, c) = (1, 1) AND e = 2 ALLOW FILTERING");
- assertEquals(1, results.size());
- checkRow(0, results, 0, 1, 1, 1, 2);
-
- results = execute("SELECT * FROM %s.multiple_clustering_with_indices WHERE (b) IN ((1)) AND e = 2 ALLOW FILTERING");
- assertEquals(1, results.size());
- checkRow(0, results, 0, 1, 1, 1, 2);
-
- results = execute("SELECT * FROM %s.multiple_clustering_with_indices WHERE (b) IN ((0), (1)) AND e = 2 ALLOW FILTERING");
- assertEquals(2, results.size());
- checkRow(0, results, 0, 0, 1, 1, 2);
- checkRow(1, results, 0, 1, 1, 1, 2);
-
- results = execute("SELECT * FROM %s.multiple_clustering_with_indices WHERE (b, c) IN ((0, 1)) AND e = 2 ALLOW FILTERING");
- assertEquals(1, results.size());
- checkRow(0, results, 0, 0, 1, 1, 2);
-
- results = execute("SELECT * FROM %s.multiple_clustering_with_indices WHERE (b, c) IN ((0, 1), (1, 1)) AND e = 2 ALLOW FILTERING");
- assertEquals(2, results.size());
- checkRow(0, results, 0, 0, 1, 1, 2);
- checkRow(1, results, 0, 1, 1, 1, 2);
-
- results = execute("SELECT * FROM %s.multiple_clustering_with_indices WHERE (b) >= (1) AND e = 2 ALLOW FILTERING");
- assertEquals(1, results.size());
- checkRow(0, results, 0, 1, 1, 1, 2);
-
- results = execute("SELECT * FROM %s.multiple_clustering_with_indices WHERE (b, c) >= (1, 1) AND e = 2 ALLOW FILTERING");
- assertEquals(1, results.size());
- checkRow(0, results, 0, 1, 1, 1, 2);
++ createTable("CREATE TABLE %s (a int, b int, c int, d int, e int, PRIMARY KEY (a, b, c, d))");
++ createIndex("CREATE INDEX ON %s (b)");
++ createIndex("CREATE INDEX ON %s (e)");
++ execute("INSERT INTO %s (a, b, c, d, e) VALUES (?, ?, ?, ?, ?)", 0, 0, 0, 0, 0);
++ execute("INSERT INTO %s (a, b, c, d, e) VALUES (?, ?, ?, ?, ?)", 0, 0, 1, 0, 1);
++ execute("INSERT INTO %s (a, b, c, d, e) VALUES (?, ?, ?, ?, ?)", 0, 0, 1, 1, 2);
++ execute("INSERT INTO %s (a, b, c, d, e) VALUES (?, ?, ?, ?, ?)", 0, 1, 0, 0, 0);
++ execute("INSERT INTO %s (a, b, c, d, e) VALUES (?, ?, ?, ?, ?)", 0, 1, 1, 0, 1);
++ execute("INSERT INTO %s (a, b, c, d, e) VALUES (?, ?, ?, ?, ?)", 0, 1, 1, 1, 2);
++ execute("INSERT INTO %s (a, b, c, d, e) VALUES (?, ?, ?, ?, ?)", 0, 2, 0, 0, 0);
++ assertRows(execute("SELECT * FROM %s WHERE (b) = (?)", 1),
++ row(0, 1, 0, 0, 0),
++ row(0, 1, 1, 0, 1),
++ row(0, 1, 1, 1, 2));
++ assertRows(execute("SELECT * FROM %s WHERE (b, c) = (?, ?) ALLOW FILTERING", 1, 1),
++ row(0, 1, 1, 0, 1),
++ row(0, 1, 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 (b) IN ((?)) AND e = ?", 1, 2),
++ row(0, 1, 1, 1, 2));
++
++ assertRows(execute("SELECT * FROM %s WHERE (b) IN ((?), (?)) AND e = ?", 0, 1, 2),
++ row(0, 0, 1, 1, 2),
++ row(0, 1, 1, 1, 2));
++
++ assertRows(execute("SELECT * FROM %s WHERE (b, c) IN ((?, ?)) AND e = ?", 0, 1, 2),
++ row(0, 0, 1, 1, 2));
++
++ assertRows(execute("SELECT * FROM %s WHERE (b, c) IN ((?, ?), (?, ?)) AND e = ?", 0, 1, 1, 1, 2),
++ row(0, 0, 1, 1, 2),
++ row(0, 1, 1, 1, 2));
++
++ assertRows(execute("SELECT * FROM %s WHERE (b) >= (?) AND e = ?", 1, 2),
++ row(0, 1, 1, 1, 2));
++
++ assertRows(execute("SELECT * FROM %s WHERE (b, c) >= (?, ?) AND e = ?", 1, 1, 2),
++ row(0, 1, 1, 1, 2));
+ }
+
+ @Test
- public void testPartitionWithIndex() throws Throwable
++ public void testMultiplePartitionKeyAndMultiClusteringWithIndex() throws Throwable
+ {
- execute("INSERT INTO %s.partition_with_indices (a, b, c, d, e, f) VALUES (0, 0, 0, 0, 0, 0)");
- execute("INSERT INTO %s.partition_with_indices (a, b, c, d, e, f) VALUES (0, 0, 0, 1, 0, 1)");
- execute("INSERT INTO %s.partition_with_indices (a, b, c, d, e, f) VALUES (0, 0, 0, 1, 1, 2)");
-
- execute("INSERT INTO %s.partition_with_indices (a, b, c, d, e, f) VALUES (0, 0, 1, 0, 0, 3)");
- execute("INSERT INTO %s.partition_with_indices (a, b, c, d, e, f) VALUES (0, 0, 1, 1, 0, 4)");
- execute("INSERT INTO %s.partition_with_indices (a, b, c, d, e, f) VALUES (0, 0, 1, 1, 1, 5)");
-
- execute("INSERT INTO %s.partition_with_indices (a, b, c, d, e, f) VALUES (0, 0, 2, 0, 0, 5)");
-
- UntypedResultSet results = execute("SELECT * FROM %s.partition_with_indices WHERE a = 0 AND (c) = (1) ALLOW FILTERING");
- assertEquals(3, results.size());
- checkRow(0, results, 0, 0, 1, 0, 0, 3);
- checkRow(1, results, 0, 0, 1, 1, 0, 4);
- checkRow(2, results, 0, 0, 1, 1, 1, 5);
-
- results = execute("SELECT * FROM %s.partition_with_indices WHERE a = 0 AND (c, d) = (1, 1) ALLOW FILTERING");
- assertEquals(2, results.size());
- checkRow(0, results, 0, 0, 1, 1, 0, 4);
- checkRow(1, results, 0, 0, 1, 1, 1, 5);
-
- results = execute("SELECT * FROM %s.partition_with_indices WHERE a = 0 AND (c) IN ((1)) AND f = 5 ALLOW FILTERING");
- assertEquals(1, results.size());
- checkRow(0, results, 0, 0, 1, 1, 1, 5);
-
- results = execute("SELECT * FROM %s.partition_with_indices WHERE a = 0 AND (c) IN ((1), (2)) AND f = 5 ALLOW FILTERING");
- assertEquals(2, results.size());
- checkRow(0, results, 0, 0, 1, 1, 1, 5);
- checkRow(1, results, 0, 0, 2, 0, 0, 5);
-
- results = execute("SELECT * FROM %s.partition_with_indices WHERE a = 0 AND (c, d) IN ((1, 0)) AND f = 3 ALLOW FILTERING");
- assertEquals(1, results.size());
- checkRow(0, results, 0, 0, 1, 0, 0, 3);
-
- results = execute("SELECT * FROM %s.partition_with_indices WHERE a = 0 AND (c) >= (1) AND f = 5 ALLOW FILTERING");
- assertEquals(2, results.size());
- checkRow(0, results, 0, 0, 1, 1, 1, 5);
- checkRow(1, results, 0, 0, 2, 0, 0, 5);
-
- results = execute("SELECT * FROM %s.partition_with_indices WHERE a = 0 AND (c, d) >= (1, 1) AND f = 5 ALLOW FILTERING");
- assertEquals(2, results.size());
- checkRow(0, results, 0, 0, 1, 1, 1, 5);
- checkRow(1, results, 0, 0, 2, 0, 0, 5);
- }
++ createTable("CREATE TABLE %s (a int, b int, c int, d int, e int, f int, PRIMARY KEY ((a, b), c, d, e))");
++ createIndex("CREATE INDEX ON %s (c)");
++ createIndex("CREATE INDEX ON %s (f)");
+
- @Test(expected=InvalidRequestException.class)
- public void testMissingPartitionComponentWithInRestrictionOnIndexedColumn() throws Throwable
- {
- execute("SELECT * FROM %s.partition_with_indices WHERE a = 0 AND (c, d) IN ((1, 1)) ALLOW FILTERING");
- }
++ execute("INSERT INTO %s (a, b, c, d, e, f) VALUES (?, ?, ?, ?, ?, ?)", 0, 0, 0, 0, 0, 0);
++ execute("INSERT INTO %s (a, b, c, d, e, f) VALUES (?, ?, ?, ?, ?, ?)", 0, 0, 0, 1, 0, 1);
++ execute("INSERT INTO %s (a, b, c, d, e, f) VALUES (?, ?, ?, ?, ?, ?)", 0, 0, 0, 1, 1, 2);
+
- @Test(expected=InvalidRequestException.class)
- public void testMissingPartitionComponentWithSliceRestrictionOnIndexedColumn() throws Throwable
- {
- execute("SELECT * FROM %s.partition_with_indices WHERE a = 0 AND (c, d) >= (1, 1) ALLOW FILTERING");
- }
++ execute("INSERT INTO %s (a, b, c, d, e, f) VALUES (?, ?, ?, ?, ?, ?)", 0, 0, 1, 0, 0, 3);
++ execute("INSERT INTO %s (a, b, c, d, e, f) VALUES (?, ?, ?, ?, ?, ?)", 0, 0, 1, 1, 0, 4);
++ execute("INSERT INTO %s (a, b, c, d, e, f) VALUES (?, ?, ?, ?, ?, ?)", 0, 0, 1, 1, 1, 5);
+
- @Test(expected=InvalidRequestException.class)
- public void testPrepareLiteralInWithShortTuple() throws Throwable
- {
- prepare("SELECT * FROM %s.multiple_clustering WHERE a=0 AND (b, c, d) IN ((?, ?))");
- }
++ execute("INSERT INTO %s (a, b, c, d, e, f) VALUES (?, ?, ?, ?, ?, ?)", 0, 0, 2, 0, 0, 5);
+
- @Test(expected=InvalidRequestException.class)
- public void testPrepareLiteralInWithLongTuple() throws Throwable
- {
- prepare("SELECT * FROM %s.multiple_clustering WHERE a=0 AND (b, c, d) IN ((?, ?, ?, ?, ?))");
- }
++ 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));
+
- @Test(expected=InvalidRequestException.class)
- public void testPrepareLiteralInWithPartitionKey() throws Throwable
- {
- prepare("SELECT * FROM %s.multiple_clustering WHERE (a, b, c, d) IN ((?, ?, ?, ?))");
- }
++ 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));
+
- @Test(expected=InvalidRequestException.class)
- public void testPrepareLiteralInSkipsClusteringColumn() throws Throwable
- {
- prepare("SELECT * FROM %s.multiple_clustering WHERE (c, d) IN ((?, ?))");
- }
++ assertInvalidMessage("Partition key part b must be restricted since preceding part is",
++ "SELECT * FROM %s WHERE a = ? AND (c, d) IN ((?, ?)) ALLOW FILTERING", 0, 1, 1);
+
- private static QueryOptions makeIntOptions(Integer... values)
- {
- List<ByteBuffer> buffers = new ArrayList<>(values.length);
- for (int value : values)
- buffers.add(ByteBufferUtil.bytes(value));
- return new QueryOptions(ConsistencyLevel.ONE, buffers);
- }
++ assertInvalidMessage("Partition key part b must be restricted since preceding part is",
++ "SELECT * FROM %s WHERE a = ? AND (c, d) >= (?, ?) ALLOW FILTERING", 0, 1, 1);
+
- private static ByteBuffer tuple(Integer... values)
- {
- List<AbstractType<?>> types = new ArrayList<>(values.length);
- ByteBuffer[] buffers = new ByteBuffer[values.length];
- for (int i = 0; i < values.length; i++)
- {
- types.add(Int32Type.instance);
- buffers[i] = ByteBufferUtil.bytes(values[i]);
- }
++ assertRows(execute("SELECT * FROM %s WHERE a = ? AND (c) IN ((?)) AND f = ? ALLOW FILTERING", 0, 1, 5),
++ row(0, 0, 1, 1, 1, 5));
+
- TupleType type = new TupleType(types);
- return type.buildValue(buffers);
- }
++ 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));
+
- private static ByteBuffer list(ByteBuffer... values)
- {
- return CollectionType.pack(Arrays.asList(values), values.length);
- }
++ 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));
+
- private static QueryOptions options(ByteBuffer... buffers)
- {
- return new QueryOptions(ConsistencyLevel.ONE, Arrays.asList(buffers));
- }
++ assertRows(execute("SELECT * FROM %s WHERE a = ? AND (c) >= (?) AND f = ? ALLOW FILTERING", 0, 1, 5),
++ row(0, 0, 1, 1, 1, 5),
++ row(0, 0, 2, 0, 0, 5));
+
- private static void checkRow(int rowIndex, UntypedResultSet results, Integer... expectedValues)
- {
- List<UntypedResultSet.Row> rows = newArrayList(results.iterator());
- UntypedResultSet.Row row = rows.get(rowIndex);
- Iterator<ColumnSpecification> columns = row.getColumns().iterator();
- for (Integer expected : expectedValues)
- {
- String columnName = columns.next().name.toString();
- int actual = row.getInt(columnName);
- assertEquals(String.format("Expected value %d for column %s in row %d, but got %s", actual, columnName, rowIndex, expected),
- (long) expected, actual);
- }
++ 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),
++ row(0, 0, 2, 0, 0, 5));
+ }
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/07ffe1b1/test/unit/org/apache/cassandra/cql3/SingleColumnRelationTest.java
----------------------------------------------------------------------
diff --cc test/unit/org/apache/cassandra/cql3/SingleColumnRelationTest.java
index 2ad4bda,34d3bf1..604ec60
--- a/test/unit/org/apache/cassandra/cql3/SingleColumnRelationTest.java
+++ b/test/unit/org/apache/cassandra/cql3/SingleColumnRelationTest.java
@@@ -17,51 -17,129 +17,91 @@@
*/
package org.apache.cassandra.cql3;
-import java.util.Iterator;
-import java.util.List;
-
-import org.junit.AfterClass;
-import org.junit.BeforeClass;
import org.junit.Test;
-import org.apache.cassandra.SchemaLoader;
-import org.apache.cassandra.db.ConsistencyLevel;
-import org.apache.cassandra.exceptions.InvalidRequestException;
-import org.apache.cassandra.gms.Gossiper;
-import org.apache.cassandra.service.ClientState;
-
-import static com.google.common.collect.Lists.newArrayList;
-import static org.apache.cassandra.cql3.QueryProcessor.process;
-import static org.apache.cassandra.cql3.QueryProcessor.processInternal;
-import static org.junit.Assert.assertEquals;
+import java.util.ArrayList;
+import java.util.List;
-public class SingleColumnRelationTest
+public class SingleColumnRelationTest extends CQLTester
{
- static ClientState clientState;
- static String keyspace = "single_column_relation_test";
-
- @BeforeClass
- public static void setUpClass() throws Throwable
- {
- SchemaLoader.loadSchema();
- executeSchemaChange("CREATE KEYSPACE IF NOT EXISTS %s WITH replication = {'class': 'SimpleStrategy', 'replication_factor': '1'}");
-
- executeSchemaChange("CREATE TABLE IF NOT EXISTS %s.partition_with_indices (a int, b int, c int, d int, e int, f int, PRIMARY KEY ((a, b), c, d, e))");
- executeSchemaChange("CREATE INDEX ON %s.partition_with_indices (c)");
- executeSchemaChange("CREATE INDEX ON %s.partition_with_indices (f)");
-
- clientState = ClientState.forInternalCalls();
- }
-
- @AfterClass
- public static void stopGossiper()
+ @Test
+ public void testInvalidCollectionEqualityRelation() throws Throwable
{
- Gossiper.instance.stop();
+ createTable("CREATE TABLE %s (a int PRIMARY KEY, b set<int>, c list<int>, d map<int, int>)");
+ createIndex("CREATE INDEX ON %s (b)");
+ createIndex("CREATE INDEX ON %s (c)");
+ createIndex("CREATE INDEX ON %s (d)");
+
+ assertInvalid("SELECT * FROM %s WHERE a = 0 AND b=?", set(0));
+ assertInvalid("SELECT * FROM %s WHERE a = 0 AND c=?", list(0));
+ assertInvalid("SELECT * FROM %s WHERE a = 0 AND d=?", map(0, 0));
}
- private static void executeSchemaChange(String query) throws Throwable
+ @Test
+ public void testInvalidCollectionNonEQRelation() throws Throwable
{
- try
- {
- process(String.format(query, keyspace), ConsistencyLevel.ONE);
- } catch (RuntimeException exc)
- {
- throw exc.getCause();
- }
+ createTable("CREATE TABLE %s (a int PRIMARY KEY, b set<int>, c int)");
+ createIndex("CREATE INDEX ON %s (c)");
+ execute("INSERT INTO %s (a, b, c) VALUES (0, {0}, 0)");
+
+ // non-EQ operators
+ assertInvalid("SELECT * FROM %s WHERE c = 0 AND b > ?", set(0));
+ assertInvalid("SELECT * FROM %s WHERE c = 0 AND b >= ?", set(0));
+ assertInvalid("SELECT * FROM %s WHERE c = 0 AND b < ?", set(0));
+ assertInvalid("SELECT * FROM %s WHERE c = 0 AND b <= ?", set(0));
+ assertInvalid("SELECT * FROM %s WHERE c = 0 AND b IN (?)", set(0));
}
- private static UntypedResultSet execute(String query) throws Throwable
+ @Test
+ public void testLargeClusteringINValues() throws Throwable
{
- try
- {
- return processInternal(String.format(query, keyspace));
- } catch (RuntimeException exc)
- {
- if (exc.getCause() != null)
- throw exc.getCause();
- throw exc;
- }
+ createTable("CREATE TABLE %s (k int, c int, v int, PRIMARY KEY (k, c))");
+ execute("INSERT INTO %s (k, c, v) VALUES (0, 0, 0)");
+ List<Integer> inValues = new ArrayList<>(10000);
+ for (int i = 0; i < 10000; i++)
+ inValues.add(i);
+ assertRows(execute("SELECT * FROM %s WHERE k=? AND c IN ?", 0, inValues),
+ row(0, 0, 0)
+ );
}
+
+ @Test
- public void testPartitionWithIndex() throws Throwable
++ public void testMultiplePartitionKeyWithIndex() throws Throwable
+ {
- execute("INSERT INTO %s.partition_with_indices (a, b, c, d, e, f) VALUES (0, 0, 0, 0, 0, 0)");
- execute("INSERT INTO %s.partition_with_indices (a, b, c, d, e, f) VALUES (0, 0, 0, 1, 0, 1)");
- execute("INSERT INTO %s.partition_with_indices (a, b, c, d, e, f) VALUES (0, 0, 0, 1, 1, 2)");
-
- execute("INSERT INTO %s.partition_with_indices (a, b, c, d, e, f) VALUES (0, 0, 1, 0, 0, 3)");
- execute("INSERT INTO %s.partition_with_indices (a, b, c, d, e, f) VALUES (0, 0, 1, 1, 0, 4)");
- execute("INSERT INTO %s.partition_with_indices (a, b, c, d, e, f) VALUES (0, 0, 1, 1, 1, 5)");
-
- execute("INSERT INTO %s.partition_with_indices (a, b, c, d, e, f) VALUES (0, 0, 2, 0, 0, 5)");
-
- UntypedResultSet results = execute("SELECT * FROM %s.partition_with_indices WHERE a = 0 AND c = 1 ALLOW FILTERING");
- assertEquals(3, results.size());
- checkRow(0, results, 0, 0, 1, 0, 0, 3);
- checkRow(1, results, 0, 0, 1, 1, 0, 4);
- checkRow(2, results, 0, 0, 1, 1, 1, 5);
-
- results = execute("SELECT * FROM %s.partition_with_indices WHERE a = 0 AND c = 1 AND d = 1 ALLOW FILTERING");
- assertEquals(2, results.size());
- checkRow(0, results, 0, 0, 1, 1, 0, 4);
- checkRow(1, results, 0, 0, 1, 1, 1, 5);
-
- results = execute("SELECT * FROM %s.partition_with_indices WHERE a = 0 AND c >= 1 AND f = 5 ALLOW FILTERING");
- assertEquals(2, results.size());
- checkRow(0, results, 0, 0, 1, 1, 1, 5);
- checkRow(1, results, 0, 0, 2, 0, 0, 5);
-
- results = execute("SELECT * FROM %s.partition_with_indices WHERE a = 0 AND c = 1 AND d >= 1 AND f = 5 ALLOW FILTERING");
- assertEquals(1, results.size());
- checkRow(0, results, 0, 0, 1, 1, 1, 5);
- }
++ createTable("CREATE TABLE %s (a int, b int, c int, d int, e int, f int, PRIMARY KEY ((a, b), c, d, e))");
++ createIndex("CREATE INDEX ON %s (c)");
++ createIndex("CREATE INDEX ON %s (f)");
+
- @Test(expected=InvalidRequestException.class)
- public void testMissingPartitionComponentAndFileringOnTheSecondClusteringColumnWithoutAllowFiltering() throws Throwable
- {
- execute("SELECT * FROM %s.partition_with_indices WHERE d >= 1 AND f = 5");
- }
++ execute("INSERT INTO %s (a, b, c, d, e, f) VALUES (?, ?, ?, ?, ?, ?)", 0, 0, 0, 0, 0, 0);
++ execute("INSERT INTO %s (a, b, c, d, e, f) VALUES (?, ?, ?, ?, ?, ?)", 0, 0, 0, 1, 0, 1);
++ execute("INSERT INTO %s (a, b, c, d, e, f) VALUES (?, ?, ?, ?, ?, ?)", 0, 0, 0, 1, 1, 2);
+
- @Test(expected=InvalidRequestException.class)
- public void testMissingPartitionComponentWithSliceRestrictionOnIndexedColumn() throws Throwable
- {
- execute("SELECT * FROM %s.partition_with_indices WHERE a = 0 AND c >= 1 ALLOW FILTERING");
- }
++ execute("INSERT INTO %s (a, b, c, d, e, f) VALUES (?, ?, ?, ?, ?, ?)", 0, 0, 1, 0, 0, 3);
++ execute("INSERT INTO %s (a, b, c, d, e, f) VALUES (?, ?, ?, ?, ?, ?)", 0, 0, 1, 1, 0, 4);
++ execute("INSERT INTO %s (a, b, c, d, e, f) VALUES (?, ?, ?, ?, ?, ?)", 0, 0, 1, 1, 1, 5);
+
- private static void checkRow(int rowIndex, UntypedResultSet results, Integer... expectedValues)
- {
- List<UntypedResultSet.Row> rows = newArrayList(results.iterator());
- UntypedResultSet.Row row = rows.get(rowIndex);
- Iterator<ColumnSpecification> columns = row.getColumns().iterator();
- for (Integer expected : expectedValues)
- {
- String columnName = columns.next().name.toString();
- int actual = row.getInt(columnName);
- assertEquals(String.format("Expected value %d for column %s in row %d, but got %s", actual, columnName, rowIndex, expected),
- (long) expected, actual);
- }
++ execute("INSERT INTO %s (a, b, c, d, e, f) VALUES (?, ?, ?, ?, ?, ?)", 0, 0, 2, 0, 0, 5);
++
++ 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));
++
++ assertRows(execute("SELECT * FROM %s WHERE a = ? AND c = ? AND d = ? ALLOW FILTERING", 0, 1, 1),
++ row(0, 0, 1, 1, 0, 4),
++ row(0, 0, 1, 1, 1, 5));
++
++ assertInvalidMessage("Partition key part b must be restricted since preceding part is",
++ "SELECT * FROM %s WHERE a = ? AND c >= ? ALLOW FILTERING", 0, 1);
++
++ assertRows(execute("SELECT * FROM %s WHERE a = ? AND c >= ? AND f = ? ALLOW FILTERING", 0, 1, 5),
++ row(0, 0, 1, 1, 1, 5),
++ row(0, 0, 2, 0, 0, 5));
++
++ assertRows(execute("SELECT * FROM %s WHERE a = ? AND c = ? AND d >= ? AND f = ? ALLOW FILTERING", 0, 1, 1, 5),
++ row(0, 0, 1, 1, 1, 5));
++
++ assertInvalidMessage("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",
++ "SELECT * FROM %s WHERE a = ? AND d >= ? AND f = ?", 0, 1, 5);
+ }
}