Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -107,15 +107,16 @@ public void init(List<TransformFunction> arguments, Map<String, ColumnContext> 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
Expand Down Expand Up @@ -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) {
Expand All @@ -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]));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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<Integer, Pair<byte[][], RoaringBitmap>> 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++) {
Expand Down Expand Up @@ -872,6 +875,7 @@ protected byte[][] transformToBytesValuesSVUsingValueAndNull(ValueBlock valueBlo
return _bytesValuesSV;
}


Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove it

@Override
public RoaringBitmap getNullBitmap(ValueBlock valueBlock) {
int[] selected = getSelectedArray(valueBlock, true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,15 @@
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;
import org.testng.annotations.Test;

import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotEquals;
import static org.testng.Assert.assertTrue;


public class CaseTransformFunctionTest extends BaseTransformFunctionTest {
Expand Down Expand Up @@ -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]);
Expand Down Expand Up @@ -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
}
Expand All @@ -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);

Expand All @@ -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];
Expand All @@ -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);

Expand Down Expand Up @@ -618,7 +665,7 @@ private void testCaseQueryWithIntResults(List<String> 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);
}
Expand All @@ -628,7 +675,7 @@ private void testCaseQueryWithLongResults(List<String> 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);
}
Expand All @@ -638,7 +685,7 @@ private void testCaseQueryWithFloatResults(List<String> 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);
}
Expand All @@ -648,7 +695,7 @@ private void testCaseQueryWithDoubleResults(List<String> 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);
}
Expand All @@ -658,7 +705,7 @@ private void testCaseQueryWithBigDecimalResults(List<String> 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);
}
Expand All @@ -668,7 +715,7 @@ private void testCaseQueryWithStringResults(List<String> 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);
}
Expand All @@ -678,7 +725,7 @@ private void testCaseQueryWithBytesResults(List<String> 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);
}
Expand All @@ -688,7 +735,7 @@ private void testCaseQueryWithTimestampResults(List<String> 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);
}
Expand Down
Loading
Loading