Fix handling of clustering key > 64K Prevent select statements with clustering key > 64k, nicer error message when writing a value larger than unsigned short, catch Throwable for OutboundTCPConnection.
Patch by Lerh Chuan Low; reviewed by Branimir Lambov for CASSANDRA-11882 Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/452d626a Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/452d626a Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/452d626a Branch: refs/heads/trunk Commit: 452d626a7a6b03917b7bd72a5dfe9da8a27e0903 Parents: 720870b Author: Lerh Chuan Low <l...@instaclustr.com> Authored: Tue May 31 18:01:58 2016 +1000 Committer: Sylvain Lebresne <sylv...@datastax.com> Committed: Thu Jun 23 10:52:14 2016 +0200 ---------------------------------------------------------------------- CHANGES.txt | 1 + .../cql3/statements/SelectStatement.java | 7 ++- .../cassandra/net/OutboundTcpConnection.java | 3 +- .../apache/cassandra/utils/ByteBufferUtil.java | 8 +++- .../org/apache/cassandra/cql3/CQLTester.java | 2 + .../cql3/validation/operations/InsertTest.java | 45 ++++++++++++++++++++ .../cql3/validation/operations/SelectTest.java | 29 +++++++++++++ 7 files changed, 91 insertions(+), 4 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cassandra/blob/452d626a/CHANGES.txt ---------------------------------------------------------------------- diff --git a/CHANGES.txt b/CHANGES.txt index 7474045..9a3779c 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,4 +1,5 @@ 2.1.15 + * Prevent select statements with clustering key > 64k (CASSANDRA-11882) * Fix clock skew corrupting other nodes with paxos (CASSANDRA-11991) * Remove distinction between non-existing static columns and existing but null in LWTs (CASSANDRA-9842) * Support mlockall on IBM POWER arch (CASSANDRA-11576) http://git-wip-us.apache.org/repos/asf/cassandra/blob/452d626a/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 8a6d704..1e142e0 100644 --- a/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java +++ b/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java @@ -1081,7 +1081,12 @@ public class SelectStatement implements CQLStatement private List<Composite> getRequestedBound(Bound b, QueryOptions options) throws InvalidRequestException { assert isColumnRange(); - return buildBound(b, cfm.clusteringColumns(), columnRestrictions, isReversed, cfm.comparator, options); + List<Composite> bound = buildBound(b, cfm.clusteringColumns(), columnRestrictions, isReversed, cfm.comparator, options); + for (Composite c : bound) { + if (!c.isEmpty()) + QueryProcessor.validateComposite(c, cfm.comparator); + } + return bound; } /** http://git-wip-us.apache.org/repos/asf/cassandra/blob/452d626a/src/java/org/apache/cassandra/net/OutboundTcpConnection.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/net/OutboundTcpConnection.java b/src/java/org/apache/cassandra/net/OutboundTcpConnection.java index 0d588c8..1a88220 100644 --- a/src/java/org/apache/cassandra/net/OutboundTcpConnection.java +++ b/src/java/org/apache/cassandra/net/OutboundTcpConnection.java @@ -285,8 +285,9 @@ public class OutboundTcpConnection extends Thread if (flush) out.flush(); } - catch (Exception e) + catch (Throwable e) { + JVMStabilityInspector.inspectThrowable(e); disconnect(); if (e instanceof IOException) { http://git-wip-us.apache.org/repos/asf/cassandra/blob/452d626a/src/java/org/apache/cassandra/utils/ByteBufferUtil.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/utils/ByteBufferUtil.java b/src/java/org/apache/cassandra/utils/ByteBufferUtil.java index e41069f..b78b8eb 100644 --- a/src/java/org/apache/cassandra/utils/ByteBufferUtil.java +++ b/src/java/org/apache/cassandra/utils/ByteBufferUtil.java @@ -287,7 +287,9 @@ public class ByteBufferUtil public static void writeWithShortLength(ByteBuffer buffer, DataOutputPlus out) throws IOException { int length = buffer.remaining(); - assert 0 <= length && length <= FBUtilities.MAX_UNSIGNED_SHORT : length; + assert 0 <= length && length <= FBUtilities.MAX_UNSIGNED_SHORT : + String.format("Attempted serializing to buffer exceeded maximum of %s bytes: %s", FBUtilities.MAX_UNSIGNED_SHORT, length); + out.writeShort(length); out.write(buffer); } @@ -295,7 +297,9 @@ public class ByteBufferUtil public static void writeWithShortLength(byte[] buffer, DataOutput out) throws IOException { int length = buffer.length; - assert 0 <= length && length <= FBUtilities.MAX_UNSIGNED_SHORT : length; + assert 0 <= length && length <= FBUtilities.MAX_UNSIGNED_SHORT : + String.format("Attempted serializing to buffer exceeded maximum of %s bytes: %s", FBUtilities.MAX_UNSIGNED_SHORT, length); + out.writeShort(length); out.write(buffer); } http://git-wip-us.apache.org/repos/asf/cassandra/blob/452d626a/test/unit/org/apache/cassandra/cql3/CQLTester.java ---------------------------------------------------------------------- diff --git a/test/unit/org/apache/cassandra/cql3/CQLTester.java b/test/unit/org/apache/cassandra/cql3/CQLTester.java index 5288c2f..34c0980 100644 --- a/test/unit/org/apache/cassandra/cql3/CQLTester.java +++ b/test/unit/org/apache/cassandra/cql3/CQLTester.java @@ -51,6 +51,7 @@ import org.apache.cassandra.dht.Murmur3Partitioner; import org.apache.cassandra.exceptions.*; import org.apache.cassandra.io.util.FileUtils; import org.apache.cassandra.serializers.TypeSerializer; +import org.apache.cassandra.utils.FBUtilities; /** * Base class for CQL tests. @@ -63,6 +64,7 @@ public abstract class CQLTester private static final boolean USE_PREPARED_VALUES = Boolean.valueOf(System.getProperty("cassandra.test.use_prepared", "true")); protected static final long ROW_CACHE_SIZE_IN_MB = Integer.valueOf(System.getProperty("cassandra.test.row_cache_size_in_mb", "0")); private static final AtomicInteger seqNumber = new AtomicInteger(); + protected static final ByteBuffer TOO_BIG = ByteBuffer.allocate(FBUtilities.MAX_UNSIGNED_SHORT + 1024); static { http://git-wip-us.apache.org/repos/asf/cassandra/blob/452d626a/test/unit/org/apache/cassandra/cql3/validation/operations/InsertTest.java ---------------------------------------------------------------------- diff --git a/test/unit/org/apache/cassandra/cql3/validation/operations/InsertTest.java b/test/unit/org/apache/cassandra/cql3/validation/operations/InsertTest.java new file mode 100644 index 0000000..99ec908 --- /dev/null +++ b/test/unit/org/apache/cassandra/cql3/validation/operations/InsertTest.java @@ -0,0 +1,45 @@ +/* + * 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.validation.operations; + +import org.junit.Test; + +import org.apache.cassandra.cql3.CQLTester; +import org.apache.cassandra.exceptions.InvalidRequestException; + +public class InsertTest extends CQLTester +{ + @Test + public void testOverlyLargeInsertPK() throws Throwable + { + createTable("CREATE TABLE %s (a text, b text, PRIMARY KEY ((a), b))"); + + assertInvalidThrow(InvalidRequestException.class, + "INSERT INTO %s (a, b) VALUES (?, 'foo')", new String(TOO_BIG.array())); + } + + @Test + public void testOverlyLargeInsertCK() throws Throwable + { + createTable("CREATE TABLE %s (a text, b text, PRIMARY KEY ((a), b))"); + + assertInvalidThrow(InvalidRequestException.class, + "INSERT INTO %s (a, b) VALUES ('foo', ?)", new String(TOO_BIG.array())); + } +} http://git-wip-us.apache.org/repos/asf/cassandra/blob/452d626a/test/unit/org/apache/cassandra/cql3/validation/operations/SelectTest.java ---------------------------------------------------------------------- diff --git a/test/unit/org/apache/cassandra/cql3/validation/operations/SelectTest.java b/test/unit/org/apache/cassandra/cql3/validation/operations/SelectTest.java index c8c1f1a..6acab6f 100644 --- a/test/unit/org/apache/cassandra/cql3/validation/operations/SelectTest.java +++ b/test/unit/org/apache/cassandra/cql3/validation/operations/SelectTest.java @@ -28,6 +28,7 @@ import org.apache.cassandra.config.DatabaseDescriptor; import org.apache.cassandra.cql3.UntypedResultSet; import org.apache.cassandra.cql3.CQLTester; import org.apache.cassandra.dht.Murmur3Partitioner; +import org.apache.cassandra.exceptions.InvalidRequestException; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; @@ -1235,4 +1236,32 @@ public class SelectTest extends CQLTester assertRows(execute("SELECT * FROM %s WHERE a=1 AND b=2 ORDER BY b DESC"), row(1, 2, 3, 3)); } + + @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())); + } }