@@ -657,6 +657,42 @@ class CometJoinSuite extends CometTestBase {
657657 }
658658 }
659659
660+ // Reproducer for SPARK-43113: full outer SMJ with a join filter that references
661+ // a nullable column should not match when the filter evaluates to NULL.
662+ test(" SPARK-43113: Full outer SMJ with NULL in join filter" ) {
663+ withTempView(" l" , " r" ) {
664+ // testData2: (a, b) — all non-null
665+ Seq ((1 , 1 ), (1 , 2 ), (2 , 1 ), (2 , 2 ), (3 , 1 ), (3 , 2 ))
666+ .toDF(" a" , " b" )
667+ .createOrReplaceTempView(" l" )
668+
669+ // testData3: (a, b) — b is nullable
670+ Seq ((1 , None ), (2 , Some (2 )))
671+ .toDF(" a" , " b" )
672+ .createOrReplaceTempView(" r" )
673+
674+ val query =
675+ """ select /*+ MERGE(r) */ *
676+ |from l
677+ |full outer join r
678+ |on l.a = r.a
679+ |and l.b < (r.b + 1)
680+ |and l.b < (r.a + 1)""" .stripMargin
681+
682+ val expected = Seq (
683+ (Some (1 ), Some (1 ), None , None ),
684+ (Some (1 ), Some (2 ), None , None ),
685+ (None , None , Some (1 ), None ),
686+ (Some (2 ), Some (1 ), Some (2 ), Some (2 )),
687+ (Some (2 ), Some (2 ), Some (2 ), Some (2 )),
688+ (Some (3 ), Some (1 ), None , None ),
689+ (Some (3 ), Some (2 ), None , None )).toDF(" a" , " b" , " a" , " b" )
690+
691+ val df = sql(query)
692+ checkAnswer(df, expected)
693+ }
694+ }
695+
660696 test(" Broadcast exchange respects AQE shuffle partition coalescing" ) {
661697 // When a shuffle feeds into a broadcast exchange, AQE may coalesce the shuffle
662698 // partitions. The broadcast collect should execute through the AQEShuffleReadExec
0 commit comments