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 d424eecb91b Rework UUID type conversion to use java.util.UUID as the
external form (#18927)
d424eecb91b is described below
commit d424eecb91b04051810b2249fab72d7899ec78cb
Author: Xiaotian (Jackie) Jiang <[email protected]>
AuthorDate: Mon Jul 6 22:31:50 2026 -0700
Rework UUID type conversion to use java.util.UUID as the external form
(#18927)
Establish a consistent internal/external representation for the UUID type:
- PinotDataType: java.util.UUID is the external form and byte[] the internal
form. UUID.convert / UUID_ARRAY.convert return UUID / UUID[], while
toInternal
returns byte[] / byte[][]. UUID.convert delegates to sourceType.toUUID,
and
every single-value type now defines toUUID so an unsupported conversion
(e.g.
INT -> UUID) throws a descriptive "Cannot convert value from INT to UUID"
instead of a confusing "There is no single-value type" error. The
JSON->UUID
parsing moves into JSON.toUUID. Removes the now-unused toUuidBytesArray.
- FieldSpec.DataType: UUID values are represented uniformly as byte[],
matching
the BYTES stored type. equals / hashCode / compare / toString drop the
toBytesValue helper and operate on byte[] directly. Adds enum-level
Javadoc
documenting the in-memory value representation per type.
- UuidUtils.toBytes(String) accepts the dashless 32-char hex form in
addition to
the canonical string, so byte[] default null values (stringified as raw
hex)
round-trip back through FieldSpec.getDefaultNullValue.
---
.../java/org/apache/pinot/spi/data/FieldSpec.java | 89 +++++-------
.../org/apache/pinot/spi/utils/PinotDataType.java | 156 ++++++++++++---------
.../java/org/apache/pinot/spi/utils/UuidUtils.java | 13 +-
.../org/apache/pinot/spi/data/FieldSpecTest.java | 22 ++-
.../apache/pinot/spi/utils/PinotDataTypeTest.java | 26 ++--
.../org/apache/pinot/spi/utils/UuidUtilsTest.java | 11 +-
6 files changed, 178 insertions(+), 139 deletions(-)
diff --git a/pinot-spi/src/main/java/org/apache/pinot/spi/data/FieldSpec.java
b/pinot-spi/src/main/java/org/apache/pinot/spi/data/FieldSpec.java
index 511d2674435..c5c3a491f6c 100644
--- a/pinot-spi/src/main/java/org/apache/pinot/spi/data/FieldSpec.java
+++ b/pinot-spi/src/main/java/org/apache/pinot/spi/data/FieldSpec.java
@@ -37,7 +37,6 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
-import java.util.UUID;
import javax.annotation.Nullable;
import org.apache.pinot.spi.utils.BooleanUtils;
import org.apache.pinot.spi.utils.ByteArray;
@@ -419,8 +418,9 @@ public abstract class FieldSpec implements
Comparable<FieldSpec>, Serializable {
return _defaultNullValue;
}
+ @JsonIgnore
public String getDefaultNullValueString() {
- return _dataType != null ? _dataType.toString(_defaultNullValue) :
getStringValue(_defaultNullValue);
+ return _dataType.toString(_defaultNullValue);
}
/// Returns the [String] representation of the given object.
@@ -462,22 +462,13 @@ public abstract class FieldSpec implements
Comparable<FieldSpec>, Serializable {
@JsonIgnore
public void setDefaultNullValue(@Nullable Object defaultNullValue) {
if (defaultNullValue != null) {
- _stringDefaultNullValue = getStringDefaultNullValue(defaultNullValue);
+ _stringDefaultNullValue = getStringValue(defaultNullValue);
}
if (_dataType != null) {
_defaultNullValue = getDefaultNullValue(getFieldType(), _dataType,
_stringDefaultNullValue);
}
}
- // UUID default values must stringify to their canonical 8-4-4-4-12 form
(not raw hex) so they round-trip back
- // through getDefaultNullValue(...); all other types keep the generic
getStringValue() form.
- private String getStringDefaultNullValue(Object defaultNullValue) {
- if (_dataType == DataType.UUID && !(defaultNullValue instanceof String)) {
- return _dataType.toString(defaultNullValue);
- }
- return getStringValue(defaultNullValue);
- }
-
public static Object getDefaultNullValue(FieldType fieldType, DataType
dataType,
@Nullable String stringDefaultNullValue) {
if (stringDefaultNullValue != null) {
@@ -748,9 +739,25 @@ public abstract class FieldSpec implements
Comparable<FieldSpec>, Serializable {
DIMENSION, METRIC, TIME, DATE_TIME, COMPLEX
}
- /**
- * The <code>DataType</code> enum is used to demonstrate the data type of a
field.
- */
+ /// The `DataType` enum represents the data type of a field.
+ ///
+ /// A value of a given type is held in memory as a fixed Java class, and
every value-handling method on this enum
+ /// (`convert`, `equals`, `hashCode`, `compare`, `toString`) expects and
produces that representation:
+ /// - `INT` → [Integer]
+ /// - `LONG` → [Long]
+ /// - `FLOAT` → [Float]
+ /// - `DOUBLE` → [Double]
+ /// - `BIG_DECIMAL` → [BigDecimal]
+ /// - `BOOLEAN` → [Integer] (`0` or `1`)
+ /// - `TIMESTAMP` → [Long] (epoch millis)
+ /// - `STRING` / `JSON` → [String]
+ /// - `BYTES` → `byte[]`
+ /// - `UUID` → `byte[]` (fixed 16-byte big-endian form)
+ /// - `MAP` / `OPEN_STRUCT` → [Map]
+ /// - `LIST` → [List]
+ ///
+ /// `convertInternal` is the exception: it returns the internal storage
form, which for `BYTES` and `UUID` is
+ /// [ByteArray] rather than `byte[]`.
@SuppressWarnings("rawtypes")
public enum DataType {
// LIST is for complex lists which is different from multi-value column of
primitives
@@ -881,23 +888,16 @@ public abstract class FieldSpec implements
Comparable<FieldSpec>, Serializable {
throw new IllegalStateException();
}
} catch (Exception e) {
- throw new IllegalArgumentException(
- "Cannot convert value: '" + value + "' to type: " + this + " (" +
e.getMessage() + ")", e);
+ throw new IllegalArgumentException("Cannot convert value: '" + value +
"' to type: " + this);
}
}
public boolean equals(Object value1, Object value2) {
- if (this == UUID) {
- return UuidUtils.equals(toBytesValue(value1), toBytesValue(value2));
- }
- return this == BYTES ? Arrays.equals(toBytesValue(value1),
toBytesValue(value2)) : value1.equals(value2);
+ return this == BYTES || this == UUID ? Arrays.equals((byte[]) value1,
(byte[]) value2) : value1.equals(value2);
}
public int hashCode(Object value) {
- if (this == UUID) {
- return UuidUtils.hashCode(toBytesValue(value));
- }
- return this == BYTES ? Arrays.hashCode(toBytesValue(value)) :
value.hashCode();
+ return this == BYTES || this == UUID ? Arrays.hashCode((byte[]) value) :
value.hashCode();
}
/**
@@ -910,8 +910,10 @@ public abstract class FieldSpec implements
Comparable<FieldSpec>, Serializable {
public int compare(Object value1, Object value2) {
switch (this) {
case INT:
+ case BOOLEAN:
return Integer.compare((int) value1, (int) value2);
case LONG:
+ case TIMESTAMP:
return Long.compare((long) value1, (long) value2);
case FLOAT:
return Float.compare((float) value1, (float) value2);
@@ -919,17 +921,12 @@ public abstract class FieldSpec implements
Comparable<FieldSpec>, Serializable {
return Double.compare((double) value1, (double) value2);
case BIG_DECIMAL:
return ((BigDecimal) value1).compareTo((BigDecimal) value2);
- case BOOLEAN:
- return Boolean.compare((boolean) value1, (boolean) value2);
- case TIMESTAMP:
- return Long.compare((long) value1, (long) value2);
case STRING:
case JSON:
return ((String) value1).compareTo((String) value2);
case BYTES:
- return ByteArray.compare(toBytesValue(value1), toBytesValue(value2));
case UUID:
- return UuidUtils.compare(toBytesValue(value1), toBytesValue(value2));
+ return ByteArray.compare((byte[]) value1, (byte[]) value2);
case MAP:
case OPEN_STRUCT:
case LIST:
@@ -946,14 +943,11 @@ public abstract class FieldSpec implements
Comparable<FieldSpec>, Serializable {
if (this == BIG_DECIMAL) {
return ((BigDecimal) value).toPlainString();
}
- if (this == UUID) {
- if (value instanceof UUID) {
- return UuidUtils.toString((UUID) value);
- }
- return UuidUtils.toString(toBytesValue(value));
- }
if (this == BYTES) {
- return BytesUtils.toHexString(toBytesValue(value));
+ return BytesUtils.toHexString((byte[]) value);
+ }
+ if (this == UUID) {
+ return UuidUtils.toString((byte[]) value);
}
if (this == MAP || this == OPEN_STRUCT || this == LIST) {
try {
@@ -1000,25 +994,8 @@ public abstract class FieldSpec implements
Comparable<FieldSpec>, Serializable {
throw new IllegalStateException();
}
} catch (Exception e) {
- throw new IllegalArgumentException(
- "Cannot convert value: '" + value + "' to type: " + this + " (" +
e.getMessage() + ")", e);
- }
- }
-
- private byte[] toBytesValue(Object value) {
- if (value instanceof byte[]) {
- return (byte[]) value;
- }
- if (value instanceof ByteArray) {
- return ((ByteArray) value).getBytes();
- }
- if (value instanceof UUID) {
- return UuidUtils.toBytes((UUID) value);
- }
- if (value instanceof String && this == UUID) {
- return UuidUtils.toBytes((String) value);
+ throw new IllegalArgumentException("Cannot convert value: '" + value +
"' to type: " + this);
}
- throw new IllegalArgumentException("Unsupported value for " + this + ":
" + value);
}
}
diff --git
a/pinot-spi/src/main/java/org/apache/pinot/spi/utils/PinotDataType.java
b/pinot-spi/src/main/java/org/apache/pinot/spi/utils/PinotDataType.java
index 15a950000e0..5f987425aa6 100644
--- a/pinot-spi/src/main/java/org/apache/pinot/spi/utils/PinotDataType.java
+++ b/pinot-spi/src/main/java/org/apache/pinot/spi/utils/PinotDataType.java
@@ -112,6 +112,11 @@ public enum PinotDataType {
throw new UnsupportedOperationException("Cannot convert value from
BOOLEAN to BYTES");
}
+ @Override
+ public UUID toUUID(Object value) {
+ throw new UnsupportedOperationException("Cannot convert value from
BOOLEAN to UUID");
+ }
+
@Override
public Boolean convert(Object value, PinotDataType sourceType) {
return sourceType.toBoolean(value);
@@ -168,6 +173,11 @@ public enum PinotDataType {
public byte[] toBytes(Object value) {
throw new UnsupportedOperationException("Cannot convert value from BYTE
to BYTES");
}
+
+ @Override
+ public UUID toUUID(Object value) {
+ throw new UnsupportedOperationException("Cannot convert value from BYTE
to UUID");
+ }
},
CHARACTER {
@@ -215,6 +225,11 @@ public enum PinotDataType {
public byte[] toBytes(Object value) {
throw new UnsupportedOperationException("Cannot convert value from
CHARACTER to BYTES");
}
+
+ @Override
+ public UUID toUUID(Object value) {
+ throw new UnsupportedOperationException("Cannot convert value from
CHARACTER to UUID");
+ }
},
SHORT {
@@ -262,6 +277,11 @@ public enum PinotDataType {
public byte[] toBytes(Object value) {
throw new UnsupportedOperationException("Cannot convert value from SHORT
to BYTES");
}
+
+ @Override
+ public UUID toUUID(Object value) {
+ throw new UnsupportedOperationException("Cannot convert value from SHORT
to UUID");
+ }
},
INT {
@@ -310,6 +330,11 @@ public enum PinotDataType {
throw new UnsupportedOperationException("Cannot convert value from INT
to BYTES");
}
+ @Override
+ public UUID toUUID(Object value) {
+ throw new UnsupportedOperationException("Cannot convert value from INT
to UUID");
+ }
+
@Override
public Integer convert(Object value, PinotDataType sourceType) {
return sourceType.toInt(value);
@@ -365,6 +390,11 @@ public enum PinotDataType {
throw new UnsupportedOperationException("Cannot convert value from LONG
to BYTES");
}
+ @Override
+ public UUID toUUID(Object value) {
+ throw new UnsupportedOperationException("Cannot convert value from LONG
to UUID");
+ }
+
@Override
public Long convert(Object value, PinotDataType sourceType) {
return sourceType.toLong(value);
@@ -419,6 +449,11 @@ public enum PinotDataType {
throw new UnsupportedOperationException("Cannot convert value from FLOAT
to BYTES");
}
+ @Override
+ public UUID toUUID(Object value) {
+ throw new UnsupportedOperationException("Cannot convert value from FLOAT
to UUID");
+ }
+
@Override
public Float convert(Object value, PinotDataType sourceType) {
return sourceType.toFloat(value);
@@ -473,6 +508,11 @@ public enum PinotDataType {
throw new UnsupportedOperationException("Cannot convert value from
DOUBLE to BYTES");
}
+ @Override
+ public UUID toUUID(Object value) {
+ throw new UnsupportedOperationException("Cannot convert value from
DOUBLE to UUID");
+ }
+
@Override
public Double convert(Object value, PinotDataType sourceType) {
return sourceType.toDouble(value);
@@ -525,6 +565,11 @@ public enum PinotDataType {
return BigDecimalUtils.serialize((BigDecimal) value);
}
+ @Override
+ public UUID toUUID(Object value) {
+ throw new UnsupportedOperationException("Cannot convert value from
BIG_DECIMAL to UUID");
+ }
+
@Override
public BigDecimal convert(Object value, PinotDataType sourceType) {
return sourceType.toBigDecimal(value);
@@ -588,6 +633,11 @@ public enum PinotDataType {
throw new UnsupportedOperationException("Cannot convert value from
TIMESTAMP to BYTES");
}
+ @Override
+ public UUID toUUID(Object value) {
+ throw new UnsupportedOperationException("Cannot convert value from
TIMESTAMP to UUID");
+ }
+
@Override
public Timestamp convert(Object value, PinotDataType sourceType) {
return sourceType.toTimestamp(value);
@@ -654,6 +704,11 @@ public enum PinotDataType {
throw new UnsupportedOperationException("Cannot convert value from DATE
to BYTES");
}
+ @Override
+ public UUID toUUID(Object value) {
+ throw new UnsupportedOperationException("Cannot convert value from DATE
to UUID");
+ }
+
@Override
public LocalDate convert(Object value, PinotDataType sourceType) {
switch (sourceType) {
@@ -741,6 +796,11 @@ public enum PinotDataType {
throw new UnsupportedOperationException("Cannot convert value from TIME
to BYTES");
}
+ @Override
+ public UUID toUUID(Object value) {
+ throw new UnsupportedOperationException("Cannot convert value from TIME
to UUID");
+ }
+
@Override
public LocalTime convert(Object value, PinotDataType sourceType) {
switch (sourceType) {
@@ -890,6 +950,17 @@ public enum PinotDataType {
}
}
+ @Override
+ public UUID toUUID(Object value) {
+ // JSON-encoded UUID is a quoted JSON string; Jackson's UUIDDeserializer
handles both the canonical-string form
+ // and 16-byte binary form natively.
+ try {
+ return JsonUtils.stringToObject(value.toString(), UUID.class);
+ } catch (IOException e) {
+ throw new RuntimeException("Cannot parse JSON value as UUID: " +
value, e);
+ }
+ }
+
@Override
public String convert(Object value, PinotDataType sourceType) {
return sourceType.toJson(value);
@@ -944,7 +1015,7 @@ public enum PinotDataType {
@Override
public UUID toUUID(Object value) {
- return UuidUtils.toUUID(value);
+ return UuidUtils.toUUID((byte[]) value);
}
@Override
@@ -1001,52 +1072,22 @@ public enum PinotDataType {
@Override
public String toString(Object value) {
- return UuidUtils.toUUID(value).toString();
+ return value.toString();
}
@Override
public byte[] toBytes(Object value) {
- return UuidUtils.toBytes(value);
+ return UuidUtils.toBytes((UUID) value);
}
@Override
public UUID toUUID(Object value) {
- return UuidUtils.toUUID(value);
+ return (UUID) value;
}
@Override
public UUID convert(Object value, PinotDataType sourceType) {
- switch (sourceType) {
- case UUID:
- return UuidUtils.toUUID(value);
- case STRING:
- return UuidUtils.toUUID(value.toString().trim());
- case JSON:
- try {
- // JSON-encoded UUID is a quoted JSON string; Jackson's
UUIDDeserializer handles both the
- // canonical-string form and 16-byte binary form natively.
- return JsonUtils.stringToObject(value.toString(), UUID.class);
- } catch (IOException e) {
- throw new RuntimeException("Cannot parse JSON value as UUID: " +
value, e);
- }
- case BYTES:
- return UuidUtils.toUUID(value);
- case OBJECT:
- case COLLECTION:
- case UUID_ARRAY:
- case BYTES_ARRAY:
- case STRING_ARRAY:
- case OBJECT_ARRAY:
- // OBJECT, collections and single-element arrays can carry a UUID
(e.g., scalar-function arguments
- // resolved by FunctionInvoker, or an MV source feeding an SV UUID
column); these types have meaningful
- // toUUID implementations.
- return sourceType.toUUID(value);
- default:
- // Numeric and other types have no meaningful UUID interpretation;
fail with an explicit message instead
- // of the confusing "There is no single-value type ..." from the
generic single-value fallback.
- throw new UnsupportedOperationException(
- "Cannot convert value from " + sourceType + " to UUID. Input
value: " + value);
- }
+ return sourceType.toUUID(value);
}
@Override
@@ -1131,6 +1172,11 @@ public enum PinotDataType {
return MapUtils.serializeMap((Map<String, Object>) value);
}
+ @Override
+ public UUID toUUID(Object value) {
+ throw new UnsupportedOperationException("Cannot convert value from MAP
to UUID");
+ }
+
@Override
public Object convert(Object value, PinotDataType sourceType) {
switch (sourceType) {
@@ -1272,7 +1318,7 @@ public enum PinotDataType {
TIMESTAMP_ARRAY {
@Override
- public Object convert(Object value, PinotDataType sourceType) {
+ public Timestamp[] convert(Object value, PinotDataType sourceType) {
return sourceType.toTimestampArray(value);
}
@@ -1342,13 +1388,19 @@ public enum PinotDataType {
UUID_ARRAY {
@Override
- public byte[][] convert(Object value, PinotDataType sourceType) {
- return sourceType.toUuidBytesArray(value);
+ public UUID[] convert(Object value, PinotDataType sourceType) {
+ return sourceType.toUuidArray(value);
}
@Override
public byte[][] toInternal(Object value) {
- return toUuidBytesArray(value);
+ UUID[] uuidArray = (UUID[]) value;
+ int length = uuidArray.length;
+ byte[][] bytesArray = new byte[length][];
+ for (int i = 0; i < length; i++) {
+ bytesArray[i] = UuidUtils.toBytes(uuidArray[i]);
+ }
+ return bytesArray;
}
},
@@ -1707,28 +1759,6 @@ public enum PinotDataType {
}
}
- public byte[][] toUuidBytesArray(Object value) {
- if (value instanceof byte[][]) {
- byte[][] values = (byte[][]) value;
- byte[][] uuidBytes = new byte[values.length][];
- for (int i = 0; i < values.length; i++) {
- uuidBytes[i] = UuidUtils.toBytes(values[i]);
- }
- return uuidBytes;
- }
- if (isSingleValue()) {
- return new byte[][]{UuidUtils.toBytes(value)};
- } else {
- Object[] valueArray = toObjectArray(value);
- int length = valueArray.length;
- byte[][] uuidBytes = new byte[length][];
- for (int i = 0; i < length; i++) {
- uuidBytes[i] = UuidUtils.toBytes(valueArray[i]);
- }
- return uuidBytes;
- }
- }
-
public LocalDate[] toLocalDateArray(Object value) {
if (value instanceof LocalDate[]) {
return (LocalDate[]) value;
@@ -2024,10 +2054,10 @@ public enum PinotDataType {
return JSON;
}
throw new IllegalStateException("There is no multi-value type for
JSON");
- case UUID:
- return fieldSpec.isSingleValueField() ? UUID : UUID_ARRAY;
case BYTES:
return fieldSpec.isSingleValueField() ? BYTES : BYTES_ARRAY;
+ case UUID:
+ return fieldSpec.isSingleValueField() ? UUID : UUID_ARRAY;
case MAP:
if (fieldSpec.isSingleValueField()) {
return MAP;
diff --git a/pinot-spi/src/main/java/org/apache/pinot/spi/utils/UuidUtils.java
b/pinot-spi/src/main/java/org/apache/pinot/spi/utils/UuidUtils.java
index 86365a49d08..2da10eea3d0 100644
--- a/pinot-spi/src/main/java/org/apache/pinot/spi/utils/UuidUtils.java
+++ b/pinot-spi/src/main/java/org/apache/pinot/spi/utils/UuidUtils.java
@@ -32,16 +32,13 @@ public class UuidUtils {
}
public static final int UUID_NUM_BYTES = 16;
- private static final byte[] NULL_UUID_BYTES = new byte[UUID_NUM_BYTES];
// Gregorian-to-Unix offset in 100-nanosecond units. Matches RFC 4122 / RFC
9562.
// This is the count of 100-ns intervals between 1582-10-15T00:00:00Z and
1970-01-01T00:00:00Z.
private static final long GREGORIAN_TO_UNIX_OFFSET_100NS =
0x01b21dd213814000L;
public static byte[] nullUuidBytes() {
- byte[] uuidBytes = new byte[UUID_NUM_BYTES];
- System.arraycopy(NULL_UUID_BYTES, 0, uuidBytes, 0, UUID_NUM_BYTES);
- return uuidBytes;
+ return new byte[UUID_NUM_BYTES];
}
public static byte[] toBytes(long mostSignificantBits, long
leastSignificantBits) {
@@ -60,6 +57,14 @@ public class UuidUtils {
try {
uuid = UUID.fromString(uuidString);
} catch (Exception e) {
+ try {
+ // Try parsing the string as hex-encoded bytes
+ byte[] bytes = BytesUtils.toBytes(uuidString);
+ if (bytes.length == UUID_NUM_BYTES) {
+ return bytes;
+ }
+ } catch (Exception ignore) {
+ }
throw new IllegalArgumentException("Invalid UUID value: '" + uuidString
+ "'", e);
}
String canonical = uuid.toString();
diff --git
a/pinot-spi/src/test/java/org/apache/pinot/spi/data/FieldSpecTest.java
b/pinot-spi/src/test/java/org/apache/pinot/spi/data/FieldSpecTest.java
index fd47f0312dc..b156bb84865 100644
--- a/pinot-spi/src/test/java/org/apache/pinot/spi/data/FieldSpecTest.java
+++ b/pinot-spi/src/test/java/org/apache/pinot/spi/data/FieldSpecTest.java
@@ -227,6 +227,7 @@ public class FieldSpecTest {
@Test
public void testUUIDConversions() {
byte[] uuidBytes = UuidUtils.toBytes(UUID_VALUE);
+ byte[] equalUuidBytes = UuidUtils.toBytes(UUID_VALUE);
byte[] largerUuidBytes = UuidUtils.toBytes(LARGER_UUID_VALUE);
String mixedCaseUuidValue = UUID_VALUE.toUpperCase();
ByteArray uuidInternal = new ByteArray(uuidBytes);
@@ -236,10 +237,9 @@ public class FieldSpecTest {
Assert.assertEquals(UUID.convertInternal(UUID_VALUE), uuidInternal);
Assert.assertEquals(UUID.convertInternal(mixedCaseUuidValue),
uuidInternal);
Assert.assertEquals(UUID.toString(uuidBytes), UUID_VALUE);
- Assert.assertEquals(UUID.toString(uuidInternal), UUID_VALUE);
- Assert.assertTrue(UUID.equals(uuidBytes, uuidInternal));
- Assert.assertEquals(UUID.hashCode(uuidBytes), uuidInternal.hashCode());
- Assert.assertEquals(UUID.compare(uuidBytes, uuidInternal), 0);
+ Assert.assertTrue(UUID.equals(uuidBytes, equalUuidBytes));
+ Assert.assertEquals(UUID.hashCode(uuidBytes),
UUID.hashCode(equalUuidBytes));
+ Assert.assertEquals(UUID.compare(uuidBytes, equalUuidBytes), 0);
Assert.assertTrue(UUID.compare(uuidBytes, largerUuidBytes) < 0);
Assert.assertTrue(UUID.compare(largerUuidBytes, uuidBytes) > 0);
}
@@ -248,7 +248,19 @@ public class FieldSpecTest {
public void testInvalidUUIDConversion() {
IllegalArgumentException exception =
Assert.expectThrows(IllegalArgumentException.class,
() -> UUID.convert("not-a-uuid"));
- assertThat(exception).hasMessageContaining("Invalid UUID");
+ assertThat(exception).hasMessageContaining("Cannot convert value:
'not-a-uuid' to type: UUID");
+ }
+
+ @Test
+ public void testCompare() {
+ // BOOLEAN values are held as Integer (0/1) and TIMESTAMP as Long (epoch
millis), so compare dispatches them
+ // through the INT and LONG cases respectively.
+ Assert.assertTrue(BOOLEAN.compare(0, 1) < 0);
+ Assert.assertTrue(BOOLEAN.compare(1, 0) > 0);
+ Assert.assertEquals(BOOLEAN.compare(1, 1), 0);
+ Assert.assertTrue(TIMESTAMP.compare(1000L, 2000L) < 0);
+ Assert.assertTrue(TIMESTAMP.compare(2000L, 1000L) > 0);
+ Assert.assertEquals(TIMESTAMP.compare(1000L, 1000L), 0);
}
/**
diff --git
a/pinot-spi/src/test/java/org/apache/pinot/spi/utils/PinotDataTypeTest.java
b/pinot-spi/src/test/java/org/apache/pinot/spi/utils/PinotDataTypeTest.java
index fe6f86c1fb0..9d8b65697ca 100644
--- a/pinot-spi/src/test/java/org/apache/pinot/spi/utils/PinotDataTypeTest.java
+++ b/pinot-spi/src/test/java/org/apache/pinot/spi/utils/PinotDataTypeTest.java
@@ -160,14 +160,16 @@ public class PinotDataTypeTest {
{BYTES_ARRAY, BYTES_ARRAY, new byte[][] { "foo".getBytes(UTF_8),
"bar".getBytes(UTF_8) },
new byte[][] { "foo".getBytes(UTF_8), "bar".getBytes(UTF_8) }},
{STRING_ARRAY, UUID_ARRAY, new String[] {UUID_VALUE},
- new byte[][] {UuidUtils.toBytes(UUID_VALUE)}},
+ new java.util.UUID[] {java.util.UUID.fromString(UUID_VALUE)}},
{UUID_ARRAY, UUID_ARRAY, new java.util.UUID[]
{java.util.UUID.fromString(UUID_VALUE)},
- new byte[][] {UuidUtils.toBytes(UUID_VALUE)}},
+ new java.util.UUID[] {java.util.UUID.fromString(UUID_VALUE)}},
{COLLECTION, STRING_ARRAY, Arrays.asList("test1", "test2"), new
String[] {"test1", "test2"}},
- {COLLECTION, UUID_ARRAY, Arrays.asList(UUID_VALUE), new byte[][]
{UuidUtils.toBytes(UUID_VALUE)}},
+ {COLLECTION, UUID_ARRAY, Arrays.asList(UUID_VALUE),
+ new java.util.UUID[] {java.util.UUID.fromString(UUID_VALUE)}},
{COLLECTION, FLOAT_ARRAY, Arrays.asList(1.0f, 2.0f), new Float[]
{1.0f, 2.0f}},
{OBJECT_ARRAY, STRING_ARRAY, new Object[] {"test1", "test2"}, new
String[] {"test1", "test2"}},
- {OBJECT_ARRAY, UUID_ARRAY, new Object[] {UUID_VALUE}, new byte[][]
{UuidUtils.toBytes(UUID_VALUE)}},
+ {OBJECT_ARRAY, UUID_ARRAY, new Object[] {UUID_VALUE},
+ new java.util.UUID[] {java.util.UUID.fromString(UUID_VALUE)}},
{OBJECT_ARRAY, FLOAT_ARRAY, new Object[] {1.0f, 2.0f}, new Float[]
{1.0f, 2.0f}},
};
}
@@ -336,14 +338,18 @@ public class PinotDataTypeTest {
UUID u1 =
java.util.UUID.fromString("550e8400-e29b-41d4-a716-446655440000");
UUID u2 =
java.util.UUID.fromString("00000000-0000-0000-0000-000000000001");
UUID[] uuids = {u1, u2};
- byte[][] convertedBytes = (byte[][]) UUID_ARRAY.convert(uuids, UUID_ARRAY);
- assertEquals(UUID.convert(convertedBytes[0], BYTES), u1);
- assertEquals(UUID.convert(convertedBytes[1], BYTES), u2);
+ UUID[] converted = (UUID[]) UUID_ARRAY.convert(uuids, UUID_ARRAY);
+ assertEquals(converted[0], u1);
+ assertEquals(converted[1], u2);
// STRING_ARRAY → UUID_ARRAY: per-element parse.
- byte[][] convertedStringBytes = (byte[][]) UUID_ARRAY.convert(
+ UUID[] convertedFromStrings = (UUID[]) UUID_ARRAY.convert(
new String[]{"550e8400-e29b-41d4-a716-446655440000",
"00000000-0000-0000-0000-000000000001"}, STRING_ARRAY);
- assertEquals(UUID.convert(convertedStringBytes[0], BYTES), u1);
- assertEquals(UUID.convert(convertedStringBytes[1], BYTES), u2);
+ assertEquals(convertedFromStrings[0], u1);
+ assertEquals(convertedFromStrings[1], u2);
+ // toInternal yields the 16-byte big-endian form per element.
+ byte[][] internal = (byte[][]) UUID_ARRAY.toInternal(uuids);
+ assertEquals(UUID.convert(internal[0], BYTES), u1);
+ assertEquals(UUID.convert(internal[1], BYTES), u2);
// STRING_ARRAY destination: canonical strings.
assertEquals(STRING_ARRAY.convert(uuids, UUID_ARRAY),
new String[]{"550e8400-e29b-41d4-a716-446655440000",
"00000000-0000-0000-0000-000000000001"});
diff --git
a/pinot-spi/src/test/java/org/apache/pinot/spi/utils/UuidUtilsTest.java
b/pinot-spi/src/test/java/org/apache/pinot/spi/utils/UuidUtilsTest.java
index 2ccbfe52f51..731c63bfab5 100644
--- a/pinot-spi/src/test/java/org/apache/pinot/spi/utils/UuidUtilsTest.java
+++ b/pinot-spi/src/test/java/org/apache/pinot/spi/utils/UuidUtilsTest.java
@@ -41,7 +41,6 @@ public class UuidUtilsTest {
{"550e8400-e29b-41d4-a716-44665544000"},
{"550e8400-e29b-41d4-a716-4466554400000"},
{"550e8400-e29b-41d4-a716-44665544000g"},
- {"550e8400e29b41d4a716446655440000"},
{""}
};
}
@@ -72,6 +71,16 @@ public class UuidUtilsTest {
assertTrue(UuidUtils.isUuid(mixedCaseUuid));
}
+ @Test
+ public void testDashlessHexStringRoundTrips() {
+ String hexUuid = "550e8400e29b41d4a716446655440000";
+
+ assertEquals(UuidUtils.toBytes(hexUuid), UuidUtils.toBytes(UUID_VALUE));
+ assertEquals(UuidUtils.toString(UuidUtils.toBytes(hexUuid)), UUID_VALUE);
+ assertEquals(UuidUtils.toUUID(hexUuid), UUID.fromString(UUID_VALUE));
+ assertTrue(UuidUtils.isUuid(hexUuid));
+ }
+
@Test(dataProvider = "invalidUuidStrings")
public void testRejectsInvalidUuidStrings(String invalidUuid) {
Assert.expectThrows(IllegalArgumentException.class, () ->
UuidUtils.toBytes(invalidUuid));
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]