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 d3604a585db Render UUID casts as canonical strings (#19165)
d3604a585db is described below
commit d3604a585db46dcf75691887b9e9d3c7f91721d9
Author: Xiang Fu <[email protected]>
AuthorDate: Thu Aug 6 10:33:08 2026 -0700
Render UUID casts as canonical strings (#19165)
* Render UUID casts as canonical strings
* Add UUID to STRING cast coverage
* Harden UUID to STRING casts
* Use consistent UUID cast case scoping
* Simplify UUID cast handling
---------
Co-authored-by: Xiang Fu <[email protected]>
---
.../scalar/DataTypeConversionFunctionsTest.java | 3 +
.../transform/function/CastTransformFunction.java | 33 ++++++++++
.../function/CastTransformFunctionTest.java | 74 ++++++++++++++++++++++
3 files changed, 110 insertions(+)
diff --git
a/pinot-common/src/test/java/org/apache/pinot/common/function/scalar/DataTypeConversionFunctionsTest.java
b/pinot-common/src/test/java/org/apache/pinot/common/function/scalar/DataTypeConversionFunctionsTest.java
index 025e5fa2137..db17f924aa5 100644
---
a/pinot-common/src/test/java/org/apache/pinot/common/function/scalar/DataTypeConversionFunctionsTest.java
+++
b/pinot-common/src/test/java/org/apache/pinot/common/function/scalar/DataTypeConversionFunctionsTest.java
@@ -18,6 +18,7 @@
*/
package org.apache.pinot.common.function.scalar;
+import java.util.UUID;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
@@ -54,6 +55,8 @@ public class DataTypeConversionFunctionsTest {
{10, "long", 10L},
{10D, "float", 10F},
{10F, "double", 10D},
+ {UUID.fromString("550e8400-e29b-41d4-a716-446655440000"), "string",
+ "550e8400-e29b-41d4-a716-446655440000"},
{"abc1", "bytes", new byte[]{(byte) 0xab, (byte) 0xc1}},
{new byte[]{(byte) 0xab, (byte) 0xc1}, "string", "abc1"}
};
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 6d61c1c99ef..efef5b2b65c 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
@@ -28,6 +28,7 @@ import
org.apache.pinot.core.operator.transform.TransformResultMetadata;
import org.apache.pinot.spi.data.FieldSpec.DataType;
import org.apache.pinot.spi.utils.ArrayCopyUtils;
import org.apache.pinot.spi.utils.TimestampUtils;
+import org.apache.pinot.spi.utils.UuidUtils;
import org.roaringbitmap.RoaringBitmap;
@@ -261,6 +262,24 @@ public class CastTransformFunction extends
BaseTransformFunction {
ArrayCopyUtils.copyFromTimestamp(longValues, _stringValuesSV,
length);
return _stringValuesSV;
}
+ case UUID: {
+ int length = valueBlock.getNumDocs();
+ initStringValuesSV(length);
+ byte[][] uuidValues =
_transformFunction.transformToBytesValuesSV(valueBlock);
+ RoaringBitmap nullBitmap =
_transformFunction.getNullBitmap(valueBlock);
+ if (_nullHandlingEnabled && nullBitmap != null &&
!nullBitmap.isEmpty()) {
+ RoaringBitmapUtils.forEachUnset(length,
nullBitmap.getIntIterator(), (from, to) -> {
+ for (int i = from; i < to; i++) {
+ _stringValuesSV[i] = UuidUtils.toString(uuidValues[i]);
+ }
+ });
+ } else {
+ for (int i = 0; i < length; i++) {
+ _stringValuesSV[i] = UuidUtils.toString(uuidValues[i]);
+ }
+ }
+ return _stringValuesSV;
+ }
default:
return _transformFunction.transformToStringValuesSV(valueBlock);
}
@@ -423,6 +442,20 @@ public class CastTransformFunction extends
BaseTransformFunction {
long[][] longValuesMV =
_transformFunction.transformToLongValuesMV(valueBlock);
ArrayCopyUtils.copyFromTimestamp(longValuesMV, _stringValuesMV,
length);
return _stringValuesMV;
+ case UUID: {
+ length = valueBlock.getNumDocs();
+ initStringValuesMV(length);
+ byte[][][] uuidValuesMV =
_transformFunction.transformToBytesValuesMV(valueBlock);
+ for (int i = 0; i < length; i++) {
+ int numValues = uuidValuesMV[i].length;
+ String[] stringValues = new String[numValues];
+ for (int j = 0; j < numValues; j++) {
+ stringValues[j] = UuidUtils.toString(uuidValuesMV[i][j]);
+ }
+ _stringValuesMV[i] = stringValues;
+ }
+ return _stringValuesMV;
+ }
default:
return _transformFunction.transformToStringValuesMV(valueBlock);
}
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 7ae8af7b713..db5fc9d0cfe 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
@@ -21,20 +21,94 @@ package org.apache.pinot.core.operator.transform.function;
import java.math.BigDecimal;
import java.sql.Timestamp;
import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
import org.apache.pinot.common.request.context.ExpressionContext;
+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.utils.ArrayCopyUtils;
+import org.apache.pinot.spi.utils.CommonConstants.NullValuePlaceHolder;
+import org.apache.pinot.spi.utils.UuidUtils;
import org.roaringbitmap.RoaringBitmap;
import org.testng.Assert;
import org.testng.annotations.Test;
import static
org.apache.pinot.common.function.scalar.DataTypeConversionFunctions.cast;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
public class CastTransformFunctionTest extends BaseTransformFunctionTest {
+ @Test
+ public void testCastUuidToString() {
+ String uuid = "550e8400-e29b-41d4-a716-446655440000";
+ ExpressionContext expression =
RequestContextUtils.getExpression("CAST(toUuid('" + uuid + "') AS STRING)");
+ TransformFunction transformFunction =
TransformFunctionFactory.get(expression, _dataSourceMap);
+
+ String[] expectedValues = new String[NUM_ROWS];
+ Arrays.fill(expectedValues, uuid);
+ testTransformFunction(transformFunction, expectedValues);
+ }
+
+ @Test
+ public void testCastNullableUuidToString() {
+ String uuid = "550e8400-e29b-41d4-a716-446655440000";
+ byte[][] uuidValues = new byte[NUM_ROWS][];
+ String[] expectedValues = new String[NUM_ROWS];
+ RoaringBitmap nullBitmap = new RoaringBitmap();
+ for (int i = 0; i < NUM_ROWS; i++) {
+ if (isNullRow(i)) {
+ uuidValues[i] = NullValuePlaceHolder.BYTES;
+ nullBitmap.add(i);
+ } else {
+ uuidValues[i] = UuidUtils.toBytes(uuid);
+ expectedValues[i] = uuid;
+ }
+ }
+
+ TransformFunction uuidTransformFunction = mock(TransformFunction.class);
+ when(uuidTransformFunction.getResultMetadata())
+ .thenReturn(new TransformResultMetadata(FieldSpec.DataType.UUID, true,
false));
+
when(uuidTransformFunction.transformToBytesValuesSV(_projectionBlock)).thenReturn(uuidValues);
+
when(uuidTransformFunction.getNullBitmap(_projectionBlock)).thenReturn(nullBitmap);
+
+ CastTransformFunction castTransformFunction =
createUuidCastFunction(uuidTransformFunction, true);
+ testTransformFunctionWithNull(castTransformFunction, expectedValues,
nullBitmap);
+ }
+
+ @Test
+ public void testCastUuidMvToString() {
+ String firstUuid = "550e8400-e29b-41d4-a716-446655440000";
+ String secondUuid = "123e4567-e89b-12d3-a456-426614174000";
+ byte[][][] uuidValues = new byte[NUM_ROWS][][];
+ String[][] expectedValues = new String[NUM_ROWS][];
+ for (int i = 0; i < NUM_ROWS; i++) {
+ uuidValues[i] = new byte[][]{UuidUtils.toBytes(firstUuid),
UuidUtils.toBytes(secondUuid)};
+ expectedValues[i] = new String[]{firstUuid, secondUuid};
+ }
+
+ TransformFunction uuidTransformFunction = mock(TransformFunction.class);
+ when(uuidTransformFunction.getResultMetadata())
+ .thenReturn(new TransformResultMetadata(FieldSpec.DataType.UUID,
false, false));
+
when(uuidTransformFunction.transformToBytesValuesMV(_projectionBlock)).thenReturn(uuidValues);
+
+ CastTransformFunction castTransformFunction =
createUuidCastFunction(uuidTransformFunction, false);
+ testTransformFunctionMV(castTransformFunction, expectedValues);
+ }
+
+ private static CastTransformFunction
createUuidCastFunction(TransformFunction uuidTransformFunction,
+ boolean nullHandlingEnabled) {
+ CastTransformFunction castTransformFunction = new CastTransformFunction();
+ LiteralTransformFunction targetType =
+ new LiteralTransformFunction(new
LiteralContext(FieldSpec.DataType.STRING, "STRING"));
+ castTransformFunction.init(List.of(uuidTransformFunction, targetType),
Map.of(), nullHandlingEnabled);
+ return castTransformFunction;
+ }
+
@Test
public void testCastTransformFunction() {
ExpressionContext expression =
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]