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

lidavidm pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow.git


The following commit(s) were added to refs/heads/main by this push:
     new a004102790 GH-37702: [Java] Add vector validation consistent with C++ 
(#37942)
a004102790 is described below

commit a0041027902ac71f00572d5b31022ee98502ed6a
Author: James Duong <[email protected]>
AuthorDate: Fri Sep 29 06:11:12 2023 -0700

    GH-37702: [Java] Add vector validation consistent with C++ (#37942)
    
    ### Rationale for this change
    Make vector validation code more consistent with C++. Add missing checks 
and have the entry point
    be the same so that the code is easier to read/write when working with both 
languages.
    
    ### What changes are included in this PR?
    Make vector validation more consistent with Array::Validate() in C++:
    * Add validate() and validateFull() instance methods to vectors.
    * Validate that VarCharVector and LargeVarCharVector contents are valid 
UTF-8.
    * Validate that DecimalVector and Decimal256Vector contents fit within the 
supplied precision and scale.
    * Validate that NullVectors contain only nulls.
    * Validate that FixedSizeBinaryVector values have the correct length.
    
    ### Are these changes tested?
    Yes.
    
    ### Are there any user-facing changes?
    No.
    * Closes: #37702
    
    Authored-by: James Duong <[email protected]>
    Signed-off-by: David Li <[email protected]>
---
 .../apache/arrow/vector/BaseFixedWidthVector.java  |  7 ++
 .../arrow/vector/BaseLargeVariableWidthVector.java |  7 ++
 .../arrow/vector/BaseVariableWidthVector.java      |  7 ++
 .../org/apache/arrow/vector/Decimal256Vector.java  | 13 ++++
 .../org/apache/arrow/vector/DecimalVector.java     | 13 ++++
 .../apache/arrow/vector/FixedSizeBinaryVector.java | 13 ++++
 .../apache/arrow/vector/LargeVarCharVector.java    | 12 ++++
 .../java/org/apache/arrow/vector/ValueVector.java  |  9 +++
 .../org/apache/arrow/vector/VarCharVector.java     | 12 ++++
 .../apache/arrow/vector/util/DecimalUtility.java   | 10 ++-
 .../java/org/apache/arrow/vector/util/Text.java    | 50 +++++++++++----
 .../vector/validate/ValidateVectorDataVisitor.java |  5 ++
 .../arrow/vector/validate/TestValidateVector.java  | 14 ++++
 .../vector/validate/TestValidateVectorFull.java    | 74 ++++++++++++++++++++++
 14 files changed, 233 insertions(+), 13 deletions(-)

diff --git 
a/java/vector/src/main/java/org/apache/arrow/vector/BaseFixedWidthVector.java 
b/java/vector/src/main/java/org/apache/arrow/vector/BaseFixedWidthVector.java
index 223ae9aa8c..04a038a0b5 100644
--- 
a/java/vector/src/main/java/org/apache/arrow/vector/BaseFixedWidthVector.java
+++ 
b/java/vector/src/main/java/org/apache/arrow/vector/BaseFixedWidthVector.java
@@ -550,6 +550,13 @@ public abstract class BaseFixedWidthVector extends 
BaseValueVector
     }
   }
 
+  /**
+   * Validate the scalar values held by this vector.
+   */
+  public void validateScalars() {
+    // No validation by default.
+  }
+
   /**
    * Construct a transfer pair of this vector and another vector of same type.
    * @param ref name of the target vector
diff --git 
a/java/vector/src/main/java/org/apache/arrow/vector/BaseLargeVariableWidthVector.java
 
b/java/vector/src/main/java/org/apache/arrow/vector/BaseLargeVariableWidthVector.java
index 90694db830..4d5a8a5119 100644
--- 
a/java/vector/src/main/java/org/apache/arrow/vector/BaseLargeVariableWidthVector.java
+++ 
b/java/vector/src/main/java/org/apache/arrow/vector/BaseLargeVariableWidthVector.java
@@ -643,6 +643,13 @@ public abstract class BaseLargeVariableWidthVector extends 
BaseValueVector
     return buffers;
   }
 
+  /**
+   * Validate the scalar values held by this vector.
+   */
+  public void validateScalars() {
+    // No validation by default.
+  }
+
   /**
    * Construct a transfer pair of this vector and another vector of same type.
    * @param ref name of the target vector
diff --git 
a/java/vector/src/main/java/org/apache/arrow/vector/BaseVariableWidthVector.java
 
b/java/vector/src/main/java/org/apache/arrow/vector/BaseVariableWidthVector.java
index 2a89590bf8..d7f5ff05a9 100644
--- 
a/java/vector/src/main/java/org/apache/arrow/vector/BaseVariableWidthVector.java
+++ 
b/java/vector/src/main/java/org/apache/arrow/vector/BaseVariableWidthVector.java
@@ -685,6 +685,13 @@ public abstract class BaseVariableWidthVector extends 
BaseValueVector
     return buffers;
   }
 
+  /**
+   * Validate the scalar values held by this vector.
+   */
+  public void validateScalars() {
+    // No validation by default.
+  }
+
   /**
    * Construct a transfer pair of this vector and another vector of same type.
    * @param ref name of the target vector
diff --git 
a/java/vector/src/main/java/org/apache/arrow/vector/Decimal256Vector.java 
b/java/vector/src/main/java/org/apache/arrow/vector/Decimal256Vector.java
index 70a895ff40..79a9badc39 100644
--- a/java/vector/src/main/java/org/apache/arrow/vector/Decimal256Vector.java
+++ b/java/vector/src/main/java/org/apache/arrow/vector/Decimal256Vector.java
@@ -35,6 +35,7 @@ import org.apache.arrow.vector.types.pojo.Field;
 import org.apache.arrow.vector.types.pojo.FieldType;
 import org.apache.arrow.vector.util.DecimalUtility;
 import org.apache.arrow.vector.util.TransferPair;
+import org.apache.arrow.vector.validate.ValidateUtil;
 
 
 /**
@@ -527,6 +528,18 @@ public final class Decimal256Vector extends 
BaseFixedWidthVector {
     set(index, isSet, start, buffer);
   }
 
+  @Override
+  public void validateScalars() {
+    for (int i = 0; i < getValueCount(); ++i) {
+      BigDecimal value = getObject(i);
+      if (value != null) {
+        
ValidateUtil.validateOrThrow(DecimalUtility.checkPrecisionAndScaleNoThrow(value,
 getPrecision(), getScale()),
+            "Invalid value for Decimal256Vector at position " + i + ". Value 
does not fit in precision " +
+                getPrecision() + " and scale " + getScale() + ".");
+      }
+    }
+  }
+
   /*----------------------------------------------------------------*
    |                                                                |
    |                      vector transfer                           |
diff --git 
a/java/vector/src/main/java/org/apache/arrow/vector/DecimalVector.java 
b/java/vector/src/main/java/org/apache/arrow/vector/DecimalVector.java
index 6a3ec60afc..d1a3bfc3af 100644
--- a/java/vector/src/main/java/org/apache/arrow/vector/DecimalVector.java
+++ b/java/vector/src/main/java/org/apache/arrow/vector/DecimalVector.java
@@ -35,6 +35,7 @@ import org.apache.arrow.vector.types.pojo.Field;
 import org.apache.arrow.vector.types.pojo.FieldType;
 import org.apache.arrow.vector.util.DecimalUtility;
 import org.apache.arrow.vector.util.TransferPair;
+import org.apache.arrow.vector.validate.ValidateUtil;
 
 /**
  * DecimalVector implements a fixed width vector (16 bytes) of
@@ -526,6 +527,18 @@ public final class DecimalVector extends 
BaseFixedWidthVector {
     set(index, isSet, start, buffer);
   }
 
+  @Override
+  public void validateScalars() {
+    for (int i = 0; i < getValueCount(); ++i) {
+      BigDecimal value = getObject(i);
+      if (value != null) {
+        
ValidateUtil.validateOrThrow(DecimalUtility.checkPrecisionAndScaleNoThrow(value,
 getPrecision(), getScale()),
+            "Invalid value for DecimalVector at position " + i + ". Value does 
not fit in precision " +
+                getPrecision() + " and scale " + getScale() + ".");
+      }
+    }
+  }
+
   /*----------------------------------------------------------------*
    |                                                                |
    |                      vector transfer                           |
diff --git 
a/java/vector/src/main/java/org/apache/arrow/vector/FixedSizeBinaryVector.java 
b/java/vector/src/main/java/org/apache/arrow/vector/FixedSizeBinaryVector.java
index 3ce2bb77cc..967d560d78 100644
--- 
a/java/vector/src/main/java/org/apache/arrow/vector/FixedSizeBinaryVector.java
+++ 
b/java/vector/src/main/java/org/apache/arrow/vector/FixedSizeBinaryVector.java
@@ -31,6 +31,7 @@ import 
org.apache.arrow.vector.types.pojo.ArrowType.FixedSizeBinary;
 import org.apache.arrow.vector.types.pojo.Field;
 import org.apache.arrow.vector.types.pojo.FieldType;
 import org.apache.arrow.vector.util.TransferPair;
+import org.apache.arrow.vector.validate.ValidateUtil;
 
 /**
  * FixedSizeBinaryVector implements a fixed width vector of
@@ -320,6 +321,18 @@ public class FixedSizeBinaryVector extends 
BaseFixedWidthVector {
     return dst;
   }
 
+  @Override
+  public void validateScalars() {
+    for (int i = 0; i < getValueCount(); ++i) {
+      byte[] value = get(i);
+      if (value != null) {
+        ValidateUtil.validateOrThrow(value.length == byteWidth,
+            "Invalid value for FixedSizeBinaryVector at position " + i + ". 
The length was " +
+                value.length + " but the length of each element should be " + 
byteWidth + ".");
+      }
+    }
+  }
+
   /*----------------------------------------------------------------*
    |                                                                |
    |                      vector transfer                           |
diff --git 
a/java/vector/src/main/java/org/apache/arrow/vector/LargeVarCharVector.java 
b/java/vector/src/main/java/org/apache/arrow/vector/LargeVarCharVector.java
index 1f8d9b7d3a..e9472c9f2c 100644
--- a/java/vector/src/main/java/org/apache/arrow/vector/LargeVarCharVector.java
+++ b/java/vector/src/main/java/org/apache/arrow/vector/LargeVarCharVector.java
@@ -27,6 +27,7 @@ import org.apache.arrow.vector.types.pojo.Field;
 import org.apache.arrow.vector.types.pojo.FieldType;
 import org.apache.arrow.vector.util.Text;
 import org.apache.arrow.vector.util.TransferPair;
+import org.apache.arrow.vector.validate.ValidateUtil;
 
 /**
  * LargeVarCharVector implements a variable width vector of VARCHAR
@@ -261,6 +262,17 @@ public final class LargeVarCharVector extends 
BaseLargeVariableWidthVector {
     setSafe(index, text.getBytes(), 0, text.getLength());
   }
 
+  @Override
+  public void validateScalars() {
+    for (int i = 0; i < getValueCount(); ++i) {
+      byte[] value = get(i);
+      if (value != null) {
+        ValidateUtil.validateOrThrow(Text.validateUTF8NoThrow(value),
+            "Non-UTF-8 data in VarCharVector at position " + i + ".");
+      }
+    }
+  }
+
   /*----------------------------------------------------------------*
    |                                                                |
    |                      vector transfer                           |
diff --git a/java/vector/src/main/java/org/apache/arrow/vector/ValueVector.java 
b/java/vector/src/main/java/org/apache/arrow/vector/ValueVector.java
index aa29c29314..462b512c65 100644
--- a/java/vector/src/main/java/org/apache/arrow/vector/ValueVector.java
+++ b/java/vector/src/main/java/org/apache/arrow/vector/ValueVector.java
@@ -29,6 +29,7 @@ import org.apache.arrow.vector.types.Types.MinorType;
 import org.apache.arrow.vector.types.pojo.Field;
 import org.apache.arrow.vector.util.CallBack;
 import org.apache.arrow.vector.util.TransferPair;
+import org.apache.arrow.vector.util.ValueVectorUtility;
 
 /**
  * An abstraction that is used to store a sequence of values in an individual 
column.
@@ -282,4 +283,12 @@ public interface ValueVector extends Closeable, 
Iterable<ValueVector> {
    * @return the name of the vector.
    */
   String getName();
+
+  default void validate() {
+    ValueVectorUtility.validate(this);
+  }
+
+  default void validateFull() {
+    ValueVectorUtility.validateFull(this);
+  }
 }
diff --git 
a/java/vector/src/main/java/org/apache/arrow/vector/VarCharVector.java 
b/java/vector/src/main/java/org/apache/arrow/vector/VarCharVector.java
index bc5c68b29f..2c83893819 100644
--- a/java/vector/src/main/java/org/apache/arrow/vector/VarCharVector.java
+++ b/java/vector/src/main/java/org/apache/arrow/vector/VarCharVector.java
@@ -29,6 +29,7 @@ import org.apache.arrow.vector.types.pojo.Field;
 import org.apache.arrow.vector.types.pojo.FieldType;
 import org.apache.arrow.vector.util.Text;
 import org.apache.arrow.vector.util.TransferPair;
+import org.apache.arrow.vector.validate.ValidateUtil;
 
 /**
  * VarCharVector implements a variable width vector of VARCHAR
@@ -261,6 +262,17 @@ public final class VarCharVector extends 
BaseVariableWidthVector {
     setSafe(index, text.getBytes(), 0, text.getLength());
   }
 
+  @Override
+  public void validateScalars() {
+    for (int i = 0; i < getValueCount(); ++i) {
+      byte[] value = get(i);
+      if (value != null) {
+        ValidateUtil.validateOrThrow(Text.validateUTF8NoThrow(value),
+            "Non-UTF-8 data in VarCharVector at position " + i + ".");
+      }
+    }
+  }
+
   /*----------------------------------------------------------------*
    |                                                                |
    |                      vector transfer                           |
diff --git 
a/java/vector/src/main/java/org/apache/arrow/vector/util/DecimalUtility.java 
b/java/vector/src/main/java/org/apache/arrow/vector/util/DecimalUtility.java
index 137ac746f4..a81169b8f7 100644
--- a/java/vector/src/main/java/org/apache/arrow/vector/util/DecimalUtility.java
+++ b/java/vector/src/main/java/org/apache/arrow/vector/util/DecimalUtility.java
@@ -95,11 +95,19 @@ public class DecimalUtility {
     }
     if (value.precision() > vectorPrecision) {
       throw new UnsupportedOperationException("BigDecimal precision can not be 
greater than that in the Arrow " +
-        "vector: " + value.precision() + " > " + vectorPrecision);
+          "vector: " + value.precision() + " > " + vectorPrecision);
     }
     return true;
   }
 
+  /**
+   * Check that the BigDecimal scale equals the vectorScale and that the 
BigDecimal precision is
+   * less than or equal to the vectorPrecision. Return true if so, otherwise 
return false.
+   */
+  public static boolean checkPrecisionAndScaleNoThrow(BigDecimal value, int 
vectorPrecision, int vectorScale) {
+    return value.scale() == vectorScale && value.precision() < vectorPrecision;
+  }
+
   /**
    * Check that the decimal scale equals the vectorScale and that the decimal 
precision is
    * less than or equal to the vectorPrecision. If not, then an 
UnsupportedOperationException is
diff --git a/java/vector/src/main/java/org/apache/arrow/vector/util/Text.java 
b/java/vector/src/main/java/org/apache/arrow/vector/util/Text.java
index b479305c6e..778af0ca95 100644
--- a/java/vector/src/main/java/org/apache/arrow/vector/util/Text.java
+++ b/java/vector/src/main/java/org/apache/arrow/vector/util/Text.java
@@ -30,6 +30,7 @@ import java.nio.charset.MalformedInputException;
 import java.text.CharacterIterator;
 import java.text.StringCharacterIterator;
 import java.util.Arrays;
+import java.util.Optional;
 
 import com.fasterxml.jackson.core.JsonGenerationException;
 import com.fasterxml.jackson.core.JsonGenerator;
@@ -466,6 +467,16 @@ public class Text {
 
   private static final int TRAIL_BYTE = 2;
 
+  /**
+   * Check if a byte array contains valid utf-8.
+   *
+   * @param utf8 byte array
+   * @return true if the input is valid UTF-8. False otherwise.
+   */
+  public static boolean validateUTF8NoThrow(byte[] utf8) {
+    return !validateUTF8Internal(utf8, 0, utf8.length).isPresent();
+  }
+
   /**
    * Check if a byte array contains valid utf-8.
    *
@@ -484,8 +495,22 @@ public class Text {
    * @param len   the length of the byte sequence
    * @throws MalformedInputException if the byte array contains invalid bytes
    */
-  public static void validateUTF8(byte[] utf8, int start, int len)
-      throws MalformedInputException {
+  public static void validateUTF8(byte[] utf8, int start, int len) throws 
MalformedInputException {
+    Optional<Integer> result = validateUTF8Internal(utf8, start, len);
+    if (result.isPresent()) {
+      throw new MalformedInputException(result.get());
+    }
+  }
+
+  /**
+   * Check to see if a byte array is valid utf-8.
+   *
+   * @param utf8  the array of bytes
+   * @param start the offset of the first byte in the array
+   * @param len   the length of the byte sequence
+   * @return the position where a malformed byte occurred or Optional.empty() 
if the byte array was valid UTF-8.
+   */
+  private static Optional<Integer> validateUTF8Internal(byte[] utf8, int 
start, int len) {
     int count = start;
     int leadByte = 0;
     int length = 0;
@@ -501,51 +526,51 @@ public class Text {
           switch (length) {
             case 0: // check for ASCII
               if (leadByte > 0x7F) {
-                throw new MalformedInputException(count);
+                return Optional.of(count);
               }
               break;
             case 1:
               if (leadByte < 0xC2 || leadByte > 0xDF) {
-                throw new MalformedInputException(count);
+                return Optional.of(count);
               }
               state = TRAIL_BYTE_1;
               break;
             case 2:
               if (leadByte < 0xE0 || leadByte > 0xEF) {
-                throw new MalformedInputException(count);
+                return Optional.of(count);
               }
               state = TRAIL_BYTE_1;
               break;
             case 3:
               if (leadByte < 0xF0 || leadByte > 0xF4) {
-                throw new MalformedInputException(count);
+                return Optional.of(count);
               }
               state = TRAIL_BYTE_1;
               break;
             default:
               // too long! Longest valid UTF-8 is 4 bytes (lead + three)
               // or if < 0 we got a trail byte in the lead byte position
-              throw new MalformedInputException(count);
+              return Optional.of(count);
           } // switch (length)
           break;
 
         case TRAIL_BYTE_1:
           if (leadByte == 0xF0 && aByte < 0x90) {
-            throw new MalformedInputException(count);
+            return Optional.of(count);
           }
           if (leadByte == 0xF4 && aByte > 0x8F) {
-            throw new MalformedInputException(count);
+            return Optional.of(count);
           }
           if (leadByte == 0xE0 && aByte < 0xA0) {
-            throw new MalformedInputException(count);
+            return Optional.of(count);
           }
           if (leadByte == 0xED && aByte > 0x9F) {
-            throw new MalformedInputException(count);
+            return Optional.of(count);
           }
           // falls through to regular trail-byte test!!
         case TRAIL_BYTE:
           if (aByte < 0x80 || aByte > 0xBF) {
-            throw new MalformedInputException(count);
+            return Optional.of(count);
           }
           if (--length == 0) {
             state = LEAD_BYTE;
@@ -558,6 +583,7 @@ public class Text {
       } // switch (state)
       count++;
     }
+    return Optional.empty();
   }
 
   /**
diff --git 
a/java/vector/src/main/java/org/apache/arrow/vector/validate/ValidateVectorDataVisitor.java
 
b/java/vector/src/main/java/org/apache/arrow/vector/validate/ValidateVectorDataVisitor.java
index cdeb4f1eaa..6d33be7a0d 100644
--- 
a/java/vector/src/main/java/org/apache/arrow/vector/validate/ValidateVectorDataVisitor.java
+++ 
b/java/vector/src/main/java/org/apache/arrow/vector/validate/ValidateVectorDataVisitor.java
@@ -85,18 +85,21 @@ public class ValidateVectorDataVisitor implements 
VectorVisitor<Void, Void> {
 
   @Override
   public Void visit(BaseFixedWidthVector vector, Void value) {
+    vector.validateScalars();
     return null;
   }
 
   @Override
   public Void visit(BaseVariableWidthVector vector, Void value) {
     validateOffsetBuffer(vector, vector.getValueCount());
+    vector.validateScalars();
     return null;
   }
 
   @Override
   public Void visit(BaseLargeVariableWidthVector vector, Void value) {
     validateLargeOffsetBuffer(vector, vector.getValueCount());
+    vector.validateScalars();
     return null;
   }
 
@@ -169,6 +172,8 @@ public class ValidateVectorDataVisitor implements 
VectorVisitor<Void, Void> {
 
   @Override
   public Void visit(NullVector vector, Void value) {
+    ValidateUtil.validateOrThrow(vector.getNullCount() == 
vector.getValueCount(),
+        "NullVector should have only null entries.");
     return null;
   }
 
diff --git 
a/java/vector/src/test/java/org/apache/arrow/vector/validate/TestValidateVector.java
 
b/java/vector/src/test/java/org/apache/arrow/vector/validate/TestValidateVector.java
index 2354b281ed..20492036da 100644
--- 
a/java/vector/src/test/java/org/apache/arrow/vector/validate/TestValidateVector.java
+++ 
b/java/vector/src/test/java/org/apache/arrow/vector/validate/TestValidateVector.java
@@ -251,6 +251,20 @@ public class TestValidateVector {
     }
   }
 
+  @Test
+  public void testBaseFixedWidthVectorInstanceMethod() {
+    try (final IntVector vector = new IntVector("v", allocator)) {
+      vector.validate();
+      setVector(vector, 1, 2, 3);
+      vector.validate();
+
+      vector.getDataBuffer().capacity(0);
+      ValidateUtil.ValidateException e = 
assertThrows(ValidateUtil.ValidateException.class,
+          () -> vector.validate());
+      assertTrue(e.getMessage().contains("Not enough capacity for fixed width 
data buffer"));
+    }
+  }
+
   private void writeStructVector(NullableStructWriter writer, int value1, long 
value2) {
     writer.start();
     writer.integer("f0").writeInt(value1);
diff --git 
a/java/vector/src/test/java/org/apache/arrow/vector/validate/TestValidateVectorFull.java
 
b/java/vector/src/test/java/org/apache/arrow/vector/validate/TestValidateVectorFull.java
index 4241a0d9cf..ca71a622bb 100644
--- 
a/java/vector/src/test/java/org/apache/arrow/vector/validate/TestValidateVectorFull.java
+++ 
b/java/vector/src/test/java/org/apache/arrow/vector/validate/TestValidateVectorFull.java
@@ -23,11 +23,14 @@ import static org.junit.Assert.assertTrue;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 
+import java.nio.charset.StandardCharsets;
 import java.util.Arrays;
 
 import org.apache.arrow.memory.ArrowBuf;
 import org.apache.arrow.memory.BufferAllocator;
 import org.apache.arrow.memory.RootAllocator;
+import org.apache.arrow.vector.Decimal256Vector;
+import org.apache.arrow.vector.DecimalVector;
 import org.apache.arrow.vector.Float4Vector;
 import org.apache.arrow.vector.IntVector;
 import org.apache.arrow.vector.LargeVarCharVector;
@@ -231,4 +234,75 @@ public class TestValidateVectorFull {
       assertTrue(e.getMessage().contains("Dense union vector offset exceeds 
sub-vector boundary"));
     }
   }
+
+  @Test
+  public void testBaseVariableWidthVectorInstanceMethod() {
+    try (final VarCharVector vector = new VarCharVector("v", allocator)) {
+      vector.validateFull();
+      setVector(vector, "aaa", "bbb", "ccc");
+      vector.validateFull();
+
+      ArrowBuf offsetBuf = vector.getOffsetBuffer();
+      offsetBuf.setInt(0, 100);
+      offsetBuf.setInt(4, 50);
+
+      ValidateUtil.ValidateException e = 
assertThrows(ValidateUtil.ValidateException.class,
+          vector::validateFull);
+      assertTrue(e.getMessage().contains("The values in positions 0 and 1 of 
the offset buffer are decreasing"));
+    }
+  }
+
+  @Test
+  public void testValidateVarCharUTF8() {
+    try (final VarCharVector vector = new VarCharVector("v", allocator)) {
+      vector.validateFull();
+      setVector(vector, "aaa".getBytes(StandardCharsets.UTF_8), 
"bbb".getBytes(StandardCharsets.UTF_8),
+          new byte[] {(byte) 0xFF, (byte) 0xFE});
+      ValidateUtil.ValidateException e = 
assertThrows(ValidateUtil.ValidateException.class,
+          vector::validateFull);
+      assertTrue(e.getMessage().contains("UTF"));
+    }
+  }
+
+  @Test
+  public void testValidateLargeVarCharUTF8() {
+    try (final LargeVarCharVector vector = new LargeVarCharVector("v", 
allocator)) {
+      vector.validateFull();
+      setVector(vector, "aaa".getBytes(StandardCharsets.UTF_8), 
"bbb".getBytes(StandardCharsets.UTF_8),
+          new byte[] {(byte) 0xFF, (byte) 0xFE});
+      ValidateUtil.ValidateException e = 
assertThrows(ValidateUtil.ValidateException.class,
+          vector::validateFull);
+      assertTrue(e.getMessage().contains("UTF"));
+    }
+  }
+
+  @Test
+  public void testValidateDecimal() {
+    try (final DecimalVector vector = new DecimalVector(Field.nullable("v",
+        new ArrowType.Decimal(2, 0, DecimalVector.TYPE_WIDTH * 8)), 
allocator)) {
+      vector.validateFull();
+      setVector(vector, 1L);
+      vector.validateFull();
+      vector.clear();
+      setVector(vector, Long.MAX_VALUE);
+      ValidateUtil.ValidateException e = 
assertThrows(ValidateUtil.ValidateException.class,
+          vector::validateFull);
+      assertTrue(e.getMessage().contains("Decimal"));
+    }
+  }
+
+  @Test
+  public void testValidateDecimal256() {
+    try (final Decimal256Vector vector = new 
Decimal256Vector(Field.nullable("v",
+        new ArrowType.Decimal(2, 0, DecimalVector.TYPE_WIDTH * 8)), 
allocator)) {
+      vector.validateFull();
+      setVector(vector, 1L);
+      vector.validateFull();
+      vector.clear();
+      setVector(vector, Long.MAX_VALUE);
+      ValidateUtil.ValidateException e = 
assertThrows(ValidateUtil.ValidateException.class,
+          vector::validateFull);
+      assertTrue(e.getMessage().contains("Decimal"));
+    }
+  }
 }

Reply via email to