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: [email protected] For additional commands, e-mail: [email protected]
