diff --git a/docs/installation.rst b/docs/installation.rst index ecce52f48..85183c04b 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -405,6 +405,11 @@ You can also use `PyAthena` library(no java required) like this :: See `PyAthena `_. +MSSQL +----- + +Full Unicode support requires SQLAlchemy 1.3 or later. + Snowflake --------- diff --git a/superset/connectors/sqla/models.py b/superset/connectors/sqla/models.py index 8a21f529a..73f45c4a4 100644 --- a/superset/connectors/sqla/models.py +++ b/superset/connectors/sqla/models.py @@ -115,7 +115,9 @@ class TableColumn(Model, BaseColumn): label = label if label else self.column_name label = self.table.get_label(label) if not self.expression: - col = column(self.column_name).label(label) + db_engine_spec = self.table.database.db_engine_spec + type_ = db_engine_spec.get_sqla_column_type(self.type) + col = column(self.column_name, type_=type_).label(label) else: col = literal_column(self.expression).label(label) return col diff --git a/superset/db_engine_specs.py b/superset/db_engine_specs.py index f7247810b..937537bdb 100644 --- a/superset/db_engine_specs.py +++ b/superset/db_engine_specs.py @@ -46,6 +46,7 @@ from sqlalchemy.engine import create_engine from sqlalchemy.engine.url import make_url from sqlalchemy.sql import quoted_name, text from sqlalchemy.sql.expression import TextAsFrom +from sqlalchemy.types import UnicodeText import sqlparse from werkzeug.utils import secure_filename @@ -400,6 +401,15 @@ class BaseEngineSpec(object): label = cls.mutate_label(label) return quoted_name(label, True) if cls.force_column_alias_quotes else label + @classmethod + def get_sqla_column_type(cls, type_): + """ + Return a sqlalchemy native column type that corresponds to the column type + defined in the data source (optional). Needs to be overridden if column requires + special handling (see MSSQL for example of NCHAR/NVARCHAR handling). + """ + return None + @staticmethod def mutate_label(label): """ @@ -1362,6 +1372,12 @@ class MssqlEngineSpec(BaseEngineSpec): data = [[elem for elem in r] for r in data] return data + @classmethod + def get_sqla_column_type(cls, type_): + if isinstance(type_, str) and re.match(r'^N(VAR){0-1}CHAR', type_): + return UnicodeText() + return None + class AthenaEngineSpec(BaseEngineSpec): engine = 'awsathena'