|
9 | 9 | from sqlbuild.adapter.type_system.main.normalize_type import normalize_type |
10 | 10 | from sqlbuild.adapter.type_system.main.types_equal import types_equal |
11 | 11 | from sqlbuild.compiler.compile.constants import SQL_WILDCARD_TOKEN |
| 12 | +from sqlbuild.compiler.compile.models import CteFactResolvers |
12 | 13 | from sqlbuild.compiler.lineage.types import InferredNullability |
13 | 14 | from sqlbuild.compiler.sql_analysis.constants import ( |
14 | 15 | POLYGLOT_BINARY_OPERAND_COUNT as _POLYGLOT_BINARY_OPERAND_COUNT, |
@@ -97,36 +98,57 @@ def __call__( |
97 | 98 | ) -> dict[str, InferredNullability]: ... |
98 | 99 |
|
99 | 100 |
|
100 | | -def _polyglot_cte_passthrough_type_facts( |
| 101 | +def _polyglot_cte_passthrough_facts( |
101 | 102 | *, |
102 | 103 | polyglot_module: Any, |
103 | 104 | cleaned_sql: str, |
104 | 105 | dialect: str | None, |
105 | 106 | column_types_by_table: dict[str, dict[str, str]], |
| 107 | + column_nullability_by_table: dict[str, dict[str, InferredNullability]], |
106 | 108 | inference_profile: ExpressionInferenceProfile, |
107 | 109 | analysis: dict[str, Any], |
108 | | - expression_type_resolver: _ExpressionTypeResolver, |
109 | | -) -> tuple[dict[str, str], frozenset[str]]: |
110 | | - """Recover types that compact analysis incorrectly skips across direct CTE reads.""" |
| 110 | + resolvers: CteFactResolvers, |
| 111 | +) -> tuple[dict[str, str], dict[str, InferredNullability], frozenset[str]]: |
| 112 | + """Recover facts that compact analysis skips across direct CTE reads.""" |
111 | 113 |
|
112 | | - if not column_types_by_table or not analysis.get("cteFacts"): |
113 | | - return {}, frozenset() |
| 114 | + if not analysis.get("cteFacts") or not (column_types_by_table or column_nullability_by_table): |
| 115 | + return {}, {}, frozenset() |
114 | 116 | try: |
115 | 117 | parsed: Any = polyglot_module.parse_one(cleaned_sql, dialect=dialect or "generic") |
116 | 118 | except polyglot_module.PolyglotError: |
117 | | - return {}, frozenset() |
| 119 | + return {}, {}, frozenset() |
118 | 120 | ctes: tuple[tuple[str, Any, bool], ...] = _polyglot_top_level_ctes(parsed) |
119 | 121 | if not ctes: |
120 | | - return {}, frozenset() |
121 | | - inferred_types: dict[str, str] = _polyglot_cte_passthrough_types_from_parsed( |
122 | | - parsed=parsed, |
123 | | - column_types_by_table=column_types_by_table, |
124 | | - inference_profile=inference_profile, |
125 | | - expression_type_resolver=expression_type_resolver, |
| 122 | + return {}, {}, frozenset() |
| 123 | + inferred_types: dict[str, str] = ( |
| 124 | + _polyglot_cte_passthrough_types_from_parsed( |
| 125 | + parsed=parsed, |
| 126 | + column_types_by_table=column_types_by_table, |
| 127 | + inference_profile=inference_profile, |
| 128 | + expression_type_resolver=resolvers.expression_type, |
| 129 | + ) |
| 130 | + if column_types_by_table |
| 131 | + else {} |
126 | 132 | ) |
127 | | - return inferred_types, _polyglot_direct_cte_output_names( |
128 | | - parsed=parsed, |
129 | | - cte_names=frozenset(name for name, _, _ in ctes), |
| 133 | + inferred_nullability: dict[str, InferredNullability] = ( |
| 134 | + _polyglot_cte_passthrough_nullability_from_parsed( |
| 135 | + parsed=parsed, |
| 136 | + column_nullability_by_table=column_nullability_by_table, |
| 137 | + inference_profile=inference_profile, |
| 138 | + nullability_resolver=resolvers.nullability, |
| 139 | + shallow_nullability_resolver=resolvers.shallow_nullability, |
| 140 | + alias_nullability_resolver=resolvers.alias_nullability, |
| 141 | + ) |
| 142 | + if column_nullability_by_table |
| 143 | + else {} |
| 144 | + ) |
| 145 | + return ( |
| 146 | + inferred_types, |
| 147 | + inferred_nullability, |
| 148 | + _polyglot_direct_cte_output_names( |
| 149 | + parsed=parsed, |
| 150 | + cte_names=frozenset(name for name, _, _ in ctes), |
| 151 | + ), |
130 | 152 | ) |
131 | 153 |
|
132 | 154 |
|
|
0 commit comments