http://git-wip-us.apache.org/repos/asf/cassandra/blob/ce8c9b55/test/unit/org/apache/cassandra/cql3/validation/ThriftIntegrationTest.java
----------------------------------------------------------------------
diff --git 
a/test/unit/org/apache/cassandra/cql3/validation/ThriftIntegrationTest.java 
b/test/unit/org/apache/cassandra/cql3/validation/ThriftIntegrationTest.java
new file mode 100644
index 0000000..def489e
--- /dev/null
+++ b/test/unit/org/apache/cassandra/cql3/validation/ThriftIntegrationTest.java
@@ -0,0 +1,942 @@
+/*
+ * 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;
+
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import org.apache.cassandra.cql3.ColumnIdentifier;
+import org.apache.cassandra.cql3.UntypedResultSet;
+import org.apache.cassandra.cql3.validation.operations.ThriftCQLTester;
+import org.apache.cassandra.db.Keyspace;
+import org.apache.cassandra.db.marshal.AsciiType;
+import org.apache.cassandra.db.marshal.CounterColumnType;
+import org.apache.cassandra.db.marshal.Int32Type;
+import org.apache.cassandra.db.marshal.LongType;
+import org.apache.cassandra.locator.SimpleStrategy;
+import org.apache.cassandra.service.StorageService;
+import org.apache.cassandra.thrift.Cassandra;
+import org.apache.cassandra.thrift.CfDef;
+import org.apache.cassandra.thrift.Column;
+import org.apache.cassandra.thrift.ColumnDef;
+import org.apache.cassandra.thrift.ColumnOrSuperColumn;
+import org.apache.cassandra.thrift.ColumnParent;
+import org.apache.cassandra.thrift.ColumnPath;
+import org.apache.cassandra.thrift.CounterColumn;
+import org.apache.cassandra.thrift.CounterSuperColumn;
+import org.apache.cassandra.thrift.Deletion;
+import org.apache.cassandra.thrift.KsDef;
+import org.apache.cassandra.thrift.Mutation;
+import org.apache.cassandra.thrift.SlicePredicate;
+import org.apache.cassandra.thrift.SliceRange;
+import org.apache.cassandra.thrift.SuperColumn;
+import org.apache.cassandra.utils.ByteBufferUtil;
+import org.apache.cassandra.utils.FBUtilities;
+
+import static org.apache.cassandra.thrift.ConsistencyLevel.ONE;
+import static org.junit.Assert.assertEquals;
+
+public class ThriftIntegrationTest extends ThriftCQLTester
+{
+    final static AtomicInteger seqNumber = new AtomicInteger();
+    final String KEYSPACE = "thrift_compact_table_with_supercolumns_test_" + 
seqNumber.incrementAndGet();
+
+    @Before
+    public void setupSuperColumnFamily() throws Throwable
+    {
+        StorageService.instance.setRpcReady(true);
+
+        final String denseTableName = createTableName();
+        final String sparseTableName =  currentSparseTable();
+        final String counterTableName = currentCounterTable();
+
+        CfDef cfDef = new CfDef().setColumn_type("Super")
+                                 
.setSubcomparator_type(Int32Type.instance.toString())
+                                 
.setComparator_type(AsciiType.instance.toString())
+                                 
.setDefault_validation_class(AsciiType.instance.toString())
+                                 
.setKey_validation_class(AsciiType.instance.toString())
+                                 .setKeyspace(KEYSPACE)
+                                 .setName(denseTableName);
+
+        CfDef sparseCfDef = new CfDef().setColumn_type("Super")
+                                       
.setComparator_type(AsciiType.instance.toString())
+                                       
.setSubcomparator_type(AsciiType.instance.toString())
+                                       
.setKey_validation_class(AsciiType.instance.toString())
+                                       .setColumn_metadata(Arrays.asList(new 
ColumnDef(ByteBufferUtil.bytes("col1"), LongType.instance.toString()),
+                                                                         new 
ColumnDef(ByteBufferUtil.bytes("col2"), LongType.instance.toString())))
+                                       .setKeyspace(KEYSPACE)
+                                       .setName(sparseTableName);
+
+        CfDef counterCfDef = new CfDef().setColumn_type("Super")
+                                        
.setSubcomparator_type(AsciiType.instance.toString())
+                                        
.setComparator_type(AsciiType.instance.toString())
+                                        
.setDefault_validation_class(CounterColumnType.instance.toString())
+                                        
.setKey_validation_class(AsciiType.instance.toString())
+                                        .setKeyspace(KEYSPACE)
+                                        .setName(counterTableName);
+
+        KsDef ksDef = new KsDef(KEYSPACE,
+                                SimpleStrategy.class.getName(),
+                                Arrays.asList(cfDef, sparseCfDef, 
counterCfDef));
+
+        
ksDef.setStrategy_options(Collections.singletonMap("replication_factor", "1"));
+
+        Cassandra.Client client = getClient();
+        client.system_add_keyspace(ksDef);
+        client.set_keyspace(KEYSPACE);
+    }
+
+    @After
+    public void tearDown() throws Throwable
+    {
+        getClient().send_system_drop_keyspace(KEYSPACE);
+    }
+
+    @Test
+    public void testCounterTableReads() throws Throwable
+    {
+        populateCounterTable();
+        beforeAndAfterFlush(this::testCounterTableReadsInternal);
+    }
+
+    private void testCounterTableReadsInternal() throws Throwable
+    {
+        UntypedResultSet resultSet = execute(String.format("select * from 
%s.%s", KEYSPACE, currentCounterTable()));
+        assertRows(resultSet,
+                   row("key1", "ck1", "counter1", 10L),
+                   row("key1", "ck1", "counter2", 5L),
+                   row("key2", "ck1", "counter1", 10L),
+                   row("key2", "ck1", "counter2", 5L));
+    }
+
+    @Test
+    public void testCounterTableThriftUpdates() throws Throwable
+    {
+        populateCounterTable();
+
+        Cassandra.Client client = getClient();
+        Mutation mutation = new Mutation();
+        ColumnOrSuperColumn csoc = new ColumnOrSuperColumn();
+        csoc.setCounter_super_column(new 
CounterSuperColumn(ByteBufferUtil.bytes("ck1"),
+                                                            Arrays.asList(new 
CounterColumn(ByteBufferUtil.bytes("counter1"), 1))));
+        mutation.setColumn_or_supercolumn(csoc);
+
+        Mutation mutation2 = new Mutation();
+        ColumnOrSuperColumn csoc2 = new ColumnOrSuperColumn();
+        csoc2.setCounter_super_column(new 
CounterSuperColumn(ByteBufferUtil.bytes("ck1"),
+                                                             Arrays.asList(new 
CounterColumn(ByteBufferUtil.bytes("counter1"), 100))));
+        mutation2.setColumn_or_supercolumn(csoc2);
+        
client.batch_mutate(Collections.singletonMap(ByteBufferUtil.bytes("key1"),
+                                                     
Collections.singletonMap(currentCounterTable(), Arrays.asList(mutation))),
+                            ONE);
+        
client.batch_mutate(Collections.singletonMap(ByteBufferUtil.bytes("key2"),
+                                                     
Collections.singletonMap(currentCounterTable(), Arrays.asList(mutation2))),
+                            ONE);
+
+        beforeAndAfterFlush(() -> {
+            UntypedResultSet resultSet = execute(String.format("select * from 
%s.%s", KEYSPACE, currentCounterTable()));
+            assertRows(resultSet,
+                       row("key1", "ck1", "counter1", 11L),
+                       row("key1", "ck1", "counter2", 5L),
+                       row("key2", "ck1", "counter1", 110L),
+                       row("key2", "ck1", "counter2", 5L));
+        });
+    }
+
+    @Test
+    public void testCounterTableCqlUpdates() throws Throwable
+    {
+        populateCounterTable();
+
+        execute(String.format("UPDATE %s.%s set value = value + 1 WHERE key = 
? AND column1 = ? AND column2 = ?", KEYSPACE, currentCounterTable()),
+                "key1", "ck1", "counter1");
+        execute(String.format("UPDATE %s.%s set value = value + 100 WHERE key 
= 'key2' AND column1 = 'ck1' AND column2 = 'counter1'", KEYSPACE, 
currentCounterTable()));
+
+        execute(String.format("UPDATE %s.%s set value = value - ? WHERE key = 
'key1' AND column1 = 'ck1' AND column2 = 'counter2'", KEYSPACE, 
currentCounterTable()), 2L);
+        execute(String.format("UPDATE %s.%s set value = value - ? WHERE key = 
'key2' AND column1 = 'ck1' AND column2 = 'counter2'", KEYSPACE, 
currentCounterTable()), 100L);
+
+        beforeAndAfterFlush(() -> {
+            UntypedResultSet resultSet = execute(String.format("select * from 
%s.%s", KEYSPACE, currentCounterTable()));
+            assertRows(resultSet,
+                       row("key1", "ck1", "counter1", 11L),
+                       row("key1", "ck1", "counter2", 3L),
+                       row("key2", "ck1", "counter1", 110L),
+                       row("key2", "ck1", "counter2", -95L));
+        });
+    }
+
+    @Test
+    public void testCounterTableCqlDeletes() throws Throwable
+    {
+        populateCounterTable();
+
+        assertRows(execute(String.format("select * from %s.%s", KEYSPACE, 
currentCounterTable())),
+                   row("key1", "ck1", "counter1", 10L),
+                   row("key1", "ck1", "counter2", 5L),
+                   row("key2", "ck1", "counter1", 10L),
+                   row("key2", "ck1", "counter2", 5L));
+
+        execute(String.format("DELETE value FROM %s.%s WHERE key = ? AND 
column1 = ? AND column2 = ?", KEYSPACE, currentCounterTable()),
+                "key1", "ck1", "counter1");
+
+        assertRows(execute(String.format("select * from %s.%s", KEYSPACE, 
currentCounterTable())),
+                   row("key1", "ck1", "counter2", 5L),
+                   row("key2", "ck1", "counter1", 10L),
+                   row("key2", "ck1", "counter2", 5L));
+
+        execute(String.format("DELETE FROM %s.%s WHERE key = ? AND column1 = 
?", KEYSPACE, currentCounterTable()),
+                "key1", "ck1");
+
+        assertRows(execute(String.format("select * from %s.%s", KEYSPACE, 
currentCounterTable())),
+                   row("key2", "ck1", "counter1", 10L),
+                   row("key2", "ck1", "counter2", 5L));
+
+        execute(String.format("DELETE FROM %s.%s WHERE key = ?", KEYSPACE, 
currentCounterTable()),
+                "key2");
+
+        assertEmpty(execute(String.format("select * from %s.%s", KEYSPACE, 
currentCounterTable())));
+    }
+
+    @Test
+    public void testDenseTableAlter() throws Throwable
+    {
+        populateDenseTable();
+
+        alterTable(String.format("ALTER TABLE %s.%s RENAME column1 TO 
renamed_column1", KEYSPACE, currentDenseTable()));
+        alterTable(String.format("ALTER TABLE %s.%s RENAME column2 TO 
renamed_column2", KEYSPACE, currentDenseTable()));
+        alterTable(String.format("ALTER TABLE %s.%s RENAME key TO 
renamed_key", KEYSPACE, currentDenseTable()));
+        alterTable(String.format("ALTER TABLE %s.%s RENAME value TO 
renamed_value", KEYSPACE, currentDenseTable()));
+
+        beforeAndAfterFlush(() -> {
+            UntypedResultSet resultSet = execute(String.format("select * from 
%s.%s", KEYSPACE, currentDenseTable()));
+            assertEquals("renamed_key", 
resultSet.metadata().get(0).name.toString());
+            assertEquals("renamed_column1", 
resultSet.metadata().get(1).name.toString());
+                                assertEquals("renamed_column2", 
resultSet.metadata().get(2).name.toString());
+                                assertEquals("renamed_value", 
resultSet.metadata().get(3).name.toString());
+            assertRows(resultSet,
+                       row("key1", "val1", 1, "value1"),
+                       row("key1", "val1", 2, "value2"),
+                       row("key1", "val2", 4, "value4"),
+                       row("key1", "val2", 5, "value5"),
+                       row("key2", "val1", 1, "value1"),
+                       row("key2", "val1", 2, "value2"),
+                       row("key2", "val2", 4, "value4"),
+                       row("key2", "val2", 5, "value5"));
+        });
+    }
+
+    @Test
+    public void testDenseTableReads() throws Throwable
+    {
+        populateDenseTable();
+        beforeAndAfterFlush(this::testDenseTableReadsInternal);
+    }
+
+    private void testDenseTableReadsInternal() throws Throwable
+    {
+        UntypedResultSet resultSet = execute(String.format("select * from 
%s.%s", KEYSPACE, currentDenseTable()));
+        assertEquals("key", resultSet.metadata().get(0).name.toString());
+        assertEquals("column1", resultSet.metadata().get(1).name.toString());
+        assertEquals("column2", resultSet.metadata().get(2).name.toString());
+        assertEquals("value", resultSet.metadata().get(3).name.toString());
+
+
+        assertRows(resultSet,
+                   row("key1", "val1", 1, "value1"),
+                   row("key1", "val1", 2, "value2"),
+                   row("key1", "val2", 4, "value4"),
+                   row("key1", "val2", 5, "value5"),
+                   row("key2", "val1", 1, "value1"),
+                   row("key2", "val1", 2, "value2"),
+                   row("key2", "val2", 4, "value4"),
+                   row("key2", "val2", 5, "value5"));
+
+        assertRows(execute(String.format("select * from %s.%s LIMIT 5", 
KEYSPACE, currentDenseTable())),
+                   row("key1", "val1", 1, "value1"),
+                   row("key1", "val1", 2, "value2"),
+                   row("key1", "val2", 4, "value4"),
+                   row("key1", "val2", 5, "value5"),
+                   row("key2", "val1", 1, "value1"));
+
+        assertRows(execute(String.format("select value, column2, column1, key 
from %s.%s", KEYSPACE, currentDenseTable())),
+                   row("value1", 1, "val1", "key1"),
+                   row("value2", 2, "val1", "key1"),
+                   row("value4", 4, "val2", "key1"),
+                   row("value5", 5, "val2", "key1"),
+                   row("value1", 1, "val1", "key2"),
+                   row("value2", 2, "val1", "key2"),
+                   row("value4", 4, "val2", "key2"),
+                   row("value5", 5, "val2", "key2"));
+
+        assertRows(execute(String.format("select * from %s.%s WHERE key = ? 
AND column1 = ?", KEYSPACE, currentDenseTable()), "key1", "val2"),
+                   row("key1", "val2", 4, "value4"),
+                   row("key1", "val2", 5, "value5"));
+
+        assertRows(execute(String.format("select * from %s.%s where key IN 
('key1', 'key2') and column1 = 'val1' and column2 = 2", KEYSPACE, 
currentDenseTable())),
+                   row("key1", "val1", 2, "value2"),
+                   row("key2", "val1", 2, "value2"));
+        assertRows(execute(String.format("select * from %s.%s where key IN 
('key1', 'key2') and column1 = 'val1' and column2 > 1", KEYSPACE, 
currentDenseTable())),
+                   row("key1", "val1", 2, "value2"),
+                   row("key2", "val1", 2, "value2"));
+        assertRows(execute(String.format("select * from %s.%s where key IN 
('key1', 'key2') and column1 = 'val1' and column2 >= 2", KEYSPACE, 
currentDenseTable())),
+                   row("key1", "val1", 2, "value2"),
+                   row("key2", "val1", 2, "value2"));
+        assertEmpty(execute(String.format("select * from %s.%s where key IN 
('key1', 'key2') and column1 = 'val1' and column2 > 2", KEYSPACE, 
currentDenseTable())));
+
+        assertRows(execute(String.format("select column2, key from %s.%s WHERE 
key = ? AND column1 = ? and column2 = 5", KEYSPACE, currentDenseTable()), 
"key1", "val2"),
+                   row(5, "key1"));
+        assertRows(execute(String.format("select * from %s.%s WHERE key = ? 
AND column1 = ? and column2 >= ?", KEYSPACE, currentDenseTable()), "key1", 
"val2", 5),
+                   row("key1", "val2", 5, "value5"));
+        assertRows(execute(String.format("select * from %s.%s WHERE key = ? 
AND column1 = ? and column2 > ?", KEYSPACE, currentDenseTable()), "key1", 
"val2", 4),
+                   row("key1", "val2", 5, "value5"));
+        assertRows(execute(String.format("select * from %s.%s WHERE key = ? 
AND column1 = ? and column2 < ?", KEYSPACE, currentDenseTable()), "key1", 
"val2", 5),
+                   row("key1", "val2", 4, "value4"));
+        assertRows(execute(String.format("select * from %s.%s WHERE key = ? 
AND column1 = ? and column2 <= ?", KEYSPACE, currentDenseTable()), "key1", 
"val2", 5),
+                   row("key1", "val2", 4, "value4"),
+                   row("key1", "val2", 5, "value5"));
+
+        assertRows(execute(String.format("select * from %s.%s where key = 
'key1' and column1 in ('val1', 'val2') and column2 IN (1, 4)", KEYSPACE, 
currentDenseTable())),
+                   row("key1", "val1", 1, "value1"),
+                   row("key1", "val2", 4, "value4"));
+
+        assertRows(execute(String.format("select * from %s.%s where key = 
'key1' and column1 in ('val1', 'val2')", KEYSPACE, currentDenseTable())),
+                   row("key1", "val1", 1, "value1"),
+                   row("key1", "val1", 2, "value2"),
+                   row("key1", "val2", 4, "value4"),
+                   row("key1", "val2", 5, "value5"));
+
+        assertRows(execute(String.format("select * from %s.%s where key = 
'key1' and column1 in ('val1', 'val2') and column2 = 1", KEYSPACE, 
currentDenseTable())),
+                   row("key1", "val1", 1, "value1"));
+
+        assertRows(execute(String.format("select * from %s.%s where key = 
'key1' and (column1, column2) = ('val2', 4)", KEYSPACE, currentDenseTable())),
+                   row("key1", "val2", 4, "value4"));
+
+        assertRows(execute(String.format("select * from %s.%s where key = 
'key1' and (column1, column2) >= ('val2', 4)", KEYSPACE, currentDenseTable())),
+                   row("key1", "val2", 4, "value4"),
+                   row("key1", "val2", 5, "value5"));
+
+        assertRows(execute(String.format("select * from %s.%s where key = 
'key1' and (column1, column2) > ('val1', 1)", KEYSPACE, currentDenseTable())),
+                   row("key1", "val1", 2, "value2"),
+                   row("key1", "val2", 4, "value4"),
+                   row("key1", "val2", 5, "value5"));
+
+        assertRows(execute(String.format("select * from %s.%s where key = 
'key1' and (column1, column2) > ('val2', 1)", KEYSPACE, currentDenseTable())),
+                   row("key1", "val2", 4, "value4"),
+                   row("key1", "val2", 5, "value5"));
+
+        resultSet = execute(String.format("select key as a, column1 as b, 
column2 as c, value as d " +
+                                          "from %s.%s WHERE key = ? AND 
column1 = ?", KEYSPACE, currentDenseTable()), "key1", "val2");
+        assertRows(resultSet,
+                   row("key1", "val2", 4, "value4"),
+                   row("key1", "val2", 5, "value5"));
+        assertEquals(resultSet.metadata().get(2).type, Int32Type.instance);
+        assertEquals(resultSet.metadata().get(3).type, AsciiType.instance);
+
+        assertRows(execute(String.format("select column2, value from %s.%s 
WHERE key = ? AND column1 = ?", KEYSPACE, currentDenseTable()), "key1", "val2"),
+                   row(4, "value4"),
+                   row(5, "value5"));
+
+        assertRows(execute(String.format("select column1, value from %s.%s 
WHERE key = ? AND column1 = ?", KEYSPACE, currentDenseTable()), "key2", "val1"),
+                   row("val1", "value1"),
+                   row("val1", "value2"));
+
+        assertInvalidMessage("Secondary indexes are not supported on COMPACT 
STORAGE tables that have clustering columns",
+                             String.format("CREATE INDEX ON %s.%s (column2)", 
KEYSPACE, currentDenseTable()));
+        assertInvalidMessage("Secondary indexes are not supported on COMPACT 
STORAGE tables that have clustering columns",
+                             String.format("CREATE INDEX ON %s.%s (value)", 
KEYSPACE, currentDenseTable()));
+
+        assertRows(execute(String.format("SELECT JSON * FROM %s.%s WHERE key = 
? AND column1 = ?", KEYSPACE, currentDenseTable()), "key1", "val2"),
+                   row("{\"key\": \"key1\", \"column1\": \"val2\", 
\"column2\": 4, \"value\": \"value4\"}"),
+                   row("{\"key\": \"key1\", \"column1\": \"val2\", 
\"column2\": 5, \"value\": \"value5\"}"));
+    }
+
+    @Test
+    public void testDenseTablePartialCqlInserts() throws Throwable
+    {
+        assertInvalidMessage("Column value is mandatory for SuperColumn 
tables",
+                             String.format("INSERT INTO %s.%s (key, column1, 
column2) VALUES ('key1', 'val1', 1)", KEYSPACE, currentDenseTable()));
+
+        // That's slightly different from 2.X, since null map keys are not 
allowed
+        assertInvalidMessage("Column key is mandatory for SuperColumn tables",
+                             String.format("INSERT INTO %s.%s (key, column1, 
value) VALUES ('key1', 'val1', 'value1')", KEYSPACE, currentDenseTable()));
+
+        execute(String.format("INSERT INTO %s.%s (key, column1, column2, 
value) VALUES ('key1', 'val1', 1, NULL)", KEYSPACE, currentDenseTable()));
+        execute(String.format("INSERT INTO %s.%s (key, column1, column2, 
value) VALUES ('key1', 'val1', 1, ?)", KEYSPACE, currentDenseTable()), unset());
+        assertEmpty(execute(String.format("select * from %s.%s", KEYSPACE, 
currentDenseTable())));
+    }
+
+    @Test
+    public void testDenseTableCqlInserts() throws Throwable
+    {
+        Cassandra.Client client = getClient();
+
+        execute(String.format("INSERT INTO %s.%s (key, column1, column2, 
value) VALUES (?, ?, ?, ?)", KEYSPACE, currentDenseTable()),
+                "key1", "val1", 1, "value1");
+        execute(String.format("INSERT INTO %s.%s (key, column1, column2, 
value) VALUES (?, ?, 2, ?)", KEYSPACE, currentDenseTable()),
+                "key1", "val1", "value2");
+        execute(String.format("INSERT INTO %s.%s (key, column1, column2, 
value) VALUES ('key1', 'val2', 4, 'value4')", KEYSPACE, currentDenseTable()));
+        execute(String.format("INSERT INTO %s.%s (key, column1, column2, 
value) VALUES ('key1', 'val2', 5, 'value5')", KEYSPACE, currentDenseTable()));
+
+        execute(String.format("INSERT INTO %s.%s (key, column1, column2, 
value) VALUES ('key2', 'val1', 1, 'value1')", KEYSPACE, currentDenseTable()));
+        execute(String.format("INSERT INTO %s.%s (key, column1, column2, 
value) VALUES ('key2', 'val1', 2, 'value2')", KEYSPACE, currentDenseTable()));
+        execute(String.format("INSERT INTO %s.%s (key, column1, column2, 
value) VALUES ('key2', 'val2', 4, 'value4')", KEYSPACE, currentDenseTable()));
+        execute(String.format("INSERT INTO %s.%s (key, column1, column2, 
value) VALUES ('key2', 'val2', 5, 'value5')", KEYSPACE, currentDenseTable()));
+
+        ColumnPath path = new ColumnPath(currentDenseTable());
+        path.setSuper_column(ByteBufferUtil.bytes("val1"));
+
+        ColumnOrSuperColumn cosc = client.get(ByteBufferUtil.bytes("key1"), 
path, ONE);
+        assertEquals(cosc.getSuper_column().columns.get(0).name, 
ByteBufferUtil.bytes(1));
+        assertEquals(cosc.getSuper_column().columns.get(0).value, 
ByteBufferUtil.bytes("value1"));
+        assertEquals(cosc.getSuper_column().columns.get(1).name, 
ByteBufferUtil.bytes(2));
+        assertEquals(cosc.getSuper_column().columns.get(1).value, 
ByteBufferUtil.bytes("value2"));
+    }
+
+    @Test
+    public void testDenseTableCqlUpdates() throws Throwable
+    {
+        assertInvalidMessage("Column key is mandatory for SuperColumn tables",
+                             String.format("UPDATE %s.%s SET column2 = 1, 
value = 'value1' WHERE key = 'key1' AND column1 = 'val1'", KEYSPACE, 
currentDenseTable()));
+        assertInvalidMessage("Column `column2` of type `int` found in SET 
part",
+                             String.format("UPDATE %s.%s SET column2 = 1, 
value = 'value1' WHERE key = 'key1' AND column1 = 'val1' AND column2 = 1", 
KEYSPACE, currentDenseTable()));
+        assertInvalidMessage("Some clustering keys are missing: column1",
+                             String.format("UPDATE %s.%s SET value = 'value1' 
WHERE key = 'key1' AND column2 = 1", KEYSPACE, currentDenseTable()));
+
+        execute(String.format("UPDATE %s.%s SET value = 'value1' WHERE key = 
'key1' AND column1 = 'val1' AND column2 = 1", KEYSPACE, currentDenseTable()));
+        execute(String.format("UPDATE %s.%s SET value = 'value2' WHERE key = 
'key1' AND column1 = 'val1' AND column2 = 2", KEYSPACE, currentDenseTable()));
+
+        execute(String.format("UPDATE %s.%s SET value = ? WHERE key = ? AND 
column1 = ? AND column2 = ?", KEYSPACE, currentDenseTable()),
+                "value1", "key2", "val2", 1);
+        execute(String.format("UPDATE %s.%s SET value = 'value2' WHERE key = 
'key2' AND column1 = ? AND column2 = ?", KEYSPACE, currentDenseTable()),
+                "val2", 2);
+
+        Cassandra.Client client = getClient();
+        ColumnPath path = new ColumnPath(currentDenseTable());
+        path.setSuper_column(ByteBufferUtil.bytes("val1"));
+
+        ColumnOrSuperColumn cosc = client.get(ByteBufferUtil.bytes("key1"), 
path, ONE);
+        assertEquals(cosc.getSuper_column().columns.get(0).name, 
ByteBufferUtil.bytes(1));
+        assertEquals(cosc.getSuper_column().columns.get(0).value, 
ByteBufferUtil.bytes("value1"));
+        assertEquals(cosc.getSuper_column().columns.get(1).name, 
ByteBufferUtil.bytes(2));
+        assertEquals(cosc.getSuper_column().columns.get(1).value, 
ByteBufferUtil.bytes("value2"));
+
+        path = new ColumnPath(currentDenseTable());
+        path.setSuper_column(ByteBufferUtil.bytes("val2"));
+
+        cosc = client.get(ByteBufferUtil.bytes("key2"), path, ONE);
+        assertEquals(cosc.getSuper_column().columns.get(0).name, 
ByteBufferUtil.bytes(1));
+        assertEquals(cosc.getSuper_column().columns.get(0).value, 
ByteBufferUtil.bytes("value1"));
+        assertEquals(cosc.getSuper_column().columns.get(1).name, 
ByteBufferUtil.bytes(2));
+        assertEquals(cosc.getSuper_column().columns.get(1).value, 
ByteBufferUtil.bytes("value2"));
+    }
+
+
+    @Test
+    public void testDenseTableCqlDeletes() throws Throwable
+    {
+        execute(String.format("INSERT INTO %s.%s (key, column1, column2, 
value) VALUES ('key1', 'val1', 1, 'value1')", KEYSPACE, currentDenseTable()));
+        execute(String.format("INSERT INTO %s.%s (key, column1, column2, 
value) VALUES ('key1', 'val1', 2, 'value2')", KEYSPACE, currentDenseTable()));
+        execute(String.format("INSERT INTO %s.%s (key, column1, column2, 
value) VALUES ('key1', 'val2', 4, 'value4')", KEYSPACE, currentDenseTable()));
+        execute(String.format("INSERT INTO %s.%s (key, column1, column2, 
value) VALUES ('key1', 'val2', 5, 'value5')", KEYSPACE, currentDenseTable()));
+
+        execute(String.format("INSERT INTO %s.%s (key, column1, column2, 
value) VALUES ('key2', 'val1', 1, 'value1')", KEYSPACE, currentDenseTable()));
+        execute(String.format("INSERT INTO %s.%s (key, column1, column2, 
value) VALUES ('key2', 'val1', 2, 'value2')", KEYSPACE, currentDenseTable()));
+        execute(String.format("INSERT INTO %s.%s (key, column1, column2, 
value) VALUES ('key2', 'val2', 4, 'value4')", KEYSPACE, currentDenseTable()));
+        execute(String.format("INSERT INTO %s.%s (key, column1, column2, 
value) VALUES ('key2', 'val2', 5, 'value5')", KEYSPACE, currentDenseTable()));
+
+        execute(String.format("DELETE FROM %s.%s WHERE key = 'key1' AND 
column1 = 'val2' AND column2 = 5", KEYSPACE, currentDenseTable()));
+        assertRows(execute(String.format("SELECT * FROM %s.%s WHERE key = 
'key1'", KEYSPACE, currentDenseTable())),
+                   row("key1", "val1", 1, "value1"),
+                   row("key1", "val1", 2, "value2"),
+                   row("key1", "val2", 4, "value4"));
+        execute(String.format("DELETE FROM %s.%s WHERE key = 'key1' AND 
column1 = 'val2'", KEYSPACE, currentDenseTable()));
+        assertRows(execute(String.format("SELECT * FROM %s.%s WHERE key = 
'key1'", KEYSPACE, currentDenseTable())),
+                   row("key1", "val1", 1, "value1"),
+                   row("key1", "val1", 2, "value2"));
+        execute(String.format("DELETE FROM %s.%s WHERE key = 'key1'", 
KEYSPACE, currentDenseTable()));
+        assertEmpty(execute(String.format("SELECT * FROM %s.%s WHERE key = 
'key1'", KEYSPACE, currentDenseTable())));
+
+        Cassandra.Client client = getClient();
+
+        Mutation mutation1 = new Mutation();
+        SlicePredicate slicePredicate = new SlicePredicate();
+        slicePredicate.setSlice_range(new 
SliceRange(ByteBufferUtil.bytes("val1"), ByteBufferUtil.bytes("val1"), false, 
1));
+        Deletion deletion1 = new Deletion();
+        deletion1.setTimestamp(FBUtilities.timestampMicros());
+        deletion1.setPredicate(slicePredicate);
+        mutation1.setDeletion(deletion1);
+        
client.batch_mutate(Collections.singletonMap(ByteBufferUtil.bytes("key2"),
+                                                     
Collections.singletonMap(currentDenseTable(), Arrays.asList(mutation1))),
+                            ONE);
+        assertRows(execute(String.format("SELECT * FROM %s.%s WHERE key = 
'key2'", KEYSPACE, currentDenseTable())),
+                   row("key2", "val2", 4, "value4"),
+                   row("key2", "val2", 5, "value5"));
+
+        Mutation mutation2 = new Mutation();
+        Deletion deletion2 = new Deletion();
+        deletion2.setTimestamp(FBUtilities.timestampMicros());
+        deletion2.setSuper_column(ByteBufferUtil.bytes("val2"));
+        mutation2.setDeletion(deletion2);
+        
client.batch_mutate(Collections.singletonMap(ByteBufferUtil.bytes("key2"),
+                                                     
Collections.singletonMap(currentDenseTable(), Arrays.asList(mutation2))),
+                            ONE);
+
+        assertEmpty(execute(String.format("SELECT * FROM %s.%s WHERE key = 
'key2'", KEYSPACE, currentDenseTable())));
+
+        execute(String.format("INSERT INTO %s.%s (key, column1, column2, 
value) VALUES ('key1', 'val1', 1, 'value1')", KEYSPACE, currentDenseTable()));
+        execute(String.format("INSERT INTO %s.%s (key, column1, column2, 
value) VALUES ('key2', 'val1', 1, 'value1')", KEYSPACE, currentDenseTable()));
+        execute(String.format("INSERT INTO %s.%s (key, column1, column2, 
value) VALUES ('key3', 'val1', 1, 'value1')", KEYSPACE, currentDenseTable()));
+
+        execute(String.format("DELETE FROM %s.%s WHERE key IN ('key1', 
'key2')", KEYSPACE, currentDenseTable()));
+        assertRows(execute(String.format("SELECT * FROM %s.%s", KEYSPACE, 
currentDenseTable())),
+                   row("key3", "val1", 1, "value1"));
+
+        assertInvalidMessage("Multi-column relations cannot be used in WHERE 
clauses for UPDATE and DELETE statements",
+                             String.format("DELETE FROM %s.%s WHERE key = 
'key3' AND (column1, column2) = ('val1', 1)", KEYSPACE, currentDenseTable()));
+
+        assertInvalidMessage("Token relations cannot be used in WHERE clauses 
for UPDATE and DELETE statements: token(key) > token('key3')",
+                             String.format("DELETE FROM %s.%s WHERE token(key) 
> token('key3')", KEYSPACE, currentDenseTable()));
+    }
+
+    @Test
+    public void testSparseTableAlter() throws Throwable
+    {
+        populateSparseTable();
+
+        alterTable(String.format("ALTER TABLE %s.%s RENAME column1 TO 
renamed_column1", KEYSPACE, currentSparseTable()));
+        alterTable(String.format("ALTER TABLE %s.%s RENAME key TO 
renamed_key", KEYSPACE, currentSparseTable()));
+        assertInvalidMessage("Cannot rename non PRIMARY KEY part col1",
+                             String.format("ALTER TABLE %s.%s RENAME col1 TO 
renamed_col1", KEYSPACE, currentSparseTable()));
+        assertInvalidMessage("Cannot rename non PRIMARY KEY part col2",
+                             String.format("ALTER TABLE %s.%s RENAME col2 TO 
renamed_col2", KEYSPACE, currentSparseTable()));
+        assertInvalidMessage("Cannot rename unknown column column2 in 
keyspace",
+                             String.format("ALTER TABLE %s.%s RENAME column2 
TO renamed_column2", KEYSPACE, currentSparseTable()));
+        assertInvalidMessage("Cannot rename unknown column value in keyspace",
+                             String.format("ALTER TABLE %s.%s RENAME value TO 
renamed_value", KEYSPACE, currentSparseTable()));
+
+
+        UntypedResultSet resultSet = execute(String.format("select * from 
%s.%s", KEYSPACE, currentSparseTable()));
+        assertEquals("renamed_key", 
resultSet.metadata().get(0).name.toString());
+        assertEquals("renamed_column1", 
resultSet.metadata().get(1).name.toString());
+        assertEquals("col1", resultSet.metadata().get(2).name.toString());
+        assertEquals("col2", resultSet.metadata().get(3).name.toString());
+
+        assertRows(resultSet,
+                   row("key1", "val1", 3L, 4L),
+                   row("key1", "val2", 3L, 4L),
+                   row("key2", "val1", 3L, 4L),
+                   row("key2", "val2", 3L, 4L));
+    }
+
+    @Test
+    public void testSparseTableCqlReads() throws Throwable
+    {
+        populateSparseTable();
+        beforeAndAfterFlush(this::testSparseTableCqlReadsInternal);
+    }
+
+    private void testSparseTableCqlReadsInternal() throws Throwable
+    {
+        UntypedResultSet resultSet = execute(String.format("select * from 
%s.%s", KEYSPACE, currentSparseTable()));
+        assertEquals("key", resultSet.metadata().get(0).name.toString());
+        assertEquals("column1", resultSet.metadata().get(1).name.toString());
+        assertEquals("col1", resultSet.metadata().get(2).name.toString());
+        assertEquals("col2", resultSet.metadata().get(3).name.toString());
+
+        assertRows(resultSet,
+                   row("key1", "val1", 3L, 4L),
+                   row("key1", "val2", 3L, 4L),
+                   row("key2", "val1", 3L, 4L),
+                   row("key2", "val2", 3L, 4L));
+
+        assertRows(execute(String.format("select col1, col2, column1, key from 
%s.%s", KEYSPACE, currentSparseTable())),
+                   row(3L, 4L, "val1", "key1"),
+                   row(3L, 4L, "val2", "key1"),
+                   row(3L, 4L, "val1", "key2"),
+                   row(3L, 4L, "val2", "key2"));
+
+        assertInvalidMessage("Undefined name value in selection clause",
+                             String.format("select value from %s.%s", 
KEYSPACE, currentSparseTable()));
+
+        assertRows(execute(String.format("select * from %s.%s WHERE key = ? 
AND column1 = ?", KEYSPACE, currentSparseTable()), "key1", "val2"),
+                   row("key1", "val2", 3L, 4L));
+
+        resultSet = execute(String.format("select col1 as a, col2 as b, 
column1 as c, key as d from %s.%s WHERE key = ? AND column1 = ?", KEYSPACE, 
currentSparseTable()), "key1", "val2");
+        assertRows(resultSet,
+                   row(3L, 4L, "val2", "key1"));
+        assertEquals(resultSet.metadata().get(0).name, 
ColumnIdentifier.getInterned("a", true));
+        assertEquals(resultSet.metadata().get(1).name, 
ColumnIdentifier.getInterned("b", true));
+        assertEquals(resultSet.metadata().get(2).name, 
ColumnIdentifier.getInterned("c", true));
+        assertEquals(resultSet.metadata().get(3).name, 
ColumnIdentifier.getInterned("d", true));
+
+        assertRows(execute(String.format("select col1, col2 from %s.%s WHERE 
key = ? AND column1 = ?", KEYSPACE, currentSparseTable()), "key1", "val2"),
+                   row(3L, 4L));
+
+        assertInvalidMessage("Secondary indexes are not supported on COMPACT 
STORAGE tables that have clustering columns",
+                             String.format("CREATE INDEX ON %s.%s (column1)", 
KEYSPACE, currentSparseTable()));
+        assertInvalidMessage("Secondary indexes are not supported on COMPACT 
STORAGE tables that have clustering columns",
+                             String.format("CREATE INDEX ON %s.%s (col1)", 
KEYSPACE, currentSparseTable()));
+
+        assertRows(execute(String.format("SELECT JSON * FROM %s.%s WHERE key = 
? AND column1 = ?", KEYSPACE, currentSparseTable()), "key1", "val2"),
+                   row("{\"key\": \"key1\", \"column1\": \"val2\", \"col1\": 
3, \"col2\": 4}"));
+    }
+
+    @Test
+    public void testSparseTableCqlInserts() throws Throwable
+    {
+        execute(String.format("insert into %s.%s (key, column1, col1, col2) 
values ('key1', 'val1', 1, 2)", KEYSPACE, currentSparseTable()));
+        execute(String.format("insert into %s.%s (key, column1, col1, col2) 
values ('key1', 'val2', 3, 4)", KEYSPACE, currentSparseTable()));
+        execute(String.format("insert into %s.%s (key, column1, col1, col2) 
values ('key2', 'val1', 5, 6)", KEYSPACE, currentSparseTable()));
+        execute(String.format("insert into %s.%s (key, column1, col1, col2) 
values ('key2', 'val2', 7, 8)", KEYSPACE, currentSparseTable()));
+
+        assertRows(execute(String.format("SELECT * FROM %s.%s", KEYSPACE, 
currentSparseTable())),
+                   row("key1", "val1", 1L, 2L),
+                   row("key1", "val2", 3L, 4L),
+                   row("key2", "val1", 5L, 6L),
+                   row("key2", "val2", 7L, 8L));
+
+        execute(String.format("truncate %s.%s", KEYSPACE, 
currentSparseTable()));
+
+        execute(String.format("insert into %s.%s (key, column1) values 
('key1', 'val1')", KEYSPACE, currentSparseTable()));
+        assertRows(execute(String.format("select * from %s.%s", KEYSPACE, 
currentSparseTable())));
+
+        execute(String.format("insert into %s.%s (key, column1, col1) values 
('key1', 'val1', 1)", KEYSPACE, currentSparseTable()));
+        execute(String.format("insert into %s.%s (key, column1, col2) values 
('key1', 'val1', 2)", KEYSPACE, currentSparseTable()));
+        assertRows(execute(String.format("select * from %s.%s", KEYSPACE, 
currentSparseTable())),
+                   row("key1", "val1", 1L, 2L));
+
+        Cassandra.Client client = getClient();
+        ColumnPath path = new ColumnPath(currentSparseTable());
+        path.setSuper_column(ByteBufferUtil.bytes("val1"));
+
+        ColumnOrSuperColumn cosc = client.get(ByteBufferUtil.bytes("key1"), 
path, ONE);
+        assertEquals(cosc.getSuper_column().columns.get(0).value, 
ByteBufferUtil.bytes(1L));
+        assertEquals(cosc.getSuper_column().columns.get(0).name, 
ByteBufferUtil.bytes("col1"));
+        assertEquals(cosc.getSuper_column().columns.get(1).value, 
ByteBufferUtil.bytes(2L));
+        assertEquals(cosc.getSuper_column().columns.get(1).name, 
ByteBufferUtil.bytes("col2"));
+    }
+
+    @Test
+    public void testSparseTableCqlUpdates() throws Throwable
+    {
+        execute(String.format("UPDATE %s.%s set col1 = 1, col2 = 2 WHERE key = 
'key1' AND column1 = 'val1'", KEYSPACE, currentSparseTable()));
+        execute(String.format("UPDATE %s.%s set col1 = 3, col2 = 4 WHERE key = 
'key1' AND column1 = 'val2'", KEYSPACE, currentSparseTable()));
+        execute(String.format("UPDATE %s.%s set col1 = 5, col2 = 6 WHERE key = 
'key2' AND column1 = 'val1'", KEYSPACE, currentSparseTable()));
+        execute(String.format("UPDATE %s.%s set col1 = 7, col2 = 8 WHERE key = 
'key2' AND column1 = 'val2'", KEYSPACE, currentSparseTable()));
+
+        assertRows(execute(String.format("SELECT * FROM %s.%s", KEYSPACE, 
currentSparseTable())),
+                   row("key1", "val1", 1L, 2L),
+                   row("key1", "val2", 3L, 4L),
+                   row("key2", "val1", 5L, 6L),
+                   row("key2", "val2", 7L, 8L));
+
+        Cassandra.Client client = getClient();
+        ColumnPath path = new ColumnPath(currentSparseTable());
+        path.setSuper_column(ByteBufferUtil.bytes("val1"));
+
+        ColumnOrSuperColumn cosc = client.get(ByteBufferUtil.bytes("key1"), 
path, ONE);
+        assertEquals(cosc.getSuper_column().columns.get(0).value, 
ByteBufferUtil.bytes(1L));
+        assertEquals(cosc.getSuper_column().columns.get(0).name, 
ByteBufferUtil.bytes("col1"));
+        assertEquals(cosc.getSuper_column().columns.get(1).value, 
ByteBufferUtil.bytes(2L));
+        assertEquals(cosc.getSuper_column().columns.get(1).name, 
ByteBufferUtil.bytes("col2"));
+    }
+
+    @Test
+    public void testSparseTableCqlDeletes() throws Throwable
+    {
+        execute(String.format("insert into %s.%s (key, column1, col1, col2) 
values ('key1', 'val1', 1, 2)", KEYSPACE, currentSparseTable()));
+        execute(String.format("insert into %s.%s (key, column1, col1, col2) 
values ('key1', 'val2', 3, 4)", KEYSPACE, currentSparseTable()));
+        execute(String.format("insert into %s.%s (key, column1, col1, col2) 
values ('key2', 'val1', 5, 6)", KEYSPACE, currentSparseTable()));
+        execute(String.format("insert into %s.%s (key, column1, col1, col2) 
values ('key2', 'val2', 7, 8)", KEYSPACE, currentSparseTable()));
+
+        execute(String.format("DELETE col1 FROM %s.%s WHERE key = 'key1' AND 
column1 = 'val1'", KEYSPACE, currentSparseTable()));
+
+        assertRows(execute(String.format("SELECT * FROM %s.%s", KEYSPACE, 
currentSparseTable())),
+                   row("key1", "val1", null, 2L),
+                   row("key1", "val2", 3L, 4L),
+                   row("key2", "val1", 5L, 6L),
+                   row("key2", "val2", 7L, 8L));
+
+        execute(String.format("DELETE FROM %s.%s WHERE key = 'key1' AND 
column1 = 'val2'", KEYSPACE, currentSparseTable()));
+
+        assertRows(execute(String.format("SELECT * FROM %s.%s", KEYSPACE, 
currentSparseTable())),
+                   row("key1", "val1", null, 2L),
+                   row("key2", "val1", 5L, 6L),
+                   row("key2", "val2", 7L, 8L));
+
+        execute(String.format("DELETE FROM %s.%s WHERE key = 'key2'", 
KEYSPACE, currentSparseTable()));
+
+        assertRows(execute(String.format("SELECT * FROM %s.%s", KEYSPACE, 
currentSparseTable())),
+                   row("key1", "val1", null, 2L));
+    }
+
+    @Test
+    public void testInsertJson() throws Throwable
+    {
+        execute(String.format("INSERT INTO %s.%s JSON ?", KEYSPACE, 
currentDenseTable()),
+                "{\"key\": \"key5\", \"column1\": \"val2\", \"column2\": 4, 
\"value\": \"value4\"}");
+        assertRows(execute(String.format("SELECT * FROM %s.%s", KEYSPACE, 
currentDenseTable())),
+                   row("key5", "val2", 4, "value4"));
+
+        execute(String.format("INSERT INTO %s.%s JSON ?", KEYSPACE, 
currentSparseTable()),
+                "{\"key\": \"key1\", \"column1\": \"val1\", \"col1\": 1, 
\"col2\": 2}");
+        assertRows(execute(String.format("SELECT * FROM %s.%s", KEYSPACE, 
currentSparseTable())),
+                   row("key1", "val1", 1L, 2L));
+    }
+
+    @Test
+    public void testFiltering() throws Throwable
+    {
+        assertInvalidMessage("Filtering is not supported on SuperColumn 
tables",
+                             String.format("select * from %s.%s WHERE value = 
?", KEYSPACE, currentDenseTable()),
+                             "value5");
+        assertInvalidMessage("Filtering is not supported on SuperColumn 
tables",
+                             String.format("select * from %s.%s WHERE value = 
? ALLOW FILTERING", KEYSPACE, currentDenseTable()),
+                             "value5");
+        assertInvalidMessage("Filtering is not supported on SuperColumn 
tables",
+                             String.format("SELECT * FROM %s.%s WHERE value = 
'value2' ALLOW FILTERING", KEYSPACE, currentDenseTable()));
+        assertInvalidMessage("Filtering is not supported on SuperColumn 
tables",
+                             String.format("SELECT * FROM %s.%s WHERE column2 
= 1 ALLOW FILTERING", KEYSPACE, currentDenseTable()));
+    }
+
+    @Test
+    public void testLwt() throws Throwable
+    {
+        assertRows(execute(String.format("INSERT INTO %s.%s (key, column1, 
column2, value) VALUES (?, ?, ?, ?) IF NOT EXISTS", KEYSPACE, 
currentDenseTable()),
+                           "key1", "val1", 1, "value1"),
+                   row(true));
+        assertRows(execute(String.format("SELECT * FROM %s.%s", KEYSPACE, 
currentDenseTable())),
+                   row("key1", "val1", 1, "value1"));
+        assertRows(execute(String.format("INSERT INTO %s.%s (key, column1, 
column2, value) VALUES (?, ?, ?, ?) IF NOT EXISTS", KEYSPACE, 
currentDenseTable()),
+                           "key1", "val1", 1, "value1"),
+                   row(false, "key1", "val1", 1, "value1"));
+
+        // in 2.2 this query was a no-op
+        assertInvalidMessage("Lightweight transactions on SuperColumn tables 
are only supported with supplied SuperColumn key",
+                             String.format("UPDATE %s.%s SET value = 'changed' 
WHERE key = ? AND column1 = ? IF value = ?", KEYSPACE, currentDenseTable()));
+
+        assertRows(execute(String.format("UPDATE %s.%s SET value = 'changed' 
WHERE key = ? AND column1 = ? AND column2 = ? IF value = ?", KEYSPACE, 
currentDenseTable()),
+                           "key1", "val1", 1, "value1"),
+                   row(true));
+        assertRows(execute(String.format("SELECT * FROM %s.%s", KEYSPACE, 
currentDenseTable())),
+                   row("key1", "val1", 1, "changed"));
+        assertRows(execute(String.format("UPDATE %s.%s SET value = 'changed' 
WHERE key = ? AND column1 = ? AND column2 = ? IF value = ?", KEYSPACE, 
currentDenseTable()),
+                           "key1", "val1", 1, "value1"),
+                   row(false, "changed"));
+
+        assertRows(execute(String.format("UPDATE %s.%s SET value = 'changed2' 
WHERE key = ? AND column1 = ? AND column2 = ? IF value > ?", KEYSPACE, 
currentDenseTable()),
+                           "key1", "val1", 1, "a"),
+                   row(true));
+        assertRows(execute(String.format("SELECT * FROM %s.%s", KEYSPACE, 
currentDenseTable())),
+                   row("key1", "val1", 1, "changed2"));
+        assertRows(execute(String.format("UPDATE %s.%s SET value = 'changed2' 
WHERE key = ? AND column1 = ? AND column2 = ? IF value < ?", KEYSPACE, 
currentDenseTable()),
+                           "key1", "val1", 1, "a"),
+                   row(false, "changed2"));
+
+        assertInvalidMessage("PRIMARY KEY column 'column2' cannot have IF 
conditions",
+                             String.format("UPDATE %s.%s SET value = 
'changed2' WHERE key = ? AND column1 = ? AND column2 = ? IF value > ? AND 
column2 = ?", KEYSPACE, currentDenseTable()));
+
+        assertInvalidMessage("Lightweight transactions on SuperColumn tables 
are only supported with supplied SuperColumn key",
+                             String.format("UPDATE %s.%s SET value = 
'changed2' WHERE key = ? AND column1 = ? IF value > ?", KEYSPACE, 
currentDenseTable()));
+
+        execute(String.format("DELETE FROM %s.%s WHERE key = 'key1' AND 
column1 = 'val1' AND column2 = 1 IF EXISTS", KEYSPACE, currentDenseTable()));
+        assertEmpty(execute(String.format("SELECT * FROM %s.%s", KEYSPACE, 
currentDenseTable())));
+
+        execute(String.format("INSERT INTO %s.%s (key, column1, column2, 
value) VALUES (?, ?, ?, ?)", KEYSPACE, currentDenseTable()),
+                "key1", "val1", 1, "value1");
+
+        assertRows(execute(String.format("DELETE FROM %s.%s WHERE key = 'key1' 
AND column1 = 'val1' AND column2 = 1 IF value = 'value1'", KEYSPACE, 
currentDenseTable())),
+                   row(true));
+        assertEmpty(execute(String.format("SELECT * FROM %s.%s", KEYSPACE, 
currentDenseTable())));
+
+        assertRows(execute(String.format("DELETE FROM %s.%s WHERE key = 'key1' 
AND column1 = 'val1' AND column2 = 1 IF value = 'value1'", KEYSPACE, 
currentDenseTable())),
+                   row(false));
+        assertEmpty(execute(String.format("SELECT * FROM %s.%s", KEYSPACE, 
currentDenseTable())));
+    }
+
+    @Test
+    public void testCqlAggregateFunctions() throws Throwable
+    {
+        populateDenseTable();
+        populateSparseTable();
+
+        assertRows(execute(String.format("select count(*) from %s.%s", 
KEYSPACE, currentDenseTable())),
+                   row(8L));
+        assertRows(execute(String.format("select count(*) from %s.%s", 
KEYSPACE, currentSparseTable())),
+                   row(4L));
+
+        assertRows(execute(String.format("select count(*) from %s.%s where key 
= ? AND column1 = ?", KEYSPACE, currentDenseTable()), "key1", "val1"),
+                   row(2L));
+        assertRows(execute(String.format("select count(*) from %s.%s where key 
= ? AND column1 = ?", KEYSPACE, currentSparseTable()), "key1", "val1"),
+                   row(1L));
+        assertRows(execute(String.format("select count(*) from %s.%s where key 
= ?", KEYSPACE, currentSparseTable()), "key1"),
+                   row(2L));
+
+        assertRows(execute(String.format("select max(value) from %s.%s", 
KEYSPACE, currentDenseTable())),
+                   row("value5"));
+        assertRows(execute(String.format("select max(col1) from %s.%s", 
KEYSPACE, currentSparseTable())),
+                   row(3L));
+
+        assertRows(execute(String.format("select avg(column2) from %s.%s", 
KEYSPACE, currentDenseTable())),
+                   row(3));
+        assertRows(execute(String.format("select avg(col1) from %s.%s", 
KEYSPACE, currentSparseTable())),
+                   row(3L));
+    }
+
+    private void populateDenseTable() throws Throwable
+    {
+        Cassandra.Client client = getClient();
+
+        Mutation mutation = new Mutation();
+        ColumnOrSuperColumn csoc = new ColumnOrSuperColumn();
+        
csoc.setSuper_column(getSuperColumnForInsert(ByteBufferUtil.bytes("val1"),
+                                                     
Arrays.asList(getColumnForInsert(ByteBufferUtil.bytes(1), 
ByteBufferUtil.bytes("value1")),
+                                                                   
getColumnForInsert(ByteBufferUtil.bytes(2), ByteBufferUtil.bytes("value2")))));
+        mutation.setColumn_or_supercolumn(csoc);
+
+        Mutation mutation2 = new Mutation();
+        ColumnOrSuperColumn csoc2 = new ColumnOrSuperColumn();
+        
csoc2.setSuper_column(getSuperColumnForInsert(ByteBufferUtil.bytes("val2"),
+                                                      
Arrays.asList(getColumnForInsert(ByteBufferUtil.bytes(4), 
ByteBufferUtil.bytes("value4")),
+                                                                    
getColumnForInsert(ByteBufferUtil.bytes(5), ByteBufferUtil.bytes("value5")))));
+        mutation2.setColumn_or_supercolumn(csoc2);
+
+        
client.batch_mutate(Collections.singletonMap(ByteBufferUtil.bytes("key1"),
+                                                     
Collections.singletonMap(currentDenseTable(), Arrays.asList(mutation, 
mutation2))),
+                            ONE);
+
+        
client.batch_mutate(Collections.singletonMap(ByteBufferUtil.bytes("key2"),
+                                                     
Collections.singletonMap(currentDenseTable(), Arrays.asList(mutation, 
mutation2))),
+                            ONE);
+    }
+
+    private void populateSparseTable() throws Throwable
+    {
+        Cassandra.Client client = getClient();
+
+        Mutation mutation = new Mutation();
+        ColumnOrSuperColumn csoc = new ColumnOrSuperColumn();
+        
csoc.setSuper_column(getSuperColumnForInsert(ByteBufferUtil.bytes("val1"),
+                                                     
Arrays.asList(getColumnForInsert(ByteBufferUtil.bytes("value1"), 
ByteBufferUtil.bytes(1L)),
+                                                                   
getColumnForInsert(ByteBufferUtil.bytes("value2"), ByteBufferUtil.bytes(2L)),
+                                                                   
getColumnForInsert(ByteBufferUtil.bytes("col1"), ByteBufferUtil.bytes(3L)),
+                                                                   
getColumnForInsert(ByteBufferUtil.bytes("col2"), ByteBufferUtil.bytes(4L)))));
+        mutation.setColumn_or_supercolumn(csoc);
+
+        Mutation mutation2 = new Mutation();
+        ColumnOrSuperColumn csoc2 = new ColumnOrSuperColumn();
+        
csoc2.setSuper_column(getSuperColumnForInsert(ByteBufferUtil.bytes("val2"),
+                                                      
Arrays.asList(getColumnForInsert(ByteBufferUtil.bytes("value1"), 
ByteBufferUtil.bytes(1L)),
+                                                                    
getColumnForInsert(ByteBufferUtil.bytes("value2"), ByteBufferUtil.bytes(2L)),
+                                                                    
getColumnForInsert(ByteBufferUtil.bytes("col1"), ByteBufferUtil.bytes(3L)),
+                                                                    
getColumnForInsert(ByteBufferUtil.bytes("col2"), ByteBufferUtil.bytes(4L)))));
+        mutation2.setColumn_or_supercolumn(csoc2);
+
+        
client.batch_mutate(Collections.singletonMap(ByteBufferUtil.bytes("key1"),
+                                                     
Collections.singletonMap(currentSparseTable(), Arrays.asList(mutation, 
mutation2))),
+                            ONE);
+
+        
client.batch_mutate(Collections.singletonMap(ByteBufferUtil.bytes("key2"),
+                                                     
Collections.singletonMap(currentSparseTable(), Arrays.asList(mutation, 
mutation2))),
+                            ONE);
+    }
+
+    private void populateCounterTable() throws Throwable
+    {
+        Cassandra.Client client = getClient();
+
+        ColumnParent cp = new ColumnParent(currentCounterTable());
+        cp.setSuper_column(ByteBufferUtil.bytes("ck1"));
+        client.add(ByteBufferUtil.bytes("key1"),
+                   cp,
+                   new CounterColumn(ByteBufferUtil.bytes("counter1"), 10L),
+                   ONE);
+        cp = new ColumnParent(currentCounterTable());
+        cp.setSuper_column(ByteBufferUtil.bytes("ck1"));
+        client.add(ByteBufferUtil.bytes("key1"),
+                   cp,
+                   new CounterColumn(ByteBufferUtil.bytes("counter2"), 5L),
+                   ONE);
+        cp = new ColumnParent(currentCounterTable());
+        cp.setSuper_column(ByteBufferUtil.bytes("ck1"));
+        client.add(ByteBufferUtil.bytes("key2"),
+                   cp,
+                   new CounterColumn(ByteBufferUtil.bytes("counter1"), 10L),
+                   ONE);
+        cp = new ColumnParent(currentCounterTable());
+        cp.setSuper_column(ByteBufferUtil.bytes("ck1"));
+        client.add(ByteBufferUtil.bytes("key2"),
+                   cp,
+                   new CounterColumn(ByteBufferUtil.bytes("counter2"), 5L),
+                   ONE);
+    }
+
+    private String currentCounterTable()
+    {
+        return currentTable() + "_counter";
+    }
+
+    private String currentSparseTable()
+    {
+        return currentTable() + "_sparse";
+    }
+
+    private String currentDenseTable()
+    {
+        return currentTable();
+    }
+
+    private Column getColumnForInsert(ByteBuffer columnName, ByteBuffer value)
+    {
+        Column column = new Column();
+        column.setName(columnName);
+        column.setValue(value);
+        column.setTimestamp(System.currentTimeMillis());
+        return column;
+    }
+
+    private SuperColumn getSuperColumnForInsert(ByteBuffer columnName, 
List<Column> columns)
+    {
+        SuperColumn column = new SuperColumn();
+        column.setName(columnName);
+        for (Column c : columns)
+            column.addToColumns(c);
+        return column;
+    }
+
+    public void beforeAndAfterFlush(CheckedFunction runnable) throws Throwable
+    {
+        runnable.apply();
+        flushAll();
+        runnable.apply();
+    }
+
+    private void flushAll()
+    {
+        for (String cfName : new String[]{ currentTable(), 
currentSparseTable(), currentCounterTable() })
+            Keyspace.open(KEYSPACE).getColumnFamilyStore(cfName);
+    }
+}

http://git-wip-us.apache.org/repos/asf/cassandra/blob/ce8c9b55/test/unit/org/apache/cassandra/cql3/validation/operations/ThriftCQLTester.java
----------------------------------------------------------------------
diff --git 
a/test/unit/org/apache/cassandra/cql3/validation/operations/ThriftCQLTester.java
 
b/test/unit/org/apache/cassandra/cql3/validation/operations/ThriftCQLTester.java
new file mode 100644
index 0000000..a77e861
--- /dev/null
+++ 
b/test/unit/org/apache/cassandra/cql3/validation/operations/ThriftCQLTester.java
@@ -0,0 +1,90 @@
+/*
+ * 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 java.io.IOException;
+import java.net.InetAddress;
+import java.net.ServerSocket;
+import java.net.UnknownHostException;
+
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+
+import org.apache.cassandra.config.DatabaseDescriptor;
+import org.apache.cassandra.cql3.*;
+import org.apache.cassandra.dht.ByteOrderedPartitioner;
+import org.apache.cassandra.dht.Murmur3Partitioner;
+import org.apache.cassandra.service.*;
+import org.apache.cassandra.thrift.*;
+import org.apache.thrift.protocol.TBinaryProtocol;
+import org.apache.thrift.transport.TFramedTransport;
+import org.apache.thrift.transport.TSocket;
+
+public class ThriftCQLTester extends CQLTester
+{
+    private Cassandra.Client client;
+
+    private static ThriftServer thriftServer;
+    private static int thriftPort;
+
+    static {
+        try (ServerSocket serverSocket = new ServerSocket(0))
+        {
+            thriftPort = serverSocket.getLocalPort();
+        }
+        catch (IOException e)
+        {
+            // ignore
+        }
+    }
+
+    @BeforeClass
+    public static void setup() throws Exception
+    {
+        StorageService.instance.initServer(0);
+
+        if (thriftServer == null || ! thriftServer.isRunning())
+        {
+            thriftServer = new ThriftServer(InetAddress.getLocalHost(), 
thriftPort, 50);
+            thriftServer.start();
+        }
+    }
+
+    @AfterClass
+    public static void teardown()
+    {
+        if (thriftServer != null && thriftServer.isRunning())
+        {
+            thriftServer.stop();
+        }
+    }
+
+    public Cassandra.Client getClient() throws Throwable
+    {
+        return getClient(InetAddress.getLocalHost().getHostName(), thriftPort);
+    }
+
+    public Cassandra.Client getClient(String hostname, int thriftPort) throws 
Throwable
+       {
+        if (client == null)
+            client = new Cassandra.Client(new TBinaryProtocol(new 
TFramedTransportFactory().openTransport(hostname, thriftPort)));
+
+        return client;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cassandra/blob/ce8c9b55/test/unit/org/apache/cassandra/db/ColumnFamilyStoreCQLHelperTest.java
----------------------------------------------------------------------
diff --git 
a/test/unit/org/apache/cassandra/db/ColumnFamilyStoreCQLHelperTest.java 
b/test/unit/org/apache/cassandra/db/ColumnFamilyStoreCQLHelperTest.java
index c2e5cb7..714b61a 100644
--- a/test/unit/org/apache/cassandra/db/ColumnFamilyStoreCQLHelperTest.java
+++ b/test/unit/org/apache/cassandra/db/ColumnFamilyStoreCQLHelperTest.java
@@ -650,9 +650,8 @@ public class ColumnFamilyStoreCQLHelperTest extends 
CQLTester
         final String TABLE = "test_table_1";
 
         CFMetaData cfm = CFMetaData.Builder.createSuper(KEYSPACE, TABLE, false)
-                                           .addPartitionKey("pk", 
BytesType.instance)
-                                           .addClusteringColumn("c1", 
AsciiType.instance)
-                                           .addClusteringColumn("c2", 
AsciiType.instance)
+                                           .addPartitionKey("key", 
BytesType.instance)
+                                           .addClusteringColumn("column1", 
AsciiType.instance)
                                            .addRegularColumn("", 
MapType.getInstance(Int32Type.instance, AsciiType.instance, true))
                                            .build();
 
@@ -668,11 +667,10 @@ public class ColumnFamilyStoreCQLHelperTest extends 
CQLTester
         "Approximate structure, for reference:\n" +
         "(this should not be used to reproduce this schema)\n\n" +
         "CREATE TABLE IF NOT EXISTS " + KEYSPACE + "." + TABLE + " (\n" +
-        "\tpk blob,\n" +
-        "\tc1 ascii,\n" +
-        "\tc2 ascii,\n" +
+        "\tkey blob,\n" +
+        "\tcolumn1 ascii,\n" +
         "\t\"\" map<int, ascii>,\n" +
-        "\tPRIMARY KEY (pk, c1, c2))\n" +
+        "\tPRIMARY KEY (key, column1))\n" +
         "\tWITH ID = " + cfs.metadata.cfId + "\n" +
         "\tAND COMPACT STORAGE"));
     }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/ce8c9b55/test/unit/org/apache/cassandra/schema/LegacySchemaMigratorTest.java
----------------------------------------------------------------------
diff --git 
a/test/unit/org/apache/cassandra/schema/LegacySchemaMigratorTest.java 
b/test/unit/org/apache/cassandra/schema/LegacySchemaMigratorTest.java
index fe91ddc..f7b0e47 100644
--- a/test/unit/org/apache/cassandra/schema/LegacySchemaMigratorTest.java
+++ b/test/unit/org/apache/cassandra/schema/LegacySchemaMigratorTest.java
@@ -164,14 +164,8 @@ public class LegacySchemaMigratorTest
                                                                     
.compaction(CompactionParams.scts(compactionOptions)),
                                                         
SchemaLoader.standardCFMD(ks1, "StandardGCGS0").gcGraceSeconds(0),
                                                         
SchemaLoader.standardCFMD(ks1, "StandardLong1"),
-                                                        
SchemaLoader.superCFMD(ks1, "Super1", LongType.instance),
-                                                        
SchemaLoader.superCFMD(ks1, "Super2", UTF8Type.instance),
-                                                        
SchemaLoader.superCFMD(ks1, "Super5", BytesType.instance),
-                                                        
SchemaLoader.superCFMD(ks1, "Super6", LexicalUUIDType.instance, 
UTF8Type.instance),
                                                         
SchemaLoader.keysIndexCFMD(ks1, "Indexed1", true),
                                                         
SchemaLoader.keysIndexCFMD(ks1, "Indexed2", false),
-                                                        
SchemaLoader.superCFMD(ks1, "SuperDirectGC", BytesType.instance)
-                                                                    
.gcGraceSeconds(0),
                                                         
SchemaLoader.jdbcCFMD(ks1, "JdbcUtf8", UTF8Type.instance)
                                                                     
.addColumnDefinition(SchemaLoader.utf8Column(ks1, "JdbcUtf8")),
                                                         
SchemaLoader.jdbcCFMD(ks1, "JdbcLong", LongType.instance),
@@ -190,8 +184,6 @@ public class LegacySchemaMigratorTest
         keyspaces.add(KeyspaceMetadata.create(ks2,
                                               KeyspaceParams.simple(1),
                                               
Tables.of(SchemaLoader.standardCFMD(ks2, "Standard1"),
-                                                        
SchemaLoader.superCFMD(ks2, "Super3", BytesType.instance),
-                                                        
SchemaLoader.superCFMD(ks2, "Super4", TimeUUIDType.instance),
                                                         
SchemaLoader.keysIndexCFMD(ks2, "Indexed1", true),
                                                         
SchemaLoader.compositeIndexCFMD(ks2, "Indexed2", true),
                                                         
SchemaLoader.compositeIndexCFMD(ks2, "Indexed3", true)
@@ -206,10 +198,7 @@ public class LegacySchemaMigratorTest
         // Keyspace 4
         keyspaces.add(KeyspaceMetadata.create(ks4,
                                               KeyspaceParams.simple(3),
-                                              
Tables.of(SchemaLoader.standardCFMD(ks4, "Standard1"),
-                                                        
SchemaLoader.superCFMD(ks4, "Super3", BytesType.instance),
-                                                        
SchemaLoader.superCFMD(ks4, "Super4", TimeUUIDType.instance),
-                                                        
SchemaLoader.superCFMD(ks4, "Super5", TimeUUIDType.instance, 
BytesType.instance))));
+                                              
Tables.of(SchemaLoader.standardCFMD(ks4, "Standard1"))));
 
         // Keyspace 5
         keyspaces.add(KeyspaceMetadata.create(ks5,


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@cassandra.apache.org
For additional commands, e-mail: commits-h...@cassandra.apache.org

Reply via email to