1313 _polyglot_cte_passthrough_facts ,
1414 _polyglot_cte_passthrough_nullability_from_parsed ,
1515 _polyglot_cte_passthrough_types_from_parsed ,
16+ _polyglot_expression_is_non_null_after_filter ,
17+ _polyglot_filtered_non_null_outputs ,
18+ _polyglot_non_null_filter_context ,
1619)
1720from sqlbuild .compiler .compile .constants import (
1821 DECIMAL_SQL_TYPE_NAME ,
2932 CompileSqlReference ,
3033 CteFactResolvers ,
3134 InferredColumn ,
35+ NonNullFilterContext ,
3236 PolyglotAnalysisResult ,
3337)
3438from sqlbuild .compiler .compile .types import CompiledResourceType
@@ -483,7 +487,7 @@ def _analyze_columns_and_lineage_with_compact_polyglot(
483487 return None
484488 reference_map : dict [str , tuple [CompiledResourceType , str ]] = _lineage_reference_map (references )
485489 relation_alias_by_name : dict [str , str | None ] = _compact_relation_alias_by_name (analysis )
486- cte_passthrough_types , cte_passthrough_nullability , direct_cte_outputs = (
490+ cte_passthrough_types , cte_passthrough_nullability , direct_cte_outputs , parsed = (
487491 _polyglot_cte_passthrough_facts (
488492 polyglot_module = polyglot_module ,
489493 cleaned_sql = cleaned_sql ,
@@ -500,7 +504,15 @@ def _analyze_columns_and_lineage_with_compact_polyglot(
500504 ),
501505 )
502506 if recover_cte_facts
503- else ({}, {}, frozenset ())
507+ else ({}, {}, frozenset (), None )
508+ )
509+ filtered_non_null_outputs : frozenset [str ] = _polyglot_filtered_non_null_outputs (
510+ polyglot_module = polyglot_module ,
511+ cleaned_sql = cleaned_sql ,
512+ dialect = dialect ,
513+ analysis = analysis ,
514+ column_nullability_by_table = column_nullability_by_table ,
515+ parsed = parsed ,
504516 )
505517 columns : list [InferredColumn ] = []
506518 lineage_columns : list [CompiledLineageColumnFact ] = []
@@ -527,12 +539,19 @@ def _analyze_columns_and_lineage_with_compact_polyglot(
527539 )
528540 ),
529541 nullability = (
530- cte_passthrough_nullability .get (output_column )
531- if output_column in direct_cte_outputs
532- else None
533- )
534- or _compact_projection_nullability (
535- projection = projection , infer_nullability = infer_nullability
542+ InferredNullability .NON_NULL
543+ if output_column in filtered_non_null_outputs
544+ else (
545+ (
546+ cte_passthrough_nullability .get (output_column )
547+ if output_column in direct_cte_outputs
548+ else None
549+ )
550+ or _compact_projection_nullability (
551+ projection = projection ,
552+ infer_nullability = infer_nullability ,
553+ )
554+ )
536555 ),
537556 )
538557 )
@@ -848,6 +867,10 @@ def _infer_columns_from_polyglot_ast(
848867 alias_nullability_resolver = _polyglot_alias_nullability_from_select ,
849868 )
850869 )
870+ non_null_filter_context : NonNullFilterContext | None = _polyglot_non_null_filter_context (
871+ select = select ,
872+ column_nullability_by_table = column_nullability_by_table ,
873+ )
851874 columns : list [InferredColumn ] = []
852875 projection : Any
853876 for projection in getattr (select , "expressions" , ()):
@@ -868,14 +891,21 @@ def _infer_columns_from_polyglot_ast(
868891 )
869892 nullability : InferredNullability = InferredNullability .UNKNOWN
870893 if infer_nullability :
871- nullability = cte_passthrough_nullability . get (
872- name ,
873- _infer_polyglot_nullability (
894+ nullability = (
895+ InferredNullability . NON_NULL
896+ if _polyglot_expression_is_non_null_after_filter (
874897 expression = inner ,
875- alias_nullability = alias_nullability ,
876- column_nullability_by_table = column_nullability_by_table ,
877- inference_profile = inference_profile ,
878- ),
898+ context = non_null_filter_context ,
899+ )
900+ else cte_passthrough_nullability .get (
901+ name ,
902+ _infer_polyglot_nullability (
903+ expression = inner ,
904+ alias_nullability = alias_nullability ,
905+ column_nullability_by_table = column_nullability_by_table ,
906+ inference_profile = inference_profile ,
907+ ),
908+ )
879909 )
880910 columns .append (InferredColumn (name = name , type = col_type , nullability = nullability ))
881911 return tuple (columns )
@@ -935,6 +965,10 @@ def _analyze_columns_and_lineage_from_polyglot_ast(
935965 if recover_cte_facts
936966 else {}
937967 )
968+ non_null_filter_context : NonNullFilterContext | None = _polyglot_non_null_filter_context (
969+ select = select ,
970+ column_nullability_by_table = column_nullability_by_table ,
971+ )
938972 columns : list [InferredColumn ] = []
939973 lineage_columns : list [CompiledLineageColumnFact ] = []
940974 has_star : bool = False
@@ -963,21 +997,28 @@ def _analyze_columns_and_lineage_from_polyglot_ast(
963997 )
964998 nullability : InferredNullability = InferredNullability .UNKNOWN
965999 if infer_nullability :
966- nullability = cte_passthrough_nullability .get (
967- output_column ,
968- (
969- _infer_polyglot_nullability (
970- expression = inner ,
971- alias_nullability = alias_nullability ,
972- column_nullability_by_table = column_nullability_by_table ,
973- inference_profile = inference_profile ,
974- )
975- if has_known_nullability
976- else _infer_polyglot_shallow_nullability (
977- expression = inner ,
978- inference_profile = inference_profile ,
979- )
980- ),
1000+ nullability = (
1001+ InferredNullability .NON_NULL
1002+ if _polyglot_expression_is_non_null_after_filter (
1003+ expression = inner ,
1004+ context = non_null_filter_context ,
1005+ )
1006+ else cte_passthrough_nullability .get (
1007+ output_column ,
1008+ (
1009+ _infer_polyglot_nullability (
1010+ expression = inner ,
1011+ alias_nullability = alias_nullability ,
1012+ column_nullability_by_table = column_nullability_by_table ,
1013+ inference_profile = inference_profile ,
1014+ )
1015+ if has_known_nullability
1016+ else _infer_polyglot_shallow_nullability (
1017+ expression = inner ,
1018+ inference_profile = inference_profile ,
1019+ )
1020+ ),
1021+ )
9811022 )
9821023 columns .append (InferredColumn (name = output_column , type = col_type , nullability = nullability ))
9831024
0 commit comments