Skip to content

Commit 96d44e2

Browse files
kingjaitehclaude
andcommitted
fix(duckdb): match catalog names case-insensitively in _get_catalog_type
Catalog aliases keep their case in duckdb_databases() (e.g. MyLake), but SQLMesh lowercases table names, so the DuckLake lookup missed and CASCADE was emitted again. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: kingjaiteh <omarjaiteh453@gmail.com>
1 parent 9d3a6fb commit 96d44e2

2 files changed

Lines changed: 26 additions & 1 deletion

File tree

‎sqlmesh/core/engine_adapter/duckdb.py‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,11 @@ def _get_catalog_type(self, catalog: t.Optional[str]) -> t.Optional[str]:
232232
catalog_type_tuple = self.fetchone(
233233
exp.select("type")
234234
.from_("duckdb_databases()")
235-
.where(exp.column("database_name").eq(catalog))
235+
.where(
236+
exp.func("LOWER", exp.column("database_name")).eq(
237+
exp.func("LOWER", exp.Literal.string(catalog))
238+
)
239+
)
236240
)
237241
return catalog_type_tuple[0] if catalog_type_tuple else None
238242

‎tests/core/engine_adapter/test_duckdb.py‎

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,27 @@ def test_drop_table_ducklake_no_cascade(adapter: EngineAdapter, duck_conn, tmp_p
187187
assert not adapter.table_exists("memory.main.native_v")
188188

189189

190+
def test_drop_table_ducklake_no_cascade_mixed_case_alias(
191+
adapter: EngineAdapter, duck_conn, tmp_path
192+
):
193+
# Catalog aliases keep their case in duckdb_databases(), but SQLMesh normalizes
194+
# table names to lowercase, so the catalog type lookup must be case-insensitive.
195+
duck_conn.install_extension("ducklake")
196+
duck_conn.load_extension("ducklake")
197+
duck_conn.execute(
198+
f"ATTACH 'ducklake:{tmp_path}/my_lake.ducklake' AS \"MyLake\" (DATA_PATH '{tmp_path}');"
199+
)
200+
duck_conn.execute("CREATE SCHEMA MyLake.phys")
201+
duck_conn.execute("CREATE TABLE MyLake.phys.t (i INTEGER)")
202+
duck_conn.execute("CREATE VIEW MyLake.phys.v AS SELECT * FROM MyLake.phys.t")
203+
204+
adapter.drop_table("mylake.phys.t", cascade=True)
205+
adapter.drop_view("mylake.phys.v", cascade=True)
206+
207+
assert not adapter.table_exists("mylake.phys.t")
208+
assert not adapter.table_exists("mylake.phys.v")
209+
210+
190211
def test_drop_object_cascade_by_catalog_type(make_mocked_engine_adapter: t.Callable):
191212
adapter = make_mocked_engine_adapter(DuckDBEngineAdapter)
192213
adapter.fetchone = lambda *_args, **_kwargs: ("ducklake",) # type: ignore

0 commit comments

Comments
 (0)