@@ -12342,3 +12342,170 @@ def test_audits_in_embedded_model():
1234212342 )
1234312343 with pytest .raises (ConfigError , match = "Audits are not supported for embedded models" ):
1234412344 load_sql_based_model (expression ).validate_definition ()
12345+
12346+
12347+ def test_default_catalog_not_leaked_to_unsupported_gateway ():
12348+ """
12349+ Regression test for https://github.com/SQLMesh/sqlmesh/issues/5748
12350+
12351+ When a model targets a gateway that is NOT in default_catalog_per_gateway,
12352+ the global default_catalog should be cleared (set to None) instead of
12353+ leaking through from the default gateway.
12354+ """
12355+ from sqlglot import parse
12356+
12357+ expressions = parse (
12358+ """
12359+ MODEL (
12360+ name my_schema.my_model,
12361+ kind FULL,
12362+ gateway clickhouse_gw,
12363+ dialect clickhouse,
12364+ );
12365+
12366+ SELECT 1 AS id
12367+ """ ,
12368+ read = "clickhouse" ,
12369+ )
12370+
12371+ default_catalog_per_gateway = {
12372+ "default_gw" : "example_catalog" ,
12373+ }
12374+
12375+ models = load_sql_based_models (
12376+ expressions ,
12377+ get_variables = lambda gw : {},
12378+ dialect = "clickhouse" ,
12379+ default_catalog_per_gateway = default_catalog_per_gateway ,
12380+ default_catalog = "example_catalog" ,
12381+ )
12382+
12383+ assert len (models ) == 1
12384+ model = models [0 ]
12385+
12386+ assert not model .catalog , (
12387+ f"Default gateway catalog leaked into catalog-unsupported gateway model. "
12388+ f"Expected no catalog, got: { model .catalog } "
12389+ )
12390+ assert "example_catalog" not in model .fqn , (
12391+ f"Default gateway catalog found in model FQN: { model .fqn } "
12392+ )
12393+
12394+
12395+ def test_default_catalog_still_applied_to_supported_gateway ():
12396+ """
12397+ Control test: when a model targets a gateway that IS in default_catalog_per_gateway,
12398+ the catalog should still be correctly applied.
12399+ """
12400+ from sqlglot import parse
12401+
12402+ expressions = parse (
12403+ """
12404+ MODEL (
12405+ name my_schema.my_model,
12406+ kind FULL,
12407+ gateway other_duckdb,
12408+ );
12409+
12410+ SELECT 1 AS id
12411+ """ ,
12412+ read = "duckdb" ,
12413+ )
12414+
12415+ default_catalog_per_gateway = {
12416+ "default_gw" : "example_catalog" ,
12417+ "other_duckdb" : "other_db" ,
12418+ }
12419+
12420+ models = load_sql_based_models (
12421+ expressions ,
12422+ get_variables = lambda gw : {},
12423+ dialect = "duckdb" ,
12424+ default_catalog_per_gateway = default_catalog_per_gateway ,
12425+ default_catalog = "example_catalog" ,
12426+ )
12427+
12428+ assert len (models ) == 1
12429+ model = models [0 ]
12430+
12431+ assert model .catalog == "other_db" , f"Expected catalog 'other_db', got: { model .catalog } "
12432+
12433+
12434+ def test_no_gateway_uses_global_default_catalog ():
12435+ """
12436+ Control test: when a model does NOT specify a gateway, the global
12437+ default_catalog should still be applied as before.
12438+ """
12439+ from sqlglot import parse
12440+
12441+ expressions = parse (
12442+ """
12443+ MODEL (
12444+ name my_schema.my_model,
12445+ kind FULL,
12446+ );
12447+
12448+ SELECT 1 AS id
12449+ """ ,
12450+ read = "duckdb" ,
12451+ )
12452+
12453+ model = load_sql_based_model (
12454+ expressions ,
12455+ default_catalog = "example_catalog" ,
12456+ dialect = "duckdb" ,
12457+ )
12458+
12459+ assert model .catalog == "example_catalog"
12460+
12461+
12462+ def test_blueprint_catalog_not_cross_contaminated ():
12463+ """
12464+ When blueprints iterate over different gateways, the catalog from one
12465+ blueprint iteration should not leak into the next. A ClickHouse blueprint
12466+ setting default_catalog to None should not prevent the following blueprint
12467+ from getting its correct catalog.
12468+ """
12469+ from sqlglot import parse
12470+
12471+ expressions = parse (
12472+ """
12473+ MODEL (
12474+ name @{blueprint}.my_model,
12475+ kind FULL,
12476+ gateway @{gw},
12477+ blueprints (
12478+ (blueprint := ch_schema, gw := clickhouse_gw),
12479+ (blueprint := db_schema, gw := default_gw),
12480+ ),
12481+ );
12482+
12483+ SELECT 1 AS id
12484+ """ ,
12485+ read = "duckdb" ,
12486+ )
12487+
12488+ default_catalog_per_gateway = {
12489+ "default_gw" : "example_catalog" ,
12490+ }
12491+
12492+ models = load_sql_based_models (
12493+ expressions ,
12494+ get_variables = lambda gw : {},
12495+ dialect = "duckdb" ,
12496+ default_catalog_per_gateway = default_catalog_per_gateway ,
12497+ default_catalog = "example_catalog" ,
12498+ )
12499+
12500+ assert len (models ) == 2
12501+
12502+ ch_model = next (m for m in models if "ch_schema" in m .fqn )
12503+ db_model = next (m for m in models if "db_schema" in m .fqn )
12504+
12505+ assert not ch_model .catalog , (
12506+ f"Catalog leaked into ClickHouse blueprint. Got: { ch_model .catalog } "
12507+ )
12508+
12509+ assert db_model .catalog == "example_catalog" , (
12510+ f"Catalog lost for DuckDB blueprint after ClickHouse iteration. Got: { db_model .catalog } "
12511+ )
0 commit comments