From: Mike Bayer Date: Tue, 4 Oct 2016 15:17:26 +0000 (-0400) Subject: Use SQL Server SERVERPROPERTY for version info w/ pyodbc X-Git-Tag: rel_1_1_0~10 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f0ea9e37f94bd39fa4f0785dbdcd0ee1759c4a11;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git Use SQL Server SERVERPROPERTY for version info w/ pyodbc Updated the server version info scheme for pyodbc to use SQL Server SERVERPROPERTY(), rather than relying upon pyodbc.SQL_DBMS_VER, which continues to be unreliable particularly with FreeTDS. Change-Id: I4ff49ae13c8ff51bd764980131d41c18d73d87ce Fixes: #3814 --- diff --git a/doc/build/changelog/changelog_10.rst b/doc/build/changelog/changelog_10.rst index b3e76b4756..0ea3633b7a 100644 --- a/doc/build/changelog/changelog_10.rst +++ b/doc/build/changelog/changelog_10.rst @@ -18,6 +18,15 @@ .. changelog:: :version: 1.0.16 + .. change:: + :tags: bug, mssql + :tickets: 3814 + :versions: 1.1.0 + + Updated the server version info scheme for pyodbc to use SQL Server + SERVERPROPERTY(), rather than relying upon pyodbc.SQL_DBMS_VER, which + continues to be unreliable particularly with FreeTDS. + .. change:: :tags: bug, orm :tickets: 3800 diff --git a/lib/sqlalchemy/connectors/pyodbc.py b/lib/sqlalchemy/connectors/pyodbc.py index 68bbcc4356..1811229d70 100644 --- a/lib/sqlalchemy/connectors/pyodbc.py +++ b/lib/sqlalchemy/connectors/pyodbc.py @@ -153,7 +153,6 @@ class PyODBCConnector(Connector): # run other initialization which asks for user name, etc. super(PyODBCConnector, self).initialize(connection) - def _dbapi_version(self): if not self.dbapi: return () @@ -172,6 +171,9 @@ class PyODBCConnector(Connector): return vers def _get_server_version_info(self, connection): + # NOTE: this function is not reliable, particularly when + # freetds is in use. Implement database-specific server version + # queries. dbapi_con = connection.connection version = [] r = re.compile('[.\-]') diff --git a/lib/sqlalchemy/dialects/mssql/base.py b/lib/sqlalchemy/dialects/mssql/base.py index 20b812731b..9db025df78 100644 --- a/lib/sqlalchemy/dialects/mssql/base.py +++ b/lib/sqlalchemy/dialects/mssql/base.py @@ -571,6 +571,8 @@ from ...util import update_wrapper from . import information_schema as ischema # http://sqlserverbuilds.blogspot.com/ +MS_2016_VERSION = (13,) +MS_2014_VERSION = (12,) MS_2012_VERSION = (11,) MS_2008_VERSION = (10,) MS_2005_VERSION = (9,) @@ -1712,18 +1714,9 @@ class MSDialect(default.DefaultDialect): def _setup_version_attributes(self): if self.server_version_info[0] not in list(range(8, 17)): - # FreeTDS with version 4.2 seems to report here - # a number like "95.10.255". Don't know what - # that is. So emit warning. - # Use TDS Version 7.0 through 7.3, per the MS information here: - # https://msdn.microsoft.com/en-us/library/dd339982.aspx - # and FreeTDS information here (7.3 highest supported version): - # http://www.freetds.org/userguide/choosingtdsprotocol.htm util.warn( - "Unrecognized server version info '%s'. Version specific " - "behaviors may not function properly. If using ODBC " - "with FreeTDS, ensure TDS_VERSION 7.0 through 7.3, not " - "4.2, is configured in the FreeTDS configuration." % + "Unrecognized server version info '%s'. Some SQL Server " + "features may not function properly." % ".".join(str(x) for x in self.server_version_info)) if self.server_version_info >= MS_2005_VERSION and \ 'implicit_returning' not in self.__dict__: diff --git a/lib/sqlalchemy/dialects/mssql/pyodbc.py b/lib/sqlalchemy/dialects/mssql/pyodbc.py index 45c091cfb8..30db94e49d 100644 --- a/lib/sqlalchemy/dialects/mssql/pyodbc.py +++ b/lib/sqlalchemy/dialects/mssql/pyodbc.py @@ -104,8 +104,9 @@ versioning. from .base import MSExecutionContext, MSDialect, VARBINARY from ...connectors.pyodbc import PyODBCConnector -from ... import types as sqltypes, util +from ... import types as sqltypes, util, exc import decimal +import re class _ms_numeric_pyodbc(object): @@ -269,4 +270,22 @@ class MSDialect_pyodbc(PyODBCConnector, MSDialect): self._need_decimal_fix = self.dbapi and \ self._dbapi_version() < (2, 1, 8) + def _get_server_version_info(self, connection): + try: + raw = connection.scalar("SELECT SERVERPROPERTY('ProductVersion')") + except exc.ProgrammingError: + # SQL Server docs indicate this function isn't present prior to + # 2008 + return super(MSDialect_pyodbc, self).\ + _get_server_version_info(connection) + else: + version = [] + r = re.compile('[.\-]') + for n in r.split(raw): + try: + version.append(int(n)) + except ValueError: + version.append(n) + return tuple(version) + dialect = MSDialect_pyodbc