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]