@@ -584,3 +584,277 @@ FROM employees | WHERE emp_no IN (10001, null) AND first_name IS NOT NULL | SORT
584584emp_no:integer | first_name:keyword
58558510001 | Georgi
586586;
587+
588+ // Tests for fix: (a IS NOT NULL OR p) AND a IS NULL must not discard the surviving OR branch p.
589+ // Without the fix, PropagateNullable.nullify() replaced the entire OR with null, returning 0 rows.
590+
591+ isNullWithOrDisjunctionAllRows
592+ required_capability: fix_propagate_nullable_or_disjunction
593+
594+ FROM employees
595+ | WHERE (gender IS NOT NULL OR emp_no > 10000) AND gender IS NULL
596+ | STATS c = COUNT(*)
597+ ;
598+
599+ c:long
600+ 10
601+ ;
602+
603+ isNullWithOrDisjunctionSurvivingBranchFilters
604+ required_capability: fix_propagate_nullable_or_disjunction
605+
606+ FROM employees
607+ | WHERE (gender IS NOT NULL OR emp_no > 10015) AND gender IS NULL
608+ | SORT emp_no
609+ | KEEP emp_no, gender
610+ ;
611+
612+ emp_no:integer|gender:keyword
613+ 10016 |null
614+ 10017 |null
615+ 10018 |null
616+ 10019 |null
617+ ;
618+
619+ isNullWithNestedOrDisjunction
620+ required_capability: fix_propagate_nullable_or_disjunction
621+
622+ FROM employees
623+ | WHERE emp_no > 10000 AND (gender IS NOT NULL OR languages > 4) AND gender IS NULL
624+ | SORT emp_no
625+ | KEEP emp_no, gender
626+ ;
627+
628+ emp_no:integer|gender:keyword
629+ 10011 |null
630+ 10012 |null
631+ 10014 |null
632+ 10015 |null
633+ ;
634+
635+ isNullWithIsNullInsideOr
636+ required_capability: fix_propagate_nullable_or_disjunction
637+
638+ FROM employees
639+ | WHERE (gender IS NULL OR emp_no > 10000) AND gender IS NULL
640+ | STATS c = COUNT(*)
641+ ;
642+
643+ c:long
644+ 10
645+ ;
646+
647+ isNullWithOrSalaryFilter
648+ required_capability: fix_propagate_nullable_or_disjunction
649+
650+ FROM employees
651+ | WHERE (gender IS NOT NULL OR salary > 50000) AND gender IS NULL
652+ | SORT emp_no
653+ | KEEP emp_no, gender, salary
654+ ;
655+
656+ emp_no:integer|gender:keyword|salary:integer
657+ 10016 |null |61358
658+ 10017 |null |58715
659+ 10018 |null |56760
660+ 10019 |null |73717
661+ ;
662+
663+ isNullWithOrLanguageFilter
664+ required_capability: fix_propagate_nullable_or_disjunction
665+
666+ FROM employees
667+ | WHERE (gender IS NOT NULL OR languages > 3) AND gender IS NULL
668+ | SORT emp_no
669+ | KEEP emp_no, gender, languages
670+ ;
671+
672+ emp_no:integer|gender:keyword|languages:integer
673+ 10010 |null |4
674+ 10011 |null |5
675+ 10012 |null |5
676+ 10014 |null |5
677+ 10015 |null |5
678+ ;
679+
680+ isNullWithOrDisjunctionSeparateWhereClauses
681+ required_capability: fix_propagate_nullable_or_disjunction
682+
683+ FROM employees
684+ | WHERE gender IS NOT NULL OR emp_no > 10015
685+ | WHERE gender IS NULL
686+ | SORT emp_no
687+ | KEEP emp_no, gender
688+ ;
689+
690+ emp_no:integer|gender:keyword
691+ 10016 |null
692+ 10017 |null
693+ 10018 |null
694+ 10019 |null
695+ ;
696+
697+ isNullWithOrDisjunctionStatsByLanguage
698+ required_capability: fix_propagate_nullable_or_disjunction
699+ required_capability: inline_stats
700+
701+ FROM employees
702+ | WHERE (gender IS NOT NULL OR languages > 3) AND gender IS NULL
703+ | INLINE STATS c = COUNT(*) BY languages
704+ | SORT emp_no
705+ | KEEP emp_no, gender, languages, c
706+ ;
707+
708+ emp_no:integer|gender:keyword|languages:integer|c:long
709+ 10010 |null |4 |1
710+ 10011 |null |5 |4
711+ 10012 |null |5 |4
712+ 10014 |null |5 |4
713+ 10015 |null |5 |4
714+ ;
715+
716+ isNullWithOrThreeBranches
717+ required_capability: fix_propagate_nullable_or_disjunction
718+
719+ FROM employees
720+ | WHERE (gender IS NOT NULL OR emp_no > 10017 OR salary > 60000) AND gender IS NULL
721+ | SORT emp_no
722+ | KEEP emp_no, gender, salary
723+ ;
724+
725+ emp_no:integer|gender:keyword|salary:integer
726+ 10016 |null |61358
727+ 10018 |null |56760
728+ 10019 |null |73717
729+ ;
730+
731+ isNullWithOrEvalAlias
732+ required_capability: fix_propagate_nullable_or_disjunction
733+
734+ FROM employees
735+ | EVAL g = gender
736+ | WHERE (g IS NOT NULL OR emp_no > 10015) AND g IS NULL
737+ | SORT emp_no
738+ | KEEP emp_no, g
739+ ;
740+
741+ emp_no:integer|g:keyword
742+ 10016 |null
743+ 10017 |null
744+ 10018 |null
745+ 10019 |null
746+ ;
747+
748+ isNullWithOrCompoundAndRangeEvalSeparateWhereClauses
749+ required_capability: fix_propagate_nullable_or_disjunction
750+
751+ FROM employees
752+ | EVAL nullable = gender
753+ | KEEP emp_no, nullable, gender
754+ | WHERE nullable IS NOT NULL OR (emp_no > 10010 AND emp_no <= 10016)
755+ | WHERE nullable IS NULL
756+ | SORT emp_no
757+ ;
758+
759+ emp_no:integer|nullable:keyword|gender:keyword
760+ 10011 |null |null
761+ 10012 |null |null
762+ 10013 |null |null
763+ 10014 |null |null
764+ 10015 |null |null
765+ 10016 |null |null
766+ ;
767+
768+ isNullWithOrDisjunctionMvEvalNull
769+ required_capability: fix_propagate_nullable_or_disjunction
770+
771+ FROM employees
772+ | WHERE emp_no >= 10009 AND emp_no <= 10015
773+ | EVAL sc = salary_change + 1
774+ | WHERE (sc IS NOT NULL OR emp_no > 10011) AND sc IS NULL
775+ | SORT emp_no
776+ | KEEP emp_no, salary_change, sc
777+ ;
778+ warningRegex:Line \d+:\d+: evaluation of \[salary_change \+ 1\] failed, treating result as null\. Only first 20 failures recorded\.
779+ warningRegex:Line \d+:\d+: java\.lang\.IllegalArgumentException: single-value function encountered multi-value
780+
781+ emp_no:integer|salary_change:double|sc:double
782+ 10013 |null |null
783+ 10014 |[-1.89, 9.07] |null
784+ 10015 |[12.4, 14.25] |null
785+ ;
786+
787+ isNullWithOrDisjunctionMvEvalNullSeparateWhereClauses
788+ required_capability: fix_propagate_nullable_or_disjunction
789+
790+ FROM employees
791+ | WHERE emp_no >= 10009 AND emp_no <= 10015
792+ | EVAL sc = salary_change + 1
793+ | WHERE sc IS NOT NULL OR emp_no > 10011
794+ | WHERE sc IS NULL
795+ | SORT emp_no
796+ | KEEP emp_no, salary_change, sc
797+ ;
798+ warningRegex:Line \d+:\d+: evaluation of \[salary_change \+ 1\] failed, treating result as null\. Only first 20 failures recorded\.
799+ warningRegex:Line \d+:\d+: java\.lang\.IllegalArgumentException: single-value function encountered multi-value
800+
801+ emp_no:integer|salary_change:double|sc:double
802+ 10013 |null |null
803+ 10014 |[-1.89, 9.07] |null
804+ 10015 |[12.4, 14.25] |null
805+ ;
806+
807+ isNotNullWithOrDisjunctionSurvivingBranch
808+ required_capability: fix_propagate_nullable_or_disjunction
809+
810+ FROM employees
811+ | WHERE (gender IS NULL OR emp_no <= 10009) AND gender IS NOT NULL
812+ | SORT emp_no
813+ | KEEP emp_no, gender
814+ ;
815+
816+ emp_no:integer|gender:keyword
817+ 10001 |M
818+ 10002 |F
819+ 10003 |M
820+ 10004 |M
821+ 10005 |M
822+ 10006 |F
823+ 10007 |F
824+ 10008 |M
825+ 10009 |F
826+ ;
827+
828+ isNotNullWithIsNotNullInsideOr
829+ required_capability: fix_propagate_nullable_or_disjunction
830+
831+ FROM employees
832+ | WHERE (gender IS NOT NULL OR emp_no <= 10009) AND gender IS NOT NULL
833+ | STATS c = COUNT(*)
834+ ;
835+
836+ c:long
837+ 90
838+ ;
839+
840+ isNotNullWithOrDisjunctionSeparateWhereClauses
841+ required_capability: fix_propagate_nullable_or_disjunction
842+
843+ FROM employees
844+ | WHERE gender IS NULL OR emp_no <= 10009
845+ | WHERE gender IS NOT NULL
846+ | SORT emp_no
847+ | KEEP emp_no, gender
848+ ;
849+
850+ emp_no:integer|gender:keyword
851+ 10001 |M
852+ 10002 |F
853+ 10003 |M
854+ 10004 |M
855+ 10005 |M
856+ 10006 |F
857+ 10007 |F
858+ 10008 |M
859+ 10009 |F
860+ ;
0 commit comments