Skip to content

Commit de84a53

Browse files
authored
fix(DB update): Gracefully handle querry error during DB update (#33250)
1 parent ac636c7 commit de84a53

File tree

3 files changed

+45
-3
lines changed

3 files changed

+45
-3
lines changed

superset/commands/database/update.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,9 +80,19 @@ def run(self) -> Model:
8080
# existing personal tokens.
8181
self._handle_oauth2()
8282

83-
# build new DB
83+
# Some DBs require running a query to get the default catalog.
84+
# In these cases, if the current connection is broken then
85+
# `get_default_catalog` would raise an exception. We need to
86+
# gracefully handle that so that the connection can be fixed.
8487
original_database_name = self._model.database_name
85-
original_catalog = self._model.get_default_catalog()
88+
force_update: bool = False
89+
try:
90+
original_catalog = self._model.get_default_catalog()
91+
except Exception:
92+
original_catalog = None
93+
force_update = True
94+
95+
# build new DB
8696
database = DatabaseDAO.update(self._model, self._properties)
8797
database.set_sqlalchemy_uri(database.sqlalchemy_uri)
8898
ssh_tunnel = self._handle_ssh_tunnel(database)
@@ -92,7 +102,8 @@ def run(self) -> Model:
92102
# configured with multi-catalog support; if it was enabled or is enabled in the
93103
# update we don't update the assets
94104
if (
95-
new_catalog != original_catalog
105+
force_update
106+
or new_catalog != original_catalog
96107
and not self._model.allow_multi_catalog
97108
and not database.allow_multi_catalog
98109
):

superset/db_engine_specs/databricks.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -440,6 +440,8 @@ def get_default_catalog(cls, database: Database) -> str:
440440
"""
441441
Return the default catalog.
442442
443+
It's optionally specified in `connect_args.catalog`. If not:
444+
443445
The default behavior for Databricks is confusing. When Unity Catalog is not
444446
enabled we have (the DB engine spec hasn't been tested with it enabled):
445447
@@ -451,6 +453,10 @@ def get_default_catalog(cls, database: Database) -> str:
451453
To handle permissions correctly we use the result of `SHOW CATALOGS` when a
452454
single catalog is returned.
453455
"""
456+
connect_args = cls.get_extra_params(database)["engine_params"]["connect_args"]
457+
if default_catalog := connect_args.get("catalog"):
458+
return default_catalog
459+
454460
with database.get_sqla_engine() as engine:
455461
catalogs = {catalog for (catalog,) in engine.execute("SHOW CATALOGS")}
456462
if len(catalogs) == 1:

tests/unit_tests/commands/databases/update_test.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -642,3 +642,28 @@ def test_update_without_catalog_change(mocker: MockerFixture) -> None:
642642
UpdateDatabaseCommand(1, {}).run()
643643

644644
update_catalog_attribute.assert_not_called()
645+
646+
647+
def test_update_broken_connection(mocker: MockerFixture) -> None:
648+
"""
649+
Test that updating a database with a broken connection works
650+
even if it has to run a query to get the default catalog.
651+
"""
652+
database = mocker.MagicMock()
653+
database.get_default_catalog.side_effect = Exception("Broken connection")
654+
database.id = 1
655+
new_db = mocker.MagicMock()
656+
new_db.get_default_catalog.return_value = "main"
657+
658+
database_dao = mocker.patch("superset.commands.database.update.DatabaseDAO")
659+
database_dao.find_by_id.return_value = database
660+
database_dao.update.return_value = new_db
661+
mocker.patch("superset.commands.database.update.SyncPermissionsCommand")
662+
663+
update_catalog_attribute = mocker.patch.object(
664+
UpdateDatabaseCommand,
665+
"_update_catalog_attribute",
666+
)
667+
UpdateDatabaseCommand(1, {}).run()
668+
669+
update_catalog_attribute.assert_called_once_with(1, "main")

0 commit comments

Comments
 (0)