Skip to content

Commit

Permalink
Bump SQLAlchemy to 1.3 (apache#7099)
Browse files Browse the repository at this point in the history
* Bump sqla to >=1.3.1

* Refine mssql column types to only use N-prefixing when necessary

* make join explicit

* replace set with list

* Add additional test case for N-prefix

* Replace engine with dialect and fix linting error

* Remove unneeded import
  • Loading branch information
villebro authored and mistercrunch committed Mar 25, 2019
1 parent 80d6f5a commit 23e823f
Show file tree
Hide file tree
Showing 6 changed files with 48 additions and 13 deletions.
5 changes: 0 additions & 5 deletions docs/installation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -415,11 +415,6 @@ You can also use `PyAthena` library(no java required) like this ::

See `PyAthena <https://github.com/laughingman7743/PyAthena#sqlalchemy>`_.

MSSQL
-----

Full Unicode support requires SQLAlchemy 1.3 or later.

Snowflake
---------

Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ selenium==3.141.0
simplejson==3.15.0
six==1.11.0 # via bleach, cryptography, isodate, pathlib2, polyline, pydruid, python-dateutil, sqlalchemy-utils, wtforms-json
sqlalchemy-utils==0.32.21
sqlalchemy==1.2.18
sqlalchemy==1.3.1
sqlparse==0.2.4
unicodecsv==0.14.1
urllib3==1.22 # via requests, selenium
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ def get_git_sha():
'retry>=0.9.2',
'selenium>=3.141.0',
'simplejson>=3.15.0',
'sqlalchemy>=1.2.18, <1.3.0',
'sqlalchemy>=1.3.1,<2.0',
'sqlalchemy-utils',
'sqlparse',
'unicodecsv',
Expand Down
12 changes: 9 additions & 3 deletions superset/db_engine_specs.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
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
from sqlalchemy.types import String, UnicodeText
import sqlparse
from werkzeug.utils import secure_filename

Expand Down Expand Up @@ -1423,10 +1423,16 @@ def fetch_data(cls, cursor, limit):
data = [[elem for elem in r] for r in data]
return data

column_types = [
(String(), re.compile(r'^(?<!N)((VAR){0,1}CHAR|TEXT|STRING)', re.IGNORECASE)),
(UnicodeText(), re.compile(r'^N((VAR){0,1}CHAR|TEXT)', re.IGNORECASE)),
]

@classmethod
def get_sqla_column_type(cls, type_):
if isinstance(type_, str) and re.match(r'^N(VAR){0-1}CHAR', type_):
return UnicodeText()
for sqla_type, regex in cls.column_types:
if regex.match(type_):
return sqla_type
return None


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,8 @@ def replace(source, target):

query = (
session.query(Slice, Database)
.join(Table)
.join(Database)
.join(Table, Slice.datasource_id == Table.id)
.join(Database, Table.database_id == Database.id)
.filter(Slice.datasource_type == 'table')
.all()
)
Expand Down
36 changes: 35 additions & 1 deletion tests/db_engine_specs_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@
import inspect

import mock
from sqlalchemy import column
from sqlalchemy import column, select, table
from sqlalchemy.dialects.mssql import pymssql
from sqlalchemy.types import String, UnicodeText

from superset import db_engine_specs
from superset.db_engine_specs import (
Expand Down Expand Up @@ -346,3 +348,35 @@ def test_oracle_sqla_column_name_length_exceeded(self):
self.assertEqual(label.quote, True)
label_expected = '3b26974078683be078219674eeb8f5'
self.assertEqual(label, label_expected)

def test_mssql_column_types(self):
def assert_type(type_string, type_expected):
type_assigned = MssqlEngineSpec.get_sqla_column_type(type_string)
if type_expected is None:
self.assertIsNone(type_assigned)
else:
self.assertIsInstance(type_assigned, type_expected)

assert_type('INT', None)
assert_type('STRING', String)
assert_type('CHAR(10)', String)
assert_type('VARCHAR(10)', String)
assert_type('TEXT', String)
assert_type('NCHAR(10)', UnicodeText)
assert_type('NVARCHAR(10)', UnicodeText)
assert_type('NTEXT', UnicodeText)

def test_mssql_where_clause_n_prefix(self):
dialect = pymssql.dialect()
spec = MssqlEngineSpec
str_col = column('col', type_=spec.get_sqla_column_type('VARCHAR(10)'))
unicode_col = column('unicode_col', type_=spec.get_sqla_column_type('NTEXT'))
tbl = table('tbl')
sel = select([str_col, unicode_col]).\
select_from(tbl).\
where(str_col == 'abc').\
where(unicode_col == 'abc')

query = str(sel.compile(dialect=dialect, compile_kwargs={'literal_binds': True}))
query_expected = "SELECT col, unicode_col \nFROM tbl \nWHERE col = 'abc' AND unicode_col = N'abc'" # noqa
self.assertEqual(query, query_expected)

0 comments on commit 23e823f

Please sign in to comment.