cassandra-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ble...@apache.org
Subject [1/3] cassandra git commit: Allow selecting Map values and Set elements
Date Thu, 01 Jun 2017 15:07:35 GMT
Repository: cassandra
Updated Branches:
  refs/heads/trunk 06da35fdd -> 4ebab6616


http://git-wip-us.apache.org/repos/asf/cassandra/blob/4ebab661/src/java/org/apache/cassandra/db/marshal/AbstractType.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/marshal/AbstractType.java b/src/java/org/apache/cassandra/db/marshal/AbstractType.java
index 99df8a2..b4dff56 100644
--- a/src/java/org/apache/cassandra/db/marshal/AbstractType.java
+++ b/src/java/org/apache/cassandra/db/marshal/AbstractType.java
@@ -458,6 +458,32 @@ public abstract class AbstractType<T> implements Comparator<ByteBuffer>, Assignm
     }
 
     /**
+     * Tests whether a CQL value having this type can be assigned to the provided receiver.
+     *
+     * @param keyspace the keyspace from which the receiver is.
+     * @param receiver the receiver for which we want to test type compatibility with.
+     */
+    public AssignmentTestable.TestResult testAssignment(AbstractType<?> receiverType)
+    {
+        // testAssignement is for CQL literals and native protocol values, none of which make a meaningful
+        // difference between frozen or not and reversed or not.
+
+        if (isFreezable() && !isMultiCell())
+            receiverType = receiverType.freeze();
+
+        if (isReversed() && !receiverType.isReversed())
+            receiverType = ReversedType.getInstance(receiverType);
+
+        if (equals(receiverType))
+            return AssignmentTestable.TestResult.EXACT_MATCH;
+
+        if (receiverType.isValueCompatibleWith(this))
+            return AssignmentTestable.TestResult.WEAKLY_ASSIGNABLE;
+
+        return AssignmentTestable.TestResult.NOT_ASSIGNABLE;
+    }
+
+    /**
      * This must be overriden by subclasses if necessary so that for any
      * AbstractType, this == TypeParser.parse(toString()).
      *
@@ -494,23 +520,4 @@ public abstract class AbstractType<T> implements Comparator<ByteBuffer>, Assignm
     {
         return testAssignment(receiver.type);
     }
-
-    public final AssignmentTestable.TestResult testAssignment(AbstractType<?> receiverType)
-    {
-        // We should ignore the fact that the output type is frozen in our comparison as functions do not support
-        // frozen types for arguments
-        if (isFreezable() && !isMultiCell())
-            receiverType = receiverType.freeze();
-
-        if (isReversed())
-            receiverType = ReversedType.getInstance(receiverType);
-
-        if (equals(receiverType))
-            return AssignmentTestable.TestResult.EXACT_MATCH;
-
-        if (receiverType.isValueCompatibleWith(this))
-            return AssignmentTestable.TestResult.WEAKLY_ASSIGNABLE;
-
-        return AssignmentTestable.TestResult.NOT_ASSIGNABLE;
-    }
 }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/4ebab661/src/java/org/apache/cassandra/db/marshal/ListType.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/marshal/ListType.java b/src/java/org/apache/cassandra/db/marshal/ListType.java
index 29ccaa5..4b3f3f9 100644
--- a/src/java/org/apache/cassandra/db/marshal/ListType.java
+++ b/src/java/org/apache/cassandra/db/marshal/ListType.java
@@ -236,6 +236,12 @@ public class ListType<T> extends CollectionType<List<T>>
         return sb.append("]").toString();
     }
 
+    public ByteBuffer getSliceFromSerialized(ByteBuffer collection, ByteBuffer from, ByteBuffer to)
+    {
+        // We don't support slicing on lists so we don't need that function
+        throw new UnsupportedOperationException();
+    }
+
     @Override
     public String toJSONString(ByteBuffer buffer, ProtocolVersion protocolVersion)
     {

http://git-wip-us.apache.org/repos/asf/cassandra/blob/4ebab661/src/java/org/apache/cassandra/schema/ColumnMetadata.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/schema/ColumnMetadata.java b/src/java/org/apache/cassandra/schema/ColumnMetadata.java
index 6943fa4..ea80708 100644
--- a/src/java/org/apache/cassandra/schema/ColumnMetadata.java
+++ b/src/java/org/apache/cassandra/schema/ColumnMetadata.java
@@ -19,6 +19,7 @@ package org.apache.cassandra.schema;
 
 import java.nio.ByteBuffer;
 import java.util.*;
+import java.util.function.Predicate;
 
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.MoreObjects;
@@ -310,6 +311,18 @@ public final class ColumnMetadata extends ColumnSpecification implements Selecta
         return kind.isPrimaryKeyKind();
     }
 
+    @Override
+    public boolean selectColumns(Predicate<ColumnMetadata> predicate)
+    {
+        return predicate.test(this);
+    }
+
+    @Override
+    public boolean processesSelection()
+    {
+        return false;
+    }
+
     /**
      * Converts the specified column definitions into column identifiers.
      *
@@ -484,12 +497,6 @@ public final class ColumnMetadata extends ColumnSpecification implements Selecta
         public abstract ColumnMetadata prepare(TableMetadata table);
 
         @Override
-        public boolean processesSelection()
-        {
-            return false;
-        }
-
-        @Override
         public final int hashCode()
         {
             return toString().hashCode();

http://git-wip-us.apache.org/repos/asf/cassandra/blob/4ebab661/src/java/org/apache/cassandra/serializers/CollectionSerializer.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/serializers/CollectionSerializer.java b/src/java/org/apache/cassandra/serializers/CollectionSerializer.java
index 95a0388..9d261c6 100644
--- a/src/java/org/apache/cassandra/serializers/CollectionSerializer.java
+++ b/src/java/org/apache/cassandra/serializers/CollectionSerializer.java
@@ -23,6 +23,7 @@ import java.util.Collection;
 import java.util.List;
 
 import org.apache.cassandra.transport.ProtocolVersion;
+import org.apache.cassandra.db.marshal.AbstractType;
 import org.apache.cassandra.utils.ByteBufferUtil;
 
 public abstract class CollectionSerializer<T> implements TypeSerializer<T>
@@ -71,7 +72,7 @@ public abstract class CollectionSerializer<T> implements TypeSerializer<T>
 
     protected static void writeCollectionSize(ByteBuffer output, int elements, ProtocolVersion version)
     {
-            output.putInt(elements);
+        output.putInt(elements);
     }
 
     public static int readCollectionSize(ByteBuffer input, ProtocolVersion version)
@@ -105,8 +106,61 @@ public abstract class CollectionSerializer<T> implements TypeSerializer<T>
         return ByteBufferUtil.readBytes(input, size);
     }
 
+    protected static void skipValue(ByteBuffer input, ProtocolVersion version)
+    {
+        int size = input.getInt();
+        input.position(input.position() + size);
+    }
+
     public static int sizeOfValue(ByteBuffer value, ProtocolVersion version)
     {
         return value == null ? 4 : 4 + value.remaining();
     }
+
+    /**
+     * Extract an element from a serialized collection.
+     * <p>
+     * Note that this is only supported to sets and maps. For sets, this mostly ends up being
+     * a check for the presence of the provide key: it will return the key if it's present and
+     * {@code null} otherwise.
+     *
+     * @param collection the serialized collection. This cannot be {@code null}.
+     * @param key the key to extract (This cannot be {@code null} nor {@code ByteBufferUtil.UNSET_BYTE_BUFFER}).
+     * @param comparator the type to use to compare the {@code key} value to those
+     * in the collection.
+     * @return the value associated with {@code key} if one exists, {@code null} otherwise
+     */
+    public abstract ByteBuffer getSerializedValue(ByteBuffer collection, ByteBuffer key, AbstractType<?> comparator);
+
+    /**
+     * Returns the slice of a collection directly from its serialized value.
+     *
+     * @param collection the serialized collection. This cannot be {@code null}.
+     * @param from the left bound of the slice to extract. This cannot be {@code null} but if this is
+     * {@code ByteBufferUtil.UNSET_BYTE_BUFFER}, then the returned slice starts at the beginning
+     * of {@code collection}.
+     * @param comparator the type to use to compare the {@code from} and {@code to} values to those
+     * in the collection.
+     * @return a valid serialized collection (possibly empty) corresponding to slice {@code [from, to]}
+     * of {@code collection}.
+     */
+    public abstract ByteBuffer getSliceFromSerialized(ByteBuffer collection, ByteBuffer from, ByteBuffer to, AbstractType<?> comparator);
+
+    /**
+     * Creates a new serialized map composed from the data from {@code input} between {@code startPos}
+     * (inclusive) and {@code endPos} (exclusive), assuming that data holds {@code count} elements.
+     */
+    protected ByteBuffer copyAsNewCollection(ByteBuffer input, int count, int startPos, int endPos, ProtocolVersion version)
+    {
+        int sizeLen = sizeOfCollectionSize(count, version);
+        if (count == 0)
+            return ByteBuffer.allocate(sizeLen);
+
+        int bodyLen = endPos - startPos;
+        ByteBuffer output = ByteBuffer.allocate(sizeLen + bodyLen);
+        writeCollectionSize(output, count, version);
+        output.position(0);
+        ByteBufferUtil.arrayCopy(input, startPos, output, sizeLen, bodyLen);
+        return output;
+    }
 }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/4ebab661/src/java/org/apache/cassandra/serializers/ListSerializer.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/serializers/ListSerializer.java b/src/java/org/apache/cassandra/serializers/ListSerializer.java
index 3a20cd5..98ebd48 100644
--- a/src/java/org/apache/cassandra/serializers/ListSerializer.java
+++ b/src/java/org/apache/cassandra/serializers/ListSerializer.java
@@ -18,14 +18,15 @@
 
 package org.apache.cassandra.serializers;
 
-import org.apache.cassandra.transport.ProtocolVersion;
-
 import java.nio.BufferUnderflowException;
 import java.nio.ByteBuffer;
 import java.util.*;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 
+import org.apache.cassandra.db.marshal.AbstractType;
+import org.apache.cassandra.transport.ProtocolVersion;
+
 public class ListSerializer<T> extends CollectionSerializer<List<T>>
 {
     // interning instances
@@ -167,4 +168,16 @@ public class ListSerializer<T> extends CollectionSerializer<List<T>>
     {
         return (Class) List.class;
     }
+
+    public ByteBuffer getSerializedValue(ByteBuffer collection, ByteBuffer key, AbstractType<?> comparator)
+    {
+        // We don't allow selecting an element of a list so we don't need this.
+        throw new UnsupportedOperationException();
+    }
+
+    public ByteBuffer getSliceFromSerialized(ByteBuffer collection, ByteBuffer from, ByteBuffer to, AbstractType<?> comparator)
+    {
+        // We don't allow slicing of list so we don't need this.
+        throw new UnsupportedOperationException();
+    }
 }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/4ebab661/src/java/org/apache/cassandra/serializers/MapSerializer.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/serializers/MapSerializer.java b/src/java/org/apache/cassandra/serializers/MapSerializer.java
index 7ba45d6..f428502 100644
--- a/src/java/org/apache/cassandra/serializers/MapSerializer.java
+++ b/src/java/org/apache/cassandra/serializers/MapSerializer.java
@@ -26,6 +26,7 @@ import java.util.concurrent.ConcurrentMap;
 
 import org.apache.cassandra.db.marshal.AbstractType;
 import org.apache.cassandra.transport.ProtocolVersion;
+import org.apache.cassandra.utils.ByteBufferUtil;
 import org.apache.cassandra.utils.Pair;
 
 public class MapSerializer<K, V> extends CollectionSerializer<Map<K, V>>
@@ -128,29 +129,23 @@ public class MapSerializer<K, V> extends CollectionSerializer<Map<K, V>>
         }
     }
 
-    /**
-     * Given a serialized map, gets the value associated with a given key.
-     * @param serializedMap a serialized map
-     * @param serializedKey a serialized key
-     * @param keyType the key type for the map
-     * @return the value associated with the key if one exists, null otherwise
-     */
-    public ByteBuffer getSerializedValue(ByteBuffer serializedMap, ByteBuffer serializedKey, AbstractType keyType)
+    public ByteBuffer getSerializedValue(ByteBuffer collection, ByteBuffer key, AbstractType<?> comparator)
     {
         try
         {
-            ByteBuffer input = serializedMap.duplicate();
+            ByteBuffer input = collection.duplicate();
             int n = readCollectionSize(input, ProtocolVersion.V3);
             for (int i = 0; i < n; i++)
             {
                 ByteBuffer kbb = readValue(input, ProtocolVersion.V3);
-                ByteBuffer vbb = readValue(input, ProtocolVersion.V3);
-                int comparison = keyType.compare(kbb, serializedKey);
+                int comparison = comparator.compareForCQL(kbb, key);
                 if (comparison == 0)
-                    return vbb;
+                    return readValue(input, ProtocolVersion.V3);
                 else if (comparison > 0)
                     // since the map is in sorted order, we know we've gone too far and the element doesn't exist
                     return null;
+                else // comparison < 0
+                    skipValue(input, ProtocolVersion.V3);
             }
             return null;
         }
@@ -160,6 +155,67 @@ public class MapSerializer<K, V> extends CollectionSerializer<Map<K, V>>
         }
     }
 
+    public ByteBuffer getSliceFromSerialized(ByteBuffer collection, ByteBuffer from, ByteBuffer to, AbstractType<?> comparator)
+    {
+        if (from == ByteBufferUtil.UNSET_BYTE_BUFFER && to == ByteBufferUtil.UNSET_BYTE_BUFFER)
+            return collection;
+
+        try
+        {
+            ByteBuffer input = collection.duplicate();
+            int n = readCollectionSize(input, ProtocolVersion.V3);
+            int startPos = input.position();
+            int count = 0;
+            boolean inSlice = from == ByteBufferUtil.UNSET_BYTE_BUFFER;
+
+            for (int i = 0; i < n; i++)
+            {
+                int pos = input.position();
+                ByteBuffer kbb = readValue(input, ProtocolVersion.V3); // key
+
+                // If we haven't passed the start already, check if we have now
+                if (!inSlice)
+                {
+                    int comparison = comparator.compareForCQL(from, kbb);
+                    if (comparison <= 0)
+                    {
+                        // We're now within the slice
+                        inSlice = true;
+                        startPos = pos;
+                    }
+                    else
+                    {
+                        // We're before the slice so we know we don't care about this element
+                        skipValue(input, ProtocolVersion.V3); // value
+                        continue;
+                    }
+                }
+
+                // Now check if we're done
+                int comparison = to == ByteBufferUtil.UNSET_BYTE_BUFFER ? -1 : comparator.compareForCQL(kbb, to);
+                if (comparison > 0)
+                {
+                    // We're done and shouldn't include the key we just read
+                    input.position(pos);
+                    break;
+                }
+
+                // Otherwise, we'll include that element
+                skipValue(input, ProtocolVersion.V3); // value
+                ++count;
+
+                // But if we know if was the last of the slice, we break early
+                if (comparison == 0)
+                    break;
+            }
+            return copyAsNewCollection(collection, count, startPos, input.position(), ProtocolVersion.V3);
+        }
+        catch (BufferUnderflowException e)
+        {
+            throw new MarshalException("Not enough bytes to read a map");
+        }
+    }
+
     public String toString(Map<K, V> value)
     {
         StringBuilder sb = new StringBuilder();

http://git-wip-us.apache.org/repos/asf/cassandra/blob/4ebab661/src/java/org/apache/cassandra/serializers/SetSerializer.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/serializers/SetSerializer.java b/src/java/org/apache/cassandra/serializers/SetSerializer.java
index b874978..e4e970c 100644
--- a/src/java/org/apache/cassandra/serializers/SetSerializer.java
+++ b/src/java/org/apache/cassandra/serializers/SetSerializer.java
@@ -26,6 +26,9 @@ import java.util.concurrent.ConcurrentMap;
 
 import org.apache.cassandra.transport.ProtocolVersion;
 
+import org.apache.cassandra.db.marshal.AbstractType;
+import org.apache.cassandra.utils.ByteBufferUtil;
+
 public class SetSerializer<T> extends CollectionSerializer<Set<T>>
 {
     // interning instances
@@ -136,4 +139,88 @@ public class SetSerializer<T> extends CollectionSerializer<Set<T>>
     {
         return (Class) Set.class;
     }
+
+    public ByteBuffer getSerializedValue(ByteBuffer collection, ByteBuffer key, AbstractType<?> comparator)
+    {
+        try
+        {
+            ByteBuffer input = collection.duplicate();
+            int n = readCollectionSize(input, ProtocolVersion.V3);
+            for (int i = 0; i < n; i++)
+            {
+                ByteBuffer value = readValue(input, ProtocolVersion.V3);
+                int comparison = comparator.compareForCQL(value, key);
+                if (comparison == 0)
+                    return value;
+                else if (comparison > 0)
+                    // since the set is in sorted order, we know we've gone too far and the element doesn't exist
+                    return null;
+                // else, we're before the element so continue
+            }
+            return null;
+        }
+        catch (BufferUnderflowException e)
+        {
+            throw new MarshalException("Not enough bytes to read a set");
+        }
+    }
+
+    public ByteBuffer getSliceFromSerialized(ByteBuffer collection, ByteBuffer from, ByteBuffer to, AbstractType<?> comparator)
+    {
+        if (from == ByteBufferUtil.UNSET_BYTE_BUFFER && to == ByteBufferUtil.UNSET_BYTE_BUFFER)
+            return collection;
+
+        try
+        {
+            ByteBuffer input = collection.duplicate();
+            int n = readCollectionSize(input, ProtocolVersion.V3);
+            int startPos = input.position();
+            int count = 0;
+            boolean inSlice = from == ByteBufferUtil.UNSET_BYTE_BUFFER;
+
+            for (int i = 0; i < n; i++)
+            {
+                int pos = input.position();
+                ByteBuffer value = readValue(input, ProtocolVersion.V3);
+
+                // If we haven't passed the start already, check if we have now
+                if (!inSlice)
+                {
+                    int comparison = comparator.compareForCQL(from, value);
+                    if (comparison <= 0)
+                    {
+                        // We're now within the slice
+                        inSlice = true;
+                        startPos = pos;
+                    }
+                    else
+                    {
+                        // We're before the slice so we know we don't care about this value
+                        continue;
+                    }
+                }
+
+                // Now check if we're done
+                int comparison = to == ByteBufferUtil.UNSET_BYTE_BUFFER ? -1 : comparator.compareForCQL(value, to);
+                if (comparison > 0)
+                {
+                    // We're done and shouldn't include the value we just read
+                    input.position(pos);
+                    break;
+                }
+
+                // Otherwise, we'll include that value
+                ++count;
+
+                // But if we know if was the last of the slice, we break early
+                if (comparison == 0)
+                    break;
+            }
+            return copyAsNewCollection(collection, count, startPos, input.position(), ProtocolVersion.V3);
+        }
+        catch (BufferUnderflowException e)
+        {
+            throw new MarshalException("Not enough bytes to read a set");
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/4ebab661/test/unit/org/apache/cassandra/cql3/CQLTester.java
----------------------------------------------------------------------
diff --git a/test/unit/org/apache/cassandra/cql3/CQLTester.java b/test/unit/org/apache/cassandra/cql3/CQLTester.java
index 5a73c8d..6d46a50 100644
--- a/test/unit/org/apache/cassandra/cql3/CQLTester.java
+++ b/test/unit/org/apache/cassandra/cql3/CQLTester.java
@@ -1561,7 +1561,7 @@ public abstract class CQLTester
     protected Object map(Object...values)
     {
         if (values.length % 2 != 0)
-            throw new IllegalArgumentException();
+            throw new IllegalArgumentException("Invalid number of arguments, got " + values.length);
 
         int size = values.length / 2;
         Map m = new LinkedHashMap(size);

http://git-wip-us.apache.org/repos/asf/cassandra/blob/4ebab661/test/unit/org/apache/cassandra/cql3/validation/entities/CollectionsTest.java
----------------------------------------------------------------------
diff --git a/test/unit/org/apache/cassandra/cql3/validation/entities/CollectionsTest.java b/test/unit/org/apache/cassandra/cql3/validation/entities/CollectionsTest.java
index 56ba0a0..dad5d68 100644
--- a/test/unit/org/apache/cassandra/cql3/validation/entities/CollectionsTest.java
+++ b/test/unit/org/apache/cassandra/cql3/validation/entities/CollectionsTest.java
@@ -21,7 +21,14 @@ import java.util.*;
 
 import org.junit.Test;
 
+import com.datastax.driver.core.ColumnDefinitions;
+import com.datastax.driver.core.DataType;
+import com.datastax.driver.core.ResultSet;
+import com.datastax.driver.core.Session;
 import org.apache.cassandra.cql3.CQLTester;
+import org.apache.cassandra.cql3.ColumnSpecification;
+import org.apache.cassandra.cql3.UntypedResultSet;
+import org.apache.cassandra.db.marshal.UTF8Type;
 import org.apache.cassandra.utils.FBUtilities;
 
 import static org.junit.Assert.assertEquals;
@@ -1098,4 +1105,788 @@ public class CollectionsTest extends CQLTester
         execute("UPDATE %s SET s = s - ? , s = s + ?  WHERE pk = ?", set(3), set(3, 4), 1);
         assertRows(execute("SELECT * FROM %s WHERE pk = 1") , row(1, set(0, 1, 2, 4)));
     }
+
+    @Test
+    public void testMapOperation() throws Throwable
+    {
+        createTable("CREATE TABLE %s (k int, c int, l text, " +
+                    "m map<text, text>, " +
+                    "fm frozen<map<text, text>>, " +
+                    "sm map<text, text> STATIC, " +
+                    "fsm frozen<map<text, text>> STATIC, " +
+                    "o int, PRIMARY KEY (k, c))");
+
+        execute("INSERT INTO %s(k, c, l, m, fm, sm, fsm, o) VALUES (0, 0, 'foobar', ?, ?, ?, ?, 42)",
+                map("22", "value22", "333", "value333"),
+                map("1", "fvalue1", "22", "fvalue22", "333", "fvalue333"),
+                map("22", "svalue22", "333", "svalue333"),
+                map("1", "fsvalue1", "22", "fsvalue22", "333", "fsvalue333"));
+
+        execute("INSERT INTO %s(k, c, l, m, fm, sm, fsm, o) VALUES (2, 0, 'row2', ?, ?, ?, ?, 88)",
+                map("22", "2value22", "333", "2value333"),
+                map("1", "2fvalue1", "22", "2fvalue22", "333", "2fvalue333"),
+                map("22", "2svalue22", "333", "2svalue333"),
+                map("1", "2fsvalue1", "22", "2fsvalue22", "333", "2fsvalue333"));
+
+        flush();
+
+        execute("UPDATE %s SET m = m + ? WHERE k = 0 AND c = 0",
+                map("1", "value1"));
+
+        execute("UPDATE %s SET sm = sm + ? WHERE k = 0",
+                map("1", "svalue1"));
+
+        flush();
+
+        assertRows(execute("SELECT m['22'] FROM %s WHERE k = 0 AND c = 0"),
+                   row("value22")
+        );
+        assertRows(execute("SELECT m['1'], m['22'], m['333'] FROM %s WHERE k = 0 AND c = 0"),
+                   row("value1", "value22", "value333")
+        );
+        assertRows(execute("SELECT m['2'..'3'] FROM %s WHERE k = 0 AND c = 0"),
+                   row(map("22", "value22"))
+        );
+
+        execute("INSERT INTO %s(k, c, l, m, fm, o) VALUES (0, 1, 'foobar', ?, ?, 42)",
+                map("1", "value1_2", "333", "value333_2"),
+                map("1", "fvalue1_2", "333", "fvalue333_2"));
+
+        assertRows(execute("SELECT c, m['1'], fm['1'] FROM %s WHERE k = 0"),
+                   row(0, "value1", "fvalue1"),
+                   row(1, "value1_2", "fvalue1_2")
+        );
+        assertRows(execute("SELECT c, sm['1'], fsm['1'] FROM %s WHERE k = 0"),
+                   row(0, "svalue1", "fsvalue1"),
+                   row(1, "svalue1", "fsvalue1")
+        );
+
+        assertRows(execute("SELECT c, m['1'], fm['1'] FROM %s WHERE k = 0 AND c = 0"),
+                   row(0, "value1", "fvalue1")
+        );
+
+        assertRows(execute("SELECT c, m['1'], fm['1'] FROM %s WHERE k = 0"),
+                   row(0, "value1", "fvalue1"),
+                   row(1, "value1_2", "fvalue1_2")
+        );
+
+        assertColumnNames(execute("SELECT k, l, m['1'] as mx, o FROM %s WHERE k = 0"),
+                          "k", "l", "mx", "o");
+        assertColumnNames(execute("SELECT k, l, m['1'], o FROM %s WHERE k = 0"),
+                          "k", "l", "m['1']", "o");
+
+        assertRows(execute("SELECT k, l, m['22'], o FROM %s WHERE k = 0"),
+                   row(0, "foobar", "value22", 42),
+                   row(0, "foobar", null, 42)
+        );
+        assertColumnNames(execute("SELECT k, l, m['22'], o FROM %s WHERE k = 0"),
+                          "k", "l", "m['22']", "o");
+
+        assertRows(execute("SELECT k, l, m['333'], o FROM %s WHERE k = 0"),
+                   row(0, "foobar", "value333", 42),
+                   row(0, "foobar", "value333_2", 42)
+        );
+
+        assertRows(execute("SELECT k, l, m['foobar'], o FROM %s WHERE k = 0"),
+                   row(0, "foobar", null, 42),
+                   row(0, "foobar", null, 42)
+        );
+
+        assertRows(execute("SELECT k, l, m['1'..'22'], o FROM %s WHERE k = 0"),
+                   row(0, "foobar", map("1", "value1",
+                                        "22", "value22"), 42),
+                   row(0, "foobar", map("1", "value1_2"), 42)
+        );
+
+        assertRows(execute("SELECT k, l, m[''..'23'], o FROM %s WHERE k = 0"),
+                   row(0, "foobar", map("1", "value1",
+                                        "22", "value22"), 42),
+                   row(0, "foobar", map("1", "value1_2"), 42)
+        );
+        assertColumnNames(execute("SELECT k, l, m[''..'23'], o FROM %s WHERE k = 0"),
+                          "k", "l", "m[''..'23']", "o");
+
+        assertRows(execute("SELECT k, l, m['2'..'3'], o FROM %s WHERE k = 0"),
+                   row(0, "foobar", map("22", "value22"), 42),
+                   row(0, "foobar", map(), 42)
+        );
+
+        assertRows(execute("SELECT k, l, m['22'..], o FROM %s WHERE k = 0"),
+                   row(0, "foobar", map("22", "value22",
+                                        "333", "value333"), 42),
+                   row(0, "foobar", map("333", "value333_2"), 42)
+        );
+
+        assertRows(execute("SELECT k, l, m[..'22'], o FROM %s WHERE k = 0"),
+                   row(0, "foobar", map("1", "value1",
+                                        "22", "value22"), 42),
+                   row(0, "foobar", map("1", "value1_2"), 42)
+        );
+
+        assertRows(execute("SELECT k, l, m, o FROM %s WHERE k = 0"),
+                   row(0, "foobar", map("1", "value1",
+                                        "22", "value22",
+                                        "333", "value333"), 42),
+                   row(0, "foobar", map("1", "value1_2",
+                                        "333", "value333_2"), 42)
+        );
+
+        assertRows(execute("SELECT k, l, m, m as m2, o FROM %s WHERE k = 0"),
+                   row(0, "foobar", map("1", "value1",
+                                        "22", "value22",
+                                        "333", "value333"),
+                       map("1", "value1",
+                           "22", "value22",
+                           "333", "value333"), 42),
+                   row(0, "foobar", map("1", "value1_2",
+                                        "333", "value333_2"),
+                       map("1", "value1_2",
+                           "333", "value333_2"), 42)
+        );
+
+        // with UDF as slice arg
+
+        String f = createFunction(KEYSPACE, "text",
+                                  "CREATE FUNCTION %s(arg text) " +
+                                  "CALLED ON NULL INPUT " +
+                                  "RETURNS TEXT " +
+                                  "LANGUAGE java AS 'return arg;'");
+
+        assertRows(execute("SELECT k, c, l, m[" + f +"('1').." + f +"('22')], o FROM %s WHERE k = 0"),
+                   row(0, 0, "foobar", map("1", "value1",
+                                           "22", "value22"), 42),
+                   row(0, 1, "foobar", map("1", "value1_2"), 42)
+        );
+
+        assertRows(execute("SELECT k, c, l, m[" + f +"(?).." + f +"(?)], o FROM %s WHERE k = 0", "1", "22"),
+                   row(0, 0, "foobar", map("1", "value1",
+                                           "22", "value22"), 42),
+                   row(0, 1, "foobar", map("1", "value1_2"), 42)
+        );
+
+        // with UDF taking a map
+
+        f = createFunction(KEYSPACE, "map<text,text>",
+                           "CREATE FUNCTION %s(m text) " +
+                           "CALLED ON NULL INPUT " +
+                           "RETURNS TEXT " +
+                           "LANGUAGE java AS $$return m;$$");
+
+        assertRows(execute("SELECT k, c, " + f + "(m['1']) FROM %s WHERE k = 0"),
+                   row(0, 0, "value1"),
+                   row(0, 1, "value1_2"));
+
+        // with UDF taking multiple cols
+
+        f = createFunction(KEYSPACE, "map<text,text>,map<text,text>,int,int",
+                           "CREATE FUNCTION %s(m1 map<text,text>, m2 text, k int, c int) " +
+                           "CALLED ON NULL INPUT " +
+                           "RETURNS TEXT " +
+                           "LANGUAGE java AS $$return m1.get(\"1\") + ':' + m2 + ':' + k + ':' + c;$$");
+
+        assertRows(execute("SELECT " + f + "(m, m['1'], k, c) FROM %s WHERE k = 0"),
+                   row("value1:value1:0:0"),
+                   row("value1_2:value1_2:0:1"));
+
+        // with nested UDF + aggregation and multiple cols
+
+        f = createFunction(KEYSPACE, "int,int",
+                           "CREATE FUNCTION %s(k int, c int) " +
+                           "CALLED ON NULL INPUT " +
+                           "RETURNS int " +
+                           "LANGUAGE java AS $$return k + c;$$");
+
+        assertColumnNames(execute("SELECT max(" + f + "(k, c)) as sel1, max(" + f + "(k, c)) FROM %s WHERE k = 0"),
+                          "sel1", "system.max(" + f + "(k, c))");
+        assertRows(execute("SELECT max(" + f + "(k, c)) as sel1, max(" + f + "(k, c)) FROM %s WHERE k = 0"),
+                   row(1, 1));
+
+        assertColumnNames(execute("SELECT max(" + f + "(k, c)) as sel1, max(" + f + "(k, c)) FROM %s"),
+                          "sel1", "system.max(" + f + "(k, c))");
+        assertRows(execute("SELECT max(" + f + "(k, c)) as sel1, max(" + f + "(k, c)) FROM %s"),
+                   row(2, 2));
+
+        // prepared parameters
+
+        assertRows(execute("SELECT c, m[?], fm[?] FROM %s WHERE k = 0", "1", "1"),
+                   row(0, "value1", "fvalue1"),
+                   row(1, "value1_2", "fvalue1_2")
+        );
+        assertRows(execute("SELECT c, sm[?], fsm[?] FROM %s WHERE k = 0", "1", "1"),
+                   row(0, "svalue1", "fsvalue1"),
+                   row(1, "svalue1", "fsvalue1")
+        );
+        assertRows(execute("SELECT k, l, m[?..?], o FROM %s WHERE k = 0", "1", "22"),
+                   row(0, "foobar", map("1", "value1",
+                                        "22", "value22"), 42),
+                   row(0, "foobar", map("1", "value1_2"), 42)
+        );
+    }
+
+    @Test
+    public void testMapOperationWithIntKey() throws Throwable
+    {
+        // used type "int" as map key intentionally since CQL parsing relies on "BigInteger"
+
+        createTable("CREATE TABLE %s (k int, c int, l text, " +
+                    "m map<int, text>, " +
+                    "fm frozen<map<int, text>>, " +
+                    "sm map<int, text> STATIC, " +
+                    "fsm frozen<map<int, text>> STATIC, " +
+                    "o int, PRIMARY KEY (k, c))");
+
+        execute("INSERT INTO %s(k, c, l, m, fm, sm, fsm, o) VALUES (0, 0, 'foobar', ?, ?, ?, ?, 42)",
+                map(22, "value22", 333, "value333"),
+                map(1, "fvalue1", 22, "fvalue22", 333, "fvalue333"),
+                map(22, "svalue22", 333, "svalue333"),
+                map(1, "fsvalue1", 22, "fsvalue22", 333, "fsvalue333"));
+
+        execute("INSERT INTO %s(k, c, l, m, fm, sm, fsm, o) VALUES (2, 0, 'row2', ?, ?, ?, ?, 88)",
+                map(22, "2value22", 333, "2value333"),
+                map(1, "2fvalue1", 22, "2fvalue22", 333, "2fvalue333"),
+                map(22, "2svalue22", 333, "2svalue333"),
+                map(1, "2fsvalue1", 22, "2fsvalue22", 333, "2fsvalue333"));
+
+        flush();
+
+        execute("UPDATE %s SET m = m + ? WHERE k = 0 AND c = 0",
+                map(1, "value1"));
+
+        execute("UPDATE %s SET sm = sm + ? WHERE k = 0",
+                map(1, "svalue1"));
+
+        flush();
+
+        assertRows(execute("SELECT m[22] FROM %s WHERE k = 0 AND c = 0"),
+                   row("value22")
+        );
+        assertRows(execute("SELECT m[1], m[22], m[333] FROM %s WHERE k = 0 AND c = 0"),
+                   row("value1", "value22", "value333")
+        );
+        assertRows(execute("SELECT m[20 .. 25] FROM %s WHERE k = 0 AND c = 0"),
+                   row(map(22, "value22"))
+        );
+
+        execute("INSERT INTO %s(k, c, l, m, fm, o) VALUES (0, 1, 'foobar', ?, ?, 42)",
+                map(1, "value1_2", 333, "value333_2"),
+                map(1, "fvalue1_2", 333, "fvalue333_2"));
+
+        assertRows(execute("SELECT c, m[1], fm[1] FROM %s WHERE k = 0"),
+                   row(0, "value1", "fvalue1"),
+                   row(1, "value1_2", "fvalue1_2")
+        );
+        assertRows(execute("SELECT c, sm[1], fsm[1] FROM %s WHERE k = 0"),
+                   row(0, "svalue1", "fsvalue1"),
+                   row(1, "svalue1", "fsvalue1")
+        );
+
+        // with UDF as slice arg
+
+        String f = createFunction(KEYSPACE, "int",
+                                  "CREATE FUNCTION %s(arg int) " +
+                                  "CALLED ON NULL INPUT " +
+                                  "RETURNS int " +
+                                  "LANGUAGE java AS 'return arg;'");
+
+        assertRows(execute("SELECT k, c, l, m[" + f +"(1).." + f +"(22)], o FROM %s WHERE k = 0"),
+                   row(0, 0, "foobar", map(1, "value1",
+                                           22, "value22"), 42),
+                   row(0, 1, "foobar", map(1, "value1_2"), 42)
+        );
+
+        assertRows(execute("SELECT k, c, l, m[" + f +"(?).." + f +"(?)], o FROM %s WHERE k = 0", 1, 22),
+                   row(0, 0, "foobar", map(1, "value1",
+                                           22, "value22"), 42),
+                   row(0, 1, "foobar", map(1, "value1_2"), 42)
+        );
+
+        // with UDF taking a map
+
+        f = createFunction(KEYSPACE, "map<int,text>",
+                           "CREATE FUNCTION %s(m text) " +
+                           "CALLED ON NULL INPUT " +
+                           "RETURNS TEXT " +
+                           "LANGUAGE java AS $$return m;$$");
+
+        assertRows(execute("SELECT k, c, " + f + "(m[1]) FROM %s WHERE k = 0"),
+                   row(0, 0, "value1"),
+                   row(0, 1, "value1_2"));
+
+        // with UDF taking multiple cols
+
+        f = createFunction(KEYSPACE, "map<int,text>,map<int,text>,int,int",
+                           "CREATE FUNCTION %s(m1 map<int,text>, m2 text, k int, c int) " +
+                           "CALLED ON NULL INPUT " +
+                           "RETURNS TEXT " +
+                           "LANGUAGE java AS $$return m1.get(1) + ':' + m2 + ':' + k + ':' + c;$$");
+
+        assertRows(execute("SELECT " + f + "(m, m[1], k, c) FROM %s WHERE k = 0"),
+                   row("value1:value1:0:0"),
+                   row("value1_2:value1_2:0:1"));
+
+        // with nested UDF + aggregation and multiple cols
+
+        f = createFunction(KEYSPACE, "int,int",
+                           "CREATE FUNCTION %s(k int, c int) " +
+                           "CALLED ON NULL INPUT " +
+                           "RETURNS int " +
+                           "LANGUAGE java AS $$return k + c;$$");
+
+        assertColumnNames(execute("SELECT max(" + f + "(k, c)) as sel1, max(" + f + "(k, c)) FROM %s WHERE k = 0"),
+                          "sel1", "system.max(" + f + "(k, c))");
+        assertRows(execute("SELECT max(" + f + "(k, c)) as sel1, max(" + f + "(k, c)) FROM %s WHERE k = 0"),
+                   row(1, 1));
+
+        assertColumnNames(execute("SELECT max(" + f + "(k, c)) as sel1, max(" + f + "(k, c)) FROM %s"),
+                          "sel1", "system.max(" + f + "(k, c))");
+        assertRows(execute("SELECT max(" + f + "(k, c)) as sel1, max(" + f + "(k, c)) FROM %s"),
+                   row(2, 2));
+
+        // prepared parameters
+
+        assertRows(execute("SELECT c, m[?], fm[?] FROM %s WHERE k = 0", 1, 1),
+                   row(0, "value1", "fvalue1"),
+                   row(1, "value1_2", "fvalue1_2")
+        );
+        assertRows(execute("SELECT c, sm[?], fsm[?] FROM %s WHERE k = 0", 1, 1),
+                   row(0, "svalue1", "fsvalue1"),
+                   row(1, "svalue1", "fsvalue1")
+        );
+        assertRows(execute("SELECT k, l, m[?..?], o FROM %s WHERE k = 0", 1, 22),
+                   row(0, "foobar", map(1, "value1",
+                                        22, "value22"), 42),
+                   row(0, "foobar", map(1, "value1_2"), 42)
+        );
+    }
+
+    @Test
+    public void testMapOperationOnPartKey() throws Throwable
+    {
+        createTable("CREATE TABLE %s (k frozen<map<text, text>> PRIMARY KEY, l text, o int)");
+
+        execute("INSERT INTO %s(k, l, o) VALUES (?, 'foobar', 42)", map("1", "value1", "22", "value22", "333", "value333"));
+
+        assertRows(execute("SELECT l, k['1'], o FROM %s WHERE k = ?", map("1", "value1", "22", "value22", "333", "value333")),
+                   row("foobar", "value1", 42)
+        );
+
+        assertRows(execute("SELECT l, k['22'], o FROM %s WHERE k = ?", map("1", "value1", "22", "value22", "333", "value333")),
+                   row("foobar", "value22", 42)
+        );
+
+        assertRows(execute("SELECT l, k['333'], o FROM %s WHERE k = ?", map("1", "value1", "22", "value22", "333", "value333")),
+                   row("foobar", "value333", 42)
+        );
+
+        assertRows(execute("SELECT l, k['foobar'], o FROM %s WHERE k = ?", map("1", "value1", "22", "value22", "333", "value333")),
+                   row("foobar", null, 42)
+        );
+
+        assertRows(execute("SELECT l, k['1'..'22'], o FROM %s WHERE k = ?", map("1", "value1", "22", "value22", "333", "value333")),
+                   row("foobar", map("1", "value1",
+                                     "22", "value22"), 42)
+        );
+
+        assertRows(execute("SELECT l, k[''..'23'], o FROM %s WHERE k = ?", map("1", "value1", "22", "value22", "333", "value333")),
+                   row("foobar", map("1", "value1",
+                                     "22", "value22"), 42)
+        );
+
+        assertRows(execute("SELECT l, k['2'..'3'], o FROM %s WHERE k = ?", map("1", "value1", "22", "value22", "333", "value333")),
+                   row("foobar", map("22", "value22"), 42)
+        );
+
+        assertRows(execute("SELECT l, k['22'..], o FROM %s WHERE k = ?", map("1", "value1", "22", "value22", "333", "value333")),
+                   row("foobar", map("22", "value22",
+                                     "333", "value333"), 42)
+        );
+
+        assertRows(execute("SELECT l, k[..'22'], o FROM %s WHERE k = ?", map("1", "value1", "22", "value22", "333", "value333")),
+                   row("foobar", map("1", "value1",
+                                     "22", "value22"), 42)
+        );
+
+        assertRows(execute("SELECT l, k, o FROM %s WHERE k = ?", map("1", "value1", "22", "value22", "333", "value333")),
+                   row("foobar", map("1", "value1",
+                                     "22", "value22",
+                                     "333", "value333"), 42)
+        );
+    }
+
+    @Test
+    public void testMapOperationOnClustKey() throws Throwable
+    {
+        createTable("CREATE TABLE %s (k int, c frozen<map<text, text>>, l text, o int, PRIMARY KEY (k, c))");
+
+        execute("INSERT INTO %s(k, c, l, o) VALUES (0, ?, 'foobar', 42)", map("1", "value1", "22", "value22", "333", "value333"));
+
+        assertRows(execute("SELECT k, l, c['1'], o FROM %s WHERE k = 0 AND c = ?", map("1", "value1", "22", "value22", "333", "value333")),
+                   row(0, "foobar", "value1", 42)
+        );
+
+        assertRows(execute("SELECT k, l, c['22'], o FROM %s WHERE k = 0 AND c = ?", map("1", "value1", "22", "value22", "333", "value333")),
+                   row(0, "foobar", "value22", 42)
+        );
+
+        assertRows(execute("SELECT k, l, c['333'], o FROM %s WHERE k = 0 AND c = ?", map("1", "value1", "22", "value22", "333", "value333")),
+                   row(0, "foobar", "value333", 42)
+        );
+
+        assertRows(execute("SELECT k, l, c['foobar'], o FROM %s WHERE k = 0 AND c = ?", map("1", "value1", "22", "value22", "333", "value333")),
+                   row(0, "foobar", null, 42)
+        );
+
+        assertRows(execute("SELECT k, l, c['1'..'22'], o FROM %s WHERE k = 0 AND c = ?", map("1", "value1", "22", "value22", "333", "value333")),
+                   row(0, "foobar", map("1", "value1",
+                                        "22", "value22"), 42)
+        );
+
+        assertRows(execute("SELECT k, l, c[''..'23'], o FROM %s WHERE k = 0 AND c = ?", map("1", "value1", "22", "value22", "333", "value333")),
+                   row(0, "foobar", map("1", "value1",
+                                        "22", "value22"), 42)
+        );
+
+        assertRows(execute("SELECT k, l, c['2'..'3'], o FROM %s WHERE k = 0 AND c = ?", map("1", "value1", "22", "value22", "333", "value333")),
+                   row(0, "foobar", map("22", "value22"), 42)
+        );
+
+        assertRows(execute("SELECT k, l, c['22'..], o FROM %s WHERE k = 0 AND c = ?", map("1", "value1", "22", "value22", "333", "value333")),
+                   row(0, "foobar", map("22", "value22",
+                                        "333", "value333"), 42)
+        );
+
+        assertRows(execute("SELECT k, l, c[..'22'], o FROM %s WHERE k = 0 AND c = ?", map("1", "value1", "22", "value22", "333", "value333")),
+                   row(0, "foobar", map("1", "value1",
+                                        "22", "value22"), 42)
+        );
+
+        assertRows(execute("SELECT k, l, c, o FROM %s WHERE k = 0 AND c = ?", map("1", "value1", "22", "value22", "333", "value333")),
+                   row(0, "foobar", map("1", "value1",
+                                        "22", "value22",
+                                        "333", "value333"), 42)
+        );
+    }
+
+    @Test
+    public void testSetOperation() throws Throwable
+    {
+        createTable("CREATE TABLE %s (k int, c int, l text, " +
+                    "s set<text>, " +
+                    "fs frozen<set<text>>, " +
+                    "ss set<text> STATIC, " +
+                    "fss frozen<set<text>> STATIC, " +
+                    "o int, PRIMARY KEY (k, c))");
+
+        execute("INSERT INTO %s(k, c, l, s, fs, ss, fss, o) VALUES (0, 0, 'foobar', ?, ?, ?, ?, 42)",
+                set("1", "22", "333"),
+                set("f1", "f22", "f333"),
+                set("s1", "s22", "s333"),
+                set("fs1", "fs22", "fs333"));
+
+        flush();
+
+        execute("UPDATE %s SET s = s + ? WHERE k = 0 AND c = 0", set("22_2"));
+
+        execute("UPDATE %s SET ss = ss + ? WHERE k = 0", set("s22_2"));
+
+        flush();
+
+        execute("INSERT INTO %s(k, c, l, s, o) VALUES (0, 1, 'foobar', ?, 42)",
+                set("22", "333"));
+
+        assertRows(execute("SELECT c, s, fs, ss, fss FROM %s WHERE k = 0"),
+                   row(0, set("1", "22", "22_2", "333"), set("f1", "f22", "f333"), set("s1", "s22", "s22_2", "s333"), set("fs1", "fs22", "fs333")),
+                   row(1, set("22", "333"), null, set("s1", "s22", "s22_2", "s333"), set("fs1", "fs22", "fs333"))
+        );
+
+        assertRows(execute("SELECT c, s['1'], fs['f1'], ss['s1'], fss['fs1'] FROM %s WHERE k = 0"),
+                   row(0, "1", "f1", "s1", "fs1"),
+                   row(1, null, null, "s1", "fs1")
+        );
+
+        assertRows(execute("SELECT s['1'], fs['f1'], ss['s1'], fss['fs1'] FROM %s WHERE k = 0 AND c = 0"),
+                   row("1", "f1", "s1", "fs1")
+        );
+
+        assertRows(execute("SELECT k, c, l, s['1'], fs['f1'], ss['s1'], fss['fs1'], o FROM %s WHERE k = 0"),
+                   row(0, 0, "foobar", "1", "f1", "s1", "fs1", 42),
+                   row(0, 1, "foobar", null, null, "s1", "fs1", 42)
+        );
+
+        assertColumnNames(execute("SELECT k, l, s['1'], o FROM %s WHERE k = 0"),
+                          "k", "l", "s['1']", "o");
+
+        assertRows(execute("SELECT k, l, s['22'], o FROM %s WHERE k = 0 AND c = 0"),
+                   row(0, "foobar", "22", 42)
+        );
+
+        assertRows(execute("SELECT k, l, s['333'], o FROM %s WHERE k = 0 AND c = 0"),
+                   row(0, "foobar", "333", 42)
+        );
+
+        assertRows(execute("SELECT k, l, s['foobar'], o FROM %s WHERE k = 0 AND c = 0"),
+                   row(0, "foobar", null, 42)
+        );
+
+        assertRows(execute("SELECT k, l, s['1'..'22'], o FROM %s WHERE k = 0 AND c = 0"),
+                   row(0, "foobar", set("1", "22"), 42)
+        );
+        assertColumnNames(execute("SELECT k, l, s[''..'22'], o FROM %s WHERE k = 0"),
+                          "k", "l", "s[''..'22']", "o");
+
+        assertRows(execute("SELECT k, l, s[''..'23'], o FROM %s WHERE k = 0 AND c = 0"),
+                   row(0, "foobar", set("1", "22", "22_2"), 42)
+        );
+
+        assertRows(execute("SELECT k, l, s['2'..'3'], o FROM %s WHERE k = 0 AND c = 0"),
+                   row(0, "foobar", set("22", "22_2"), 42)
+        );
+
+        assertRows(execute("SELECT k, l, s['22'..], o FROM %s WHERE k = 0"),
+                   row(0, "foobar", set("22", "22_2", "333"), 42),
+                   row(0, "foobar", set("22", "333"), 42)
+        );
+
+        assertRows(execute("SELECT k, l, s[..'22'], o FROM %s WHERE k = 0"),
+                   row(0, "foobar", set("1", "22"), 42),
+                   row(0, "foobar", set("22"), 42)
+        );
+
+        assertRows(execute("SELECT k, l, s, o FROM %s WHERE k = 0"),
+                   row(0, "foobar", set("1", "22", "22_2", "333"), 42),
+                   row(0, "foobar", set("22", "333"), 42)
+        );
+    }
+
+    @Test
+    public void testCollectionSliceOnMV() throws Throwable
+    {
+        createTable("CREATE TABLE %s (k int, c int, l text, m map<text, text>, o int, PRIMARY KEY (k, c))");
+        assertInvalidMessage("Cannot use collection element selection when defining a materialized view",
+                             "CREATE MATERIALIZED VIEW " + KEYSPACE + ".view1 AS SELECT m['abc'] FROM %s WHERE k IS NOT NULL AND c IS NOT NULL AND m IS NOT NULL PRIMARY KEY (c, k)");
+        assertInvalidMessage("Cannot use collection slice selection when defining a materialized view",
+                             "CREATE MATERIALIZED VIEW " + KEYSPACE + ".view1 AS SELECT m['abc'..'def'] FROM %s WHERE k IS NOT NULL AND c IS NOT NULL AND m IS NOT NULL PRIMARY KEY (c, k)");
+    }
+
+    @Test
+    public void testElementAccessOnList() throws Throwable
+    {
+        createTable("CREATE TABLE %s (pk int PRIMARY KEY, l list<int>)");
+        execute("INSERT INTO %s (pk, l) VALUES (1, [1, 2, 3])");
+
+        assertInvalidMessage("Element selection is only allowed on sets and maps, but l is a list",
+                             "SELECT pk, l[0] FROM %s");
+
+        assertInvalidMessage("Slice selection is only allowed on sets and maps, but l is a list",
+                "SELECT pk, l[1..3] FROM %s");
+    }
+
+    @Test
+    public void testCollectionOperationResultSetMetadata() throws Throwable
+    {
+        createTable("CREATE TABLE %s (k int PRIMARY KEY," +
+                    "m map<text, text>," +
+                    "fm frozen<map<text, text>>," +
+                    "s set<text>," +
+                    "fs frozen<set<text>>)");
+
+        execute("INSERT INTO %s (k, m, fm, s, fs) VALUES (?, ?, ?, ?, ?)",
+                0,
+                map("1", "one", "2", "two"),
+                map("1", "one", "2", "two"),
+                set("1", "2", "3"),
+                set("1", "2", "3"));
+
+        String cql = "SELECT k, " +
+                     "m, m['2'], m['2'..'3'], m[..'2'], m['3'..], " +
+                     "fm, fm['2'], fm['2'..'3'], fm[..'2'], fm['3'..], " +
+                     "s, s['2'], s['2'..'3'], s[..'2'], s['3'..], " +
+                     "fs, fs['2'], fs['2'..'3'], fs[..'2'], fs['3'..] " +
+                     "FROM " + KEYSPACE + '.' + currentTable() + " WHERE k = 0";
+        UntypedResultSet result = execute(cql);
+        Iterator<ColumnSpecification> meta = result.metadata().iterator();
+        meta.next();
+        for (int i = 0; i < 4; i++)
+        {
+            // take the "full" collection selection
+            ColumnSpecification ref = meta.next();
+            ColumnSpecification selSingle = meta.next();
+            assertEquals(ref.toString(), UTF8Type.instance, selSingle.type);
+            for (int selOrSlice = 0; selOrSlice < 3; selOrSlice++)
+            {
+                ColumnSpecification selSlice = meta.next();
+                assertEquals(ref.toString(), ref.type, selSlice.type);
+            }
+        }
+
+        assertRows(result,
+                   row(0,
+                       map("1", "one", "2", "two"), "two", map("2", "two"), map("1", "one", "2", "two"), map(),
+                       map("1", "one", "2", "two"), "two", map("2", "two"), map("1", "one", "2", "two"), map(),
+                       set("1", "2", "3"), "2", set("2", "3"), set("1", "2"), set("3"),
+                       set("1", "2", "3"), "2", set("2", "3"), set("1", "2"), set("3")));
+
+        Session session = sessionNet();
+        ResultSet rset = session.execute(cql);
+        ColumnDefinitions colDefs = rset.getColumnDefinitions();
+        Iterator<ColumnDefinitions.Definition> colDefIter = colDefs.asList().iterator();
+        colDefIter.next();
+        for (int i = 0; i < 4; i++)
+        {
+            // take the "full" collection selection
+            ColumnDefinitions.Definition ref = colDefIter.next();
+            ColumnDefinitions.Definition selSingle = colDefIter.next();
+            assertEquals(ref.getName(), DataType.NativeType.text(), selSingle.getType());
+            for (int selOrSlice = 0; selOrSlice < 3; selOrSlice++)
+            {
+                ColumnDefinitions.Definition selSlice = colDefIter.next();
+                assertEquals(ref.getName() + ' ' + ref.getType(), ref.getType(), selSlice.getType());
+            }
+        }
+    }
+
+    @Test
+    public void testFrozenCollectionNestedAccess() throws Throwable
+    {
+        createTable("CREATE TABLE %s (k int PRIMARY KEY, m map<text, frozen<map<text, set<int>>>>)");
+
+        execute("INSERT INTO %s(k, m) VALUES (0, ?)", map("1", map("a", set(1, 2, 4), "b", set(3)), "2", map("a", set(2, 4))));
+
+        assertRows(execute("SELECT m[?] FROM %s WHERE k = 0", "1"), row(map("a", set(1, 2, 4), "b", set(3))));
+        assertRows(execute("SELECT m[?][?] FROM %s WHERE k = 0", "1", "a"), row(set(1, 2, 4)));
+        assertRows(execute("SELECT m[?][?][?] FROM %s WHERE k = 0", "1", "a", 2), row(2));
+        assertRows(execute("SELECT m[?][?][?..?] FROM %s WHERE k = 0", "1", "a", 2, 3), row(set(2)));
+
+        // Checks it still work after flush
+        flush();
+
+        assertRows(execute("SELECT m[?] FROM %s WHERE k = 0", "1"), row(map("a", set(1, 2, 4), "b", set(3))));
+        assertRows(execute("SELECT m[?][?] FROM %s WHERE k = 0", "1", "a"), row(set(1, 2, 4)));
+        assertRows(execute("SELECT m[?][?][?] FROM %s WHERE k = 0", "1", "a", 2), row(2));
+        assertRows(execute("SELECT m[?][?][?..?] FROM %s WHERE k = 0", "1", "a", 2, 3), row(set(2)));
+    }
+
+    @Test
+    public void testUDTAndCollectionNestedAccess() throws Throwable
+    {
+        String type = createType("CREATE TYPE %s (s set<int>, m map<text, text>)");
+
+        assertInvalidMessage("Non-frozen UDTs are not allowed inside collections",
+                             "CREATE TABLE " + KEYSPACE + "t (k int PRIMARY KEY, v map<text, " + type + ">)");
+
+        String mapType = "map<text, frozen<" + type + ">>";
+        for (boolean frozen : new boolean[]{false, true})
+        {
+            mapType = frozen ? "frozen<" + mapType + ">" : mapType;
+
+            createTable("CREATE TABLE %s (k int PRIMARY KEY, v " + mapType + ")");
+
+            execute("INSERT INTO %s(k, v) VALUES (0, ?)", map("abc", userType("s", set(2, 4, 6), "m", map("a", "v1", "d", "v2"))));
+
+            beforeAndAfterFlush(() ->
+            {
+                assertRows(execute("SELECT v[?].s FROM %s WHERE k = 0", "abc"), row(set(2, 4, 6)));
+                assertRows(execute("SELECT v[?].m[..?] FROM %s WHERE k = 0", "abc", "b"), row(map("a", "v1")));
+                assertRows(execute("SELECT v[?].m[?] FROM %s WHERE k = 0", "abc", "d"), row("v2"));
+            });
+        }
+
+        assertInvalidMessage("Non-frozen UDTs with nested non-frozen collections are not supported",
+                             "CREATE TABLE " + KEYSPACE + ".t (k int PRIMARY KEY, v " + type + ")");
+
+        type = createType("CREATE TYPE %s (s frozen<set<int>>, m frozen<map<text, text>>)");
+
+        for (boolean frozen : new boolean[]{false, true})
+        {
+            type = frozen ? "frozen<" + type + ">" : type;
+
+            createTable("CREATE TABLE %s (k int PRIMARY KEY, v " + type + ")");
+
+            execute("INSERT INTO %s(k, v) VALUES (0, ?)", userType("s", set(2, 4, 6), "m", map("a", "v1", "d", "v2")));
+
+            beforeAndAfterFlush(() ->
+            {
+                assertRows(execute("SELECT v.s[?] FROM %s WHERE k = 0", 2), row(2));
+                assertRows(execute("SELECT v.s[?..?] FROM %s WHERE k = 0", 2, 5), row(set(2, 4)));
+                assertRows(execute("SELECT v.s[..?] FROM %s WHERE k = 0", 3), row(set(2)));
+                assertRows(execute("SELECT v.m[..?] FROM %s WHERE k = 0", "b"), row(map("a", "v1")));
+                assertRows(execute("SELECT v.m[?] FROM %s WHERE k = 0", "d"), row("v2"));
+            });
+        }
+    }
+
+    @Test
+    public void testMapOverlappingSlices() throws Throwable
+    {
+        createTable("CREATE TABLE %s (k int PRIMARY KEY, m map<int, int>)");
+
+        execute("INSERT INTO %s(k, m) VALUES (?, ?)", 0, map(0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5));
+
+        flush();
+
+        assertRows(execute("SELECT m[7..8] FROM %s WHERE k=?", 0),
+                   row(map()));
+
+        assertRows(execute("SELECT m[0..3] FROM %s WHERE k=?", 0),
+                   row(map(0, 0, 1, 1, 2, 2, 3, 3)));
+
+        assertRows(execute("SELECT m[0..3], m[2..4] FROM %s WHERE k=?", 0),
+                   row(map(0, 0, 1, 1, 2, 2, 3, 3), map(2, 2, 3, 3, 4, 4)));
+
+        assertRows(execute("SELECT m, m[2..4] FROM %s WHERE k=?", 0),
+                   row(map(0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5), map(2, 2, 3, 3, 4, 4)));
+
+        assertRows(execute("SELECT m[..3], m[3..4] FROM %s WHERE k=?", 0),
+                   row(map(0, 0, 1, 1, 2, 2, 3, 3), map(3, 3, 4, 4)));
+
+        assertRows(execute("SELECT m[1..3], m[2] FROM %s WHERE k=?", 0),
+                   row(map(1, 1, 2, 2, 3, 3), 2));
+    }
+
+    @Test
+    public void testMapOverlappingSlicesWithDoubles() throws Throwable
+    {
+        createTable("CREATE TABLE %s (k int PRIMARY KEY, m map<double, double>)");
+
+        execute("INSERT INTO %s(k, m) VALUES (?, ?)", 0, map(0.0, 0.0, 1.1, 1.1, 2.2, 2.2, 3.0, 3.0, 4.4, 4.4, 5.5, 5.5));
+
+        flush();
+
+        assertRows(execute("SELECT m[0.0..3.0] FROM %s WHERE k=?", 0),
+                   row(map(0.0, 0.0, 1.1, 1.1, 2.2, 2.2, 3.0, 3.0)));
+
+        assertRows(execute("SELECT m[0...3.], m[2.2..4.4] FROM %s WHERE k=?", 0),
+                   row(map(0.0, 0.0, 1.1, 1.1, 2.2, 2.2, 3.0, 3.0), map(2.2, 2.2, 3.0, 3.0, 4.4, 4.4)));
+
+        assertRows(execute("SELECT m, m[2.2..4.4] FROM %s WHERE k=?", 0),
+                   row(map(0.0, 0.0, 1.1, 1.1, 2.2, 2.2, 3.0, 3.0, 4.4, 4.4, 5.5, 5.5), map(2.2, 2.2, 3.0, 3.0, 4.4, 4.4)));
+
+        assertRows(execute("SELECT m[..3.], m[3...4.4] FROM %s WHERE k=?", 0),
+                   row(map(0.0, 0.0, 1.1, 1.1, 2.2, 2.2, 3.0, 3.0), map(3.0, 3.0, 4.4, 4.4)));
+
+        assertRows(execute("SELECT m[1.1..3.0], m[2.2] FROM %s WHERE k=?", 0),
+                   row(map(1.1, 1.1, 2.2, 2.2, 3.0, 3.0), 2.2));
+    }
+
+    @Test
+    public void testNestedAccessWithNestedMap() throws Throwable
+    {
+        createTable("CREATE TABLE %s (id text PRIMARY KEY, m map<float, frozen<map<int, text>>>)");
+
+        execute("INSERT INTO %s (id,m) VALUES ('1', {1: {2: 'one-two'}})");
+
+        flush();
+
+        assertRows(execute("SELECT m[1][2] FROM %s WHERE id = '1'"),
+                   row("one-two"));
+
+        assertRows(execute("SELECT m[1..][2] FROM %s WHERE id = '1'"),
+                   row((Map) null));
+
+        assertRows(execute("SELECT m[1][..2] FROM %s WHERE id = '1'"),
+                   row(map(2, "one-two")));
+
+        assertRows(execute("SELECT m[1..][..2] FROM %s WHERE id = '1'"),
+                   row(map(1F, map(2, "one-two"))));
+    }
 }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/4ebab661/test/unit/org/apache/cassandra/cql3/validation/entities/StaticColumnsTest.java
----------------------------------------------------------------------
diff --git a/test/unit/org/apache/cassandra/cql3/validation/entities/StaticColumnsTest.java b/test/unit/org/apache/cassandra/cql3/validation/entities/StaticColumnsTest.java
index 74fed69..824e032 100644
--- a/test/unit/org/apache/cassandra/cql3/validation/entities/StaticColumnsTest.java
+++ b/test/unit/org/apache/cassandra/cql3/validation/entities/StaticColumnsTest.java
@@ -125,7 +125,8 @@ public class StaticColumnsTest extends CQLTester
         assertRows(execute("SELECT p, s FROM %s WHERE v = 1"), row(0, 42), row(1, 42));
         assertRows(execute("SELECT p FROM %s WHERE v = 1"), row(0), row(1));
         // We don't support that
-        assertInvalid("SELECT s FROM %s WHERE v = 1");
+        assertInvalidMessage("Queries using 2ndary indexes don't support selecting only static columns",
+                             "SELECT s FROM %s WHERE v = 1");
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/cassandra/blob/4ebab661/test/unit/org/apache/cassandra/cql3/validation/operations/SelectOrderByTest.java
----------------------------------------------------------------------
diff --git a/test/unit/org/apache/cassandra/cql3/validation/operations/SelectOrderByTest.java b/test/unit/org/apache/cassandra/cql3/validation/operations/SelectOrderByTest.java
index bfc0c86..e236ac8 100644
--- a/test/unit/org/apache/cassandra/cql3/validation/operations/SelectOrderByTest.java
+++ b/test/unit/org/apache/cassandra/cql3/validation/operations/SelectOrderByTest.java
@@ -455,6 +455,23 @@ public class SelectOrderByTest extends CQLTester
     }
 
     @Test
+    public void testOrderByForInClauseWithCollectionElementSelection() throws Throwable
+    {
+        createTable("CREATE TABLE %s (pk int, c frozen<set<int>>, v int, PRIMARY KEY (pk, c))");
+
+        execute("INSERT INTO %s (pk, c, v) VALUES (0, {1, 2}, 0)");
+        execute("INSERT INTO %s (pk, c, v) VALUES (0, {1, 2, 3}, 1)");
+        execute("INSERT INTO %s (pk, c, v) VALUES (1, {2, 3}, 2)");
+
+        beforeAndAfterFlush(() -> {
+            assertRows(execute("SELECT c[2], v FROM %s WHERE pk = 0 ORDER BY c"),
+                       row(2, 0), row(2, 1));
+            assertRows(execute("SELECT c[2], v FROM %s WHERE pk IN (0, 1) ORDER BY c"),
+                       row(2, 0), row(2, 1), row(2, 2));
+        });
+    }
+
+    @Test
     public void testOrderByForInClauseWithNullValue() throws Throwable
     {
         createTable("CREATE TABLE %s (a int, b int, c int, s int static, d int, PRIMARY KEY (a, b, c))");


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


Mime
View raw message