SEPURI-SAI-KRISHNA opened a new issue, #11926: URL: https://github.com/apache/seatunnel/issues/11926
### Search before asking - [x] I had searched in the [issues](https://github.com/apache/seatunnel/issues?q=is%3Aissue+label%3A%22bug%22) and found no similar issues. ### What happened Two numeric functions in the Zeta SQL transform narrow an integral result without checking that it fits, so a positive input silently produces a **negative** output. No exception is raised — the job reports success and writes the wrong number to the sink. **1. `ROUND` / `CEIL` / `CEILING` / `FLOOR` / `TRUNC` / `TRUNCATE` at negative scale** | Expression | Declared type | Actual | Expected | |---|---|---|---| | `ROUND(v, -1)` | SMALLINT, `v = 32767` | **-32766** | 32770, or an overflow error | | `ROUND(v, -1)` | INT, `v = 2147483647` | **-2147483646** | 2147483650, or an overflow error | | `ROUND(v, -1)` | BIGINT, `v = 9223372036854775807` | **-9223372036854775806** | overflow error | **2. `ABS` at the minimum negative value** | Expression | Declared type | Actual | Expected | |---|---|---|---| | `ABS(v)` | INT, `v = -2147483648` | **-2147483648** | exception | | `ABS(v)` | BIGINT, `v = -9223372036854775808` | **-9223372036854775808** | exception | For `ABS` the expected behaviour is not a matter of opinion — it is already written down. `docs/en/transforms/sql-functions.md` states: > Note that TINYINT, SMALLINT, INT, and BIGINT data types cannot represent absolute values of their minimum negative values, because they have more negative values than positive. For example, for INT data type allowed values are from -2147483648 to 2147483647. ABS(-2147483648) should be 2147483648, but this value is not allowed for this data type. **It leads to an exception.** To avoid it cast argument of this function to a higher data type. The documented contract is an exception. The implementation returns a negative absolute value instead, which is the one outcome the note exists to rule out. For the rounding family the docs specify `ROUND(numeric[, digitsInt]) -> NUMERIC (same type)` and `CEIL | CEILING (numeric) -> NUMERIC (same type, scale 0)`. Rounding a positive value *up* to a negative one satisfies neither reading of that contract. ### Root cause Both defects are the same mistake — an integral result is narrowed on the assumption that it fits. `seatunnel-transforms-v2/.../sql/zeta/functions/NumericFunction.java` `round(Number, Number, RoundingMode)` has **two independent** overflow points on the negative-scale path: ```java case "INTEGER": case "SHORT": case "LONG": { if (scale < 0) { long original = v1.longValue(); long scaled = BigDecimal.valueOf(original) .setScale(scale, roundingMode) .longValue(); // (1) overflows for BIGINT if (original != scaled) { v1 = convertTo(t, scaled); // (2) overflows for INT / SMALLINT } } break; } ``` 1. `BigDecimal.longValue()` is documented to discard all but the low-order 64 bits. `9223372036854775807` rounded up at scale `-1` is `9223372036854775810`, which wraps to `-9223372036854775806`. 2. `convertTo` narrows with `intValue()` / `shortValue()`, which truncate the same way: `2147483650 -> -2147483646`, `32770 -> -32766`. `abs(List<Object>)` relies on `Math.abs`, which is documented to return the argument unchanged when it is `MIN_VALUE`: ```java if (arg instanceof Integer) { return Math.abs(arg.intValue()); // Math.abs(Integer.MIN_VALUE) == Integer.MIN_VALUE } if (arg instanceof Long) { return Math.abs(arg.longValue()); // same for Long.MIN_VALUE } ``` Neither path is a regression from a recent change: the negative-scale block and `convertTo` both pre-date #11697, and #11697 modified only the `BIGDECIMAL` case and the `CEIL`/`FLOOR` return types. These are reachable from ordinary SQL. `ZetaSQLType` (`:463-471`) makes `ABS`/`ROUND`/`CEIL`/`CEILING`/`FLOOR`/`TRUNC`/`TRUNCATE` return the type of their first argument, so an INT column stays INT through the call. ### SeaTunnel Version dev (3.0.0-SNAPSHOT) ### SeaTunnel Config ```conf env { parallelism = 1 job.mode = "BATCH" } source { FakeSource { plugin_output = "fake" schema = { fields { int_v = "int" long_v = "bigint" small_v = "smallint" abs_int = "int" abs_long = "bigint" } } rows = [ { kind = INSERT fields = [2147483647, 9223372036854775807, 32767, -2147483648, -9223372036854775808] } ] } } transform { Sql { plugin_input = "fake" plugin_output = "out" query = "select ROUND(int_v, -1) as r_int, ROUND(long_v, -1) as r_long, ROUND(small_v, -1) as r_small, ABS(abs_int) as a_int, ABS(abs_long) as a_long from fake" } } sink { Console { plugin_input = "out" } } ``` ### Running Command ```shell ./bin/seatunnel.sh --config ./config/repro.conf -e local ``` ### Error Exception ```log None — this is silent data corruption; the job reports success. r_int = -2147483646 (expected 2147483650, or an overflow error) r_long = -9223372036854775806 (expected an overflow error) r_small = -32766 (expected 32770, or an overflow error) a_int = -2147483648 (docs require an exception) a_long = -9223372036854775808 (docs require an exception) ``` ### Zeta or Flink or Spark Version Zeta (engine-independent — the bug is in the transform) ### Java or Scala Version Java 11 / Java 17 ### Screenshots _No response_ ### Are you willing to submit PR? - [x] Yes I am willing to submit a PR! ### Code of Conduct - [x] I agree to follow this project's [Code of Conduct](https://www.apache.org/foundation/policies/conduct) -- 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]
