diff --git a/superset/db_engine_specs/base.py b/superset/db_engine_specs/base.py index 90dd89b5a5d..b26741203a1 100644 --- a/superset/db_engine_specs/base.py +++ b/superset/db_engine_specs/base.py @@ -856,3 +856,15 @@ class BaseEngineSpec: # pylint: disable=too-many-public-methods :return: Compiled column type """ return sqla_column_type.compile(dialect=dialect).upper() + + @staticmethod + def pyodbc_rows_to_tuples(data: List[Any]) -> List[Tuple]: + """ + Convert pyodbc.Row objects from `fetch_data` to tuples. + + :param data: List of tuples or pyodbc.Row objects + :return: List of tuples + """ + if data and type(data[0]).__name__ == "Row": + data = [tuple(row) for row in data] + return data diff --git a/superset/db_engine_specs/exasol.py b/superset/db_engine_specs/exasol.py index 380b59825e4..ea4a4003268 100644 --- a/superset/db_engine_specs/exasol.py +++ b/superset/db_engine_specs/exasol.py @@ -42,6 +42,4 @@ class ExasolEngineSpec(BaseEngineSpec): # pylint: disable=abstract-method def fetch_data(cls, cursor, limit: int) -> List[Tuple]: data = super().fetch_data(cursor, limit) # Lists of `pyodbc.Row` need to be unpacked further - if data and type(data[0]).__name__ == "Row": - data = [tuple(row) for row in data] - return data + return cls.pyodbc_rows_to_tuples(data) diff --git a/superset/db_engine_specs/mssql.py b/superset/db_engine_specs/mssql.py index c774077f612..94555b0a99d 100644 --- a/superset/db_engine_specs/mssql.py +++ b/superset/db_engine_specs/mssql.py @@ -63,9 +63,8 @@ class MssqlEngineSpec(BaseEngineSpec): @classmethod def fetch_data(cls, cursor, limit: int) -> List[Tuple]: data = super().fetch_data(cursor, limit) - if data and type(data[0]).__name__ == "Row": - data = [tuple(row) for row in data] - return data + # Lists of `pyodbc.Row` need to be unpacked further + return cls.pyodbc_rows_to_tuples(data) column_types = [ (String(), re.compile(r"^(?