This is an automated email from the ASF dual-hosted git repository. github-merge-queue[bot] pushed a commit to branch gh-readonly-queue/main/pr-23706-8f15682ae87c4ffb4a588fd9f93c73b79323d917 in repository https://gitbox.apache.org/repos/asf/datafusion.git
commit a8d1af6b8a82ded56eb547ad698b224c1f8bf7be Author: xudong.w <[email protected]> AuthorDate: Mon Jul 20 12:09:26 2026 +0800 fix: prevent LEAD/LAG IGNORE NULLS panic without null bitmap (#23706) ## Which issue does this PR close? - Closes #23705. ## Rationale for this change Arrow arrays containing no null values commonly omit the null bitmap. The whole-partition evaluation path for `LEAD` and `LAG` with `IGNORE NULLS` unconditionally unwrapped that optional bitmap, causing a panic for valid non-null input arrays. ## What changes are included in this PR? - Fall back to the existing regular shift implementation when the input has no null bitmap. - Add a regression test covering both `LEAD` and `LAG` with an array that explicitly has no null bitmap. ## Are these changes tested? Yes. ## Are there any user-facing changes? `LEAD` and `LAG` with `IGNORE NULLS` no longer panic when the input Arrow array has no null bitmap. There are no public API changes. --- datafusion/functions-window/src/lead_lag.rs | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/datafusion/functions-window/src/lead_lag.rs b/datafusion/functions-window/src/lead_lag.rs index de4071c0ce..2363a6beed 100644 --- a/datafusion/functions-window/src/lead_lag.rs +++ b/datafusion/functions-window/src/lead_lag.rs @@ -433,8 +433,12 @@ fn evaluate_all_with_ignore_null( default_value: &ScalarValue, is_lag: bool, ) -> Result<ArrayRef, DataFusionError> { - let valid_indices: Vec<usize> = - array.nulls().unwrap().valid_indices().collect::<Vec<_>>(); + // Arrays without NULLs do not necessarily have a null bitmap. + let Some(nulls) = array.nulls() else { + return shift_with_default_value(array, offset, default_value); + }; + + let valid_indices: Vec<usize> = nulls.valid_indices().collect::<Vec<_>>(); let direction = !is_lag; let new_array_results: Result<Vec<_>, DataFusionError> = (0..array.len()) .map(|id| { @@ -838,4 +842,25 @@ mod tests { .collect::<Int32Array>(), ) } + + #[test] + fn test_ignore_nulls_without_null_bitmap() -> Result<()> { + let input = Int32Array::from(vec![1, 2, 3]); + assert!(input.nulls().is_none()); + let input: ArrayRef = Arc::new(input); + + for (offset, expected) in [ + (1, Int32Array::from(vec![None, Some(1), Some(2)])), + (-1, Int32Array::from(vec![Some(2), Some(3), None])), + ] { + let actual = evaluate_all_with_ignore_null( + &input, + offset, + &ScalarValue::Int32(None), + offset > 0, + )?; + assert_eq!(expected, *as_int32_array(&actual)?); + } + Ok(()) + } } --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
