hanke580 opened a new issue, #68714: URL: https://github.com/apache/doris/issues/68714
### Search before asking - [x] I had searched in the [issues](https://github.com/apache/doris/issues?q=is%3Aissue) and found no similar issues. ### Version master @ `0c29961f45ee976ef61c6a5dfe7b38b40a6ec131` (2026-09-30), built from source. Also 4.1.4-rc04 (`doris-4.1.4-rc04-ad35a140c7f`) and 4.1.3-rc02. ### What's Wrong? A nonzero DOUBLE constant whose magnitude is below the smallest float32 subnormal (~1.4e-45) is treated as **false** whenever it is converted to a boolean at plan time. That covers an explicit `CAST(... AS BOOLEAN)`, `IF(x, ...)`, `CASE WHEN x`, `x AND ...`, and `WHERE x`. The same engine agrees the value is nonzero (`x > 0` is 1, `x = 0` is 0), and the same value read from a column is true. ```sql SELECT CAST('5e-324' AS DOUBLE) > 0; -- 1 SELECT CAST('5e-324' AS DOUBLE) = 0; -- 0 SELECT CAST(CAST('5e-324' AS DOUBLE) AS BOOLEAN); -- 0 <-- wrong SELECT IF(CAST('5e-324' AS DOUBLE), 1, 0); -- 0 <-- wrong SELECT CASE WHEN CAST('5e-324' AS DOUBLE) THEN 1 ELSE 0 END; -- 0 <-- wrong SELECT CAST(CAST('5e-324' AS DOUBLE) AND true AS INT); -- 0 <-- wrong ``` It affects real queries: ```sql SELECT count(*) FROM t WHERE CAST('5e-324' AS DOUBLE); -- 0 (t has 4 rows) ``` The boundary is exactly float32 underflow: | value | `CAST(literal AS BOOLEAN)` | `CAST(column AS BOOLEAN)` | `CAST(literal AS FLOAT)` | |---|---|---|---| | `5e-324`, `1e-320`, `1e-300`, `1e-46` | **0** | 1 | `0.0` | | `1e-45`, `1e-10`, `0.5` | 1 | 1 | nonzero | | `0.0` | 0 | 0 | `0.0` | `EXPLAIN SELECT CAST(CAST('5e-324' AS DOUBLE) AS BOOLEAN)` shows the constant already folded to `FALSE` in the plan. `SET debug_skip_fold_constant = true` does not change the result. **Root cause (master @ `0c29961f`).** `fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/FractionalLiteral.java:89-97` (line 92), in `uncheckedCastTo(BooleanType)`: ```java if (value instanceof Float || value instanceof Double) { if (((Number) value).floatValue() == 0) { // narrows the double to float first return BooleanLiteral.FALSE; ``` `floatValue()` rounds every double with |x| < ~1.4e-45 to `0.0f`. Using `((Number) value).doubleValue() == 0` instead gives the BE's answer (it is exact for both `Float` and `Double`). The BE's double→bool cast tests the double itself, which is why the column path is right. ### What You Expected? `CAST(x AS BOOLEAN)` is true for every nonzero DOUBLE, as in the BE (column path) and as the engine's own `x != 0` says: 1 for every row in the table above except `0.0`. Constant folding should not change the result of an expression. ### How to Reproduce? Single FE + single BE, default configuration. ```sql CREATE DATABASE d; USE d; CREATE TABLE t (i INT) DUPLICATE KEY(i) DISTRIBUTED BY HASH(i) BUCKETS 1 PROPERTIES('replication_num'='1'); INSERT INTO t VALUES (0),(1),(2),(3); CREATE TABLE v (i INT, c DOUBLE) DUPLICATE KEY(i) DISTRIBUTED BY HASH(i) BUCKETS 1 PROPERTIES('replication_num'='1'); INSERT INTO v VALUES (0, CAST('5e-324' AS DOUBLE)); -- folded constant: wrong SELECT CAST(CAST('5e-324' AS DOUBLE) AS BOOLEAN); -- 0 SELECT IF(CAST('5e-324' AS DOUBLE), 1, 0); -- 0 SELECT count(*) FROM t WHERE CAST('5e-324' AS DOUBLE); -- 0 -- same value from a column: right SELECT CAST(c AS BOOLEAN), IF(c, 1, 0) FROM v; -- 1, 1 SELECT count(*) FROM t WHERE (SELECT c FROM v); -- 4 -- the engine agrees it is nonzero SELECT CAST('5e-324' AS DOUBLE) > 0, CAST('5e-324' AS DOUBLE) = 0; -- 1, 0 -- the boundary is float32 underflow SELECT CAST(CAST('1e-45' AS DOUBLE) AS BOOLEAN), CAST(CAST('1e-46' AS DOUBLE) AS BOOLEAN); -- 1, 0 ``` ### Anything Else? The same sweep found a second FE/BE folding divergence, which might be fixed in the same pass: `acosh` and `asinh` overflow when folded. ```sql SELECT acosh(CAST('1.7976931348623157e308' AS DOUBLE)), asinh(CAST('1.7976931348623157e308' AS DOUBLE)); -- inf, inf -- same value (DBL_MAX) from a DOUBLE column: -- 710.4758600739439, 710.4758600739439 ``` The folded path is `NumericArithmetic.asinh` / `acosh` (`fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/executable/NumericArithmetic.java:672-689`), which calls commons-math `FastMath.asinh` / `FastMath.acosh`. Those return `inf` for `DBL_MAX` (presumably the `x*x` in `log(x + sqrt(x*x ± 1))` overflows), while the BE returns the finite result. ### Are you willing to submit PR? - [ ] 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] --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
