From 6ec0f97e37140666a929c36de45802c12a0f76a5 Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Fri, 2 Mar 2018 15:08:08 -0500 Subject: [PATCH] Get MySQL version info from @@version MySQL dialects now query the server version using ``SELECT @@version`` explicitly to the server to ensure we are getting the correct version information back. Proxy servers like MaxScale interfere with the value that is passed to the DBAPI's connection.server_version value so this is no longer reliable. Change-Id: Iafd39be8c9bf1982d58b34cc997ae1016ad6c48c Fixes: #4205 (cherry picked from commit 9ba77e8d3b682bff89fdab5e80271a96a52fe8c8) (cherry picked from commit 5c1ebbc3706c810f936d9e252ee5d16800e561ea) --- doc/build/changelog/unreleased_11/4205.rst | 10 ++++++++ lib/sqlalchemy/dialects/mysql/base.py | 24 +++++++++++++++++++ lib/sqlalchemy/dialects/mysql/cymysql.py | 11 --------- .../dialects/mysql/mysqlconnector.py | 5 ---- lib/sqlalchemy/dialects/mysql/mysqldb.py | 11 --------- lib/sqlalchemy/dialects/mysql/oursql.py | 11 --------- 6 files changed, 34 insertions(+), 38 deletions(-) create mode 100644 doc/build/changelog/unreleased_11/4205.rst diff --git a/doc/build/changelog/unreleased_11/4205.rst b/doc/build/changelog/unreleased_11/4205.rst new file mode 100644 index 0000000000..91b276ba41 --- /dev/null +++ b/doc/build/changelog/unreleased_11/4205.rst @@ -0,0 +1,10 @@ +.. change:: + :tags: bug, mysql + :tickets: 4205 + :versions: 1.2.5, 1.3.0b1 + + MySQL dialects now query the server version using ``SELECT @@version`` + explicitly to the server to ensure we are getting the correct version + information back. Proxy servers like MaxScale interfere with the value + that is passed to the DBAPI's connection.server_version value so this + is no longer reliable. diff --git a/lib/sqlalchemy/dialects/mysql/base.py b/lib/sqlalchemy/dialects/mysql/base.py index a304d04f68..b5d4cb4b7f 100644 --- a/lib/sqlalchemy/dialects/mysql/base.py +++ b/lib/sqlalchemy/dialects/mysql/base.py @@ -1750,6 +1750,27 @@ class MySQLDialect(default.DefaultDialect): val = val.decode() return val.upper().replace("-", " ") + def _get_server_version_info(self, connection): + # get database server version info explicitly over the wire + # to avoid proxy servers like MaxScale getting in the + # way with their own values, see #4205 + dbapi_con = connection.connection + cursor = dbapi_con.cursor() + cursor.execute("SELECT VERSION()") + val = cursor.fetchone()[0] + cursor.close() + if util.py3k and isinstance(val, bytes): + val = val.decode() + + version = [] + r = re.compile(r'[.\-]') + for n in r.split(val): + try: + version.append(int(n)) + except ValueError: + version.append(n) + return tuple(version) + def do_commit(self, dbapi_connection): """Execute a COMMIT.""" @@ -1921,6 +1942,9 @@ class MySQLDialect(default.DefaultDialect): @property def _mariadb_normalized_version_info(self): + # MariaDB's wire-protocol prepends the server_version with + # the string "5.5"; now that we use @@version we no longer see this. + if self._is_mariadb: idx = self.server_version_info.index('MariaDB') return self.server_version_info[idx - 3: idx] diff --git a/lib/sqlalchemy/dialects/mysql/cymysql.py b/lib/sqlalchemy/dialects/mysql/cymysql.py index 0738e8fdd8..d142905948 100644 --- a/lib/sqlalchemy/dialects/mysql/cymysql.py +++ b/lib/sqlalchemy/dialects/mysql/cymysql.py @@ -56,17 +56,6 @@ class MySQLDialect_cymysql(MySQLDialect_mysqldb): def dbapi(cls): return __import__('cymysql') - def _get_server_version_info(self, connection): - dbapi_con = connection.connection - version = [] - r = re.compile(r'[.\-]') - for n in r.split(dbapi_con.server_version): - try: - version.append(int(n)) - except ValueError: - version.append(n) - return tuple(version) - def _detect_charset(self, connection): return connection.connection.charset diff --git a/lib/sqlalchemy/dialects/mysql/mysqlconnector.py b/lib/sqlalchemy/dialects/mysql/mysqlconnector.py index bd732303f8..117115888b 100644 --- a/lib/sqlalchemy/dialects/mysql/mysqlconnector.py +++ b/lib/sqlalchemy/dialects/mysql/mysqlconnector.py @@ -161,11 +161,6 @@ class MySQLDialect_mysqlconnector(MySQLDialect): def _mysqlconnector_double_percents(self): return not util.py3k and self._mysqlconnector_version_info < (2, 0) - def _get_server_version_info(self, connection): - dbapi_con = connection.connection - version = dbapi_con.get_server_version() - return tuple(version) - def _detect_charset(self, connection): return connection.connection.charset diff --git a/lib/sqlalchemy/dialects/mysql/mysqldb.py b/lib/sqlalchemy/dialects/mysql/mysqldb.py index 33cbd8f3af..3da64a4913 100644 --- a/lib/sqlalchemy/dialects/mysql/mysqldb.py +++ b/lib/sqlalchemy/dialects/mysql/mysqldb.py @@ -173,17 +173,6 @@ class MySQLDialect_mysqldb(MySQLDialect): opts['client_flag'] = client_flag return [[], opts] - def _get_server_version_info(self, connection): - dbapi_con = connection.connection - version = [] - r = re.compile(r'[.\-]') - for n in r.split(dbapi_con.get_server_info()): - try: - version.append(int(n)) - except ValueError: - version.append(n) - return tuple(version) - def _extract_error_code(self, exception): return exception.args[0] diff --git a/lib/sqlalchemy/dialects/mysql/oursql.py b/lib/sqlalchemy/dialects/mysql/oursql.py index 089f872f3a..67dbb7cf23 100644 --- a/lib/sqlalchemy/dialects/mysql/oursql.py +++ b/lib/sqlalchemy/dialects/mysql/oursql.py @@ -220,17 +220,6 @@ class MySQLDialect_oursql(MySQLDialect): return [[], opts] - def _get_server_version_info(self, connection): - dbapi_con = connection.connection - version = [] - r = re.compile(r'[.\-]') - for n in r.split(dbapi_con.server_info): - try: - version.append(int(n)) - except ValueError: - version.append(n) - return tuple(version) - def _extract_error_code(self, exception): return exception.errno -- 2.47.2