Maxwell-Guo commented on code in PR #2310: URL: https://github.com/apache/cassandra/pull/2310#discussion_r1193295639
########## src/java/org/apache/cassandra/cql3/Vectors.java: ########## @@ -0,0 +1,184 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.cassandra.cql3; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; + +import org.apache.cassandra.cql3.functions.Function; +import org.apache.cassandra.db.marshal.AbstractType; +import org.apache.cassandra.db.marshal.VectorType; +import org.apache.cassandra.exceptions.InvalidRequestException; +import org.apache.cassandra.transport.ProtocolVersion; +import org.apache.cassandra.utils.ByteBufferUtil; + +public class Vectors +{ + private Vectors() {} + + private static AbstractType<?> elementsType(AbstractType<?> type) + { + return ((VectorType<?>) type.unwrap()).getElementsType(); + } + + private static ColumnSpecification valueSpecOf(ColumnSpecification column) + { + return new ColumnSpecification(column.ksName, column.cfName, new ColumnIdentifier("value(" + column.name + ")", true), elementsType(column.type)); + } + + public static class Literal extends Term.Raw + { + private final List<Term.Raw> elements; + + public Literal(List<Term.Raw> elements) + { + this.elements = elements; + } + + @Override + public TestResult testAssignment(String keyspace, ColumnSpecification receiver) + { + if (!(receiver.type instanceof VectorType)) + return AssignmentTestable.TestResult.NOT_ASSIGNABLE; + VectorType<?> type = (VectorType<?>) receiver.type; + if (elements.size() != type.dimension) + return AssignmentTestable.TestResult.NOT_ASSIGNABLE; + ColumnSpecification valueSpec = valueSpecOf(receiver); + return AssignmentTestable.TestResult.testAll(receiver.ksName, valueSpec, elements); + } + + @Override + public Term prepare(String keyspace, ColumnSpecification receiver) throws InvalidRequestException + { + if (!(receiver.type instanceof VectorType)) + throw new InvalidRequestException(String.format("Invalid vector literal for %s of type %s", receiver.name, receiver.type.asCQL3Type())); + VectorType<?> type = (VectorType<?>) receiver.type; + if (elements.size() != type.dimension) + throw new InvalidRequestException(String.format("Invalid vector literal for %s of type %s; expected %d elements, but given %d", receiver.name, receiver.type.asCQL3Type(), type.dimension, elements.size())); + + ColumnSpecification valueSpec = valueSpecOf(receiver); + for (Term.Raw rt : elements) Review Comment: 1.should we just merge the two loop from line 77 to line 85 to one loop ? 2. should we use a stream to prepare each element in the vector and add it to the list of values. This would simplify the code and make it more readable ? like : List<Term> values = elements.stream() .map(rt -> { if (!rt.testAssignment(keyspace, valueSpec).isAssignable()) { throw new InvalidRequestException(String.format("Invalid vector literal for %s: value %s is not of type %s", receiver.name, rt, valueSpec.type.asCQL3Type())); } return rt.prepare(keyspace, valueSpec); }) .collect(Collectors.toCollection(ArrayList::new)); DelayedValue value = new DelayedValue(type, values); boolean allTerminal = values.stream().noneMatch(t -> t instanceof Term.NonTerminal); return allTerminal ? value.bind(QueryOptions.DEFAULT) : value; ########## src/java/org/apache/cassandra/cql3/CQL3Type.java: ########## @@ -59,9 +58,24 @@ default boolean isUDT() * Generates CQL literal from a binary value of this type. * @param bytes the value to convert to a CQL literal. This value must be * serialized with {@code version} of the native protocol. - * @param version the native protocol version in which {@code buffer} is encoded. */ - String toCQLLiteral(ByteBuffer bytes, ProtocolVersion version); + String toCQLLiteral(ByteBuffer bytes); + + /** + * Generates a binary value for the CQL literal of this type + */ + default ByteBuffer fromCQLLiteral(String literal) + { + return fromCQLLiteral("--dummy--", literal); Review Comment: so why it is "--dummy--"? ########## test/unit/org/apache/cassandra/cql3/validation/operations/CQLVectorTest.java: ########## @@ -0,0 +1,142 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.cassandra.cql3.validation.operations; + +import org.junit.Test; + +import org.apache.cassandra.cql3.CQLTester; + +public class CQLVectorTest extends CQLTester.InMemory +{ + @Test + public void select() + { + createTable(KEYSPACE, "CREATE TABLE %s (pk vector<int, 2> primary key)"); + + execute("INSERT INTO %s (pk) VALUES ([1, 2])"); + + assertRows(execute("SELECT * FROM %s WHERE pk = [1, 2]"), row(list(1, 2))); + assertRows(execute("SELECT * FROM %s WHERE pk = ?", vector(1, 2)), row(list(1, 2))); + assertRows(execute("SELECT * FROM %s WHERE pk = [1, 1 + 1]"), row(list(1, 2))); + assertRows(execute("SELECT * FROM %s WHERE pk = [1, ?]", 2), row(list(1, 2))); + assertRows(execute("SELECT * FROM %s WHERE pk = [1, (int) ?]", 2), row(list(1, 2))); + assertRows(execute("SELECT * FROM %s WHERE pk = [1, 1 + (int) ?]", 1), row(list(1, 2))); + + assertRows(execute("SELECT * FROM %s WHERE pk IN ([1, 2])"), row(list(1, 2))); + assertRows(execute("SELECT * FROM %s WHERE pk IN ([1, 2], [1, 2])"), row(list(1, 2))); + assertRows(execute("SELECT * FROM %s WHERE pk IN (?)", vector(1, 2)), row(list(1, 2))); + assertRows(execute("SELECT * FROM %s WHERE pk IN ([1, 1 + 1])"), row(list(1, 2))); + assertRows(execute("SELECT * FROM %s WHERE pk IN ([1, ?])", 2), row(list(1, 2))); + assertRows(execute("SELECT * FROM %s WHERE pk IN ([1, (int) ?])", 2), row(list(1, 2))); + assertRows(execute("SELECT * FROM %s WHERE pk IN ([1, 1 + (int) ?])", 1), row(list(1, 2))); + + assertRows(execute("SELECT * FROM %s WHERE pk > [0, 0] AND pk < [1, 3] ALLOW FILTERING"), row(list(1, 2))); + assertRows(execute("SELECT * FROM %s WHERE token(pk) = token([1, 2])"), row(list(1, 2))); + } + + @Test + public void insert() + { + Runnable test = () -> { + assertRows(execute("SELECT * FROM %s"), row(list(1, 2))); + execute("TRUNCATE %s"); + assertRows(execute("SELECT * FROM %s")); + }; + + createTable(KEYSPACE, "CREATE TABLE %s (pk vector<int, 2> primary key)"); + + execute("INSERT INTO %s (pk) VALUES ([1, 2])"); + test.run(); + + execute("INSERT INTO %s (pk) VALUES (?)", vector(1, 2)); + test.run(); + + execute("INSERT INTO %s (pk) VALUES ([1, 1 + 1])"); + test.run(); + + execute("INSERT INTO %s (pk) VALUES ([1, ?])", 2); + test.run(); + + execute("INSERT INTO %s (pk) VALUES ([1, (int) ?])", 2); + test.run(); + + execute("INSERT INTO %s (pk) VALUES ([1, 1 + (int) ?])", 1); + test.run(); + } + + @Test + public void insertNonPK() + { + Runnable test = () -> { + assertRows(execute("SELECT * FROM %s"), row(0, list(1, 2))); + execute("TRUNCATE %s"); + assertRows(execute("SELECT * FROM %s")); + }; + + createTable(KEYSPACE, "CREATE TABLE %s (pk int primary key, value vector<int, 2>)"); + + execute("INSERT INTO %s (pk, value) VALUES (0, [1, 2])"); + test.run(); + + execute("INSERT INTO %s (pk, value) VALUES (0, ?)", vector(1, 2)); + test.run(); + + execute("INSERT INTO %s (pk, value) VALUES (0, [1, 1 + 1])"); + test.run(); + + execute("INSERT INTO %s (pk, value) VALUES (0, [1, ?])", 2); + test.run(); + + execute("INSERT INTO %s (pk, value) VALUES (0, [1, (int) ?])", 2); + test.run(); + + execute("INSERT INTO %s (pk, value) VALUES (0, [1, 1 + (int) ?])", 1); + test.run(); + } + Review Comment: do we still need test cases for tables that have verctor type in both pk and non-pks ? ########## test/unit/org/apache/cassandra/cql3/CQLTester.java: ########## @@ -1564,13 +1569,24 @@ public static void assertRows(UntypedResultSet result, Object[]... rows) { Object actualValueDecoded = actualValue == null ? null : column.type.getSerializer().deserialize(actualValue); if (!Objects.equal(expected != null ? expected[j] : null, actualValueDecoded)) + { + //TODO confirm this isn't a bug... Review Comment: //TODO confirm this isn't a bug... -----> // TODO confirm this isn't a bug... ########## src/java/org/apache/cassandra/db/marshal/VectorType.java: ########## @@ -0,0 +1,609 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.cassandra.db.marshal; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; + +import org.apache.cassandra.cql3.CQL3Type; +import org.apache.cassandra.cql3.Term; +import org.apache.cassandra.cql3.Vectors; +import org.apache.cassandra.db.TypeSizes; +import org.apache.cassandra.exceptions.InvalidRequestException; +import org.apache.cassandra.serializers.MarshalException; +import org.apache.cassandra.serializers.TypeSerializer; +import org.apache.cassandra.transport.ProtocolVersion; +import org.apache.cassandra.utils.ByteBufferUtil; +import org.apache.cassandra.utils.JsonUtils; +import org.apache.cassandra.utils.bytecomparable.ByteComparable; +import org.apache.cassandra.utils.bytecomparable.ByteSource; + +public final class VectorType<T> extends AbstractType<List<T>> +{ + private static class Key + { + private final AbstractType<?> type; + private final int dimension; + + private Key(AbstractType<?> type, int dimension) + { + this.type = type; + this.dimension = dimension; + } + + private VectorType<?> create() + { + return new VectorType<>(type, dimension); + } + + @Override + public boolean equals(Object o) + { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Key key = (Key) o; + return dimension == key.dimension && Objects.equals(type, key.type); + } + + @Override + public int hashCode() + { + return Objects.hash(type, dimension); + } + } + private static final ConcurrentHashMap<Key, VectorType<?>> instances = new ConcurrentHashMap<>(); + + public final AbstractType<T> elementType; + public final int dimension; + protected final TypeSerializer<T> elementSerializer; + private final int valueLengthIfFixed; + private final VectorSerializer serializer; + + private VectorType(AbstractType<T> elementType, int dimension) + { + super(ComparisonType.CUSTOM); + if (dimension <= 0) + throw new InvalidRequestException(String.format("vectors may only have positive dimentions; given %d", dimension)); + this.elementType = elementType; + this.dimension = dimension; + this.elementSerializer = elementType.getSerializer(); + this.valueLengthIfFixed = elementType.isValueLengthFixed() ? + elementType.valueLengthIfFixed() * dimension : + super.valueLengthIfFixed(); + this.serializer = elementType.isValueLengthFixed() ? + new FixedLengthSerializer() : + new VariableLengthSerializer(); + } + + public static <T> VectorType<T> getInstance(AbstractType<T> elements, int dimention) + { + Key key = new Key(elements, dimention); + return (VectorType<T>) instances.computeIfAbsent(key, Key::create); + } + + @Override + public boolean isVector() + { + return true; + } + + @Override + public <VL, VR> int compareCustom(VL left, ValueAccessor<VL> accessorL, VR right, ValueAccessor<VR> accessorR) + { + return getSerializer().compareCustom(left, accessorL, right, accessorR); + } + + @Override + public int valueLengthIfFixed() + { + return valueLengthIfFixed; + } + + @Override + public VectorSerializer getSerializer() + { + return serializer; + } + + public List<ByteBuffer> split(ByteBuffer buffer) + { + return split(buffer, ByteBufferAccessor.instance); + } + + public <V> List<V> split(V buffer, ValueAccessor<V> accessor) + { + return getSerializer().split(buffer, accessor); + } + + public float[] composeAsFloat(ByteBuffer input) + { + return composeAsFloat(input, ByteBufferAccessor.instance); + } + + public <V> float[] composeAsFloat(V input, ValueAccessor<V> accessor) + { + if (!(elementType instanceof FloatType)) + throw new IllegalStateException("Attempted to read as float, but element type is " + elementType.asCQL3Type()); + + if (accessor.isEmpty(input)) + return null; + float[] array = new float[dimension]; + int offset = 0; + for (int i = 0; i < dimension; i++) + { + array[i] = accessor.getFloat(input, offset); + offset += Float.BYTES; + } + return array; + } + + public ByteBuffer decomposeRaw(List<ByteBuffer> elements) + { + return decomposeRaw(elements, ByteBufferAccessor.instance); + } + + public <V> V decomposeRaw(List<V> elements, ValueAccessor<V> accessor) + { + return getSerializer().serializeRaw(elements, accessor); + } + + @Override + public <V> ByteSource asComparableBytes(ValueAccessor<V> accessor, V value, ByteComparable.Version version) + { + if (accessor.isEmpty(value)) + return null; + ByteSource[] srcs = new ByteSource[dimension]; + List<V> split = split(value, accessor); + for (int i = 0; i < dimension; i++) + srcs[i] = elementType.asComparableBytes(accessor, split.get(i), version); + return ByteSource.withTerminatorMaybeLegacy(version, 0x00, srcs); + } + + @Override + public <V> V fromComparableBytes(ValueAccessor<V> accessor, ByteSource.Peekable comparableBytes, ByteComparable.Version version) + { + if (comparableBytes == null) + return accessor.empty(); + assert version != ByteComparable.Version.LEGACY; // legacy translation is not reversible + + List<V> buffers = new ArrayList<>(); + int separator = comparableBytes.next(); + while (separator != ByteSource.TERMINATOR) + { + buffers.add(elementType.fromComparableBytes(accessor, comparableBytes, version)); + separator = comparableBytes.next(); + } + return decomposeRaw(buffers, accessor); + } + + @Override + public CQL3Type asCQL3Type() + { + return new CQL3Type.Vector(this); + } + + public AbstractType<T> getElementsType() + { + return elementType; + } + + // vector of nested types is hard to parse, so fall back to bytes string matching ListType + @Override + public <V> String getString(V value, ValueAccessor<V> accessor) + { + return BytesType.instance.getString(value, accessor); + } + + @Override + public ByteBuffer fromString(String source) throws MarshalException + { + try + { + return ByteBufferUtil.hexToBytes(source); + } + catch (NumberFormatException e) + { + throw new MarshalException(String.format("cannot parse '%s' as hex bytes", source), e); + } + } + + @Override + public List<AbstractType<?>> subTypes() + { + return Collections.singletonList(elementType); + } + + @Override + public String toJSONString(ByteBuffer buffer, ProtocolVersion protocolVersion) + { + return toJSONString(buffer, ByteBufferAccessor.instance, protocolVersion); + } + + @Override + public <V> String toJSONString(V value, ValueAccessor<V> accessor, ProtocolVersion protocolVersion) + { + StringBuilder sb = new StringBuilder(); + sb.append('['); + List<V> split = split(value, accessor); + for (int i = 0; i < dimension; i++) + { + if (i > 0) + sb.append(", "); + sb.append(elementType.toJSONString(split.get(i), accessor, protocolVersion)); + } + sb.append(']'); + return sb.toString(); + } + + @Override + public Term fromJSONObject(Object parsed) throws MarshalException + { + if (parsed instanceof String) + parsed = JsonUtils.decodeJson((String) parsed); + + if (!(parsed instanceof List)) + throw new MarshalException(String.format( + "Expected a list, but got a %s: %s", parsed.getClass().getSimpleName(), parsed)); + + List<?> list = (List<?>) parsed; + List<Term> terms = new ArrayList<>(list.size()); + for (Object element : list) + { + if (element == null) + throw new MarshalException("Invalid null element in list"); + terms.add(elementType.fromJSONObject(element)); + } + + return new Vectors.DelayedValue(this, terms); + } + + @Override + public boolean equals(Object o) + { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + VectorType<?> that = (VectorType<?>) o; + return dimension == that.dimension && Objects.equals(elementType, that.elementType); + } + + @Override + public int hashCode() + { + return Objects.hash(elementType, dimension); + } + + @Override + public String toString() + { + StringBuilder sb = new StringBuilder(); + sb.append(getClass().getName()); + sb.append('('); + sb.append(elementType.toString()); + sb.append(", "); + sb.append(dimension); + sb.append(')'); + return sb.toString(); + } + + protected void check(List<?> values) + { + if (values.size() != dimension) + throw new MarshalException(String.format("Required %d elements, but saw %d", dimension, values.size())); + { Review Comment: do we really need this brackets? ########## test/unit/org/apache/cassandra/cql3/validation/operations/CQLVectorTest.java: ########## @@ -0,0 +1,142 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.cassandra.cql3.validation.operations; + +import org.junit.Test; + +import org.apache.cassandra.cql3.CQLTester; + +public class CQLVectorTest extends CQLTester.InMemory +{ + @Test + public void select() + { + createTable(KEYSPACE, "CREATE TABLE %s (pk vector<int, 2> primary key)"); + + execute("INSERT INTO %s (pk) VALUES ([1, 2])"); + + assertRows(execute("SELECT * FROM %s WHERE pk = [1, 2]"), row(list(1, 2))); + assertRows(execute("SELECT * FROM %s WHERE pk = ?", vector(1, 2)), row(list(1, 2))); + assertRows(execute("SELECT * FROM %s WHERE pk = [1, 1 + 1]"), row(list(1, 2))); + assertRows(execute("SELECT * FROM %s WHERE pk = [1, ?]", 2), row(list(1, 2))); + assertRows(execute("SELECT * FROM %s WHERE pk = [1, (int) ?]", 2), row(list(1, 2))); + assertRows(execute("SELECT * FROM %s WHERE pk = [1, 1 + (int) ?]", 1), row(list(1, 2))); + + assertRows(execute("SELECT * FROM %s WHERE pk IN ([1, 2])"), row(list(1, 2))); + assertRows(execute("SELECT * FROM %s WHERE pk IN ([1, 2], [1, 2])"), row(list(1, 2))); + assertRows(execute("SELECT * FROM %s WHERE pk IN (?)", vector(1, 2)), row(list(1, 2))); + assertRows(execute("SELECT * FROM %s WHERE pk IN ([1, 1 + 1])"), row(list(1, 2))); + assertRows(execute("SELECT * FROM %s WHERE pk IN ([1, ?])", 2), row(list(1, 2))); + assertRows(execute("SELECT * FROM %s WHERE pk IN ([1, (int) ?])", 2), row(list(1, 2))); + assertRows(execute("SELECT * FROM %s WHERE pk IN ([1, 1 + (int) ?])", 1), row(list(1, 2))); + + assertRows(execute("SELECT * FROM %s WHERE pk > [0, 0] AND pk < [1, 3] ALLOW FILTERING"), row(list(1, 2))); + assertRows(execute("SELECT * FROM %s WHERE token(pk) = token([1, 2])"), row(list(1, 2))); Review Comment: and for compare order , pk > [0, 0] and <[1, 3] which means (the first index element in array is big than 0 and less than 1 )& (the secondary index element is big than 0 and less than 3) , or not & but | ? I think we should declaring these relationships clearly ########## test/unit/org/apache/cassandra/cql3/validation/operations/CQLVectorTest.java: ########## @@ -0,0 +1,142 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.cassandra.cql3.validation.operations; + +import org.junit.Test; + +import org.apache.cassandra.cql3.CQLTester; + +public class CQLVectorTest extends CQLTester.InMemory +{ + @Test + public void select() + { + createTable(KEYSPACE, "CREATE TABLE %s (pk vector<int, 2> primary key)"); + + execute("INSERT INTO %s (pk) VALUES ([1, 2])"); + + assertRows(execute("SELECT * FROM %s WHERE pk = [1, 2]"), row(list(1, 2))); + assertRows(execute("SELECT * FROM %s WHERE pk = ?", vector(1, 2)), row(list(1, 2))); + assertRows(execute("SELECT * FROM %s WHERE pk = [1, 1 + 1]"), row(list(1, 2))); + assertRows(execute("SELECT * FROM %s WHERE pk = [1, ?]", 2), row(list(1, 2))); + assertRows(execute("SELECT * FROM %s WHERE pk = [1, (int) ?]", 2), row(list(1, 2))); + assertRows(execute("SELECT * FROM %s WHERE pk = [1, 1 + (int) ?]", 1), row(list(1, 2))); + + assertRows(execute("SELECT * FROM %s WHERE pk IN ([1, 2])"), row(list(1, 2))); + assertRows(execute("SELECT * FROM %s WHERE pk IN ([1, 2], [1, 2])"), row(list(1, 2))); + assertRows(execute("SELECT * FROM %s WHERE pk IN (?)", vector(1, 2)), row(list(1, 2))); + assertRows(execute("SELECT * FROM %s WHERE pk IN ([1, 1 + 1])"), row(list(1, 2))); + assertRows(execute("SELECT * FROM %s WHERE pk IN ([1, ?])", 2), row(list(1, 2))); + assertRows(execute("SELECT * FROM %s WHERE pk IN ([1, (int) ?])", 2), row(list(1, 2))); + assertRows(execute("SELECT * FROM %s WHERE pk IN ([1, 1 + (int) ?])", 1), row(list(1, 2))); + + assertRows(execute("SELECT * FROM %s WHERE pk > [0, 0] AND pk < [1, 3] ALLOW FILTERING"), row(list(1, 2))); + assertRows(execute("SELECT * FROM %s WHERE token(pk) = token([1, 2])"), row(list(1, 2))); Review Comment: do we need some more test cases when element type is not just int ,decimal,collection type or udt (if not suporrt now an exception is need )? -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected] --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]

