Skip to content
59 changes: 47 additions & 12 deletions sqlmesh/core/renderer.py
Original file line number Diff line number Diff line change
Expand Up @@ -330,12 +330,32 @@ def _resolve_table(
table_mapping: t.Optional[t.Dict[str, str]] = None,
deployability_index: t.Optional[DeployabilityIndex] = None,
) -> exp.Table:
table_mapping = table_mapping or {}
if isinstance(table_name, str):
# An exact FQN match avoids scanning unrelated snapshots.
snapshot = snapshots.get(table_name) if snapshots else None
if snapshot is None and table_name not in table_mapping:
# Keys normalized under different dialects may differ in casing or quoting.
# Fall back to the full mapping so exp.replace_tables can reconcile them.
mapping = {
**self._to_table_mapping((snapshots or {}).values(), deployability_index),
**table_mapping,
}
else:
mapping = {
**self._to_table_mapping([snapshot] if snapshot else [], deployability_index),
# Keep all explicit overrides to preserve precedence for equivalent keys.
**table_mapping,
}
else:
mapping = {
**self._to_table_mapping((snapshots or {}).values(), deployability_index),
**table_mapping,
}

table = exp.replace_tables(
t.cast(exp.Table, exp.maybe_parse(table_name, into=exp.Table, dialect=self._dialect)),
{
**self._to_table_mapping((snapshots or {}).values(), deployability_index),
**(table_mapping or {}),
},
mapping,
dialect=self._dialect,
copy=False,
)
Expand Down Expand Up @@ -363,12 +383,15 @@ def _resolve_tables(

expression = expression.copy()
with self._normalize_and_quote(expression) as expression:
# An expression with no exp.Table node at all (e.g. session/virtual properties) has
# nothing for `expand` to expand or for a table mapping to replace - skip building
# the expand set and model_mapping too, not just the mapping/replace_tables below,
# since both of those are themselves O(N) in the number of snapshots.
if not expression.find(exp.Table):
return expression

snapshots = snapshots or {}
table_mapping = table_mapping or {}
mapping = {
**self._to_table_mapping(snapshots.values(), deployability_index),
**table_mapping,
}
expand = set(expand) | {
name for name, snapshot in snapshots.items() if snapshot.is_embedded
}
Expand Down Expand Up @@ -410,10 +433,22 @@ def _expand(node: exp.Expr) -> exp.Expr:

expression = expression.transform(_expand, copy=False) # type: ignore

if mapping:
expression = exp.replace_tables(
expression, mapping, dialect=self._dialect, copy=False
)
# Building the full snapshot -> table-name mapping and normalizing it in
# exp.replace_tables is O(N) in the number of snapshots in the environment; skip it
# entirely for expressions that don't reference any table at all (e.g. session/
# virtual properties), since there's nothing for the mapping to replace.
if expression.find(exp.Table):
# mypy loses the `snapshots`/`table_mapping` narrowing above because they're
# captured by the `_expand` closure defined earlier in this block.
assert snapshots is not None and table_mapping is not None
mapping = {
**self._to_table_mapping(snapshots.values(), deployability_index),
**table_mapping,
}
if mapping:
expression = exp.replace_tables(
expression, mapping, dialect=self._dialect, copy=False
)

return expression

Expand Down
Loading
Loading