From 34bc86a484feea629376c4f6b92d5b45d87d995a Mon Sep 17 00:00:00 2001 From: Yuval Moshe <53703174+Yuval-Moshe@users.noreply.github.com> Date: Mon, 21 Aug 2023 14:33:26 +0300 Subject: [PATCH] fix(mssql): avoid trying to return a resultset for DML queries with not resultset (#24999) (cherry picked from commit 66eabc253faf2c27db5aaf5283ab2e00fedaa817) --- superset/db_engine_specs/mssql.py | 2 ++ superset/sql_parse.py | 1 + tests/unit_tests/db_engine_specs/test_mssql.py | 11 ++++++++++- 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/superset/db_engine_specs/mssql.py b/superset/db_engine_specs/mssql.py index 5d29d36ba89b7..d5cc86c859a7b 100644 --- a/superset/db_engine_specs/mssql.py +++ b/superset/db_engine_specs/mssql.py @@ -141,6 +141,8 @@ def convert_dttm( def fetch_data( cls, cursor: Any, limit: Optional[int] = None ) -> list[tuple[Any, ...]]: + if not cursor.description: + return [] data = super().fetch_data(cursor, limit) # Lists of `pyodbc.Row` need to be unpacked further return cls.pyodbc_rows_to_tuples(data) diff --git a/superset/sql_parse.py b/superset/sql_parse.py index f917be80ab780..9a74b137e047f 100644 --- a/superset/sql_parse.py +++ b/superset/sql_parse.py @@ -217,6 +217,7 @@ def tables(self) -> set[Table]: def limit(self) -> Optional[int]: return self._limit + # pylint: disable=no-self-use def _get_cte_tables(self, parsed: dict[str, Any]) -> list[dict[str, Any]]: if "with" not in parsed: return [] diff --git a/tests/unit_tests/db_engine_specs/test_mssql.py b/tests/unit_tests/db_engine_specs/test_mssql.py index 8149e60cd83ee..56ff8879229e5 100644 --- a/tests/unit_tests/db_engine_specs/test_mssql.py +++ b/tests/unit_tests/db_engine_specs/test_mssql.py @@ -157,6 +157,14 @@ def test_extract_error_message() -> None: assert expected_message == error_message +def test_fetch_data_no_description() -> None: + from superset.db_engine_specs.mssql import MssqlEngineSpec + + cursor = mock.MagicMock() + cursor.description = [] + assert MssqlEngineSpec.fetch_data(cursor) == [] + + def test_fetch_data() -> None: from superset.db_engine_specs.base import BaseEngineSpec from superset.db_engine_specs.mssql import MssqlEngineSpec @@ -166,9 +174,10 @@ def test_fetch_data() -> None: "pyodbc_rows_to_tuples", return_value="converted", ) as mock_pyodbc_rows_to_tuples: + cursor = mock.MagicMock() data = [(1, "foo")] with mock.patch.object(BaseEngineSpec, "fetch_data", return_value=data): - result = MssqlEngineSpec.fetch_data(None, 0) + result = MssqlEngineSpec.fetch_data(cursor, 0) mock_pyodbc_rows_to_tuples.assert_called_once_with(data) assert result == "converted"