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

xiangfu0 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/pinot.git


The following commit(s) were added to refs/heads/master by this push:
     new 690ac21ffb6 [UUID 4a] CAST to and from the logical UUID type (#19181)
690ac21ffb6 is described below

commit 690ac21ffb6c90486e9994ca9f3b32608057e30a
Author: Xiang Fu <[email protected]>
AuthorDate: Fri Aug 7 14:03:26 2026 -0700

    [UUID 4a] CAST to and from the logical UUID type (#19181)
    
    * [UUID 4a] CAST to and from the logical UUID type
    
    Adds CAST support for the logical UUID type, in both directions and for 
single-
    and multi-value columns:
    
    - CAST(<string|bytes> AS UUID) parses the value into the 16-byte stored form
    - a UUID result read as a string renders the canonical dashed form rather 
than
      the hex a BYTES column would produce
    
    The conversions live in ArrayCopyUtils as copyToUuid / copyFromUuid, next to
    copyFromTimestamp which they mirror -- a logical type parsed into, or 
rendered
    from, its stored representation.
    
    Note the two directions are distinct and both are needed: #19165 handles a 
UUID
    *source* cast to STRING, while this handles rendering a UUID *result*, e.g.
    reading CAST(x AS UUID) as a string.
    
    Split out of #18872 to keep that PR to predicate evaluation. Depends only on
    UuidUtils (#18869) and the UUID stored type (#18870), both already on 
master.
    
    * Address UUID cast review comments
---
 .../transform/function/BaseTransformFunction.java  |  4 +
 .../transform/function/CastTransformFunction.java  | 85 +++++++++++++++++++
 .../function/BaseTransformFunctionTest.java        | 16 +++-
 .../function/CastTransformFunctionTest.java        | 96 ++++++++++++++++++++++
 .../org/apache/pinot/spi/utils/ArrayCopyUtils.java | 60 ++++++++++++++
 5 files changed, 260 insertions(+), 1 deletion(-)

diff --git 
a/pinot-core/src/main/java/org/apache/pinot/core/operator/transform/function/BaseTransformFunction.java
 
b/pinot-core/src/main/java/org/apache/pinot/core/operator/transform/function/BaseTransformFunction.java
index 9f01c30492e..b05599e5471 100644
--- 
a/pinot-core/src/main/java/org/apache/pinot/core/operator/transform/function/BaseTransformFunction.java
+++ 
b/pinot-core/src/main/java/org/apache/pinot/core/operator/transform/function/BaseTransformFunction.java
@@ -55,6 +55,8 @@ public abstract class BaseTransformFunction implements 
TransformFunction {
       new TransformResultMetadata(DataType.JSON, true, false);
   protected static final TransformResultMetadata 
BYTES_SV_NO_DICTIONARY_METADATA =
       new TransformResultMetadata(DataType.BYTES, true, false);
+  protected static final TransformResultMetadata 
UUID_SV_NO_DICTIONARY_METADATA =
+      new TransformResultMetadata(DataType.UUID, true, false);
 
   protected static final TransformResultMetadata INT_MV_NO_DICTIONARY_METADATA 
=
       new TransformResultMetadata(DataType.INT, false, false);
@@ -76,6 +78,8 @@ public abstract class BaseTransformFunction implements 
TransformFunction {
       new TransformResultMetadata(DataType.JSON, false, false);
   protected static final TransformResultMetadata 
BYTES_MV_NO_DICTIONARY_METADATA =
       new TransformResultMetadata(DataType.BYTES, false, false);
+  protected static final TransformResultMetadata 
UUID_MV_NO_DICTIONARY_METADATA =
+      new TransformResultMetadata(DataType.UUID, false, false);
   protected static final TransformResultMetadata UNKNOWN_METADATA =
       new TransformResultMetadata(DataType.UNKNOWN, true, false);
 
diff --git 
a/pinot-core/src/main/java/org/apache/pinot/core/operator/transform/function/CastTransformFunction.java
 
b/pinot-core/src/main/java/org/apache/pinot/core/operator/transform/function/CastTransformFunction.java
index efef5b2b65c..16d4533c51a 100644
--- 
a/pinot-core/src/main/java/org/apache/pinot/core/operator/transform/function/CastTransformFunction.java
+++ 
b/pinot-core/src/main/java/org/apache/pinot/core/operator/transform/function/CastTransformFunction.java
@@ -18,6 +18,7 @@
  */
 package org.apache.pinot.core.operator.transform.function;
 
+import com.google.common.base.Preconditions;
 import java.math.BigDecimal;
 import java.util.List;
 import java.util.Map;
@@ -97,6 +98,10 @@ public class CastTransformFunction extends 
BaseTransformFunction {
         case "VARBINARY":
           _resultMetadata = sourceSV ? BYTES_SV_NO_DICTIONARY_METADATA : 
BYTES_MV_NO_DICTIONARY_METADATA;
           break;
+        case "UUID":
+          Preconditions.checkState(sourceSV, "Cannot cast from MV to UUID");
+          _resultMetadata = UUID_SV_NO_DICTIONARY_METADATA;
+          break;
         case "INT_ARRAY":
         case "INTEGER_ARRAY":
           _resultMetadata = INT_MV_NO_DICTIONARY_METADATA;
@@ -119,6 +124,13 @@ public class CastTransformFunction extends 
BaseTransformFunction {
         case "VARCHAR_ARRAY":
           _resultMetadata = STRING_MV_NO_DICTIONARY_METADATA;
           break;
+        case "BYTES_ARRAY":
+          _resultMetadata = BYTES_MV_NO_DICTIONARY_METADATA;
+          break;
+        case "UUID_ARRAY":
+          Preconditions.checkState(!sourceSV, "Cannot cast from SV to 
UUID_ARRAY");
+          _resultMetadata = UUID_MV_NO_DICTIONARY_METADATA;
+          break;
         default:
           throw new IllegalArgumentException("Unable to cast expression to 
type - " + targetType);
       }
@@ -319,6 +331,12 @@ public class CastTransformFunction extends 
BaseTransformFunction {
           byte[][] bytesValues = transformToBytesValuesSV(valueBlock);
           ArrayCopyUtils.copy(bytesValues, _stringValuesSV, length);
           break;
+        // Renders a UUID *result* (e.g. CAST(x AS UUID) read as a string). 
The switch above handles the other
+        // direction, a UUID *source* cast to STRING.
+        case UUID:
+          byte[][] uuidValues = transformToBytesValuesSV(valueBlock);
+          ArrayCopyUtils.copyFromUuid(uuidValues, _stringValuesSV, length);
+          break;
         default:
           throw new IllegalStateException(String.format("Cannot cast from SV 
%s to STRING", resultDataType));
       }
@@ -326,6 +344,68 @@ public class CastTransformFunction extends 
BaseTransformFunction {
     return _stringValuesSV;
   }
 
+  @Override
+  public byte[][] transformToBytesValuesSV(ValueBlock valueBlock) {
+    switch (_resultMetadata.getDataType()) {
+      case BYTES:
+        return _transformFunction.transformToBytesValuesSV(valueBlock);
+      case UUID:
+        return transformToUuidValuesSV(valueBlock);
+      default:
+        return super.transformToBytesValuesSV(valueBlock);
+    }
+  }
+
+  // TODO: Add it to the interface
+  private byte[][] transformToUuidValuesSV(ValueBlock valueBlock) {
+    int length = valueBlock.getNumDocs();
+    initBytesValuesSV(length);
+    switch (_sourceDataType.getStoredType()) {
+      case STRING:
+        String[] stringValues = 
_transformFunction.transformToStringValuesSV(valueBlock);
+        ArrayCopyUtils.copyToUuid(stringValues, _bytesValuesSV, length);
+        break;
+      case BYTES:
+        byte[][] bytesValues = 
_transformFunction.transformToBytesValuesSV(valueBlock);
+        ArrayCopyUtils.copyToUuid(bytesValues, _bytesValuesSV, length);
+        break;
+      default:
+        throw new IllegalStateException(String.format("Cannot cast from SV %s 
to UUID", _sourceDataType));
+    }
+    return _bytesValuesSV;
+  }
+
+  @Override
+  public byte[][][] transformToBytesValuesMV(ValueBlock valueBlock) {
+    switch (_resultMetadata.getDataType()) {
+      case BYTES:
+        return _transformFunction.transformToBytesValuesMV(valueBlock);
+      case UUID:
+        return transformToUuidValuesMV(valueBlock);
+      default:
+        return super.transformToBytesValuesMV(valueBlock);
+    }
+  }
+
+  // TODO: Add it to the interface
+  private byte[][][] transformToUuidValuesMV(ValueBlock valueBlock) {
+    int length = valueBlock.getNumDocs();
+    initBytesValuesMV(length);
+    switch (_sourceDataType.getStoredType()) {
+      case STRING:
+        String[][] stringValuesMV = 
_transformFunction.transformToStringValuesMV(valueBlock);
+        ArrayCopyUtils.copyToUuid(stringValuesMV, _bytesValuesMV, length);
+        break;
+      case BYTES:
+        byte[][][] bytesValuesMV = 
_transformFunction.transformToBytesValuesMV(valueBlock);
+        ArrayCopyUtils.copyToUuid(bytesValuesMV, _bytesValuesMV, length);
+        break;
+      default:
+        throw new IllegalStateException(String.format("Cannot cast from MV %s 
to UUID", _sourceDataType));
+    }
+    return _bytesValuesMV;
+  }
+
   @Override
   public int[][] transformToIntValuesMV(ValueBlock valueBlock) {
     switch (_resultMetadata.getDataType()) {
@@ -491,6 +571,11 @@ public class CastTransformFunction extends 
BaseTransformFunction {
           longValuesMV = transformToTimestampValuesMV(valueBlock);
           ArrayCopyUtils.copyFromTimestamp(longValuesMV, _stringValuesMV, 
length);
           break;
+        // See the SV variant: this renders a UUID result, not a UUID source.
+        case UUID:
+          byte[][][] uuidValuesMV = transformToBytesValuesMV(valueBlock);
+          ArrayCopyUtils.copyFromUuid(uuidValuesMV, _stringValuesMV, length);
+          break;
         default:
           throw new IllegalStateException(String.format("Cannot cast from MV 
%s to STRING", resultDataType));
       }
diff --git 
a/pinot-core/src/test/java/org/apache/pinot/core/operator/transform/function/BaseTransformFunctionTest.java
 
b/pinot-core/src/test/java/org/apache/pinot/core/operator/transform/function/BaseTransformFunctionTest.java
index 4eb284986ea..ccc4804e0ac 100644
--- 
a/pinot-core/src/test/java/org/apache/pinot/core/operator/transform/function/BaseTransformFunctionTest.java
+++ 
b/pinot-core/src/test/java/org/apache/pinot/core/operator/transform/function/BaseTransformFunctionTest.java
@@ -32,6 +32,7 @@ import java.util.Locale;
 import java.util.Map;
 import java.util.Random;
 import java.util.Set;
+import java.util.UUID;
 import java.util.concurrent.TimeUnit;
 import org.apache.commons.io.FileUtils;
 import org.apache.commons.lang3.ArrayUtils;
@@ -59,6 +60,7 @@ import org.apache.pinot.spi.utils.BigDecimalUtils;
 import org.apache.pinot.spi.utils.BytesUtils;
 import org.apache.pinot.spi.utils.JsonUtils;
 import org.apache.pinot.spi.utils.ReadMode;
+import org.apache.pinot.spi.utils.UuidUtils;
 import org.apache.pinot.spi.utils.builder.TableConfigBuilder;
 import org.roaringbitmap.RoaringBitmap;
 import org.testng.annotations.AfterClass;
@@ -83,6 +85,7 @@ public abstract class BaseTransformFunctionTest {
   protected static final String JSON_STRING_SV_COLUMN = "jsonSV";
   protected static final String STRING_SV_NULL_COLUMN = "stringSVNull";
   protected static final String BYTES_SV_COLUMN = "bytesSV";
+  protected static final String UUID_SV_COLUMN = "uuidSV";
   protected static final String VECTOR_1_COLUMN = "vector1";
   protected static final String VECTOR_2_COLUMN = "vector2";
   protected static final String ZERO_VECTOR_COLUMN = "zeroVector";
@@ -132,6 +135,7 @@ public abstract class BaseTransformFunctionTest {
   protected final String[] _jsonArrayValues = new String[NUM_ROWS];
   protected final String[] _stringAlphaNumericSVValues = new String[NUM_ROWS];
   protected final byte[][] _bytesSVValues = new byte[NUM_ROWS][];
+  protected final byte[][] _uuidSVValues = new byte[NUM_ROWS][];
   protected final int[][] _intMVValues = new int[NUM_ROWS][];
   protected final long[][] _longMVValues = new long[NUM_ROWS][];
   protected final float[][] _floatMVValues = new float[NUM_ROWS][];
@@ -181,6 +185,9 @@ public abstract class BaseTransformFunctionTest {
           df.format(RANDOM.nextInt() * RANDOM.nextDouble()));
       _stringAlphaNumericSVValues[i] = 
RandomStringUtils.secure().nextAlphanumeric(26);
       _bytesSVValues[i] = 
RandomStringUtils.secure().nextAlphanumeric(26).getBytes();
+      long mostSignificantBits = (i % 2 == 0) ? Long.MIN_VALUE + i : 
Long.MAX_VALUE - i;
+      long leastSignificantBits = ((long) i << Integer.SIZE) | i;
+      _uuidSVValues[i] = UuidUtils.toBytes(new UUID(mostSignificantBits, 
leastSignificantBits));
 
       int numValues = 1 + RANDOM.nextInt(MAX_NUM_MULTI_VALUES);
       _intMVValues[i] = new int[numValues];
@@ -251,6 +258,7 @@ public abstract class BaseTransformFunctionTest {
         map.put(STRING_ALPHANUM_NULL_SV_COLUMN, 
_stringAlphaNumericSVValues[i]);
       }
       map.put(BYTES_SV_COLUMN, _bytesSVValues[i]);
+      map.put(UUID_SV_COLUMN, _uuidSVValues[i]);
 
       map.put(INT_MV_COLUMN, ArrayUtils.toObject(_intMVValues[i]));
       // Same values as INT_MV_COLUMN so callers can compare results against 
the dict-encoded baseline and
@@ -304,6 +312,7 @@ public abstract class BaseTransformFunctionTest {
         .addSingleValueDimension(STRING_ALPHANUM_SV_COLUMN, 
FieldSpec.DataType.STRING)
         .addSingleValueDimension(STRING_ALPHANUM_NULL_SV_COLUMN, 
FieldSpec.DataType.STRING)
         .addSingleValueDimension(BYTES_SV_COLUMN, FieldSpec.DataType.BYTES)
+        .addSingleValueDimension(UUID_SV_COLUMN, FieldSpec.DataType.UUID)
         .addSingleValueDimension(JSON_COLUMN, FieldSpec.DataType.JSON)
         .addSingleValueDimension(DEFAULT_JSON_COLUMN, FieldSpec.DataType.JSON)
         .addMultiValueDimension(INT_MV_COLUMN, FieldSpec.DataType.INT)
@@ -652,8 +661,13 @@ public abstract class BaseTransformFunctionTest {
   protected void testTransformFunction(TransformFunction transformFunction, 
byte[][] expectedValues) {
     String[] stringValues = 
transformFunction.transformToStringValuesSV(_projectionBlock);
     byte[][] bytesValues = 
transformFunction.transformToBytesValuesSV(_projectionBlock);
+    FieldSpec.DataType resultDataType = 
transformFunction.getResultMetadata().getDataType();
     for (int i = 0; i < NUM_ROWS; i++) {
-      assertEquals(bytesValues[i], BytesUtils.toBytes(stringValues[i]));
+      if (resultDataType == FieldSpec.DataType.UUID) {
+        assertEquals(bytesValues[i], UuidUtils.toBytes(stringValues[i]));
+      } else {
+        assertEquals(bytesValues[i], BytesUtils.toBytes(stringValues[i]));
+      }
       assertEquals(bytesValues[i], expectedValues[i]);
     }
     testNullBitmap(transformFunction, null);
diff --git 
a/pinot-core/src/test/java/org/apache/pinot/core/operator/transform/function/CastTransformFunctionTest.java
 
b/pinot-core/src/test/java/org/apache/pinot/core/operator/transform/function/CastTransformFunctionTest.java
index db5fc9d0cfe..7b5cba7e8b4 100644
--- 
a/pinot-core/src/test/java/org/apache/pinot/core/operator/transform/function/CastTransformFunctionTest.java
+++ 
b/pinot-core/src/test/java/org/apache/pinot/core/operator/transform/function/CastTransformFunctionTest.java
@@ -28,7 +28,9 @@ import org.apache.pinot.common.request.context.LiteralContext;
 import org.apache.pinot.common.request.context.RequestContextUtils;
 import org.apache.pinot.core.operator.transform.TransformResultMetadata;
 import org.apache.pinot.spi.data.FieldSpec;
+import org.apache.pinot.spi.exception.BadQueryRequestException;
 import org.apache.pinot.spi.utils.ArrayCopyUtils;
+import org.apache.pinot.spi.utils.BytesUtils;
 import org.apache.pinot.spi.utils.CommonConstants.NullValuePlaceHolder;
 import org.apache.pinot.spi.utils.UuidUtils;
 import org.roaringbitmap.RoaringBitmap;
@@ -39,10 +41,12 @@ import static 
org.apache.pinot.common.function.scalar.DataTypeConversionFunction
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
 import static org.testng.Assert.assertTrue;
 
 
 public class CastTransformFunctionTest extends BaseTransformFunctionTest {
+  private static final String UUID_VALUE = 
"550e8400-e29b-41d4-a716-446655440000";
   @Test
   public void testCastUuidToString() {
     String uuid = "550e8400-e29b-41d4-a716-446655440000";
@@ -331,6 +335,21 @@ public class CastTransformFunctionTest extends 
BaseTransformFunctionTest {
     testTransformFunction(transformFunction, expectedArraySums);
   }
 
+  @Test
+  public void testCastTransformFunctionBytesArray() {
+    ExpressionContext expression =
+        RequestContextUtils.getExpression(String.format("CAST(%s AS 
BYTES_ARRAY)", STRING_MV_COLUMN));
+    TransformFunction transformFunction = 
TransformFunctionFactory.get(expression, _dataSourceMap);
+    assertTrue(transformFunction instanceof CastTransformFunction);
+    TransformResultMetadata resultMetadata = 
transformFunction.getResultMetadata();
+    assertEquals(resultMetadata.getDataType(), FieldSpec.DataType.BYTES);
+    assertFalse(resultMetadata.isSingleValue());
+
+    byte[][][] expectedBytesValues = new byte[NUM_ROWS][][];
+    ArrayCopyUtils.copy(_stringMVValues, expectedBytesValues, NUM_ROWS);
+    assertEquals(transformFunction.transformToBytesValuesMV(_projectionBlock), 
expectedBytesValues);
+  }
+
   @Test
   public void testCastNullLiteral() {
     ExpressionContext expression = 
RequestContextUtils.getExpression("cast(null AS INT)");
@@ -361,4 +380,81 @@ public class CastTransformFunctionTest extends 
BaseTransformFunctionTest {
     }
     testTransformFunctionWithNull(transformFunction, expectedValues, 
roaringBitmap);
   }
+
+  @Test
+  public void testCastTransformFunctionUUID() {
+    ExpressionContext expression =
+        RequestContextUtils.getExpression(String.format("CAST('%s' AS UUID)", 
UUID_VALUE.toUpperCase()));
+    TransformFunction transformFunction = 
TransformFunctionFactory.get(expression, _dataSourceMap);
+    assertTrue(transformFunction instanceof CastTransformFunction);
+    assertEquals(transformFunction.getResultMetadata().getDataType(), 
FieldSpec.DataType.UUID);
+
+    byte[][] bytesValues = 
transformFunction.transformToBytesValuesSV(_projectionBlock);
+    String[] stringValues = 
transformFunction.transformToStringValuesSV(_projectionBlock);
+    byte[] expectedBytes = UuidUtils.toBytes(UUID_VALUE);
+    for (int i = 0; i < NUM_ROWS; i++) {
+      assertEquals(bytesValues[i], expectedBytes);
+      assertEquals(stringValues[i], UUID_VALUE);
+    }
+  }
+
+  @Test
+  public void testCastTransformFunctionUuidRoundTrips() {
+    String bytesHex = BytesUtils.toHexString(UuidUtils.toBytes(UUID_VALUE));
+
+    ExpressionContext expression = RequestContextUtils.getExpression(
+        String.format("CAST(CAST('%s' AS BYTES) AS UUID)", bytesHex));
+    TransformFunction transformFunction = 
TransformFunctionFactory.get(expression, _dataSourceMap);
+    byte[] expectedBytes = UuidUtils.toBytes(UUID_VALUE);
+    byte[][] expectedUuidValues = new byte[NUM_ROWS][];
+    for (int i = 0; i < NUM_ROWS; i++) {
+      expectedUuidValues[i] = expectedBytes;
+    }
+    testTransformFunction(transformFunction, expectedUuidValues);
+
+    expression = 
RequestContextUtils.getExpression(String.format("CAST(CAST('%s' AS UUID) AS 
STRING)", UUID_VALUE));
+    transformFunction = TransformFunctionFactory.get(expression, 
_dataSourceMap);
+    String[] expectedStringValues = new String[NUM_ROWS];
+    Arrays.fill(expectedStringValues, UUID_VALUE);
+    testTransformFunction(transformFunction, expectedStringValues);
+
+    expression = 
RequestContextUtils.getExpression(String.format("CAST(CAST('%s' AS UUID) AS 
BYTES)", UUID_VALUE));
+    transformFunction = TransformFunctionFactory.get(expression, 
_dataSourceMap);
+    byte[][] expectedBytesValues = new byte[NUM_ROWS][];
+    for (int i = 0; i < NUM_ROWS; i++) {
+      expectedBytesValues[i] = expectedBytes;
+    }
+    testTransformFunction(transformFunction, expectedBytesValues);
+  }
+
+  @Test
+  public void testCastTransformFunctionUUIDRejectsInvalidLiteral() {
+    ExpressionContext expression = 
RequestContextUtils.getExpression("CAST('not-a-uuid' AS UUID)");
+    TransformFunction transformFunction = 
TransformFunctionFactory.get(expression, _dataSourceMap);
+    assertTrue(transformFunction instanceof CastTransformFunction);
+
+    IllegalArgumentException exception = 
Assert.expectThrows(IllegalArgumentException.class,
+        () -> transformFunction.transformToBytesValuesSV(_projectionBlock));
+    assertTrue(exception.getMessage().contains("Invalid UUID"));
+  }
+
+  @Test
+  public void testCastTransformFunctionUUIDRejectsInvalidBytesLiteral() {
+    ExpressionContext expression = 
RequestContextUtils.getExpression("CAST(CAST('0011' AS BYTES) AS UUID)");
+    TransformFunction transformFunction = 
TransformFunctionFactory.get(expression, _dataSourceMap);
+    assertTrue(transformFunction instanceof CastTransformFunction);
+
+    IllegalArgumentException exception = 
Assert.expectThrows(IllegalArgumentException.class,
+        () -> transformFunction.transformToBytesValuesSV(_projectionBlock));
+    assertTrue(exception.getMessage().contains("Invalid UUID byte length"));
+  }
+
+  @Test
+  public void testCastTransformFunctionUUIDRejectsMVSource() {
+    ExpressionContext expression =
+        RequestContextUtils.getExpression(String.format("CAST(%s AS UUID)", 
STRING_MV_COLUMN));
+    BadQueryRequestException exception = 
Assert.expectThrows(BadQueryRequestException.class,
+        () -> TransformFunctionFactory.get(expression, _dataSourceMap));
+    assertTrue(exception.getMessage().contains("Cannot cast from MV to UUID"));
+  }
 }
diff --git 
a/pinot-spi/src/main/java/org/apache/pinot/spi/utils/ArrayCopyUtils.java 
b/pinot-spi/src/main/java/org/apache/pinot/spi/utils/ArrayCopyUtils.java
index f72808eb3e7..c6acf032f3c 100644
--- a/pinot-spi/src/main/java/org/apache/pinot/spi/utils/ArrayCopyUtils.java
+++ b/pinot-spi/src/main/java/org/apache/pinot/spi/utils/ArrayCopyUtils.java
@@ -276,6 +276,14 @@ public class ArrayCopyUtils {
     }
   }
 
+  /// Parses canonical UUID strings into the 16-byte stored form. Inverse of
+  /// [#copyFromUuid(byte[][], String[], int)].
+  public static void copyToUuid(String[] src, byte[][] dest, int length) {
+    for (int i = 0; i < length; i++) {
+      dest[i] = UuidUtils.toBytes(src[i]);
+    }
+  }
+
   public static void copy(String[][] src, byte[][][] dest, int length) {
     for (int i = 0; i < length; i++) {
       String[] stringValues = src[i];
@@ -286,6 +294,18 @@ public class ArrayCopyUtils {
     }
   }
 
+  /// Multi-value variant of [#copyToUuid(String[], byte[][], int)].
+  public static void copyToUuid(String[][] src, byte[][][] dest, int length) {
+    for (int i = 0; i < length; i++) {
+      int rowLength = src[i].length;
+      byte[][] row = new byte[rowLength][];
+      for (int j = 0; j < rowLength; j++) {
+        row[j] = UuidUtils.toBytes(src[i][j]);
+      }
+      dest[i] = row;
+    }
+  }
+
   public static void copy(byte[][] src, BigDecimal[] dest, int length) {
     for (int i = 0; i < length; i++) {
       dest[i] = BigDecimalUtils.deserialize(src[i]);
@@ -298,6 +318,46 @@ public class ArrayCopyUtils {
     }
   }
 
+  /// Renders UUID values, stored as 16 raw bytes, into their canonical dashed 
form. Mirrors
+  /// [#copyFromTimestamp(long[], String[], int)], which likewise renders a 
logical type from its stored form.
+  public static void copyFromUuid(byte[][] src, String[] dest, int length) {
+    for (int i = 0; i < length; i++) {
+      dest[i] = UuidUtils.toString(src[i]);
+    }
+  }
+
+  /// Normalises UUID values already in byte form, validating the 16-byte 
width. Counterpart of
+  /// [#copyToUuid(String[], byte[][], int)] for a BYTES source.
+  public static void copyToUuid(byte[][] src, byte[][] dest, int length) {
+    for (int i = 0; i < length; i++) {
+      dest[i] = UuidUtils.toBytes(src[i]);
+    }
+  }
+
+  /// Multi-value variant of [#copyFromUuid(byte[][], String[], int)].
+  public static void copyFromUuid(byte[][][] src, String[][] dest, int length) 
{
+    for (int i = 0; i < length; i++) {
+      int rowLength = src[i].length;
+      String[] row = new String[rowLength];
+      for (int j = 0; j < rowLength; j++) {
+        row[j] = UuidUtils.toString(src[i][j]);
+      }
+      dest[i] = row;
+    }
+  }
+
+  /// Multi-value variant of [#copyToUuid(byte[][], byte[][], int)].
+  public static void copyToUuid(byte[][][] src, byte[][][] dest, int length) {
+    for (int i = 0; i < length; i++) {
+      int rowLength = src[i].length;
+      byte[][] row = new byte[rowLength][];
+      for (int j = 0; j < rowLength; j++) {
+        row[j] = UuidUtils.toBytes(src[i][j]);
+      }
+      dest[i] = row;
+    }
+  }
+
   public static void copy(int[][] src, long[][] dest, int length) {
     for (int i = 0; i < length; i++) {
       int rowLength = src[i].length;


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to