Browse Source

fix(cf): prevent integer overflow in calculated field SUM output

SimpleCalculatedFieldState.formatResult cast the double result down to
  int via TbUtils.toInt when "Decimals by default" was 0 (the UI default).
  BigDecimal.intValue() returns only the low-order 32 bits, so a sum
  above ~2.1B wrapped to a negative number (e.g. 3,980,173,734 ->
  -314,793,562).

  Add TbUtils.toLong(double) alongside toInt (toInt is left untouched to
  preserve TBEL script behavior), switch the CF precision=0 path to it,
  and add a Long branch in createResultJson so the JSON node is emitted
  as a numeric long
pull/15620/head
Volodymyr Babak 5 months ago
parent
commit
6f75542315
  1. 4
      application/src/main/java/org/thingsboard/server/service/cf/ctx/state/SimpleCalculatedFieldState.java
  2. 4
      common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbUtils.java
  3. 8
      common/script/script-api/src/test/java/org/thingsboard/script/api/tbel/TbUtilsTest.java

4
application/src/main/java/org/thingsboard/server/service/cf/ctx/state/SimpleCalculatedFieldState.java

@ -85,7 +85,7 @@ public class SimpleCalculatedFieldState extends BaseCalculatedFieldState {
return expressionResult;
}
if (decimals.equals(0)) {
return TbUtils.toInt(expressionResult);
return TbUtils.toLong(expressionResult);
}
return TbUtils.toFixed(expressionResult, decimals);
}
@ -96,6 +96,8 @@ public class SimpleCalculatedFieldState extends BaseCalculatedFieldState {
ObjectNode valuesNode = JacksonUtil.newObjectNode();
if (result instanceof Double doubleValue) {
valuesNode.put(outputName, doubleValue);
} else if (result instanceof Long longValue) {
valuesNode.put(outputName, longValue);
} else if (result instanceof Integer integerValue) {
valuesNode.put(outputName, integerValue);
} else {

4
common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbUtils.java

@ -1186,6 +1186,10 @@ public class TbUtils {
return BigDecimal.valueOf(value).setScale(0, RoundingMode.HALF_UP).intValue();
}
public static long toLong(double value) {
return BigDecimal.valueOf(value).setScale(0, RoundingMode.HALF_UP).longValue();
}
public static boolean isNaN(double value) {
return Double.isNaN(value);
}

8
common/script/script-api/src/test/java/org/thingsboard/script/api/tbel/TbUtilsTest.java

@ -1249,6 +1249,14 @@ public class TbUtilsTest {
Assertions.assertEquals(28, TbUtils.toInt(28.0));
}
@Test
public void toLong() {
Assertions.assertEquals(1729L, TbUtils.toLong(doubleVal));
Assertions.assertEquals(13L, TbUtils.toLong(12.8));
Assertions.assertEquals(28L, TbUtils.toLong(28.0));
Assertions.assertEquals(3_980_173_734L, TbUtils.toLong(3_980_173_734.0));
}
@Test
public void isNaN() {
assertFalse(TbUtils.isNaN(doubleVal));

Loading…
Cancel
Save