From c432e576796527c7167f2e5e5b6e49ff5c5a7a2c Mon Sep 17 00:00:00 2001 From: comphead Date: Thu, 14 May 2026 09:09:45 -0700 Subject: [PATCH 1/2] feat: fix windows decimal casting frame --- datafusion/common/src/scalar/mod.rs | 25 ++-- datafusion/sqllogictest/test_files/window.slt | 113 ++++++++++++++++++ 2 files changed, 126 insertions(+), 12 deletions(-) diff --git a/datafusion/common/src/scalar/mod.rs b/datafusion/common/src/scalar/mod.rs index d726b5c94016f..644ed1085d742 100644 --- a/datafusion/common/src/scalar/mod.rs +++ b/datafusion/common/src/scalar/mod.rs @@ -592,38 +592,39 @@ impl PartialOrd for ScalarValue { // any newly added enum variant will require editing this list // or else face a compile error match (self, other) { - (Decimal32(v1, p1, s1), Decimal32(v2, p2, s2)) => { - if p1.eq(p2) && s1.eq(s2) { + (Decimal32(v1, _, s1), Decimal32(v2, _, s2)) => { + if s1.eq(s2) { + // Same scale means the underlying integer values share + // a common interpretation regardless of declared + // precision (arithmetic such as `add_checked` widens + // precision by 1 but does not change the numeric + // meaning). v1.partial_cmp(v2) } else { - // Two decimal values can be compared if they have the same precision and scale. None } } (Decimal32(_, _, _), _) => None, - (Decimal64(v1, p1, s1), Decimal64(v2, p2, s2)) => { - if p1.eq(p2) && s1.eq(s2) { + (Decimal64(v1, _, s1), Decimal64(v2, _, s2)) => { + if s1.eq(s2) { v1.partial_cmp(v2) } else { - // Two decimal values can be compared if they have the same precision and scale. None } } (Decimal64(_, _, _), _) => None, - (Decimal128(v1, p1, s1), Decimal128(v2, p2, s2)) => { - if p1.eq(p2) && s1.eq(s2) { + (Decimal128(v1, _, s1), Decimal128(v2, _, s2)) => { + if s1.eq(s2) { v1.partial_cmp(v2) } else { - // Two decimal values can be compared if they have the same precision and scale. None } } (Decimal128(_, _, _), _) => None, - (Decimal256(v1, p1, s1), Decimal256(v2, p2, s2)) => { - if p1.eq(p2) && s1.eq(s2) { + (Decimal256(v1, _, s1), Decimal256(v2, _, s2)) => { + if s1.eq(s2) { v1.partial_cmp(v2) } else { - // Two decimal values can be compared if they have the same precision and scale. None } } diff --git a/datafusion/sqllogictest/test_files/window.slt b/datafusion/sqllogictest/test_files/window.slt index 96b811093ecb2..fe6e229cd1c34 100644 --- a/datafusion/sqllogictest/test_files/window.slt +++ b/datafusion/sqllogictest/test_files/window.slt @@ -6431,6 +6431,119 @@ FROM ( 2 2 3 3 +############################################################################ +# RANGE frame with DECIMAL ORDER BY: decimal arithmetic widens the result +# precision (e.g. Decimal(10,0) ± Decimal(10,0) → Decimal(11,0)), which +# previously left the boundary target incomparable with the ORDER BY +# column and failed with "Internal error: Uncomparable values". +############################################################################ + +# Original reporter query. +query I +SELECT COUNT(*) OVER ( + PARTITION BY 1 + ORDER BY cast(1 as decimal(10, 0)) DESC + RANGE BETWEEN CURRENT ROW AND 1 FOLLOWING +) FROM (SELECT 1); +---- +1 + +# ASC + PRECEDING +query RRR +SELECT a, + first_value(a) OVER (ORDER BY a ASC RANGE BETWEEN 1 PRECEDING AND CURRENT ROW), + last_value(a) OVER (ORDER BY a ASC RANGE BETWEEN 1 PRECEDING AND CURRENT ROW) +FROM ( + SELECT CAST(1 AS DECIMAL(10,0)) AS a + UNION ALL SELECT CAST(2 AS DECIMAL(10,0)) + UNION ALL SELECT CAST(3 AS DECIMAL(10,0)) +) +ORDER BY a; +---- +1 1 1 +2 1 2 +3 2 3 + +# ASC + FOLLOWING +query RRR +SELECT a, + first_value(a) OVER (ORDER BY a ASC RANGE BETWEEN CURRENT ROW AND 1 FOLLOWING), + last_value(a) OVER (ORDER BY a ASC RANGE BETWEEN CURRENT ROW AND 1 FOLLOWING) +FROM ( + SELECT CAST(1 AS DECIMAL(10,0)) AS a + UNION ALL SELECT CAST(2 AS DECIMAL(10,0)) + UNION ALL SELECT CAST(3 AS DECIMAL(10,0)) +) +ORDER BY a; +---- +1 1 2 +2 2 3 +3 3 3 + +# DESC + PRECEDING +query RRR +SELECT a, + first_value(a) OVER (ORDER BY a DESC RANGE BETWEEN 1 PRECEDING AND CURRENT ROW), + last_value(a) OVER (ORDER BY a DESC RANGE BETWEEN 1 PRECEDING AND CURRENT ROW) +FROM ( + SELECT CAST(1 AS DECIMAL(10,0)) AS a + UNION ALL SELECT CAST(2 AS DECIMAL(10,0)) + UNION ALL SELECT CAST(3 AS DECIMAL(10,0)) +) +ORDER BY a DESC; +---- +3 3 3 +2 3 2 +1 2 1 + +# DESC + FOLLOWING +query RRR +SELECT a, + first_value(a) OVER (ORDER BY a DESC RANGE BETWEEN CURRENT ROW AND 1 FOLLOWING), + last_value(a) OVER (ORDER BY a DESC RANGE BETWEEN CURRENT ROW AND 1 FOLLOWING) +FROM ( + SELECT CAST(1 AS DECIMAL(10,0)) AS a + UNION ALL SELECT CAST(2 AS DECIMAL(10,0)) + UNION ALL SELECT CAST(3 AS DECIMAL(10,0)) +) +ORDER BY a DESC; +---- +3 3 2 +2 2 1 +1 1 1 + +# Symmetric N PRECEDING AND N FOLLOWING +query RRR +SELECT a, + first_value(a) OVER (ORDER BY a ASC RANGE BETWEEN 1 PRECEDING AND 1 FOLLOWING), + last_value(a) OVER (ORDER BY a ASC RANGE BETWEEN 1 PRECEDING AND 1 FOLLOWING) +FROM ( + SELECT CAST(1 AS DECIMAL(10,0)) AS a + UNION ALL SELECT CAST(2 AS DECIMAL(10,0)) + UNION ALL SELECT CAST(3 AS DECIMAL(10,0)) +) +ORDER BY a; +---- +1 1 2 +2 1 3 +3 2 3 + +# Non-zero scale: Decimal(10,2) +query RRR +SELECT a, + first_value(a) OVER (ORDER BY a ASC RANGE BETWEEN 1 PRECEDING AND 1 FOLLOWING), + last_value(a) OVER (ORDER BY a ASC RANGE BETWEEN 1 PRECEDING AND 1 FOLLOWING) +FROM ( + SELECT CAST(1.50 AS DECIMAL(10,2)) AS a + UNION ALL SELECT CAST(2.50 AS DECIMAL(10,2)) + UNION ALL SELECT CAST(3.50 AS DECIMAL(10,2)) +) +ORDER BY a; +---- +1.5 1.5 2.5 +2.5 1.5 3.5 +3.5 2.5 3.5 + ############################################################################ # ROWS frame regression guard: huge offsets already saturate via # saturating_sub / min(length), verify we keep that behavior. From 1e9ba45fe9be1de21c2a24cb7f106a160dd92b7a Mon Sep 17 00:00:00 2001 From: comphead Date: Thu, 14 May 2026 12:39:31 -0700 Subject: [PATCH 2/2] feat: fix windows decimal casting frame --- datafusion/sqllogictest/test_files/window.slt | 2 -- 1 file changed, 2 deletions(-) diff --git a/datafusion/sqllogictest/test_files/window.slt b/datafusion/sqllogictest/test_files/window.slt index fe6e229cd1c34..1c614f6a22c1e 100644 --- a/datafusion/sqllogictest/test_files/window.slt +++ b/datafusion/sqllogictest/test_files/window.slt @@ -6437,8 +6437,6 @@ FROM ( # previously left the boundary target incomparable with the ORDER BY # column and failed with "Internal error: Uncomparable values". ############################################################################ - -# Original reporter query. query I SELECT COUNT(*) OVER ( PARTITION BY 1