]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
Filter non-integer characters from pyodbc SQL Server version
authorMike Bayer <mike_mp@zzzcomputing.com>
Fri, 30 Mar 2018 15:22:30 +0000 (11:22 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Fri, 30 Mar 2018 15:22:30 +0000 (11:22 -0400)
Adjusted the SQL Server version detection for pyodbc to only allow for
numeric tokens, filtering out non-integers, since the dialect does tuple-
numeric comparisons with this value.  This is normally true for all known
SQL Server / pyodbc drivers in any case.

Change-Id: I4ab18a07e19231091b5e877ba1fccd5eda72a992
Fixes: #4227
doc/build/changelog/unreleased_12/4227.rst [new file with mode: 0644]
lib/sqlalchemy/connectors/pyodbc.py
lib/sqlalchemy/dialects/mssql/pyodbc.py
test/dialect/mssql/test_engine.py

diff --git a/doc/build/changelog/unreleased_12/4227.rst b/doc/build/changelog/unreleased_12/4227.rst
new file mode 100644 (file)
index 0000000..992497d
--- /dev/null
@@ -0,0 +1,9 @@
+.. change::
+    :tags: bug, mssql
+    :tickets: 4227
+    :versions: 1.3.0b1
+
+    Adjusted the SQL Server version detection for pyodbc to only allow for
+    numeric tokens, filtering out non-integers, since the dialect does tuple-
+    numeric comparisons with this value.  This is normally true for all known
+    SQL Server / pyodbc drivers in any case.
index d8c3fcec4d286b5b6fa408cdee53da978ef1de36..41ba89de682e30686a6e8abb249b2c1b4742fb2b 100644 (file)
@@ -134,7 +134,7 @@ class PyODBCConnector(Connector):
             vers += (m.group(2),)
         return vers
 
-    def _get_server_version_info(self, connection):
+    def _get_server_version_info(self, connection, allow_chars=True):
         # NOTE: this function is not reliable, particularly when
         # freetds is in use.   Implement database-specific server version
         # queries.
@@ -145,7 +145,8 @@ class PyODBCConnector(Connector):
             try:
                 version.append(int(n))
             except ValueError:
-                version.append(n)
+                if allow_chars:
+                    version.append(n)
         return tuple(version)
 
     def set_isolation_level(self, connection, level):
index 14e8ae83805a24ad2ce5ac5250ec26c9ae15d797..36bcc49b379c93ae0557838e3be2aec1a45551d5 100644 (file)
@@ -276,6 +276,8 @@ class MSDialect_pyodbc(PyODBCConnector, MSDialect):
 
     def _get_server_version_info(self, connection):
         try:
+            # "Version of the instance of SQL Server, in the form
+            # of 'major.minor.build.revision'"
             raw = connection.scalar(
                 "SELECT CAST(SERVERPROPERTY('ProductVersion') AS VARCHAR)")
         except exc.DBAPIError:
@@ -283,7 +285,7 @@ class MSDialect_pyodbc(PyODBCConnector, MSDialect):
             # 2008.  Before we had the VARCHAR cast above, pyodbc would also
             # fail on this query.
             return super(MSDialect_pyodbc, self).\
-                _get_server_version_info(connection)
+                _get_server_version_info(connection, allow_chars=False)
         else:
             version = []
             r = re.compile(r'[.\-]')
@@ -291,7 +293,7 @@ class MSDialect_pyodbc(PyODBCConnector, MSDialect):
                 try:
                     version.append(int(n))
                 except ValueError:
-                    version.append(n)
+                    pass
             return tuple(version)
 
     def is_disconnect(self, e, connection, cursor):
index b69e62572e064a5fc580a02d3ebb2c72645607eb..db54381cf636fd2a73a5fee14eabd41f3da6a870 100644 (file)
@@ -271,3 +271,34 @@ class VersionDetectionTest(fixtures.TestBase):
                 dialect._get_server_version_info(conn),
                 (11, 0, 9216, 62)
             )
+
+    def test_pyodbc_version_productversion(self):
+        dialect = pyodbc.MSDialect_pyodbc()
+
+        conn = Mock(scalar=Mock(return_value="11.0.9216.62"))
+        eq_(
+            dialect._get_server_version_info(conn),
+            (11, 0, 9216, 62)
+        )
+
+    def test_pyodbc_version_fallback(self):
+        dialect = pyodbc.MSDialect_pyodbc()
+        dialect.dbapi = Mock()
+
+        for vers, expected in [
+            ("11.0.9216.62", (11, 0, 9216, 62)),
+            ("notsqlserver.11.foo.0.9216.BAR.62", (11, 0, 9216, 62)),
+            ("Not SQL Server Version 10.5", (5, ))
+        ]:
+            conn = Mock(
+                scalar=Mock(
+                    side_effect=exc.DBAPIError("stmt", "params", None)),
+                connection=Mock(
+                    getinfo=Mock(return_value=vers)
+                )
+            )
+
+            eq_(
+                dialect._get_server_version_info(conn),
+                expected
+            )
\ No newline at end of file