Validate token() args are in partition key order Patch by Benjamin Lerer; reviewed by Tyler Hobbs for CASSANDRA-6075
Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/c5c0585b Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/c5c0585b Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/c5c0585b Branch: refs/heads/cassandra-2.1 Commit: c5c0585b4b5a1bad22ced00e01cc90eed8448ce7 Parents: 20eb8f0 Author: blerer <b_le...@hotmail.com> Authored: Fri Sep 19 11:24:24 2014 -0500 Committer: Tyler Hobbs <ty...@datastax.com> Committed: Fri Sep 19 11:24:24 2014 -0500 ---------------------------------------------------------------------- CHANGES.txt | 3 +- .../cql3/statements/SelectStatement.java | 22 ++++++++ .../cql3/SelectWithTokenFunctionTest.java | 55 ++++++++++++++++++++ 3 files changed, 79 insertions(+), 1 deletion(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cassandra/blob/c5c0585b/CHANGES.txt ---------------------------------------------------------------------- diff --git a/CHANGES.txt b/CHANGES.txt index 9a69dfd..d3ee7d9 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -44,7 +44,8 @@ * Include snippet of CQL query near syntax error in messages (CASSANDRA-7111) * Make repair -pr work with -local (CASSANDRA-7450) Merged from 2.0: -2.0.11: + * token() should only accept columns in the partitioning + key order (CASSANDRA-6075) * Add method to invalidate permission cache via JMX (CASSANDRA-7977) * Allow propagating multiple gossip states atomically (CASSANDRA-6125) * Log exceptions related to unclean native protocol client disconnects http://git-wip-us.apache.org/repos/asf/cassandra/blob/c5c0585b/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 586eb85..22c8468 100644 --- a/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java +++ b/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java @@ -20,6 +20,7 @@ package org.apache.cassandra.cql3.statements; import java.nio.ByteBuffer; import java.util.*; +import com.google.common.base.Joiner; import com.google.common.base.Objects; import com.google.common.base.Predicate; import com.google.common.collect.AbstractIterator; @@ -1822,6 +1823,27 @@ public class SelectStatement implements CQLStatement, MeasurableForPreparedCache } previous = cdef; } + + if (stmt.onToken && cfm.partitionKeyColumns().size() > 0) + checkTokenFunctionArgumentsOrder(cfm); + } + + /** + * Checks that the column identifiers used as argument for the token function have been specified in the + * partition key order. + * @param cfm the Column Family MetaData + * @throws InvalidRequestException if the arguments have not been provided in the proper order. + */ + private void checkTokenFunctionArgumentsOrder(CFMetaData cfm) throws InvalidRequestException + { + Iterator<ColumnDefinition> iter = cfm.partitionKeyColumns().iterator(); + for (Relation relation : whereClause) + { + SingleColumnRelation singleColumnRelation = (SingleColumnRelation) relation; + if (singleColumnRelation.onToken && !cfm.getColumnDefinition(singleColumnRelation.getEntity()).equals(iter.next())) + throw new InvalidRequestException(String.format("The token function arguments must be in the partition key order: %s", + Joiner.on(',').join(cfm.partitionKeyColumns()))); + } } private void processColumnRestrictions(SelectStatement stmt, boolean hasQueriableIndex, CFMetaData cfm) throws InvalidRequestException http://git-wip-us.apache.org/repos/asf/cassandra/blob/c5c0585b/test/unit/org/apache/cassandra/cql3/SelectWithTokenFunctionTest.java ---------------------------------------------------------------------- diff --git a/test/unit/org/apache/cassandra/cql3/SelectWithTokenFunctionTest.java b/test/unit/org/apache/cassandra/cql3/SelectWithTokenFunctionTest.java new file mode 100644 index 0000000..73a7209 --- /dev/null +++ b/test/unit/org/apache/cassandra/cql3/SelectWithTokenFunctionTest.java @@ -0,0 +1,55 @@ +/* + * 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 org.junit.Test; + +public class SelectWithTokenFunctionTest extends CQLTester +{ + @Test + public void testTokenFunctionWithSingleColumnPartitionKey() throws Throwable + { + createTable("CREATE TABLE IF NOT EXISTS %s (a int PRIMARY KEY, b text)"); + execute("INSERT INTO %s (a, b) VALUES (0, 'a')"); + + assertRows(execute("SELECT * FROM %s WHERE token(a) >= token(?)", 0), row(0, "a")); + assertInvalid("SELECT * FROM %s WHERE token(a) > token(?)", "a"); + assertInvalid("SELECT * FROM %s WHERE token(a, b) >= token(?, ?)", "b", 0); + } + + @Test + public void testTokenFunctionWithPartitionKeyAndClusteringKeyArguments() throws Throwable + { + createTable("CREATE TABLE IF NOT EXISTS %s (a int, b text, PRIMARY KEY (a, b))"); + assertInvalid("SELECT * FROM %s WHERE token(a, b) > token(0, 'c')"); + } + + @Test + public void testTokenFunctionWithMultiColumnPartitionKey() throws Throwable + { + createTable("CREATE TABLE IF NOT EXISTS %s (a int, b text, PRIMARY KEY ((a, b)))"); + execute("INSERT INTO %s (a, b) VALUES (0, 'a')"); + execute("INSERT INTO %s (a, b) VALUES (0, 'b')"); + execute("INSERT INTO %s (a, b) VALUES (0, 'c')"); + + assertRows(execute("SELECT * FROM %s WHERE token(a, b) > token(?, ?)", 0, "a"), + row(0, "b"), + row(0, "c")); + assertInvalid("SELECT * FROM %s WHERE token(b, a) > token(0, 'c')"); + } +}