diegs opened a new issue, #13197:
URL: https://github.com/apache/pinot/issues/13197

   We discovered this issue with transformation functions for realtime tables. 
We have a transform function like the following:
   
   ```
   case when length(columnName) = 64 then 
bytesToBigDecimal(hexToBytes(concat('0000', columnName))) else 
bytesToBigDecimal(hexToBytes(concat('000000', columnName))) end
   ```
   
   The goal of this function is to convert a variable-length signed 256-bit 
integer, represented in hex, to a BigDecimal. The bytesToBigDecimal expects a 
twos-complement value (with the two byte "scale" prepended, here we always use 
`0000`). So we need to special case: if the number is 32 bytes (64 hex 
characters), then we assume that it is correctly twos complement and only 
prepend `0000` for the scale. Otherwise, we prepend an extra padding byte of 
`00` to ensure that the hex is interpreted as a positive twos complement value.
   
   The issue: due to an issue the upstream was emitting an empty hex string 
instead of `00` for `columnName` to represent zero. We would expect this not to 
affect the transformation function, because `length(columnName)` is `0`, so it 
should trigger the `else` clause, and 
`bytesToBigDecimal(hexToBytes(concat('000000', '')))` evaluates to `0`.
   
   However, we started seeing exceptions in our pinot logs and the records were 
dropped. The exception chain is (note that the transformation function was 
slightly rewritten by pinot):
   
   ```
   Caused by: java.lang.RuntimeException: Caught exception while executing 
function: 
caseWhen(equals(length(columnName),'64'),bytesToBigDecimal(hexToBytes(concat('0000',columnName))),bytesToBigDecimal(hexToBytes(concat('000000',columnName))))
        at 
org.apache.pinot.segment.local.function.InbuiltFunctionEvaluator$FunctionExecutionNode.execute(InbuiltFunctionEvaluator.java:241)
 ~[pinot-all....]
        at 
org.apache.pinot.segment.local.function.InbuiltFunctionEvaluator.evaluate(InbuiltFunctionEvaluator.java:113)
 ~[pinot-all....]
        at 
org.apache.pinot.segment.local.recordtransformer.ExpressionTransformer.transform(ExpressionTransformer.java:123)
 ~[pinot-all....]
        ... 7 more
   Caused by: java.lang.RuntimeException: Caught exception while executing 
function: bytesToBigDecimal(hexToBytes(concat('0000',columnName)))
        at 
org.apache.pinot.segment.local.function.InbuiltFunctionEvaluator$FunctionExecutionNode.execute(InbuiltFunctionEvaluator.java:241)
 ~[pinot-all....]
        at 
org.apache.pinot.segment.local.function.InbuiltFunctionEvaluator$FunctionExecutionNode.execute(InbuiltFunctionEvaluator.java:224)
 ~[pinot-all....]
        at 
org.apache.pinot.segment.local.function.InbuiltFunctionEvaluator.evaluate(InbuiltFunctionEvaluator.java:113)
 ~[pinot-all....]
        at 
org.apache.pinot.segment.local.recordtransformer.ExpressionTransformer.transform(ExpressionTransformer.java:123)
 ~[pinot-all....]
        ... 7 more
   Caused by: java.lang.IllegalStateException: Caught exception while invoking 
method: public static java.math.BigDecimal 
org.apache.pinot.common.function.scalar.DataTypeConversionFunctions.bytesToBigDecimal(byte[])
 with arguments: [[B@10fb20f6]
        at 
org.apache.pinot.common.function.FunctionInvoker.invoke(FunctionInvoker.java:142)
 ~[pinot-all....]
        at 
org.apache.pinot.segment.local.function.InbuiltFunctionEvaluator$FunctionExecutionNode.execute(InbuiltFunctionEvaluator.java:239)
 ~[pinot-all....]
        at 
org.apache.pinot.segment.local.function.InbuiltFunctionEvaluator$FunctionExecutionNode.execute(InbuiltFunctionEvaluator.java:224)
 ~[pinot-all....]
        at 
org.apache.pinot.segment.local.function.InbuiltFunctionEvaluator.evaluate(InbuiltFunctionEvaluator.java:113)
 ~[pinot-all....]
        at 
org.apache.pinot.segment.local.recordtransformer.ExpressionTransformer.transform(ExpressionTransformer.java:123)
 ~[pinot-all....]
        ... 7 more
   Caused by: java.lang.reflect.InvocationTargetException
        at jdk.internal.reflect.GeneratedMethodAccessor244.invoke(Unknown 
Source) ~[?:?]
        at 
java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
 ~[?:?]
        at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[?:?]
        at 
org.apache.pinot.common.function.FunctionInvoker.invoke(FunctionInvoker.java:139)
 ~[pinot-all....]
        at 
org.apache.pinot.segment.local.function.InbuiltFunctionEvaluator$FunctionExecutionNode.execute(InbuiltFunctionEvaluator.java:239)
 ~[pinot-all....]
        at 
org.apache.pinot.segment.local.function.InbuiltFunctionEvaluator$FunctionExecutionNode.execute(InbuiltFunctionEvaluator.java:224)
 ~[pinot-all....]
        at 
org.apache.pinot.segment.local.function.InbuiltFunctionEvaluator.evaluate(InbuiltFunctionEvaluator.java:113)
 ~[pinot-all....]
        at 
org.apache.pinot.segment.local.recordtransformer.ExpressionTransformer.transform(ExpressionTransformer.java:123)
 ~[pinot-all....]
        ... 7 more
   Caused by: java.lang.NumberFormatException: Zero length BigInteger
        at java.base/java.math.BigInteger.<init>(BigInteger.java:312) ~[?:?]
        at java.base/java.math.BigInteger.<init>(BigInteger.java:340) ~[?:?]
        at 
org.apache.pinot.spi.utils.BigDecimalUtils.deserialize(BigDecimalUtils.java:96) 
~[pinot-all....]
        at 
org.apache.pinot.common.function.scalar.DataTypeConversionFunctions.bytesToBigDecimal(DataTypeConversionFunctions.java:90)
 ~[pinot-all....]
        at jdk.internal.reflect.GeneratedMethodAccessor244.invoke(Unknown 
Source) ~[?:?]
        at 
java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
 ~[?:?]
        at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[?:?]
        at 
org.apache.pinot.common.function.FunctionInvoker.invoke(FunctionInvoker.java:139)
 ~[pinot-all....]
        at 
org.apache.pinot.segment.local.function.InbuiltFunctionEvaluator$FunctionExecutionNode.execute(InbuiltFunctionEvaluator.java:239)
 ~[pinot-all....]
        at 
org.apache.pinot.segment.local.function.InbuiltFunctionEvaluator$FunctionExecutionNode.execute(InbuiltFunctionEvaluator.java:224)
 ~[pinot-all....]
        at 
org.apache.pinot.segment.local.function.InbuiltFunctionEvaluator.evaluate(InbuiltFunctionEvaluator.java:113)
 ~[pinot-all....]
        at 
org.apache.pinot.segment.local.recordtransformer.ExpressionTransformer.transform(ExpressionTransformer.java:123)
 ~[pinot-all....]
        ... 7 more
   ```
   
   The length of the column is definitely not 64 digits (I verified that no 
values in the source data are 64 digits long), so the first branch should not 
be evaluated here. The exception indicates that it is evaluating this branch 
though, and then failing when it throws an exception. Based on some additional 
experimentation it seems that both branches of the `case when` statement in the 
transformation are evaluated eagerly, and the exception from the side that 
fails bubbles up and breaks the transformation function statement, even though 
its value wouldn't be used anyway.
   
   I don't think the semantics of the case statement should be to have eager 
evaluation, both from a correctness and performance standpoint. I can't 
reproduce this when writing a regular query, so I think this has to do with 
different behavior in the way transformation functions are evaluated.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to