From 86e8f72de9d41ff0fc256532f5933a19d4b8e449 Mon Sep 17 00:00:00 2001 From: Xiang Fu Date: Thu, 6 Aug 2026 23:18:09 -0700 Subject: [PATCH] [UUID 4c] CASE, IN and comparison transforms over the logical UUID type Add UUID transform regression coverage and stored-byte handling for CASE. - CASE validates bare UUID branches as fixed-width hex and initializes the bytes result buffer for null-aware evaluation; canonical dashed values require CAST(... AS UUID). - IN already uses the BYTES stored path; cover uppercase hex, explicit UUID casts, and rejection of bare canonical strings. - Binary comparisons already dispatch through BYTES stored types; add dictionary/raw regression coverage and improve diagnostics and comparator documentation. Split out of #18872. Prerequisite UUID changes #19181 and #19182 are now on master. --- .../BinaryOperatorTransformFunction.java | 22 ++++-- .../function/CaseTransformFunction.java | 14 ++-- .../BinaryOperatorTransformFunctionTest.java | 30 ++++++++ .../function/CaseTransformFunctionTest.java | 73 +++++++++++++++---- .../function/InTransformFunctionTest.java | 39 ++++++++++ 5 files changed, 154 insertions(+), 24 deletions(-) diff --git a/pinot-core/src/main/java/org/apache/pinot/core/operator/transform/function/BinaryOperatorTransformFunction.java b/pinot-core/src/main/java/org/apache/pinot/core/operator/transform/function/BinaryOperatorTransformFunction.java index 77d0f89c1dc0..f6a2101d43b3 100644 --- a/pinot-core/src/main/java/org/apache/pinot/core/operator/transform/function/BinaryOperatorTransformFunction.java +++ b/pinot-core/src/main/java/org/apache/pinot/core/operator/transform/function/BinaryOperatorTransformFunction.java @@ -107,15 +107,16 @@ public void init(List arguments, Map c _leftTransformFunction = arguments.get(0); _rightTransformFunction = arguments.get(1); DataType leftDataType = _leftTransformFunction.getResultMetadata().getDataType(); + DataType rightDataType = _rightTransformFunction.getResultMetadata().getDataType(); _leftStoredType = leftDataType.getStoredType(); - _rightStoredType = _rightTransformFunction.getResultMetadata().getDataType().getStoredType(); + _rightStoredType = rightDataType.getStoredType(); // Data type check: left and right types should be compatible. if (_leftStoredType == DataType.BYTES || _rightStoredType == DataType.BYTES) { Preconditions.checkState(_leftStoredType == _rightStoredType, String.format( "Unsupported data type for comparison: [Left Transform Function [%s] result type is [%s], Right Transform " - + "Function [%s] result type is [%s]]", _leftTransformFunction.getName(), _leftStoredType, - _rightTransformFunction.getName(), _rightStoredType)); + + "Function [%s] result type is [%s]]", getTransformFunctionDisplayName(_leftTransformFunction), + _leftStoredType, getTransformFunctionDisplayName(_rightTransformFunction), _rightStoredType)); } // Create predicate evaluator when the right side is a literal @@ -689,8 +690,15 @@ private void fillResultBigDecimal(ValueBlock valueBlock, int length) { private IllegalStateException illegalState() { throw new IllegalStateException(String.format( "Unsupported data type for comparison: [Left Transform Function [%s] result type is [%s], Right " - + "Transform Function [%s] result type is [%s]]", _leftTransformFunction.getName(), _leftStoredType, - _rightTransformFunction.getName(), _rightStoredType)); + + "Transform Function [%s] result type is [%s]]", getTransformFunctionDisplayName(_leftTransformFunction), + _leftStoredType, getTransformFunctionDisplayName(_rightTransformFunction), _rightStoredType)); + } + + private static String getTransformFunctionDisplayName(TransformFunction transformFunction) { + if (transformFunction instanceof IdentifierTransformFunction) { + return ((IdentifierTransformFunction) transformFunction).getColumnName(); + } + return transformFunction.getName(); } private void fillResultString(ValueBlock valueBlock, int length) { @@ -704,8 +712,10 @@ private void fillResultString(ValueBlock valueBlock, int length) { private void fillResultBytes(ValueBlock valueBlock, int length) { byte[][] leftBytesValues = _leftTransformFunction.transformToBytesValuesSV(valueBlock); byte[][] rightBytesValues = _rightTransformFunction.transformToBytesValuesSV(valueBlock); + // ByteArray.compare is unsigned byte-wise lexicographic; for canonical 16-byte big-endian UUIDs this is + // equivalent to UuidUtils.compare's unsigned 64-bit-word ordering, so a single comparator handles both. for (int i = 0; i < length; i++) { - _intValuesSV[i] = getIntResult((ByteArray.compare(leftBytesValues[i], rightBytesValues[i]))); + _intValuesSV[i] = getIntResult(ByteArray.compare(leftBytesValues[i], rightBytesValues[i])); } } diff --git a/pinot-core/src/main/java/org/apache/pinot/core/operator/transform/function/CaseTransformFunction.java b/pinot-core/src/main/java/org/apache/pinot/core/operator/transform/function/CaseTransformFunction.java index eac10def968b..0822ddd18064 100644 --- a/pinot-core/src/main/java/org/apache/pinot/core/operator/transform/function/CaseTransformFunction.java +++ b/pinot-core/src/main/java/org/apache/pinot/core/operator/transform/function/CaseTransformFunction.java @@ -207,10 +207,12 @@ private void checkLiteral(DataType dataType, String literal) { case JSON: break; case BYTES: + case UUID: try { - BytesUtils.toBytes(literal); + byte[] bytes = BytesUtils.toBytes(literal); + Preconditions.checkArgument(dataType != DataType.UUID || bytes.length == dataType.size()); } catch (Exception e) { - throw new IllegalArgumentException("Invalid literal: " + literal + " for BYTES"); + throw new IllegalArgumentException("Invalid literal: " + literal + " for " + dataType); } break; default: @@ -827,15 +829,16 @@ protected byte[][] transformToBytesValuesSVUsingValueAndNull(ValueBlock valueBlo final RoaringBitmap bitmap = new RoaringBitmap(); int[] selected = getSelectedArray(valueBlock, true); int numDocs = valueBlock.getNumDocs(); - initStringValuesSV(numDocs); + initBytesValuesSV(numDocs); int numThenStatements = _thenStatements.size(); BitSet unselectedDocs = new BitSet(); unselectedDocs.set(0, numDocs); Map> thenStatementsIndexToValues = new HashMap<>(); for (int i = 0; i < numThenStatements; i++) { if (_computeThenStatements[i]) { - thenStatementsIndexToValues.put(i, ImmutablePair.of(_thenStatements.get(i).transformToBytesValuesSV(valueBlock), - _thenStatements.get(i).getNullBitmap(valueBlock))); + thenStatementsIndexToValues.put(i, + ImmutablePair.of(_thenStatements.get(i).transformToBytesValuesSV(valueBlock), + _thenStatements.get(i).getNullBitmap(valueBlock))); } } for (int docId = 0; docId < numDocs; docId++) { @@ -872,6 +875,7 @@ protected byte[][] transformToBytesValuesSVUsingValueAndNull(ValueBlock valueBlo return _bytesValuesSV; } + @Override public RoaringBitmap getNullBitmap(ValueBlock valueBlock) { int[] selected = getSelectedArray(valueBlock, true); diff --git a/pinot-core/src/test/java/org/apache/pinot/core/operator/transform/function/BinaryOperatorTransformFunctionTest.java b/pinot-core/src/test/java/org/apache/pinot/core/operator/transform/function/BinaryOperatorTransformFunctionTest.java index fa32ced888a1..8ddfa1d6db11 100644 --- a/pinot-core/src/test/java/org/apache/pinot/core/operator/transform/function/BinaryOperatorTransformFunctionTest.java +++ b/pinot-core/src/test/java/org/apache/pinot/core/operator/transform/function/BinaryOperatorTransformFunctionTest.java @@ -23,6 +23,7 @@ import org.apache.pinot.core.operator.transform.TransformResultMetadata; import org.apache.pinot.spi.data.FieldSpec.DataType; import org.apache.pinot.spi.exception.BadQueryRequestException; +import org.apache.pinot.spi.utils.UuidUtils; import org.roaringbitmap.RoaringBitmap; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; @@ -256,6 +257,35 @@ public void testBinaryOperatorTransformFunctionNoDict() { testTransformFunctionWithNull(transformFunction, expectedValues, bitmap); } + @Test + public void testBinaryOperatorTransformFunctionUUID() { + String functionName = getFunctionName(); + String uuidLiteral = UuidUtils.toString(_uuidSVValues[0]); + ExpressionContext expression = RequestContextUtils.getExpression( + String.format("%s(%s, CAST('%s' AS UUID))", functionName, UUID_SV_COLUMN, uuidLiteral)); + TransformFunction transformFunction = TransformFunctionFactory.get(expression, _dataSourceMap); + boolean[] expectedValues = new boolean[NUM_ROWS]; + for (int i = 0; i < NUM_ROWS; i++) { + expectedValues[i] = getExpectedValue(UuidUtils.compare(_uuidSVValues[i], _uuidSVValues[0])); + } + testTransformFunction(transformFunction, expectedValues); + } + + @Test + public void testBinaryOperatorTransformFunctionUUIDNoDict() { + String functionName = getFunctionName(); + String uuidLiteral = UuidUtils.toString(_uuidSVValues[0]); + ExpressionContext expression = RequestContextUtils.getExpression( + String.format("%s(CAST(CAST(%s AS STRING) AS UUID), CAST('%s' AS UUID))", functionName, UUID_SV_COLUMN, + uuidLiteral)); + TransformFunction transformFunction = TransformFunctionFactory.get(expression, _dataSourceMap); + boolean[] expectedValues = new boolean[NUM_ROWS]; + for (int i = 0; i < NUM_ROWS; i++) { + expectedValues[i] = getExpectedValue(UuidUtils.compare(_uuidSVValues[i], _uuidSVValues[0])); + } + testTransformFunction(transformFunction, expectedValues); + } + @Test(dataProvider = "testIllegalArguments", expectedExceptions = {BadQueryRequestException.class}) public void testIllegalArguments(String expressionStr) { ExpressionContext expression = RequestContextUtils.getExpression(expressionStr); diff --git a/pinot-core/src/test/java/org/apache/pinot/core/operator/transform/function/CaseTransformFunctionTest.java b/pinot-core/src/test/java/org/apache/pinot/core/operator/transform/function/CaseTransformFunctionTest.java index f7acf5ff1be2..47c83ad48d37 100644 --- a/pinot-core/src/test/java/org/apache/pinot/core/operator/transform/function/CaseTransformFunctionTest.java +++ b/pinot-core/src/test/java/org/apache/pinot/core/operator/transform/function/CaseTransformFunctionTest.java @@ -29,6 +29,7 @@ import org.apache.pinot.common.request.context.RequestContextUtils; import org.apache.pinot.spi.data.FieldSpec.DataType; import org.apache.pinot.spi.utils.BytesUtils; +import org.apache.pinot.spi.utils.UuidUtils; import org.roaringbitmap.RoaringBitmap; import org.testng.Assert; import org.testng.annotations.DataProvider; @@ -36,6 +37,7 @@ import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNotEquals; +import static org.testng.Assert.assertTrue; public class CaseTransformFunctionTest extends BaseTransformFunctionTest { @@ -137,7 +139,7 @@ public void testCaseTransformFunctionWithoutCastForFloatValues() { String expression = String.format("CASE WHEN %s THEN %s ELSE 10 END", predicate, INT_SV_COLUMN); ExpressionContext expressionContext = RequestContextUtils.getExpression(expression); TransformFunction transformFunction = TransformFunctionFactory.get(expressionContext, _dataSourceMap); - Assert.assertTrue(transformFunction instanceof CaseTransformFunction); + assertTrue(transformFunction instanceof CaseTransformFunction); assertEquals(transformFunction.getResultMetadata().getDataType(), DataType.INT); int[] intValues = transformFunction.transformToIntValuesSV(_projectionBlock); assertNotEquals(intValues[index], expectedValues[0]); @@ -167,7 +169,14 @@ public static String[] illegalExpressions() { String.format("CASE WHEN true THEN %s ELSE %s END", INT_SV_COLUMN, BYTES_SV_COLUMN), String.format("CASE WHEN true THEN 100 ELSE %s END", TIMESTAMP_COLUMN), String.format("CASE WHEN true THEN 100 ELSE %s END", STRING_SV_COLUMN), - String.format("CASE WHEN true THEN 100 ELSE %s END", BYTES_SV_COLUMN) + String.format("CASE WHEN true THEN 100 ELSE %s END", BYTES_SV_COLUMN), + "CASE WHEN true THEN CAST('550e8400-e29b-41d4-a716-446655440000' AS UUID) ELSE 'not-a-uuid' END", + "CASE WHEN true THEN CAST('550e8400-e29b-41d4-a716-446655440000' AS UUID) " + + "ELSE '550e8400-e29b-41d4-a716-446655440001' END", + String.format("CASE WHEN true THEN CAST('550e8400-e29b-41d4-a716-446655440000' AS UUID) ELSE '%s' END", + "00".repeat(15)), + String.format("CASE WHEN true THEN CAST('550e8400-e29b-41d4-a716-446655440000' AS UUID) ELSE '%s' END", + "00".repeat(17)) }; //@formatter:on } @@ -177,12 +186,50 @@ public void testInvalidCaseTransformFunction(String expression) { TransformFunctionFactory.get(RequestContextUtils.getExpression(expression), _dataSourceMap); } + @Test + public void testCaseTransformFunctionWithUuidResults() { + String uuidValue = "550e8400-e29b-41d4-a716-446655440000"; + byte[] uuidBytes = UuidUtils.toBytes(uuidValue); + ExpressionContext expression = RequestContextUtils.getExpression( + "CASE WHEN true THEN CAST('" + uuidValue.toUpperCase() + "' AS UUID) ELSE '" + + BytesUtils.toHexString(uuidBytes) + "' END"); + TransformFunction transformFunction = TransformFunctionFactory.get(expression, _dataSourceMap); + assertTrue(transformFunction instanceof CaseTransformFunction); + assertEquals(transformFunction.getResultMetadata().getDataType(), DataType.UUID); + byte[][] expectedValues = new byte[NUM_ROWS][]; + for (int i = 0; i < NUM_ROWS; i++) { + expectedValues[i] = uuidBytes; + } + testTransformFunction(transformFunction, expectedValues); + } + + @Test + public void testCaseTransformFunctionWithUuidHexLiteralBranch() { + String whenUuidValue = "550e8400-e29b-41d4-a716-446655440000"; + String elseUuidValue = "550e8400-e29b-41d4-a716-446655440001"; + byte[] whenUuidBytes = UuidUtils.toBytes(whenUuidValue); + byte[] elseUuidBytes = UuidUtils.toBytes(elseUuidValue); + ExpressionContext expression = RequestContextUtils.getExpression( + String.format("CASE WHEN %s < 2 THEN '%s' ELSE CAST('%s' AS UUID) END", INT_SV_COLUMN, + BytesUtils.toHexString(whenUuidBytes).toUpperCase(), elseUuidValue)); + TransformFunction transformFunction = TransformFunctionFactory.get(expression, _dataSourceMap); + assertTrue(transformFunction instanceof CaseTransformFunction); + assertEquals(transformFunction.getResultMetadata().getDataType(), DataType.UUID); + + byte[][] expectedValues = new byte[NUM_ROWS][]; + for (int i = 0; i < NUM_ROWS; i++) { + expectedValues[i] = _intSVValues[i] < 2 ? whenUuidBytes : elseUuidBytes; + } + testTransformFunction(transformFunction, expectedValues); + } + + @Test public void testCaseTransformationWithNullColumn() { ExpressionContext expression = RequestContextUtils.getExpression( String.format("CASE WHEN %s IS NULL THEN 'aaa' ELSE 'bbb' END", STRING_ALPHANUM_NULL_SV_COLUMN)); TransformFunction transformFunction = TransformFunctionFactory.getNullHandlingEnabled(expression, _dataSourceMap); - Assert.assertTrue(transformFunction instanceof CaseTransformFunction); + assertTrue(transformFunction instanceof CaseTransformFunction); Assert.assertEquals(transformFunction.getName(), "case"); Assert.assertEquals(transformFunction.getResultMetadata().getDataType(), DataType.STRING); @@ -202,7 +249,7 @@ public void testCaseTransformationWithNullThenClause() { ExpressionContext expression = RequestContextUtils.getExpression( String.format("CASE WHEN %s IS NULL THEN NULL ELSE 'bbb' END", STRING_ALPHANUM_NULL_SV_COLUMN)); TransformFunction transformFunction = TransformFunctionFactory.getNullHandlingEnabled(expression, _dataSourceMap); - Assert.assertTrue(transformFunction instanceof CaseTransformFunction); + assertTrue(transformFunction instanceof CaseTransformFunction); Assert.assertEquals(transformFunction.getName(), "case"); Assert.assertEquals(transformFunction.getResultMetadata().getDataType(), DataType.STRING); String[] expectedValues = new String[NUM_ROWS]; @@ -222,7 +269,7 @@ public void testCaseTransformationWithNullElseClause() { ExpressionContext expression = RequestContextUtils.getExpression( String.format("CASE WHEN %s IS NULL THEN 'aaa' END", STRING_ALPHANUM_NULL_SV_COLUMN)); TransformFunction transformFunction = TransformFunctionFactory.getNullHandlingEnabled(expression, _dataSourceMap); - Assert.assertTrue(transformFunction instanceof CaseTransformFunction); + assertTrue(transformFunction instanceof CaseTransformFunction); Assert.assertEquals(transformFunction.getName(), "case"); Assert.assertEquals(transformFunction.getResultMetadata().getDataType(), DataType.STRING); @@ -618,7 +665,7 @@ private void testCaseQueryWithIntResults(List expressions, int[] expecte for (String expression : expressions) { ExpressionContext expressionContext = RequestContextUtils.getExpression(expression); TransformFunction transformFunction = TransformFunctionFactory.get(expressionContext, _dataSourceMap); - Assert.assertTrue(transformFunction instanceof CaseTransformFunction); + assertTrue(transformFunction instanceof CaseTransformFunction); assertEquals(transformFunction.getResultMetadata().getDataType(), DataType.INT); testTransformFunction(transformFunction, expectedValues); } @@ -628,7 +675,7 @@ private void testCaseQueryWithLongResults(List expressions, long[] expec for (String expression : expressions) { ExpressionContext expressionContext = RequestContextUtils.getExpression(expression); TransformFunction transformFunction = TransformFunctionFactory.get(expressionContext, _dataSourceMap); - Assert.assertTrue(transformFunction instanceof CaseTransformFunction); + assertTrue(transformFunction instanceof CaseTransformFunction); assertEquals(transformFunction.getResultMetadata().getDataType(), DataType.LONG); testTransformFunction(transformFunction, expectedValues); } @@ -638,7 +685,7 @@ private void testCaseQueryWithFloatResults(List expressions, float[] exp for (String expression : expressions) { ExpressionContext expressionContext = RequestContextUtils.getExpression(expression); TransformFunction transformFunction = TransformFunctionFactory.get(expressionContext, _dataSourceMap); - Assert.assertTrue(transformFunction instanceof CaseTransformFunction); + assertTrue(transformFunction instanceof CaseTransformFunction); assertEquals(transformFunction.getResultMetadata().getDataType(), DataType.FLOAT); testTransformFunction(transformFunction, expectedValues); } @@ -648,7 +695,7 @@ private void testCaseQueryWithDoubleResults(List expressions, double[] e for (String expression : expressions) { ExpressionContext expressionContext = RequestContextUtils.getExpression(expression); TransformFunction transformFunction = TransformFunctionFactory.get(expressionContext, _dataSourceMap); - Assert.assertTrue(transformFunction instanceof CaseTransformFunction); + assertTrue(transformFunction instanceof CaseTransformFunction); assertEquals(transformFunction.getResultMetadata().getDataType(), DataType.DOUBLE); testTransformFunction(transformFunction, expectedValues); } @@ -658,7 +705,7 @@ private void testCaseQueryWithBigDecimalResults(List expressions, BigDec for (String expression : expressions) { ExpressionContext expressionContext = RequestContextUtils.getExpression(expression); TransformFunction transformFunction = TransformFunctionFactory.get(expressionContext, _dataSourceMap); - Assert.assertTrue(transformFunction instanceof CaseTransformFunction); + assertTrue(transformFunction instanceof CaseTransformFunction); assertEquals(transformFunction.getResultMetadata().getDataType(), DataType.BIG_DECIMAL); testTransformFunction(transformFunction, expectedValues); } @@ -668,7 +715,7 @@ private void testCaseQueryWithStringResults(List expressions, String[] e for (String expression : expressions) { ExpressionContext expressionContext = RequestContextUtils.getExpression(expression); TransformFunction transformFunction = TransformFunctionFactory.get(expressionContext, _dataSourceMap); - Assert.assertTrue(transformFunction instanceof CaseTransformFunction); + assertTrue(transformFunction instanceof CaseTransformFunction); assertEquals(transformFunction.getResultMetadata().getDataType(), DataType.STRING); testTransformFunction(transformFunction, expectedValues); } @@ -678,7 +725,7 @@ private void testCaseQueryWithBytesResults(List expressions, byte[][] ex for (String expression : expressions) { ExpressionContext expressionContext = RequestContextUtils.getExpression(expression); TransformFunction transformFunction = TransformFunctionFactory.get(expressionContext, _dataSourceMap); - Assert.assertTrue(transformFunction instanceof CaseTransformFunction); + assertTrue(transformFunction instanceof CaseTransformFunction); assertEquals(transformFunction.getResultMetadata().getDataType(), DataType.BYTES); testTransformFunction(transformFunction, expectedValues); } @@ -688,7 +735,7 @@ private void testCaseQueryWithTimestampResults(List expressions, long[] for (String expression : expressions) { ExpressionContext expressionContext = RequestContextUtils.getExpression(expression); TransformFunction transformFunction = TransformFunctionFactory.get(expressionContext, _dataSourceMap); - Assert.assertTrue(transformFunction instanceof CaseTransformFunction); + assertTrue(transformFunction instanceof CaseTransformFunction); assertEquals(transformFunction.getResultMetadata().getDataType(), DataType.TIMESTAMP); testTransformFunction(transformFunction, expectedValues); } diff --git a/pinot-core/src/test/java/org/apache/pinot/core/operator/transform/function/InTransformFunctionTest.java b/pinot-core/src/test/java/org/apache/pinot/core/operator/transform/function/InTransformFunctionTest.java index 983758c3fc2f..2c8176a4a65c 100644 --- a/pinot-core/src/test/java/org/apache/pinot/core/operator/transform/function/InTransformFunctionTest.java +++ b/pinot-core/src/test/java/org/apache/pinot/core/operator/transform/function/InTransformFunctionTest.java @@ -20,15 +20,19 @@ import com.google.common.collect.Sets; import java.util.Arrays; +import java.util.Locale; import java.util.Set; import java.util.stream.Collectors; import org.apache.pinot.common.function.TransformFunctionType; import org.apache.pinot.common.request.context.ExpressionContext; import org.apache.pinot.common.request.context.RequestContextUtils; +import org.apache.pinot.spi.exception.BadQueryRequestException; import org.apache.pinot.spi.utils.ByteArray; 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; +import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import static org.testng.Assert.assertEquals; @@ -223,6 +227,41 @@ public void testBytesInTransformFunction() { } } + @Test(dataProvider = "uuidInExpressions") + public void testUuidInTransformFunction(String expressionStr) { + ExpressionContext expression = RequestContextUtils.getExpression(expressionStr); + TransformFunction transformFunction = TransformFunctionFactory.get(expression, _dataSourceMap); + assertTrue(transformFunction instanceof InTransformFunction); + assertEquals(transformFunction.getName(), TransformFunctionType.IN.getName()); + + Set inValues = Sets.newHashSet(new ByteArray(_uuidSVValues[2]), new ByteArray(_uuidSVValues[5])); + int[] intValues = transformFunction.transformToIntValuesSV(_projectionBlock); + for (int i = 0; i < NUM_ROWS; i++) { + if (i == 2 || i == 5) { + assertEquals(intValues[i], 1); + } + assertEquals(intValues[i], inValues.contains(new ByteArray(_uuidSVValues[i])) ? 1 : 0); + } + } + + @DataProvider(name = "uuidInExpressions") + public Object[][] uuidInExpressions() { + return new Object[][]{ + {String.format("%s IN ('%s','%s')", UUID_SV_COLUMN, + BytesUtils.toHexString(_uuidSVValues[5]).toUpperCase(Locale.ROOT), + BytesUtils.toHexString(_uuidSVValues[2]))}, + {String.format("%s IN (CAST('%s' AS UUID),CAST('%s' AS UUID))", UUID_SV_COLUMN, + UuidUtils.toString(_uuidSVValues[5]).toUpperCase(Locale.ROOT), UuidUtils.toString(_uuidSVValues[2]))} + }; + } + + @Test(expectedExceptions = BadQueryRequestException.class) + public void testUuidInTransformFunctionRejectsBareCanonicalLiteral() { + ExpressionContext expression = RequestContextUtils.getExpression( + String.format("%s IN ('%s')", UUID_SV_COLUMN, UuidUtils.toString(_uuidSVValues[5]))); + TransformFunctionFactory.get(expression, _dataSourceMap); + } + @Test public void testInTransformFunctionNullLiteralReturnsNull() { String expressionStr = String.format("%s IN (%s)", "NULL", INT_SV_NULL_COLUMN);