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

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


The following commit(s) were added to refs/heads/cassandra-5.0 by this push:
     new 6befb178aa Remove support for empty values on the vector data type
6befb178aa is described below

commit 6befb178aa0b7ad669f5c30e8b53fdd69a225a7a
Author: Andrés de la Peña <a.penya.gar...@gmail.com>
AuthorDate: Fri Sep 22 14:09:35 2023 +0100

    Remove support for empty values on the vector data type
    
    patch by Andrés de la Peña; reviewed by David Capwell and Maxwell Guo for 
CASSANDRA-18876
---
 CHANGES.txt                                        |  1 +
 src/java/org/apache/cassandra/cql3/Constants.java  |  2 +-
 .../db/marshal/AbstractCompositeType.java          |  6 +++
 .../cassandra/db/marshal/AbstractTimeUUIDType.java |  7 ++++
 .../apache/cassandra/db/marshal/AbstractType.java  |  2 +-
 .../apache/cassandra/db/marshal/BooleanType.java   |  7 ++++
 .../org/apache/cassandra/db/marshal/ByteType.java  |  6 ---
 .../org/apache/cassandra/db/marshal/BytesType.java |  6 +++
 .../cassandra/db/marshal/CollectionType.java       |  6 ---
 .../cassandra/db/marshal/CounterColumnType.java    |  7 ++++
 .../apache/cassandra/db/marshal/DecimalType.java   |  7 ++++
 .../apache/cassandra/db/marshal/DoubleType.java    |  7 ++++
 .../apache/cassandra/db/marshal/DurationType.java  |  6 ---
 .../org/apache/cassandra/db/marshal/FloatType.java |  7 ++++
 .../cassandra/db/marshal/InetAddressType.java      |  7 ++++
 .../org/apache/cassandra/db/marshal/Int32Type.java |  7 ++++
 .../apache/cassandra/db/marshal/IntegerType.java   |  7 ++++
 .../cassandra/db/marshal/LexicalUUIDType.java      |  7 ++++
 .../org/apache/cassandra/db/marshal/LongType.java  |  7 ++++
 .../org/apache/cassandra/db/marshal/ShortType.java |  6 ---
 .../cassandra/db/marshal/SimpleDateType.java       |  6 ---
 .../apache/cassandra/db/marshal/StringType.java    |  6 +++
 .../org/apache/cassandra/db/marshal/TimeType.java  |  6 ---
 .../apache/cassandra/db/marshal/TimestampType.java |  6 +++
 .../org/apache/cassandra/db/marshal/TupleType.java |  6 +++
 .../org/apache/cassandra/db/marshal/UUIDType.java  |  7 ++++
 .../apache/cassandra/db/marshal/VectorType.java    | 44 +++++++++++++++-------
 .../cql3/validation/operations/CQLVectorTest.java  | 43 +++++++++++++++++++++
 28 files changed, 190 insertions(+), 52 deletions(-)

diff --git a/CHANGES.txt b/CHANGES.txt
index bca22c4580..12c8fbc0e3 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,4 +1,5 @@
 5.0-alpha2
+ * Remove support for empty values on the vector data type (CASSANDRA-18876)
  * Upgrade Dropwizard Metrics to 4.2.19 (CASSANDRA-14667)
  * Upgrade caffeine cache and fix CIDR permissions cache invalidation 
(CASSANDRA-18805)
  * Remove deprecated properties in CompressionParams (CASSANDRA-18742)
diff --git a/src/java/org/apache/cassandra/cql3/Constants.java 
b/src/java/org/apache/cassandra/cql3/Constants.java
index 03341d22bd..be81bed3b0 100644
--- a/src/java/org/apache/cassandra/cql3/Constants.java
+++ b/src/java/org/apache/cassandra/cql3/Constants.java
@@ -292,7 +292,7 @@ public abstract class Constants
         public AssignmentTestable.TestResult testAssignment(String keyspace, 
ColumnSpecification receiver)
         {
             CQL3Type receiverType = receiver.type.asCQL3Type();
-            if (receiverType.isCollection() || receiverType.isUDT())
+            if (receiverType.isCollection() || receiverType.isUDT() || 
receiverType.isVector())
                 return AssignmentTestable.TestResult.NOT_ASSIGNABLE;
 
             if (!(receiverType instanceof CQL3Type.Native))
diff --git 
a/src/java/org/apache/cassandra/db/marshal/AbstractCompositeType.java 
b/src/java/org/apache/cassandra/db/marshal/AbstractCompositeType.java
index 350c124fa1..170363594f 100644
--- a/src/java/org/apache/cassandra/db/marshal/AbstractCompositeType.java
+++ b/src/java/org/apache/cassandra/db/marshal/AbstractCompositeType.java
@@ -41,6 +41,12 @@ public abstract class AbstractCompositeType extends 
AbstractType<ByteBuffer>
         super(ComparisonType.CUSTOM);
     }
 
+    @Override
+    public boolean allowsEmpty()
+    {
+        return true;
+    }
+
     public <VL, VR> int compareCustom(VL left, ValueAccessor<VL> accessorL, VR 
right, ValueAccessor<VR> accessorR)
     {
         if (accessorL.isEmpty(left) || accessorR.isEmpty(right))
diff --git a/src/java/org/apache/cassandra/db/marshal/AbstractTimeUUIDType.java 
b/src/java/org/apache/cassandra/db/marshal/AbstractTimeUUIDType.java
index 1c4088ee97..35778aff24 100644
--- a/src/java/org/apache/cassandra/db/marshal/AbstractTimeUUIDType.java
+++ b/src/java/org/apache/cassandra/db/marshal/AbstractTimeUUIDType.java
@@ -42,6 +42,13 @@ public abstract class AbstractTimeUUIDType<T> extends 
TemporalType<T>
         super(ComparisonType.CUSTOM);
     } // singleton
 
+    @Override
+    public boolean allowsEmpty()
+    {
+        return true;
+    }
+
+    @Override
     public boolean isEmptyValueMeaningless()
     {
         return true;
diff --git a/src/java/org/apache/cassandra/db/marshal/AbstractType.java 
b/src/java/org/apache/cassandra/db/marshal/AbstractType.java
index 3f4124011b..fe8b549837 100644
--- a/src/java/org/apache/cassandra/db/marshal/AbstractType.java
+++ b/src/java/org/apache/cassandra/db/marshal/AbstractType.java
@@ -512,7 +512,7 @@ public abstract class AbstractType<T> implements 
Comparator<ByteBuffer>, Assignm
      */
     public boolean allowsEmpty()
     {
-        return true;
+        return false;
     }
 
     public boolean isNull(ByteBuffer bb)
diff --git a/src/java/org/apache/cassandra/db/marshal/BooleanType.java 
b/src/java/org/apache/cassandra/db/marshal/BooleanType.java
index acaba5ba7a..471aa8dc2d 100644
--- a/src/java/org/apache/cassandra/db/marshal/BooleanType.java
+++ b/src/java/org/apache/cassandra/db/marshal/BooleanType.java
@@ -38,6 +38,13 @@ public class BooleanType extends AbstractType<Boolean>
 
     BooleanType() {super(ComparisonType.CUSTOM);} // singleton
 
+    @Override
+    public boolean allowsEmpty()
+    {
+        return true;
+    }
+
+    @Override
     public boolean isEmptyValueMeaningless()
     {
         return true;
diff --git a/src/java/org/apache/cassandra/db/marshal/ByteType.java 
b/src/java/org/apache/cassandra/db/marshal/ByteType.java
index 720168bcb3..614bdf9052 100644
--- a/src/java/org/apache/cassandra/db/marshal/ByteType.java
+++ b/src/java/org/apache/cassandra/db/marshal/ByteType.java
@@ -46,12 +46,6 @@ public class ByteType extends NumberType<Byte>
         super(ComparisonType.CUSTOM);
     } // singleton
 
-    @Override
-    public boolean allowsEmpty()
-    {
-        return false;
-    }
-
     public <VL, VR> int compareCustom(VL left, ValueAccessor<VL> accessorL, VR 
right, ValueAccessor<VR> accessorR)
     {
         return accessorL.getByte(left, 0) - accessorR.getByte(right, 0);
diff --git a/src/java/org/apache/cassandra/db/marshal/BytesType.java 
b/src/java/org/apache/cassandra/db/marshal/BytesType.java
index b5c5cc8bdf..7ad0280e55 100644
--- a/src/java/org/apache/cassandra/db/marshal/BytesType.java
+++ b/src/java/org/apache/cassandra/db/marshal/BytesType.java
@@ -38,6 +38,12 @@ public class BytesType extends AbstractType<ByteBuffer>
 
     BytesType() {super(ComparisonType.BYTE_ORDER);} // singleton
 
+    @Override
+    public boolean allowsEmpty()
+    {
+        return true;
+    }
+
     public ByteBuffer fromString(String source)
     {
         try
diff --git a/src/java/org/apache/cassandra/db/marshal/CollectionType.java 
b/src/java/org/apache/cassandra/db/marshal/CollectionType.java
index 5e546cbc96..0f140fea06 100644
--- a/src/java/org/apache/cassandra/db/marshal/CollectionType.java
+++ b/src/java/org/apache/cassandra/db/marshal/CollectionType.java
@@ -93,12 +93,6 @@ public abstract class CollectionType<T> extends 
AbstractType<T>
 
     protected abstract List<ByteBuffer> serializedValues(Iterator<Cell<?>> 
cells);
 
-    @Override
-    public boolean allowsEmpty()
-    {
-        return false;
-    }
-
     @Override
     public abstract CollectionSerializer<T> getSerializer();
 
diff --git a/src/java/org/apache/cassandra/db/marshal/CounterColumnType.java 
b/src/java/org/apache/cassandra/db/marshal/CounterColumnType.java
index b5ce7d829e..c0e1465bf1 100644
--- a/src/java/org/apache/cassandra/db/marshal/CounterColumnType.java
+++ b/src/java/org/apache/cassandra/db/marshal/CounterColumnType.java
@@ -37,6 +37,13 @@ public class CounterColumnType extends NumberType<Long>
 
     CounterColumnType() {super(ComparisonType.NOT_COMPARABLE);} // singleton
 
+    @Override
+    public boolean allowsEmpty()
+    {
+        return true;
+    }
+
+    @Override
     public boolean isEmptyValueMeaningless()
     {
         return true;
diff --git a/src/java/org/apache/cassandra/db/marshal/DecimalType.java 
b/src/java/org/apache/cassandra/db/marshal/DecimalType.java
index 51d2561aa6..00da39ac35 100644
--- a/src/java/org/apache/cassandra/db/marshal/DecimalType.java
+++ b/src/java/org/apache/cassandra/db/marshal/DecimalType.java
@@ -65,6 +65,13 @@ public class DecimalType extends NumberType<BigDecimal>
 
     DecimalType() {super(ComparisonType.CUSTOM);} // singleton
 
+    @Override
+    public boolean allowsEmpty()
+    {
+        return true;
+    }
+
+    @Override
     public boolean isEmptyValueMeaningless()
     {
         return true;
diff --git a/src/java/org/apache/cassandra/db/marshal/DoubleType.java 
b/src/java/org/apache/cassandra/db/marshal/DoubleType.java
index e1062dc538..eff3bf744d 100644
--- a/src/java/org/apache/cassandra/db/marshal/DoubleType.java
+++ b/src/java/org/apache/cassandra/db/marshal/DoubleType.java
@@ -42,6 +42,13 @@ public class DoubleType extends NumberType<Double>
 
     DoubleType() {super(ComparisonType.CUSTOM);} // singleton
 
+    @Override
+    public boolean allowsEmpty()
+    {
+        return true;
+    }
+
+    @Override
     public boolean isEmptyValueMeaningless()
     {
         return true;
diff --git a/src/java/org/apache/cassandra/db/marshal/DurationType.java 
b/src/java/org/apache/cassandra/db/marshal/DurationType.java
index 9353b2f6b7..0c46617554 100644
--- a/src/java/org/apache/cassandra/db/marshal/DurationType.java
+++ b/src/java/org/apache/cassandra/db/marshal/DurationType.java
@@ -46,12 +46,6 @@ public class DurationType extends AbstractType<Duration>
         super(ComparisonType.BYTE_ORDER);
     } // singleton
 
-    @Override
-    public boolean allowsEmpty()
-    {
-        return false;
-    }
-
     public ByteBuffer fromString(String source) throws MarshalException
     {
         // Return an empty ByteBuffer for an empty string.
diff --git a/src/java/org/apache/cassandra/db/marshal/FloatType.java 
b/src/java/org/apache/cassandra/db/marshal/FloatType.java
index abed92960d..216b077811 100644
--- a/src/java/org/apache/cassandra/db/marshal/FloatType.java
+++ b/src/java/org/apache/cassandra/db/marshal/FloatType.java
@@ -43,6 +43,13 @@ public class FloatType extends NumberType<Float>
 
     FloatType() {super(ComparisonType.CUSTOM);} // singleton
 
+    @Override
+    public boolean allowsEmpty()
+    {
+        return true;
+    }
+
+    @Override
     public boolean isEmptyValueMeaningless()
     {
         return true;
diff --git a/src/java/org/apache/cassandra/db/marshal/InetAddressType.java 
b/src/java/org/apache/cassandra/db/marshal/InetAddressType.java
index 820e0c2f77..64e178d989 100644
--- a/src/java/org/apache/cassandra/db/marshal/InetAddressType.java
+++ b/src/java/org/apache/cassandra/db/marshal/InetAddressType.java
@@ -41,6 +41,13 @@ public class InetAddressType extends 
AbstractType<InetAddress>
 
     InetAddressType() {super(ComparisonType.BYTE_ORDER);} // singleton
 
+    @Override
+    public boolean allowsEmpty()
+    {
+        return true;
+    }
+
+    @Override
     public boolean isEmptyValueMeaningless()
     {
         return true;
diff --git a/src/java/org/apache/cassandra/db/marshal/Int32Type.java 
b/src/java/org/apache/cassandra/db/marshal/Int32Type.java
index 68c32ad90e..c76d310764 100644
--- a/src/java/org/apache/cassandra/db/marshal/Int32Type.java
+++ b/src/java/org/apache/cassandra/db/marshal/Int32Type.java
@@ -46,6 +46,13 @@ public class Int32Type extends NumberType<Integer>
         super(ComparisonType.CUSTOM);
     } // singleton
 
+    @Override
+    public boolean allowsEmpty()
+    {
+        return true;
+    }
+
+    @Override
     public boolean isEmptyValueMeaningless()
     {
         return true;
diff --git a/src/java/org/apache/cassandra/db/marshal/IntegerType.java 
b/src/java/org/apache/cassandra/db/marshal/IntegerType.java
index 99fac1640d..2c4b791d83 100644
--- a/src/java/org/apache/cassandra/db/marshal/IntegerType.java
+++ b/src/java/org/apache/cassandra/db/marshal/IntegerType.java
@@ -80,6 +80,13 @@ public final class IntegerType extends NumberType<BigInteger>
 
     IntegerType() {super(ComparisonType.CUSTOM);}/* singleton */
 
+    @Override
+    public boolean allowsEmpty()
+    {
+        return true;
+    }
+
+    @Override
     public boolean isEmptyValueMeaningless()
     {
         return true;
diff --git a/src/java/org/apache/cassandra/db/marshal/LexicalUUIDType.java 
b/src/java/org/apache/cassandra/db/marshal/LexicalUUIDType.java
index 498ca49584..e37f8e2f21 100644
--- a/src/java/org/apache/cassandra/db/marshal/LexicalUUIDType.java
+++ b/src/java/org/apache/cassandra/db/marshal/LexicalUUIDType.java
@@ -47,6 +47,13 @@ public class LexicalUUIDType extends AbstractType<UUID>
         super(ComparisonType.CUSTOM);
     } // singleton
 
+    @Override
+    public boolean allowsEmpty()
+    {
+        return true;
+    }
+
+    @Override
     public boolean isEmptyValueMeaningless()
     {
         return true;
diff --git a/src/java/org/apache/cassandra/db/marshal/LongType.java 
b/src/java/org/apache/cassandra/db/marshal/LongType.java
index e0348fdb11..97b9f75468 100644
--- a/src/java/org/apache/cassandra/db/marshal/LongType.java
+++ b/src/java/org/apache/cassandra/db/marshal/LongType.java
@@ -43,6 +43,13 @@ public class LongType extends NumberType<Long>
 
     LongType() {super(ComparisonType.CUSTOM);} // singleton
 
+    @Override
+    public boolean allowsEmpty()
+    {
+        return true;
+    }
+
+    @Override
     public boolean isEmptyValueMeaningless()
     {
         return true;
diff --git a/src/java/org/apache/cassandra/db/marshal/ShortType.java 
b/src/java/org/apache/cassandra/db/marshal/ShortType.java
index bd7c2fd653..96047daf73 100644
--- a/src/java/org/apache/cassandra/db/marshal/ShortType.java
+++ b/src/java/org/apache/cassandra/db/marshal/ShortType.java
@@ -46,12 +46,6 @@ public class ShortType extends NumberType<Short>
         super(ComparisonType.CUSTOM);
     } // singleton
 
-    @Override
-    public boolean allowsEmpty()
-    {
-        return false;
-    }
-
     public <VL, VR> int compareCustom(VL left, ValueAccessor<VL> accessorL, VR 
right, ValueAccessor<VR> accessorR)
     {
         int diff = accessorL.getByte(left, 0) - accessorR.getByte(right, 0);
diff --git a/src/java/org/apache/cassandra/db/marshal/SimpleDateType.java 
b/src/java/org/apache/cassandra/db/marshal/SimpleDateType.java
index 54eabafc0c..a474d39a81 100644
--- a/src/java/org/apache/cassandra/db/marshal/SimpleDateType.java
+++ b/src/java/org/apache/cassandra/db/marshal/SimpleDateType.java
@@ -43,12 +43,6 @@ public class SimpleDateType extends TemporalType<Integer>
 
     SimpleDateType() {super(ComparisonType.BYTE_ORDER);} // singleton
 
-    @Override
-    public boolean allowsEmpty()
-    {
-        return false;
-    }
-
     @Override
     public <V> ByteSource asComparableBytes(ValueAccessor<V> accessor, V data, 
Version version)
     {
diff --git a/src/java/org/apache/cassandra/db/marshal/StringType.java 
b/src/java/org/apache/cassandra/db/marshal/StringType.java
index d823632b73..dd21bedc49 100644
--- a/src/java/org/apache/cassandra/db/marshal/StringType.java
+++ b/src/java/org/apache/cassandra/db/marshal/StringType.java
@@ -27,6 +27,12 @@ public abstract class StringType extends AbstractType<String>
         super(comparisonType);
     }
 
+    @Override
+    public boolean allowsEmpty()
+    {
+        return true;
+    }
+
     public ByteBuffer concat(String left, String right)
     {
         return decompose(left + right);
diff --git a/src/java/org/apache/cassandra/db/marshal/TimeType.java 
b/src/java/org/apache/cassandra/db/marshal/TimeType.java
index 2a87808f1b..67cf7dbceb 100644
--- a/src/java/org/apache/cassandra/db/marshal/TimeType.java
+++ b/src/java/org/apache/cassandra/db/marshal/TimeType.java
@@ -47,12 +47,6 @@ public class TimeType extends TemporalType<Long>
 
     private TimeType() {super(ComparisonType.BYTE_ORDER);} // singleton
 
-    @Override
-    public boolean allowsEmpty()
-    {
-        return false;
-    }
-
     public ByteBuffer fromString(String source) throws MarshalException
     {
         return decompose(TimeSerializer.timeStringToLong(source));
diff --git a/src/java/org/apache/cassandra/db/marshal/TimestampType.java 
b/src/java/org/apache/cassandra/db/marshal/TimestampType.java
index 67976769bd..54d88bd0da 100644
--- a/src/java/org/apache/cassandra/db/marshal/TimestampType.java
+++ b/src/java/org/apache/cassandra/db/marshal/TimestampType.java
@@ -55,6 +55,12 @@ public class TimestampType extends TemporalType<Date>
 
     private TimestampType() {super(ComparisonType.CUSTOM);} // singleton
 
+    @Override
+    public boolean allowsEmpty()
+    {
+        return true;
+    }
+
     public boolean isEmptyValueMeaningless()
     {
         return true;
diff --git a/src/java/org/apache/cassandra/db/marshal/TupleType.java 
b/src/java/org/apache/cassandra/db/marshal/TupleType.java
index 79f921920d..0a03936da7 100644
--- a/src/java/org/apache/cassandra/db/marshal/TupleType.java
+++ b/src/java/org/apache/cassandra/db/marshal/TupleType.java
@@ -76,6 +76,12 @@ public class TupleType extends AbstractType<ByteBuffer>
         this.serializer = new TupleSerializer(fieldSerializers(types));
     }
 
+    @Override
+    public boolean allowsEmpty()
+    {
+        return true;
+    }
+
     private static List<TypeSerializer<?>> 
fieldSerializers(List<AbstractType<?>> types)
     {
         int size = types.size();
diff --git a/src/java/org/apache/cassandra/db/marshal/UUIDType.java 
b/src/java/org/apache/cassandra/db/marshal/UUIDType.java
index c949524613..a5abd92234 100644
--- a/src/java/org/apache/cassandra/db/marshal/UUIDType.java
+++ b/src/java/org/apache/cassandra/db/marshal/UUIDType.java
@@ -59,6 +59,13 @@ public class UUIDType extends AbstractType<UUID>
         super(ComparisonType.CUSTOM);
     }
 
+    @Override
+    public boolean allowsEmpty()
+    {
+        return true;
+    }
+
+    @Override
     public boolean isEmptyValueMeaningless()
     {
         return true;
diff --git a/src/java/org/apache/cassandra/db/marshal/VectorType.java 
b/src/java/org/apache/cassandra/db/marshal/VectorType.java
index 7caf02e3bb..204c603d28 100644
--- a/src/java/org/apache/cassandra/db/marshal/VectorType.java
+++ b/src/java/org/apache/cassandra/db/marshal/VectorType.java
@@ -25,6 +25,8 @@ import java.util.List;
 import java.util.Objects;
 import java.util.concurrent.ConcurrentHashMap;
 
+import javax.annotation.Nullable;
+
 import org.apache.cassandra.cql3.CQL3Type;
 import org.apache.cassandra.cql3.Term;
 import org.apache.cassandra.cql3.Vectors;
@@ -172,10 +174,10 @@ public final class VectorType<T> extends 
AbstractType<List<T>>
 
     public <V> V decomposeAsFloat(ValueAccessor<V> accessor, float[] value)
     {
+        if (value == null)
+            rejectNullOrEmptyValue();
         if (!(elementType instanceof FloatType))
             throw new IllegalStateException("Attempted to read as float, but 
element type is " + elementType.asCQL3Type());
-        if (value == null)
-            return null;
         if (value.length != dimension)
             throw new IllegalArgumentException(String.format("Attempted to add 
float vector of dimension %d to %s", value.length, asCQL3Type()));
         // TODO : should we use TypeSizes to be consistent with other code?  
Its the same value at the end of the day...
@@ -215,7 +217,8 @@ public final class VectorType<T> extends 
AbstractType<List<T>>
     public <V> V fromComparableBytes(ValueAccessor<V> accessor, 
ByteSource.Peekable comparableBytes, ByteComparable.Version version)
     {
         if (comparableBytes == null)
-            return accessor.empty();
+            rejectNullOrEmptyValue();
+
         assert version != ByteComparable.Version.LEGACY; // legacy translation 
is not reversible
 
         List<V> buffers = new ArrayList<>();
@@ -358,6 +361,11 @@ public final class VectorType<T> extends 
AbstractType<List<T>>
         if (remaining > 0)
             throw new MarshalException("Unexpected " + remaining + " 
extraneous bytes after " + asCQL3Type() + " value");
     }
+    
+    private static void rejectNullOrEmptyValue()
+    {
+        throw new MarshalException("Invalid empty vector value");
+    }
 
     public abstract class VectorSerializer extends TypeSerializer<List<T>>
     {
@@ -390,6 +398,13 @@ public final class VectorType<T> extends 
AbstractType<List<T>>
         {
             return (Class) List.class;
         }
+
+        @Override
+        public <V> boolean isNull(@Nullable V buffer, ValueAccessor<V> 
accessor)
+        {
+            // we don't allow empty vectors, so we can just check for null
+            return buffer == null;
+        }
     }
 
     private class FixedLengthSerializer extends VectorSerializer
@@ -404,8 +419,6 @@ public final class VectorType<T> extends 
AbstractType<List<T>>
         {
             if (elementType.isByteOrderComparable)
                 return ValueAccessor.compare(left, accessorL, right, 
accessorR);
-            if (accessorL.isEmpty(left) || accessorR.isEmpty(right))
-                return Boolean.compare(accessorR.isEmpty(right), 
accessorL.isEmpty(left));
             int offset = 0;
             int elementLength = elementType.valueLengthIfFixed();
             for (int i = 0; i < dimension; i++)
@@ -443,7 +456,8 @@ public final class VectorType<T> extends 
AbstractType<List<T>>
         public <V> V serializeRaw(List<V> value, ValueAccessor<V> accessor)
         {
             if (value == null)
-                return accessor.empty();
+                rejectNullOrEmptyValue();
+
             check(value);
 
             int size = elementType.valueLengthIfFixed();
@@ -458,7 +472,8 @@ public final class VectorType<T> extends 
AbstractType<List<T>>
         public ByteBuffer serialize(List<T> value)
         {
             if (value == null)
-                return ByteBufferUtil.EMPTY_BYTE_BUFFER;
+                rejectNullOrEmptyValue();
+
             check(value);
 
             ByteBuffer bb = 
ByteBuffer.allocate(elementType.valueLengthIfFixed() * dimension);
@@ -492,7 +507,8 @@ public final class VectorType<T> extends 
AbstractType<List<T>>
         public <V> void validate(V input, ValueAccessor<V> accessor) throws 
MarshalException
         {
             if (accessor.isEmpty(input))
-                return;
+                rejectNullOrEmptyValue();
+
             int offset = 0;
             int elementSize = elementType.valueLengthIfFixed();
 
@@ -520,9 +536,6 @@ public final class VectorType<T> extends 
AbstractType<List<T>>
         public <VL, VR> int compareCustom(VL left, ValueAccessor<VL> accessorL,
                                           VR right, ValueAccessor<VR> 
accessorR)
         {
-            if (accessorL.isEmpty(left) || accessorR.isEmpty(right))
-                return Boolean.compare(accessorR.isEmpty(right), 
accessorL.isEmpty(left));
-
             int leftOffset = 0;
             int rightOffset = 0;
             for (int i = 0; i < dimension; i++)
@@ -584,7 +597,8 @@ public final class VectorType<T> extends 
AbstractType<List<T>>
         public <V> V serializeRaw(List<V> value, ValueAccessor<V> accessor)
         {
             if (value == null)
-                return accessor.empty();
+                rejectNullOrEmptyValue();
+
             check(value);
 
             V bb = accessor.allocate(value.stream().mapToInt(v -> sizeOf(v, 
accessor)).sum());
@@ -598,7 +612,8 @@ public final class VectorType<T> extends 
AbstractType<List<T>>
         public ByteBuffer serialize(List<T> value)
         {
             if (value == null)
-                return ByteBufferUtil.EMPTY_BYTE_BUFFER;
+                rejectNullOrEmptyValue();
+
             check(value);
 
             List<ByteBuffer> bbs = new ArrayList<>(dimension);
@@ -630,7 +645,8 @@ public final class VectorType<T> extends 
AbstractType<List<T>>
         public <V> void validate(V input, ValueAccessor<V> accessor) throws 
MarshalException
         {
             if (accessor.isEmpty(input))
-                return;
+                rejectNullOrEmptyValue();
+
             int offset = 0;
             for (int i = 0; i < dimension; i++)
             {
diff --git 
a/test/unit/org/apache/cassandra/cql3/validation/operations/CQLVectorTest.java 
b/test/unit/org/apache/cassandra/cql3/validation/operations/CQLVectorTest.java
index cf88d32d93..42daab6ada 100644
--- 
a/test/unit/org/apache/cassandra/cql3/validation/operations/CQLVectorTest.java
+++ 
b/test/unit/org/apache/cassandra/cql3/validation/operations/CQLVectorTest.java
@@ -20,6 +20,7 @@ package org.apache.cassandra.cql3.validation.operations;
 
 import java.math.BigInteger;
 import java.nio.ByteBuffer;
+import java.util.List;
 
 import org.junit.Assert;
 import org.junit.Test;
@@ -34,6 +35,7 @@ import org.apache.cassandra.db.marshal.Int32Type;
 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;
 import org.assertj.core.api.Assertions;
 
 import static java.lang.String.format;
@@ -261,6 +263,47 @@ public class CQLVectorTest extends CQLTester.InMemory
         test.run();
     }
 
+    @Test
+    public void nullValues()
+    {
+        assertAcceptsNullValues("int"); // fixed length
+        assertAcceptsNullValues("float"); // fixed length with 
special/optimized treatment
+        assertAcceptsNullValues("text"); // variable length
+    }
+
+    private void assertAcceptsNullValues(String type)
+    {
+        createTable(format("CREATE TABLE %%s (k int primary key, v vector<%s, 
2>)", type));
+
+        execute("INSERT INTO %s (k, v) VALUES (0, null)");
+        assertRows(execute("SELECT * FROM %s"), row(0, null));
+
+        execute("INSERT INTO %s (k, v) VALUES (0, ?)", (List<Integer>) null);
+        assertRows(execute("SELECT * FROM %s"), row(0, null));
+    }
+
+    @Test
+    public void emptyValues() throws Throwable
+    {
+        assertRejectsEmptyValues("int"); // fixed length
+        assertRejectsEmptyValues("float"); // fixed length with 
special/optimized treatment
+        assertRejectsEmptyValues("text"); // variable length
+    }
+
+    private void assertRejectsEmptyValues(String type) throws Throwable
+    {
+        createTable(format("CREATE TABLE %%s (k int primary key, v vector<%s, 
2>)", type));
+
+        assertInvalidThrowMessage(format("Invalid HEX constant (0x) for \"v\" 
of type vector<%s, 2>", type),
+                                  InvalidRequestException.class,
+                                  "INSERT INTO %s (k, v) VALUES (0, 0x)");
+
+        assertInvalidThrowMessage("Invalid empty vector value",
+                                  InvalidRequestException.class,
+                                  "INSERT INTO %s (k, v) VALUES (0, ?)",
+                                  ByteBufferUtil.EMPTY_BYTE_BUFFER);
+    }
+
     @Test
     public void functions()
     {


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

Reply via email to