You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cassandra.apache.org by ad...@apache.org on 2020/07/23 11:56:12 UTC

[cassandra] branch cassandra-2.2 updated: Fix CQL parsing of collections when the column type is reversed patch by Andrés de la Peña; reviewed by Berenguer Blasi for CASSANDRA-15814

This is an automated email from the ASF dual-hosted git repository.

adelapena pushed a commit to branch cassandra-2.2
in repository https://gitbox.apache.org/repos/asf/cassandra.git


The following commit(s) were added to refs/heads/cassandra-2.2 by this push:
     new 9f8d5b8  Fix CQL parsing of collections when the column type is reversed patch by Andrés de la Peña; reviewed by Berenguer Blasi for CASSANDRA-15814
9f8d5b8 is described below

commit 9f8d5b8d069a1db88e70deafff6c0edc23c896d0
Author: Andrés de la Peña <a....@gmail.com>
AuthorDate: Fri Jun 26 13:09:25 2020 +0100

    Fix CQL parsing of collections when the column type is reversed
    patch by Andrés de la Peña; reviewed by Berenguer Blasi for CASSANDRA-15814
---
 CHANGES.txt                                        |   1 +
 src/java/org/apache/cassandra/cql3/Lists.java      |  21 +-
 src/java/org/apache/cassandra/cql3/Maps.java       |  27 +-
 src/java/org/apache/cassandra/cql3/Sets.java       |  21 +-
 .../validation/entities/FrozenCollectionsTest.java | 468 +++++++++++++++++----
 5 files changed, 450 insertions(+), 88 deletions(-)

diff --git a/CHANGES.txt b/CHANGES.txt
index 02de7c1..9034ae1 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,4 +1,5 @@
 2.2.17
+ * Fix CQL parsing of collections when the column type is reversed (CASSANDRA-15814)
  * Fix nomenclature of allow and deny lists (CASSANDRA-15862)
  * Remove generated files from source artifact (CASSANDRA-15849)
  * Remove duplicated tools binaries from tarballs (CASSANDRA-15768)
diff --git a/src/java/org/apache/cassandra/cql3/Lists.java b/src/java/org/apache/cassandra/cql3/Lists.java
index cc75476..c6b78d7 100644
--- a/src/java/org/apache/cassandra/cql3/Lists.java
+++ b/src/java/org/apache/cassandra/cql3/Lists.java
@@ -21,20 +21,19 @@ import static org.apache.cassandra.cql3.Constants.UNSET_VALUE;
 
 import java.nio.ByteBuffer;
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.List;
 import java.util.concurrent.atomic.AtomicReference;
 
-import org.apache.cassandra.config.CFMetaData;
 import org.apache.cassandra.config.ColumnDefinition;
 import org.apache.cassandra.cql3.functions.Function;
 import org.apache.cassandra.db.Cell;
 import org.apache.cassandra.db.ColumnFamily;
 import org.apache.cassandra.db.composites.CellName;
 import org.apache.cassandra.db.composites.Composite;
-import org.apache.cassandra.db.composites.CompositesBuilder;
+import org.apache.cassandra.db.marshal.AbstractType;
 import org.apache.cassandra.db.marshal.Int32Type;
 import org.apache.cassandra.db.marshal.ListType;
+import org.apache.cassandra.db.marshal.ReversedType;
 import org.apache.cassandra.exceptions.InvalidRequestException;
 import org.apache.cassandra.serializers.CollectionSerializer;
 import org.apache.cassandra.serializers.MarshalException;
@@ -57,7 +56,17 @@ public abstract class Lists
 
     public static ColumnSpecification valueSpecOf(ColumnSpecification column)
     {
-        return new ColumnSpecification(column.ksName, column.cfName, new ColumnIdentifier("value(" + column.name + ")", true), ((ListType)column.type).getElementsType());
+        return new ColumnSpecification(column.ksName, column.cfName, new ColumnIdentifier("value(" + column.name + ")", true), elementsType(column.type));
+    }
+
+    private static AbstractType<?> unwrap(AbstractType<?> type)
+    {
+        return type.isReversed() ? unwrap(((ReversedType<?>) type).baseType) : type;
+    }
+
+    private static AbstractType<?> elementsType(AbstractType<?> type)
+    {
+        return ((ListType) unwrap(type)).getElementsType();
     }
 
     public static class Literal implements Term.Raw
@@ -94,7 +103,9 @@ public abstract class Lists
 
         private void validateAssignableTo(String keyspace, ColumnSpecification receiver) throws InvalidRequestException
         {
-            if (!(receiver.type instanceof ListType))
+            AbstractType<?> type = unwrap(receiver.type);
+
+            if (!(type instanceof ListType))
                 throw new InvalidRequestException(String.format("Invalid list literal for %s of type %s", receiver.name, receiver.type.asCQL3Type()));
 
             ColumnSpecification valueSpec = Lists.valueSpecOf(receiver);
diff --git a/src/java/org/apache/cassandra/cql3/Maps.java b/src/java/org/apache/cassandra/cql3/Maps.java
index 5bb3a48..8d21162 100644
--- a/src/java/org/apache/cassandra/cql3/Maps.java
+++ b/src/java/org/apache/cassandra/cql3/Maps.java
@@ -29,7 +29,9 @@ import org.apache.cassandra.cql3.functions.Function;
 import org.apache.cassandra.db.ColumnFamily;
 import org.apache.cassandra.db.composites.CellName;
 import org.apache.cassandra.db.composites.Composite;
+import org.apache.cassandra.db.marshal.AbstractType;
 import org.apache.cassandra.db.marshal.MapType;
+import org.apache.cassandra.db.marshal.ReversedType;
 import org.apache.cassandra.exceptions.InvalidRequestException;
 import org.apache.cassandra.serializers.CollectionSerializer;
 import org.apache.cassandra.serializers.MarshalException;
@@ -47,12 +49,27 @@ public abstract class Maps
 
     public static ColumnSpecification keySpecOf(ColumnSpecification column)
     {
-        return new ColumnSpecification(column.ksName, column.cfName, new ColumnIdentifier("key(" + column.name + ")", true), ((MapType)column.type).getKeysType());
+        return new ColumnSpecification(column.ksName, column.cfName, new ColumnIdentifier("key(" + column.name + ")", true), keysType(column.type));
     }
 
     public static ColumnSpecification valueSpecOf(ColumnSpecification column)
     {
-        return new ColumnSpecification(column.ksName, column.cfName, new ColumnIdentifier("value(" + column.name + ")", true), ((MapType)column.type).getValuesType());
+        return new ColumnSpecification(column.ksName, column.cfName, new ColumnIdentifier("value(" + column.name + ")", true), valuesType(column.type));
+    }
+
+    private static AbstractType<?> unwrap(AbstractType<?> type)
+    {
+        return type.isReversed() ? unwrap(((ReversedType<?>) type).baseType) : type;
+    }
+
+    private static AbstractType<?> keysType(AbstractType<?> type)
+    {
+        return ((MapType) unwrap(type)).getKeysType();
+    }
+
+    private static AbstractType<?> valuesType(AbstractType<?> type)
+    {
+        return ((MapType) unwrap(type)).getValuesType();
     }
 
     public static class Literal implements Term.Raw
@@ -85,13 +102,15 @@ public abstract class Maps
 
                 values.put(k, v);
             }
-            DelayedValue value = new DelayedValue(((MapType)receiver.type).getKeysType(), values);
+            DelayedValue value = new DelayedValue(keysType(receiver.type), values);
             return allTerminal ? value.bind(QueryOptions.DEFAULT) : value;
         }
 
         private void validateAssignableTo(String keyspace, ColumnSpecification receiver) throws InvalidRequestException
         {
-            if (!(receiver.type instanceof MapType))
+            AbstractType<?> type = unwrap(receiver.type);
+
+            if (!(type instanceof MapType))
                 throw new InvalidRequestException(String.format("Invalid map literal for %s of type %s", receiver.name, receiver.type.asCQL3Type()));
 
             ColumnSpecification keySpec = Maps.keySpecOf(receiver);
diff --git a/src/java/org/apache/cassandra/cql3/Sets.java b/src/java/org/apache/cassandra/cql3/Sets.java
index 093f1dc..4b5cd5d 100644
--- a/src/java/org/apache/cassandra/cql3/Sets.java
+++ b/src/java/org/apache/cassandra/cql3/Sets.java
@@ -31,6 +31,7 @@ import org.apache.cassandra.db.composites.CellName;
 import org.apache.cassandra.db.composites.Composite;
 import org.apache.cassandra.db.marshal.AbstractType;
 import org.apache.cassandra.db.marshal.MapType;
+import org.apache.cassandra.db.marshal.ReversedType;
 import org.apache.cassandra.db.marshal.SetType;
 import org.apache.cassandra.exceptions.InvalidRequestException;
 import org.apache.cassandra.serializers.CollectionSerializer;
@@ -48,7 +49,17 @@ public abstract class Sets
 
     public static ColumnSpecification valueSpecOf(ColumnSpecification column)
     {
-        return new ColumnSpecification(column.ksName, column.cfName, new ColumnIdentifier("value(" + column.name + ")", true), ((SetType)column.type).getElementsType());
+        return new ColumnSpecification(column.ksName, column.cfName, new ColumnIdentifier("value(" + column.name + ")", true), elementsType(column.type));
+    }
+
+    private static AbstractType<?> unwrap(AbstractType<?> type)
+    {
+        return type.isReversed() ? unwrap(((ReversedType<?>) type).baseType) : type;
+    }
+
+    private static AbstractType<?> elementsType(AbstractType<?> type)
+    {
+        return ((SetType) unwrap(type)).getElementsType();
     }
 
     public static class Literal implements Term.Raw
@@ -84,17 +95,19 @@ public abstract class Sets
 
                 values.add(t);
             }
-            DelayedValue value = new DelayedValue(((SetType)receiver.type).getElementsType(), values);
+            DelayedValue value = new DelayedValue(elementsType(receiver.type), values);
             return allTerminal ? value.bind(QueryOptions.DEFAULT) : value;
         }
 
         private void validateAssignableTo(String keyspace, ColumnSpecification receiver) throws InvalidRequestException
         {
-            if (!(receiver.type instanceof SetType))
+            AbstractType<?> type = unwrap(receiver.type);
+
+            if (!(type instanceof SetType))
             {
                 // We've parsed empty maps as a set literal to break the ambiguity so
                 // handle that case now
-                if ((receiver.type instanceof MapType) && elements.isEmpty())
+                if ((type instanceof MapType) && elements.isEmpty())
                     return;
 
                 throw new InvalidRequestException(String.format("Invalid set literal for %s of type %s", receiver.name, receiver.type.asCQL3Type()));
diff --git a/test/unit/org/apache/cassandra/cql3/validation/entities/FrozenCollectionsTest.java b/test/unit/org/apache/cassandra/cql3/validation/entities/FrozenCollectionsTest.java
index b590843..bd3d231 100644
--- a/test/unit/org/apache/cassandra/cql3/validation/entities/FrozenCollectionsTest.java
+++ b/test/unit/org/apache/cassandra/cql3/validation/entities/FrozenCollectionsTest.java
@@ -44,63 +44,92 @@ public class FrozenCollectionsTest extends CQLTester
     }
 
     @Test
-    public void testPartitionKeyUsage() throws Throwable
+    public void testPartitionKeyUsageSet() throws Throwable
     {
-        createTable("CREATE TABLE %s (k frozen<set<int>> PRIMARY KEY, v int)");
+        testPartitionKeyUsage("set<int>",
+                              set(),
+                              set(1, 2, 3),
+                              set(4, 5, 6),
+                              set(7, 8, 9));
+    }
+
+    @Test
+    public void testPartitionKeyUsageList() throws Throwable
+    {
+        testPartitionKeyUsage("list<int>",
+                              list(),
+                              list(1, 2, 3),
+                              list(4, 5, 6),
+                              list(7, 8, 9));
+    }
+
+    @Test
+    public void testPartitionKeyUsageMap() throws Throwable
+    {
+        testPartitionKeyUsage("map<int, int>",
+                              map(),
+                              map(1, 10, 2, 20, 3, 30),
+                              map(4, 40, 5, 50, 6, 60),
+                              map(7, 70, 8, 80, 9, 90));
+    }
+
+    private void testPartitionKeyUsage(String type, Object v1, Object v2, Object v3, Object v4) throws Throwable
+    {
+        createTable("CREATE TABLE %s (k frozen<" + type + "> PRIMARY KEY, v int)");
 
-        execute("INSERT INTO %s (k, v) VALUES (?, ?)", set(), 1);
-        execute("INSERT INTO %s (k, v) VALUES (?, ?)", set(1, 2, 3), 1);
-        execute("INSERT INTO %s (k, v) VALUES (?, ?)", set(4, 5, 6), 0);
-        execute("INSERT INTO %s (k, v) VALUES (?, ?)", set(7, 8, 9), 0);
+        execute("INSERT INTO %s (k, v) VALUES (?, ?)", v1, 1);
+        execute("INSERT INTO %s (k, v) VALUES (?, ?)", v2, 1);
+        execute("INSERT INTO %s (k, v) VALUES (?, ?)", v3, 0);
+        execute("INSERT INTO %s (k, v) VALUES (?, ?)", v4, 0);
 
         // overwrite with an update
-        execute("UPDATE %s SET v=? WHERE k=?", 0, set());
-        execute("UPDATE %s SET v=? WHERE k=?", 0, set(1, 2, 3));
+        execute("UPDATE %s SET v=? WHERE k=?", 0, v1);
+        execute("UPDATE %s SET v=? WHERE k=?", 0, v2);
 
         assertRows(execute("SELECT * FROM %s"),
-            row(set(), 0),
-            row(set(1, 2, 3), 0),
-            row(set(4, 5, 6), 0),
-            row(set(7, 8, 9), 0)
+                   row(v1, 0),
+                   row(v2, 0),
+                   row(v3, 0),
+                   row(v4, 0)
         );
 
         assertRows(execute("SELECT k FROM %s"),
-            row(set()),
-            row(set(1, 2, 3)),
-            row(set(4, 5, 6)),
-            row(set(7, 8, 9))
+                   row(v1),
+                   row(v2),
+                   row(v3),
+                   row(v4)
         );
 
         assertRows(execute("SELECT * FROM %s LIMIT 2"),
-                row(set(), 0),
-                row(set(1, 2, 3), 0)
+                   row(v1, 0),
+                   row(v2, 0)
         );
 
-        assertRows(execute("SELECT * FROM %s WHERE k=?", set(4, 5, 6)),
-            row(set(4, 5, 6), 0)
+        assertRows(execute("SELECT * FROM %s WHERE k=?", v3),
+                   row(v3, 0)
         );
 
-        assertRows(execute("SELECT * FROM %s WHERE k=?", set()),
-                row(set(), 0)
+        assertRows(execute("SELECT * FROM %s WHERE k=?", v1),
+                   row(v1, 0)
         );
 
-        assertRows(execute("SELECT * FROM %s WHERE k IN ?", list(set(4, 5, 6), set())),
-                   row(set(), 0),
-                   row(set(4, 5, 6), 0)
+        assertRows(execute("SELECT * FROM %s WHERE k IN ?", list(v3, v1)),
+                   row(v1, 0),
+                   row(v3, 0)
         );
 
-        assertRows(execute("SELECT * FROM %s WHERE token(k) >= token(?)", set(4, 5, 6)),
-                row(set(4, 5, 6), 0),
-                row(set(7, 8, 9), 0)
+        assertRows(execute("SELECT * FROM %s WHERE token(k) >= token(?)", v3),
+                   row(v3, 0),
+                   row(v4, 0)
         );
 
         assertInvalid("INSERT INTO %s (k, v) VALUES (null, 0)");
 
-        execute("DELETE FROM %s WHERE k=?", set());
-        execute("DELETE FROM %s WHERE k=?", set(4, 5, 6));
+        execute("DELETE FROM %s WHERE k=?", v1);
+        execute("DELETE FROM %s WHERE k=?", v3);
         assertRows(execute("SELECT * FROM %s"),
-            row(set(1, 2, 3), 0),
-            row(set(7, 8, 9), 0)
+                   row(v2, 0),
+                   row(v4, 0)
         );
     }
 
@@ -175,82 +204,223 @@ public class FrozenCollectionsTest extends CQLTester
     }
 
     @Test
-    public void testClusteringKeyUsage() throws Throwable
+    public void testClusteringKeyUsageSet() throws Throwable
+    {
+        testClusteringKeyUsage("set<int>",
+                               set(),
+                               set(1, 2, 3),
+                               set(4, 5, 6),
+                               set(7, 8, 9));
+    }
+
+    @Test
+    public void testClusteringKeyUsageList() throws Throwable
+    {
+        testClusteringKeyUsage("list<int>",
+                               list(),
+                               list(1, 2, 3),
+                               list(4, 5, 6),
+                               list(7, 8, 9));
+    }
+
+    @Test
+    public void testClusteringKeyUsageMap() throws Throwable
+    {
+        testClusteringKeyUsage("map<int, int>",
+                               map(),
+                               map(1, 10, 2, 20, 3, 30),
+                               map(4, 40, 5, 50, 6, 60),
+                               map(7, 70, 8, 80, 9, 90));
+    }
+
+    private void testClusteringKeyUsage(String type, Object v1, Object v2, Object v3, Object v4) throws Throwable
     {
         for (String option : Arrays.asList("", " WITH COMPACT STORAGE"))
         {
-            createTable("CREATE TABLE %s (a int, b frozen<set<int>>, c int, PRIMARY KEY (a, b))" + option);
+            createTable(String.format("CREATE TABLE %%s (a int, b frozen<%s>, c int, PRIMARY KEY (a, b)) %s",
+                                      type, option));
 
-            execute("INSERT INTO %s (a, b, c) VALUES (?, ?, ?)", 0, set(), 1);
-            execute("INSERT INTO %s (a, b, c) VALUES (?, ?, ?)", 0, set(1, 2, 3), 1);
-            execute("INSERT INTO %s (a, b, c) VALUES (?, ?, ?)", 0, set(4, 5, 6), 0);
-            execute("INSERT INTO %s (a, b, c) VALUES (?, ?, ?)", 0, set(7, 8, 9), 0);
+            execute("INSERT INTO %s (a, b, c) VALUES (?, ?, ?)", 0, v1, 1);
+            execute("INSERT INTO %s (a, b, c) VALUES (?, ?, ?)", 0, v2, 1);
+            execute("INSERT INTO %s (a, b, c) VALUES (?, ?, ?)", 0, v3, 0);
+            execute("INSERT INTO %s (a, b, c) VALUES (?, ?, ?)", 0, v4, 0);
 
             // overwrite with an update
-            execute("UPDATE %s SET c=? WHERE a=? AND b=?", 0, 0, set());
-            execute("UPDATE %s SET c=? WHERE a=? AND b=?", 0, 0, set(1, 2, 3));
+            execute("UPDATE %s SET c=? WHERE a=? AND b=?", 0, 0, v1);
+            execute("UPDATE %s SET c=? WHERE a=? AND b=?", 0, 0, v2);
 
             assertRows(execute("SELECT * FROM %s"),
-                row(0, set(), 0),
-                row(0, set(1, 2, 3), 0),
-                row(0, set(4, 5, 6), 0),
-                row(0, set(7, 8, 9), 0)
+                       row(0, v1, 0),
+                       row(0, v2, 0),
+                       row(0, v3, 0),
+                       row(0, v4, 0)
             );
 
             assertRows(execute("SELECT b FROM %s"),
-                row(set()),
-                row(set(1, 2, 3)),
-                row(set(4, 5, 6)),
-                row(set(7, 8, 9))
+                       row(v1),
+                       row(v2),
+                       row(v3),
+                       row(v4)
             );
 
             assertRows(execute("SELECT * FROM %s LIMIT 2"),
-                row(0, set(), 0),
-                row(0, set(1, 2, 3), 0)
+                       row(0, v1, 0),
+                       row(0, v2, 0)
             );
 
-            assertRows(execute("SELECT * FROM %s WHERE a=? AND b=?", 0, set(4, 5, 6)),
-                row(0, set(4, 5, 6), 0)
+            assertRows(execute("SELECT * FROM %s WHERE a=? AND b=?", 0, v3),
+                       row(0, v3, 0)
             );
 
-            assertRows(execute("SELECT * FROM %s WHERE a=? AND b=?", 0, set()),
-                row(0, set(), 0)
+            assertRows(execute("SELECT * FROM %s WHERE a=? AND b=?", 0, v1),
+                       row(0, v1, 0)
             );
 
-            assertRows(execute("SELECT * FROM %s WHERE a=? AND b IN ?", 0, list(set(4, 5, 6), set())),
-                row(0, set(), 0),
-                row(0, set(4, 5, 6), 0)
+            assertRows(execute("SELECT * FROM %s WHERE a=? AND b IN ?", 0, list(v3, v1)),
+                       row(0, v1, 0),
+                       row(0, v3, 0)
             );
 
-            assertRows(execute("SELECT * FROM %s WHERE a=? AND b > ?", 0, set(4, 5, 6)),
-                row(0, set(7, 8, 9), 0)
+            assertRows(execute("SELECT * FROM %s WHERE a=? AND b > ?", 0, v3),
+                       row(0, v4, 0)
             );
 
-            assertRows(execute("SELECT * FROM %s WHERE a=? AND b >= ?", 0, set(4, 5, 6)),
-                row(0, set(4, 5, 6), 0),
-                row(0, set(7, 8, 9), 0)
+            assertRows(execute("SELECT * FROM %s WHERE a=? AND b >= ?", 0, v3),
+                       row(0, v3, 0),
+                       row(0, v4, 0)
             );
 
-            assertRows(execute("SELECT * FROM %s WHERE a=? AND b < ?", 0, set(4, 5, 6)),
-                row(0, set(), 0),
-                row(0, set(1, 2, 3), 0)
+            assertRows(execute("SELECT * FROM %s WHERE a=? AND b < ?", 0, v3),
+                       row(0, v1, 0),
+                       row(0, v2, 0)
             );
 
-            assertRows(execute("SELECT * FROM %s WHERE a=? AND b <= ?", 0, set(4, 5, 6)),
-                row(0, set(), 0),
-                row(0, set(1, 2, 3), 0),
-                row(0, set(4, 5, 6), 0)
+            assertRows(execute("SELECT * FROM %s WHERE a=? AND b <= ?", 0, v3),
+                       row(0, v1, 0),
+                       row(0, v2, 0),
+                       row(0, v3, 0)
             );
 
-            assertRows(execute("SELECT * FROM %s WHERE a=? AND b > ? AND b <= ?", 0, set(1, 2, 3), set(4, 5, 6)),
-                row(0, set(4, 5, 6), 0)
+            assertRows(execute("SELECT * FROM %s WHERE a=? AND b > ? AND b <= ?", 0, v2, v3),
+                       row(0, v3, 0)
             );
 
-            execute("DELETE FROM %s WHERE a=? AND b=?", 0, set());
-            execute("DELETE FROM %s WHERE a=? AND b=?", 0, set(4, 5, 6));
+            execute("DELETE FROM %s WHERE a=? AND b=?", 0, v1);
+            execute("DELETE FROM %s WHERE a=? AND b=?", 0, v3);
             assertRows(execute("SELECT * FROM %s"),
-                row(0, set(1, 2, 3), 0),
-                row(0, set(7, 8, 9), 0)
+                       row(0, v2, 0),
+                       row(0, v4, 0)
+            );
+        }
+    }
+
+    @Test
+    public void testClusteringKeyUsageWithReverseOrderSet() throws Throwable
+    {
+        testClusteringKeyUsageWithReverseOrder("set<int>",
+                                               set(),
+                                               set(1, 2, 3),
+                                               set(4, 5, 6),
+                                               set(7, 8, 9));
+    }
+
+    @Test
+    public void testClusteringKeyUsageWithReverseOrderList() throws Throwable
+    {
+        testClusteringKeyUsageWithReverseOrder("list<int>",
+                                               list(),
+                                               list(1, 2, 3),
+                                               list(4, 5, 6),
+                                               list(7, 8, 9));
+    }
+
+    @Test
+    public void testClusteringKeyUsageWithReverseOrderMap() throws Throwable
+    {
+        testClusteringKeyUsageWithReverseOrder("map<int, int>",
+                                               map(),
+                                               map(1, 10, 2, 20, 3, 30),
+                                               map(4, 40, 5, 50, 6, 60),
+                                               map(7, 70, 8, 80, 9, 90));
+    }
+
+    private void testClusteringKeyUsageWithReverseOrder(String type, Object v1, Object v2, Object v3, Object v4) throws Throwable
+    {
+        for (String option : Arrays.asList("", " AND COMPACT STORAGE"))
+        {
+            createTable(String.format("CREATE TABLE %%s (a int, b frozen<%s>, c int, PRIMARY KEY (a, b)) " +
+                                      "WITH CLUSTERING ORDER BY (b DESC) %s", type, option));
+
+            execute("INSERT INTO %s (a, b, c) VALUES (?, ?, ?)", 0, v1, 1);
+            execute("INSERT INTO %s (a, b, c) VALUES (?, ?, ?)", 0, v2, 1);
+            execute("INSERT INTO %s (a, b, c) VALUES (?, ?, ?)", 0, v3, 0);
+            execute("INSERT INTO %s (a, b, c) VALUES (?, ?, ?)", 0, v4, 0);
+
+            // overwrite with an update
+            execute("UPDATE %s SET c=? WHERE a=? AND b=?", 0, 0, v1);
+            execute("UPDATE %s SET c=? WHERE a=? AND b=?", 0, 0, v2);
+
+            assertRows(execute("SELECT * FROM %s"),
+                       row(0, v4, 0),
+                       row(0, v3, 0),
+                       row(0, v2, 0),
+                       row(0, v1, 0)
+            );
+
+            assertRows(execute("SELECT b FROM %s"),
+                       row(v4),
+                       row(v3),
+                       row(v2),
+                       row(v1)
+            );
+
+            assertRows(execute("SELECT * FROM %s LIMIT 2"),
+                       row(0, v4, 0),
+                       row(0, v3, 0)
+            );
+
+            assertRows(execute("SELECT * FROM %s WHERE a=? AND b=?", 0, v3),
+                       row(0, v3, 0)
+            );
+
+            assertRows(execute("SELECT * FROM %s WHERE a=? AND b=?", 0, v1),
+                       row(0, v1, 0)
+            );
+
+            assertRows(execute("SELECT * FROM %s WHERE a=? AND b IN ?", 0, list(v3, v1)),
+                       row(0, v3, 0),
+                       row(0, v1, 0)
+            );
+
+            assertRows(execute("SELECT * FROM %s WHERE a=? AND b > ?", 0, v3),
+                       row(0, v4, 0)
+            );
+
+            assertRows(execute("SELECT * FROM %s WHERE a=? AND b >= ?", 0, v3),
+                       row(0, v4, 0),
+                       row(0, v3, 0)
+            );
+
+            assertRows(execute("SELECT * FROM %s WHERE a=? AND b < ?", 0, v3),
+                       row(0, v2, 0),
+                       row(0, v1, 0)
+            );
+
+            assertRows(execute("SELECT * FROM %s WHERE a=? AND b <= ?", 0, v3),
+                       row(0, v3, 0),
+                       row(0, v2, 0),
+                       row(0, v1, 0)
+            );
+
+            assertRows(execute("SELECT * FROM %s WHERE a=? AND b > ? AND b <= ?", 0, v2, v3),
+                       row(0, v3, 0)
+            );
+
+            execute("DELETE FROM %s WHERE a=? AND b=?", 0, v1);
+            execute("DELETE FROM %s WHERE a=? AND b=?", 0, v3);
+            assertRows(execute("SELECT * FROM %s"),
+                       row(0, v4, 0),
+                       row(0, v2, 0)
             );
         }
     }
@@ -370,6 +540,121 @@ public class FrozenCollectionsTest extends CQLTester
     }
 
     @Test
+    public void testNestedClusteringKeyUsageWithReverseOrder() throws Throwable
+    {
+        for (String option : Arrays.asList("", " AND COMPACT STORAGE"))
+        {
+            createTable("CREATE TABLE %s (a int, b frozen<map<set<int>, list<int>>>, c frozen<set<int>>, d int, " +
+                        "PRIMARY KEY (a, b, c)) WITH CLUSTERING ORDER BY (b DESC)" + option);
+
+            execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 0, map(), set(), 0);
+            execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 0, map(set(), list(1, 2, 3)), set(), 0);
+            execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 0, map(set(1, 2, 3), list(1, 2, 3)), set(1, 2, 3), 0);
+            execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 0, map(set(4, 5, 6), list(1, 2, 3)), set(1, 2, 3), 0);
+            execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 0, map(set(7, 8, 9), list(1, 2, 3)), set(1, 2, 3), 0);
+
+            assertRows(execute("SELECT * FROM %s"),
+                       row(0, map(set(7, 8, 9), list(1, 2, 3)), set(1, 2, 3), 0),
+                       row(0, map(set(4, 5, 6), list(1, 2, 3)), set(1, 2, 3), 0),
+                       row(0, map(set(1, 2, 3), list(1, 2, 3)), set(1, 2, 3), 0),
+                       row(0, map(set(), list(1, 2, 3)), set(), 0),
+                       row(0, map(), set(), 0)
+            );
+
+            assertRows(execute("SELECT b FROM %s"),
+                       row(map(set(7, 8, 9), list(1, 2, 3))),
+                       row(map(set(4, 5, 6), list(1, 2, 3))),
+                       row(map(set(1, 2, 3), list(1, 2, 3))),
+                       row(map(set(), list(1, 2, 3))),
+                       row(map())
+            );
+
+            assertRows(execute("SELECT c FROM %s"),
+                       row(set(1, 2, 3)),
+                       row(set(1, 2, 3)),
+                       row(set(1, 2, 3)),
+                       row(set()),
+                       row(set())
+            );
+
+            assertRows(execute("SELECT * FROM %s LIMIT 3"),
+                       row(0, map(set(7, 8, 9), list(1, 2, 3)), set(1, 2, 3), 0),
+                       row(0, map(set(4, 5, 6), list(1, 2, 3)), set(1, 2, 3), 0),
+                       row(0, map(set(1, 2, 3), list(1, 2, 3)), set(1, 2, 3), 0)
+            );
+
+            assertRows(execute("SELECT * FROM %s WHERE a=0 ORDER BY b DESC LIMIT 4"),
+                       row(0, map(set(7, 8, 9), list(1, 2, 3)), set(1, 2, 3), 0),
+                       row(0, map(set(4, 5, 6), list(1, 2, 3)), set(1, 2, 3), 0),
+                       row(0, map(set(1, 2, 3), list(1, 2, 3)), set(1, 2, 3), 0),
+                       row(0, map(set(), list(1, 2, 3)), set(), 0)
+            );
+
+            assertRows(execute("SELECT * FROM %s WHERE a=? AND b=?", 0, map()),
+                       row(0, map(), set(), 0)
+            );
+
+            assertRows(execute("SELECT * FROM %s WHERE a=? AND b=?", 0, map(set(), list(1, 2, 3))),
+                       row(0, map(set(), list(1, 2, 3)), set(), 0)
+            );
+
+            assertRows(execute("SELECT * FROM %s WHERE a=? AND b=?", 0, map(set(1, 2, 3), list(1, 2, 3))),
+                       row(0, map(set(1, 2, 3), list(1, 2, 3)), set(1, 2, 3), 0)
+            );
+
+            assertRows(execute("SELECT * FROM %s WHERE a=? AND b=? AND c=?", 0, map(set(), list(1, 2, 3)), set()),
+                       row(0, map(set(), list(1, 2, 3)), set(), 0)
+            );
+
+            assertRows(execute("SELECT * FROM %s WHERE a=? AND (b, c) IN ?", 0, list(tuple(map(set(4, 5, 6), list(1, 2, 3)), set(1, 2, 3)),
+                                                                                     tuple(map(), set()))),
+                       row(0, map(set(4, 5, 6), list(1, 2, 3)), set(1, 2, 3), 0),
+                       row(0, map(), set(), 0)
+            );
+
+            assertRows(execute("SELECT * FROM %s WHERE a=? AND b > ?", 0, map(set(4, 5, 6), list(1, 2, 3))),
+                       row(0, map(set(7, 8, 9), list(1, 2, 3)), set(1, 2, 3), 0)
+            );
+
+            assertRows(execute("SELECT * FROM %s WHERE a=? AND b >= ?", 0, map(set(4, 5, 6), list(1, 2, 3))),
+                       row(0, map(set(7, 8, 9), list(1, 2, 3)), set(1, 2, 3), 0),
+                       row(0, map(set(4, 5, 6), list(1, 2, 3)), set(1, 2, 3), 0)
+            );
+
+            assertRows(execute("SELECT * FROM %s WHERE a=? AND b < ?", 0, map(set(4, 5, 6), list(1, 2, 3))),
+                       row(0, map(set(1, 2, 3), list(1, 2, 3)), set(1, 2, 3), 0),
+                       row(0, map(set(), list(1, 2, 3)), set(), 0),
+                       row(0, map(), set(), 0)
+            );
+
+            assertRows(execute("SELECT * FROM %s WHERE a=? AND b <= ?", 0, map(set(4, 5, 6), list(1, 2, 3))),
+                       row(0, map(set(4, 5, 6), list(1, 2, 3)), set(1, 2, 3), 0),
+                       row(0, map(set(1, 2, 3), list(1, 2, 3)), set(1, 2, 3), 0),
+                       row(0, map(set(), list(1, 2, 3)), set(), 0),
+                       row(0, map(), set(), 0)
+            );
+
+            assertRows(execute("SELECT * FROM %s WHERE a=? AND b > ? AND b <= ?", 0, map(set(1, 2, 3), list(1, 2, 3)), map(set(4, 5, 6), list(1, 2, 3))),
+                       row(0, map(set(4, 5, 6), list(1, 2, 3)), set(1, 2, 3), 0)
+            );
+
+            execute("DELETE FROM %s WHERE a=? AND b=? AND c=?", 0, map(), set());
+            assertEmpty(execute("SELECT * FROM %s WHERE a=? AND b=? AND c=?", 0, map(), set()));
+
+            execute("DELETE FROM %s WHERE a=? AND b=? AND c=?", 0, map(set(), list(1, 2, 3)), set());
+            assertEmpty(execute("SELECT * FROM %s WHERE a=? AND b=? AND c=?", 0, map(set(), list(1, 2, 3)), set()));
+
+            execute("DELETE FROM %s WHERE a=? AND b=? AND c=?", 0, map(set(4, 5, 6), list(1, 2, 3)), set(1, 2, 3));
+            assertEmpty(execute("SELECT * FROM %s WHERE a=? AND b=? AND c=?", 0, map(set(4, 5, 6), list(1, 2, 3)), set(1, 2, 3)));
+
+            assertRows(execute("SELECT * FROM %s"),
+                       row(0, map(set(7, 8, 9), list(1, 2, 3)), set(1, 2, 3), 0),
+                       row(0, map(set(1, 2, 3), list(1, 2, 3)), set(1, 2, 3), 0)
+            );
+        }
+    }
+
+    @Test
     public void testNormalColumnUsage() throws Throwable
     {
         for (String option : Arrays.asList("", " WITH COMPACT STORAGE"))
@@ -1074,6 +1359,39 @@ public class FrozenCollectionsTest extends CQLTester
         );
     }
 
+    /**
+     * Test parsing of literal lists when the column type is reversed (CASSANDRA-15814)
+     */
+    @Test
+    public void testLiteralReversedList() throws Throwable
+    {
+        createTable("CREATE TABLE %s (k int, c frozen<list<int>>, PRIMARY KEY (k, c)) WITH CLUSTERING ORDER BY (c DESC)");
+        execute("INSERT INTO %s (k, c) VALUES (0, [1, 2])");
+        assertRows(execute("SELECT c FROM %s WHERE k=0 AND c=[1, 2]"), row(list(1, 2)));
+    }
+
+    /**
+     * Test parsing of literal sets when the column type is reversed (CASSANDRA-15814)
+     */
+    @Test
+    public void testLiteralReversedSet() throws Throwable
+    {
+        createTable("CREATE TABLE %s (k int, c frozen<set<int>>, PRIMARY KEY (k, c)) WITH CLUSTERING ORDER BY (c DESC)");
+        execute("INSERT INTO %s (k, c) VALUES (0, {1, 2})");
+        assertRows(execute("SELECT c FROM %s WHERE k=0 AND c={1, 2}"), row(set(1, 2)));
+    }
+
+    /**
+     * Test parsing of literal maps when the column type is reversed (CASSANDRA-15814)
+     */
+    @Test
+    public void testLiteralReversedMap() throws Throwable
+    {
+        createTable("CREATE TABLE %s (k int, c frozen<map<int,int>>, PRIMARY KEY (k, c)) WITH CLUSTERING ORDER BY (c DESC)");
+        execute("INSERT INTO %s (k, c) VALUES (0, {1:2, 3:4})");
+        assertRows(execute("SELECT c FROM %s WHERE k=0 AND c={1:2, 3:4}"), row(map(1, 2, 3, 4)));
+    }
+
     private static String clean(String classname)
     {
         return StringUtils.remove(classname, "org.apache.cassandra.db.marshal.");


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