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()));
+    }
 }

Reply via email to