Skip to content

Commit 05f8141

Browse files
committed
fix: prevent default catalog leak into catalog-unsupported gateways (#5748)
When a multi-gateway project uses a default gateway with a catalog (e.g. Trino), that catalog was silently prepended to model names targeting secondary gateways that don't support catalogs (e.g. ClickHouse), causing UnsupportedCatalogOperationError at evaluation. Root cause: catalog-unsupported adapters return None for default_catalog and are never added to default_catalog_per_gateway. The model loader cannot distinguish 'no catalog' from 'not checked', so the global default_catalog leaks through. Fix: explicitly register catalog-unsupported gateways with empty string in the per-gateway dict. The model loader's 'is not None' check picks this up and overrides default_catalog to '', preventing the leak. Signed-off-by: Bruce Arctor <brucearctor@users.noreply.github.com>
1 parent 8f092ac commit 05f8141

File tree

2 files changed

+66
-0
lines changed

2 files changed

+66
-0
lines changed

sqlmesh/core/config/scheduler.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,8 @@ def get_default_catalog_per_gateway(self, context: GenericContext) -> t.Dict[str
141141
for gateway, adapter in context.engine_adapters.items():
142142
if catalog := adapter.default_catalog:
143143
default_catalogs_per_gateway[gateway] = catalog
144+
elif adapter.catalog_support.is_unsupported:
145+
default_catalogs_per_gateway[gateway] = ""
144146
return default_catalogs_per_gateway
145147

146148

tests/core/test_model.py

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7186,6 +7186,70 @@ def test_gateway_macro_jinja() -> None:
71867186
assert model.render_query_or_raise().sql() == "SELECT 'in_memory' AS \"gateway_jinja\""
71877187

71887188

7189+
def test_default_catalog_not_leaked_to_unsupported_gateway() -> None:
7190+
"""Regression test for https://github.com/SQLMesh/sqlmesh/issues/5748.
7191+
7192+
When a model targets a gateway that does not support catalogs (e.g. ClickHouse),
7193+
the default gateway's catalog must not leak into the model's FQN. The scheduler
7194+
registers such gateways with empty string in default_catalog_per_gateway, and
7195+
the model loader should use that to override the global default_catalog.
7196+
"""
7197+
expressions = d.parse(
7198+
"""
7199+
MODEL (
7200+
name my_schema.my_model,
7201+
kind VIEW,
7202+
gateway clickhouse_gw,
7203+
dialect clickhouse,
7204+
);
7205+
SELECT 1 AS id
7206+
"""
7207+
)
7208+
7209+
# Simulate a multi-gateway setup: default gateway has catalog "example_catalog",
7210+
# but clickhouse_gw is catalog-unsupported (registered with empty string).
7211+
models = load_sql_based_models(
7212+
expressions,
7213+
get_variables=lambda gw: {},
7214+
dialect="clickhouse",
7215+
default_catalog="example_catalog",
7216+
default_catalog_per_gateway={
7217+
"default_gw": "example_catalog",
7218+
"clickhouse_gw": "",
7219+
},
7220+
)
7221+
7222+
assert len(models) == 1
7223+
model_result = models[0]
7224+
# The catalog should be empty — not the leaked "example_catalog"
7225+
assert model_result.catalog != "example_catalog"
7226+
# The FQN should be a two-part name, not three-part with the leaked catalog
7227+
assert "example_catalog" not in model_result.fqn
7228+
7229+
# Verify the positive case: without the per-gateway override, catalog leaks
7230+
models_leaked = load_sql_based_models(
7231+
d.parse(
7232+
"""
7233+
MODEL (
7234+
name my_schema.my_model2,
7235+
kind VIEW,
7236+
gateway clickhouse_gw,
7237+
dialect clickhouse,
7238+
);
7239+
SELECT 1 AS id
7240+
"""
7241+
),
7242+
get_variables=lambda gw: {},
7243+
dialect="clickhouse",
7244+
default_catalog="example_catalog",
7245+
# No entry for clickhouse_gw — catalog will leak
7246+
default_catalog_per_gateway={"default_gw": "example_catalog"},
7247+
)
7248+
assert len(models_leaked) == 1
7249+
# Without the fix, example_catalog leaks into the model name
7250+
assert "example_catalog" in models_leaked[0].fqn
7251+
7252+
71897253
def test_gateway_python_model(mocker: MockerFixture) -> None:
71907254
@model(
71917255
"test_gateway_python_model",

0 commit comments

Comments
 (0)