Comparing a DOUBLE with a DECIMAL casts the DOUBLE to Decimal128(30, 15), which fails on large values and NaN and truncates small ones
Maintainer thường phản hồi trong vòng 1 ngày
Chưa có ai nhận issue này.
Đánh giá
- Độ khó
- 4/5
- Thời gian dự kiến
- 3-5 ngày
- Mức phù hợp với người mới
- 48/100
- Loại issue
- Lỗi
- Độ rõ ràng
- Khá rõ ràng
- Mức độ hoạt động
- Sôi nổi
- Lĩnh vực
- backend-api-design, databases
Hướng nghiên cứu
Start with datafusion/expr-common/src/type_coercion/binary.rs, especially decimal_coercion and the Float64-to-Decimal128 mapping named in the issue. Read the related coercion tests and the context in #4024 to understand why decimal coercion preserves cases such as TPC-H q6. Done means comparisons and type unions handle large doubles, NaN, infinities, and tiny values as expected while preserving the documented decimal-literal behavior.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Mô tả
Describe the bug
When a FLOAT or DOUBLE meets a DECIMAL in a comparison, IN, CASE, COALESCE or another type union, DataFusion casts the float to a decimal. decimal_coercion turns Float64 into Decimal128(30, 15) (#L1395, next to a TODO saying it may overflow) and widens from there. Most doubles don't fit that type:
- values of 1e15 or more overflow, and the query fails;
- NaN and the infinities can't be cast, and the query fails;
- values smaller than 1e-15 round to zero, and the query returns wrong results.
Arithmetic isn't affected: double + decimal is a Float64.
To Reproduce
On main (e7c51c7fb), with the default settings:
SELECT CAST('1e20' AS DOUBLE) > CAST(1.5 AS DECIMAL(2, 1));
-- Arrow error: Invalid argument error: 99999999999999996863.366107917975552 is too large to store in a Decimal128 of precision 30. Max is 999999999999999.999999999999999
SELECT CAST('NaN' AS DOUBLE) > CAST(1.5 AS DECIMAL(2, 1));
-- Arrow error: Cast error: Cannot cast to Decimal128(30, 15). Overflowing on NaN
SELECT CAST('1e-20' AS DOUBLE) > CAST(0 AS DECIMAL(2, 1));
-- false
SELECT CASE WHEN true THEN CAST('NaN' AS DOUBLE) ELSE CAST(1.5 AS DECIMAL(2, 1)) END;
-- Arrow error: Cast error: Cannot cast to Decimal128(30, 15). Overflowing on NaN
CREATE TABLE m (d DOUBLE, n DECIMAL(10, 2)) AS VALUES (1e20, 1.5), (1e-20, 0);
SELECT d, n FROM m WHERE d > n;
-- Failed to cast field 'd' from Float64 to Decimal128(30, 15)
With datafusion.sql_parser.parse_float_as_decimal = true a plain literal is enough: SELECT CAST('1e-20' AS DOUBLE) > 0.0 returns false.
Expected behavior
true, true, true, NaN, and both rows of m.
Spark, which the Decimal128(30, 15) mapping comes from (DecimalType.forType), doesn't use it for comparisons: it casts the decimal to DOUBLE (DecimalPrecisionTypeCoercion.scala#L182-L185). DOUBLE is also its common type of a DECIMAL and a FLOAT or DOUBLE in CASE, IF, COALESCE and IN (TypeCoercionHelper.scala#L194-L195). Spark does this in every version from 3.4 to 4.2.
Additional context
Preferring the decimal has a purpose, though (see #4024). In TPC-H q6, l_discount between 0.06 - 0.01 and 0.06 + 0.01 compares a DECIMAL(15, 2) column with float literals, and 0.06 + 0.01 is 0.06999999999999999. Cast to Decimal128(30, 15) it rounds back to 0.07, so the rows where l_discount is 0.07 are kept. Compared as doubles, 0.07 <= 0.06 + 0.01 is false. A fix has to keep that case working. Some options:
- cast to DOUBLE only when the float side isn't a constant;
- use DOUBLE when float literals are already decimals, that is with
parse_float_as_decimalor the Spark dialect; - make the rule configurable.
This will matter more once #27185 is fixed: with the Spark dialect, 1.5 becomes a DECIMAL (#27213), so every WHERE double_col > 0.5 hits it.
- Ngôn ngữ chính
- Rust
- Star
- 9.6k
- Fork
- 2.6k
- Merge trung bình
- 3 ngày 4 giờ
- Pull request đã merge (30 ngày)
- 345
Chuẩn bị môi trường
Khởi chạy dev container của dự án ngay trên trình duyệt, bằng tài khoản GitHub của bạn.
- Không có Dockerfile hay tệp Docker Compose
- Có mẫu pull request
- Đọc hướng dẫn đóng góp
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của apache/datafusion
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 72/100
apache/datafusion#27315 · 2 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
bug
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 76/100
apache/datafusion#27094 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Substrait consumer doesn't recognise `shift_left` / `shift_right` from functions_arithmetic.yamlCó thể đã có người làm @jonasHanhan đã nhận 9 ngày trước. Đang mởbug
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 76/100
apache/datafusion#27059 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
`ProjectionExprs::project_statistics` computes approximate `Statistics::total_byte_size` ignoring column statsCó thể đã có người làm @joseph-isaacs đã nhận 10 ngày trước. Đang mởbug
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 72/100
apache/datafusion#27050 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
physical-plan: decoding an Unnest or Explain node with an unset field panicsCó thể đã có người làm @geoHeil đã nhận 8 ngày trước. Đang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 75/100
apache/datafusion#26999 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
Tất cả issue của apache/datafusion
Issue tương tự
-
P3
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 70/100
HerringtonDarkholme/hd-lang#1770 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 82/100
jonathanong/no-mistakes#3332 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
bug
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
swc-project/swc-next-issues#310 ·
-
bug
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 72/100
swc-project/swc-ai-issues#653 ·
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 72/100
lbjlaq/Antigravity-Manager#3937 ·
Maintainer thường phản hồi trong vòng 1 ngày