@@ -277,33 +277,38 @@ fn list_extract<O: OffsetSizeTrait>(
277277
278278 let mut mutable = MutableArrayData :: new ( vec ! [ & data, & default_data] , true , index_array. len ( ) ) ;
279279
280- for ( row, ( offset_window, index) ) in offsets. windows ( 2 ) . zip ( index_array. values ( ) ) . enumerate ( ) {
280+ for ( row, ( offset_window, index) ) in offsets. windows ( 2 ) . zip ( index_array. iter ( ) ) . enumerate ( ) {
281281 let start = offset_window[ 0 ] . as_usize ( ) ;
282282 let len = offset_window[ 1 ] . as_usize ( ) - start;
283283
284- if let Some ( i) = adjust_index ( * index, len) ? {
285- mutable. extend ( 0 , start + i, start + i + 1 ) ;
286- } else if list_array. is_null ( row) {
284+ if list_array. is_null ( row) {
287285 mutable. extend_nulls ( 1 ) ;
288- } else if fail_on_error {
289- // Throw appropriate error based on whether this is element_at (one_based=true)
290- // or GetArrayItem (one_based=false)
291- let error = if one_based {
292- // element_at function
293- SparkError :: InvalidElementAtIndex {
294- index_value : * index,
295- array_size : len as i32 ,
296- }
286+ } else if let Some ( index) = index {
287+ if let Some ( i) = adjust_index ( index, len) ? {
288+ mutable. extend ( 0 , start + i, start + i + 1 ) ;
289+ } else if fail_on_error {
290+ // Throw appropriate error based on whether this is element_at (one_based=true)
291+ // or GetArrayItem (one_based=false)
292+ let error = if one_based {
293+ // element_at function
294+ SparkError :: InvalidElementAtIndex {
295+ index_value : index,
296+ array_size : len as i32 ,
297+ }
298+ } else {
299+ // GetArrayItem (arr[index])
300+ SparkError :: InvalidArrayIndex {
301+ index_value : index,
302+ array_size : len as i32 ,
303+ }
304+ } ;
305+ return Err ( error_wrapper ( error) ) ;
297306 } else {
298- // GetArrayItem (arr[index])
299- SparkError :: InvalidArrayIndex {
300- index_value : * index,
301- array_size : len as i32 ,
302- }
303- } ;
304- return Err ( error_wrapper ( error) ) ;
307+ mutable. extend ( 1 , 0 , 1 ) ;
308+ }
305309 } else {
306- mutable. extend ( 1 , 0 , 1 ) ;
310+ // index is NULL → result is NULL
311+ mutable. extend_nulls ( 1 ) ;
307312 }
308313 }
309314
@@ -382,4 +387,40 @@ mod test {
382387 ) ;
383388 Ok ( ( ) )
384389 }
390+
391+ #[ test]
392+ fn test_list_extract_null_index ( ) -> Result < ( ) > {
393+ // GetArrayItem returns incorrect results with dynamic (column) index containing nulls
394+ let list = ListArray :: from_iter_primitive :: < Int32Type , _ , _ > ( vec ! [
395+ Some ( vec![ Some ( 10 ) , Some ( 20 ) , Some ( 30 ) ] ) ,
396+ Some ( vec![ Some ( 10 ) , Some ( 20 ) , Some ( 30 ) ] ) ,
397+ Some ( vec![ Some ( 10 ) , Some ( 20 ) , Some ( 30 ) ] ) ,
398+ Some ( vec![ Some ( 1 ) ] ) ,
399+ None ,
400+ Some ( vec![ Some ( 10 ) , Some ( 20 ) ] ) ,
401+ ] ) ;
402+ let indices = Int32Array :: from ( vec ! [ Some ( 0 ) , Some ( 1 ) , Some ( 2 ) , Some ( 0 ) , Some ( 0 ) , None ] ) ;
403+
404+ let null_default = ScalarValue :: Int32 ( None ) ;
405+ let error_wrapper = |error : SparkError | DataFusionError :: from ( error) ;
406+
407+ let ColumnarValue :: Array ( result) = list_extract (
408+ & list,
409+ & indices,
410+ & null_default,
411+ false ,
412+ false ,
413+ |idx, len| zero_based_index ( idx, len, & error_wrapper) ,
414+ & error_wrapper,
415+ ) ?
416+ else {
417+ unreachable ! ( )
418+ } ;
419+
420+ assert_eq ! (
421+ & result. to_data( ) ,
422+ & Int32Array :: from( vec![ Some ( 10 ) , Some ( 20 ) , Some ( 30 ) , Some ( 1 ) , None , None ] ) . to_data( )
423+ ) ;
424+ Ok ( ( ) )
425+ }
385426}
0 commit comments