You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This is a confirmed deterministic correctness bug in the BE width_bucket implementation at commit 979e053f0802fbc48f83dafe7f713c02968415a8. The issue is currently open with no labels; the supplied commit and scalar SQL are sufficient for initial triage.
For the integral overloads, this is integer division. For example, 10 / 20 and 2 / 5 truncate to 0; continue leaves the pre-zeroed result unchanged. That directly explains every reported result, including width_bucket(0, 0, 10, 20): an expression equal to the lower bound reaches the stale guard and incorrectly remains bucket 0 instead of bucket 1.
The confirmed scope is the TINYINT, SMALLINT, INT, and BIGINT execution paths when 0 < max_value - min_value < num_buckets and the expression is in [min_value, max_value). Values below min_value and values at/above max_value take earlier branches and are not affected by this guard. The same integer-truncation mechanism does not apply to the floating-point overloads.
History supports this diagnosis: the guard protected the original integer denominator. PR #24673 changed the actual bucket calculation to divide by the floating-point average_value, but retained the old integer zero check. Existing regression coverage also misses this shape: the direct integer case uses a span of 11 with 10 buckets, while the generated integral cases use a span of 1 with 1 bucket.
Missing information
No additional logs, profile, or environment details are required to establish this issue. The version, exact commit, deterministic reproduction, and expected values are all present. I did not run a Doris cluster or a candidate patch during this triage; the conclusion is based on the reported runtime output and inspection of the exact commit.
Recommended next steps
In the reporter's proposed PR, remove the stale integral-division guard or make any zero-width validation use the same non-truncating calculation as average_value. Keep the existing below-range (0) and at/above-range (num_buckets + 1) behavior unchanged.
Add the four reported constant queries as regression cases in test_width_bucket_function.groovy, including the lower-bound case.
Add explicit-cast coverage for all four integral overloads, plus expr = min_value, an in-range value near max_value, and the existing out-of-range boundaries. This prevents the fix from only covering the literal type selected by the analyzer.
Run the focused test_width_bucket_function regression suite and the existing Nereids scalar-function coverage before merge.
The fix direction above is code-derived but has not yet been implemented or test-validated here. Equal or descending bounds are outside the reported failure and should not have their semantics changed incidentally.
Activity
Doris-Breakwater commentedon Sep 19, 2026
Breakwater-GitHub-Analysis-Slot: slot_5b7a1add75c6
Initial assessment
This is a confirmed deterministic correctness bug in the BE
width_bucketimplementation at commit979e053f0802fbc48f83dafe7f713c02968415a8. The issue is currently open with no labels; the supplied commit and scalar SQL are sufficient for initial triage.Verified root cause
In
FunctionWidthBucket::_execute,average_valueis correctly computed with floating-point arithmetic:However, the in-range branch then checks the width again using the input type's arithmetic:
For the integral overloads, this is integer division. For example,
10 / 20and2 / 5truncate to0;continueleaves the pre-zeroed result unchanged. That directly explains every reported result, includingwidth_bucket(0, 0, 10, 20): an expression equal to the lower bound reaches the stale guard and incorrectly remains bucket0instead of bucket1.The confirmed scope is the
TINYINT,SMALLINT,INT, andBIGINTexecution paths when0 < max_value - min_value < num_bucketsand the expression is in[min_value, max_value). Values belowmin_valueand values at/abovemax_valuetake earlier branches and are not affected by this guard. The same integer-truncation mechanism does not apply to the floating-point overloads.History supports this diagnosis: the guard protected the original integer denominator. PR #24673 changed the actual bucket calculation to divide by the floating-point
average_value, but retained the old integer zero check. Existing regression coverage also misses this shape: the direct integer case uses a span of 11 with 10 buckets, while the generated integral cases use a span of 1 with 1 bucket.Missing information
No additional logs, profile, or environment details are required to establish this issue. The version, exact commit, deterministic reproduction, and expected values are all present. I did not run a Doris cluster or a candidate patch during this triage; the conclusion is based on the reported runtime output and inspection of the exact commit.
Recommended next steps
average_value. Keep the existing below-range (0) and at/above-range (num_buckets + 1) behavior unchanged.test_width_bucket_function.groovy, including the lower-bound case.expr = min_value, an in-range value nearmax_value, and the existing out-of-range boundaries. This prevents the fix from only covering the literal type selected by the analyzer.test_width_bucket_functionregression suite and the existing Nereids scalar-function coverage before merge.The fix direction above is code-derived but has not yet been implemented or test-validated here. Equal or descending bounds are outside the reported failure and should not have their semantics changed incidentally.