SEPURI-SAI-KRISHNA opened a new issue, #11935:
URL: https://github.com/apache/seatunnel/issues/11935

   ### 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
   
   Three Zeta SQL numeric functions dispatch on the runtime type of their 
argument with an incomplete set of branches. `TINYINT` (`Byte`) is missing 
everywhere, `SMALLINT` (`Short`) is missing from two of them. Depending on the 
function, the result is either a silently wrong answer or a hard failure on a 
documented type.
   
   **1. `ROUND` / `CEIL` / `CEILING` / `FLOOR` / `TRUNC` silently ignore 
`TINYINT`**
   
   The shared `round(Number, Number, RoundingMode)` helper 
(`NumericFunction.java:232`) switches on the argument's class simple name with 
cases `INTEGER`, `SHORT`, `LONG`, `BIGDECIMAL`, `DOUBLE`, `FLOAT`. There is 
**no `BYTE` case and no `default`**, so a `Byte` argument falls straight 
through the switch and the method returns its input unchanged.
   
   Run through the real `SQLTransform` on `dev`:
   
   | Expression | Column type | Actual | Expected |
   |---|---|---|---|
   | `ROUND(tiny_v, -1)`, `tiny_v = 44` | `TINYINT` | **`44`** | `40` |
   | `CEIL(tiny_v, -1)`, `tiny_v = 44` | `TINYINT` | **`44`** | `50` |
   | `ROUND(small_v, -2)`, `small_v = 1234` | `SMALLINT` | `1200` | `1200` ✅ |
   
   The `SMALLINT` row is the control: the identical expression one type up 
works correctly. That is what makes this a missing branch rather than a 
deliberate carve-out. No exception, no log line — the value is simply not 
rounded.
   
   Note `44` is chosen deliberately: it rounds to `40`, which fits a `TINYINT` 
comfortably. This defect is independent of any overflow concern.
   
   **2. `ABS` and `SIGN` reject `TINYINT` and `SMALLINT` outright**
   
   Both use an `instanceof` chain covering `Integer`, `Long`, `Float`, 
`Double`, `BigDecimal` and then throw. Neither has a `Byte` or `Short` branch:
   
   | Expression | Column type | Result |
   |---|---|---|
   | `ABS(tiny_v)` | `TINYINT` | `TransformException` — `Unsupported arg type 
java.lang.Byte of function ABS` |
   | `ABS(small_v)` | `SMALLINT` | `TransformException` — `Unsupported arg type 
java.lang.Short of function ABS` |
   | `SIGN(tiny_v)` | `TINYINT` | `TransformException` — `Unsupported function 
SIGN() argument type: java.lang.Byte` |
   | `SIGN(small_v)` | `SMALLINT` | `TransformException` — `Unsupported 
function SIGN() argument type: java.lang.Short` |
   
   `ABS` on a `SMALLINT` column failing is the most surprising of these, 
because the `ABS` documentation explicitly discusses `SMALLINT` as a supported 
argument type.
   
   **3. `SIGN` loses the sign of a `BigDecimal` too small for `double` (minor)**
   
   `sign` converts `BigDecimal` via `doubleValue()` before testing, so any 
magnitude below `Double.MIN_VALUE` underflows to `0.0` and a non-zero input 
reports as zero:
   
   ```java
   NumericFunction.sign(singletonList(new BigDecimal("1E-400")))   // 0, 
expected 1
   NumericFunction.sign(singletonList(new BigDecimal("-1E-400")))  // 0, 
expected -1
   NumericFunction.sign(singletonList(new BigDecimal("1E-38")))    // 1, correct
   ```
   
   **In fairness this one is not reachable through a declared column today** — 
SeaTunnel's `DECIMAL(p, s)` caps precision at 38, so no declared column can 
carry a value that small, and I could not construct an end-to-end pipeline that 
triggers it. I am listing it because it lives in the same `instanceof` chain as 
defect 2 and the fix is strictly better on every axis: `BigDecimal.signum()` is 
exact, cheaper, and allocation-free. It should be corrected while that chain is 
being touched, not tracked as a user-facing bug.
   
   ### Why `TINYINT` and `SMALLINT` are reachable
   
   `ZetaSQLType.isNumberType` accepts everything from `SqlType.TINYINT` to 
`SqlType.DECIMAL` inclusive:
   
   ```java
   // ZetaSQLType.java:254-256
   public boolean isNumberType(SqlType type) {
       return type.compareTo(SqlType.TINYINT) >= 0 && 
type.compareTo(SqlType.DECIMAL) <= 0;
   }
   ```
   
   and `BasicType.BYTE_TYPE` maps `Byte` to `SqlType.TINYINT` 
(`BasicType.java:30`). For 
`ABS`/`ROUND`/`CEIL`/`CEILING`/`FLOOR`/`TRUNC`/`TRUNCATE`, `getFunctionType` 
returns the type of the first argument, so a `TINYINT` column stays `TINYINT` 
all the way into the function.
   
   These are not theoretical types. **The same class already handles them 
deliberately elsewhere** — `NumericFunction.toBigDecimal` has an explicit 
branch for both:
   
   ```java
   // NumericFunction.java:162-172
   private static BigDecimal toBigDecimal(Number value) {
       if (value instanceof BigDecimal) {
           return (BigDecimal) value;
       }
       if (value instanceof Byte
               || value instanceof Short
               || value instanceof Integer
               || value instanceof Long) {
           return BigDecimal.valueOf(value.longValue());
       }
       ...
   ```
   
   So `Byte` and `Short` are known to flow through this class. They were simply 
omitted from these three functions.
   
   `docs/en/transforms/sql-functions.md` documents `ROUND(numeric[, digitsInt]) 
-> NUMERIC (same type)`, `CEIL | CEILING (numeric) -> NUMERIC (same type, scale 
0)`, `FLOOR(numeric) -> NUMERIC (same type, scale 0)`, `TRUNC | 
TRUNCATE(numeric[, digitsInt]) -> NUMERIC (same type)` and `SIGN(numeric) -> 
INT`, with no carve-out excluding `TINYINT` or `SMALLINT`. The `ABS` section 
names `TINYINT` and `SMALLINT` among the types it applies to.
   
   ### What you expected to happen
   
   - `ROUND`/`CEIL`/`CEILING`/`FLOOR`/`TRUNC` handle `TINYINT` like the other 
integral types, and the `switch` gains a `default` so any unhandled numeric 
type fails loudly instead of silently returning its input.
   - `ABS` and `SIGN` accept `TINYINT` and `SMALLINT`.
   - `SIGN` uses `BigDecimal.signum()` rather than `doubleValue()`.
   
   Adding the `BYTE` case to the rounding family depends on the overflow 
handling in #11926 / #11927, since `ROUND(TINYINT 127, -1)` is `130`, which 
does not fit a `TINYINT`. I raised that gap in #11927 as a known follow-up; 
this issue is that follow-up.
   
   Part of this was also found independently while reviewing #11927 
(@DanielLeens, minor observation 2): "`NumericFunction.abs()` still has no case 
for `Short` (`SMALLINT`) input — it falls through to the generic 'Unsupported 
arg type' exception. This is a pre-existing gap on `dev`, not touched or 
worsened by this PR, so it's out of scope here, just flagging for a separate 
follow-up." That covers the `ABS`/`SMALLINT` half of claim 2 above; the 
`TINYINT` rounding gap and the `SIGN` cases are additional.
   
   ### SeaTunnel Version
   
   dev (3.0.0-SNAPSHOT), reproduced at `4ba2895`
   
   ### SeaTunnel Config
   
   ```conf
   env {
     parallelism = 1
     job.mode = "BATCH"
   }
   
   source {
     FakeSource {
       plugin_output = "fake"
       schema = {
         fields {
           tiny_v = "tinyint"
           small_v = "smallint"
         }
       }
       rows = [
         {
           kind = INSERT
           fields = [44, 1234]
         }
       ]
     }
   }
   
   transform {
     Sql {
       plugin_input = "fake"
       plugin_output = "out"
       # r_tiny is silently NOT rounded; r_small on the next type up is correct.
       # Swap in ABS(tiny_v) or SIGN(small_v) to hit the hard failure instead.
       query = "select ROUND(tiny_v, -1) as r_tiny, ROUND(small_v, -2) as 
r_small from fake"
     }
   }
   
   sink {
     Console {
       plugin_input = "out"
     }
   }
   ```
   
   ### Running Command
   
   ```shell
   ./bin/seatunnel.sh --config ./config/repro.conf -e local
   ```
   
   ### Error Exception
   
   ```log
   For the ROUND query above there is no exception - the job reports success:
   
   r_tiny  = 44     (expected 40; silently not rounded)
   r_small = 1200   (correct - the same expression one type up works)
   
   Replacing the query with ABS(tiny_v) or SIGN(small_v) instead produces:
   
   ErrorCode:[TRANSFORM_COMMON-06], ErrorDescription:[The expression 
'ABS(tiny_v)' of SQL
   transform execute failed]
     caused by: ErrorCode:[COMMON-05], ErrorDescription:[Unsupported operation]
                - Unsupported arg type java.lang.Byte of function ABS
   
   ErrorCode:[TRANSFORM_COMMON-06], ErrorDescription:[The expression 
'SIGN(small_v)' of SQL
   transform execute failed]
     caused by: ErrorCode:[COMMON-05], ErrorDescription:[Unsupported operation]
                - Unsupported function SIGN() argument type: java.lang.Short
   ```
   
   ### Zeta or Flink or Spark Version
   
   Zeta (engine-independent — the defect is in the transform)
   
   ### Java or Scala Version
   
   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]

Reply via email to