@@ -406,7 +406,9 @@ class CometCodegenSourceSuite extends AnyFunSuite {
406406 // - startNewValue / endValue bracketing
407407 // - setIndexDefined on each struct entry
408408 // - keyArray() / valueArray() retrieval from the MapData source
409- // - null-guard on the value write (key is always non-null per Arrow invariant)
409+ // Non-null literals here mean `valueContainsNull == false`, so the value-side null guard is
410+ // elided; the existence and elision of the `isNullAt` guard are exercised by the dedicated
411+ // [[NullableElementElision]] tests below.
410412 val expr = CreateMap (
411413 Seq (
412414 Literal .create(" a" , StringType ),
@@ -421,12 +423,53 @@ class CometCodegenSourceSuite extends AnyFunSuite {
421423 " .endValue(" ,
422424 " .setIndexDefined(" ,
423425 " .keyArray()" ,
424- " .valueArray()" ,
425- " .isNullAt(" ).foreach { marker =>
426+ " .valueArray()" ).foreach { marker =>
426427 assert(src.contains(marker), s " expected $marker in MapType output emission; got: \n $src" )
427428 }
428429 }
429430
431+ test(" ArrayType output elides isNullAt on the element loop when containsNull is false" ) {
432+ // CreateArray over only-non-null Literals produces ArrayType(elementType, containsNull=false).
433+ // The element write should drop the `arr.isNullAt(j)` guard at source level rather than
434+ // relying on JIT folding.
435+ val expr = CreateArray (Seq (Literal (1 , IntegerType ), Literal (2 , IntegerType )))
436+ val src = CometBatchKernelCodegen .generateSource(expr, IndexedSeq .empty).body
437+ assert(
438+ ! src.contains(" .isNullAt(" ),
439+ s " expected no isNullAt in element loop when containsNull=false; got: \n $src" )
440+ assert(src.contains(" .startNewValue(" ), s " expected startNewValue still emitted; got: \n $src" )
441+ }
442+
443+ test(" ArrayType output keeps isNullAt on the element loop when containsNull is true" ) {
444+ // CreateArray with at least one nullable child produces containsNull=true; the element
445+ // null-guard must survive.
446+ val expr =
447+ CreateArray (Seq (BoundReference (0 , IntegerType , nullable = true ), Literal (2 , IntegerType )))
448+ val intSpec = ArrowColumnSpec (
449+ CometBatchKernelCodegen .vectorClassBySimpleName(" IntVector" ),
450+ nullable = true )
451+ val src = CometBatchKernelCodegen .generateSource(expr, IndexedSeq (intSpec)).body
452+ assert(
453+ src.contains(" .isNullAt(" ),
454+ s " expected isNullAt in element loop when containsNull=true; got: \n $src" )
455+ }
456+
457+ test(" MapType output keeps value isNullAt when valueContainsNull is true" ) {
458+ // ElementAt with safe-index selection produces a nullable Int; wrapping the value column in
459+ // a CreateMap with that nullable Int makes valueContainsNull=true. The value-side null-guard
460+ // must survive.
461+ val expr =
462+ CreateMap (
463+ Seq (Literal .create(" a" , StringType ), BoundReference (0 , IntegerType , nullable = true )))
464+ val intSpec = ArrowColumnSpec (
465+ CometBatchKernelCodegen .vectorClassBySimpleName(" IntVector" ),
466+ nullable = true )
467+ val src = CometBatchKernelCodegen .generateSource(expr, IndexedSeq (intSpec)).body
468+ assert(
469+ src.contains(" .isNullAt(" ),
470+ s " expected isNullAt on the value-write branch when valueContainsNull=true; got: \n $src" )
471+ }
472+
430473 test(" ArrayType(StringType) input emits InputArray_col0 nested class with UTF8 child getter" ) {
431474 // Array input with string elements: the kernel must expose a `getArray(0)` that hands Spark's
432475 // `doGenCode` a zero-allocation `ArrayData` view onto the Arrow `ListVector`'s child
0 commit comments