diff options
author | mike bayer <mike_mp@zzzcomputing.com> | 2017-06-16 18:40:13 -0400 |
---|---|---|
committer | Gerrit Code Review <gerrit@awstats.zzzcomputing.com> | 2017-06-16 18:40:13 -0400 |
commit | 139cbe4f72e587228965bbb338387842fb1cf47b (patch) | |
tree | 5954e5be21a8fc2ef8d35ff770732ce79c19e3f2 | |
parent | 6d8d89042b32078a846c67a4d33d93b0cd0e645d (diff) | |
parent | 5650a0c306391216a9c9ce1961c5b548e534b5eb (diff) | |
download | sqlalchemy-139cbe4f72e587228965bbb338387842fb1cf47b.tar.gz |
Merge "Handle SHOW VARIABLES returning no row"
-rw-r--r-- | doc/build/changelog/changelog_11.rst | 11 | ||||
-rw-r--r-- | lib/sqlalchemy/dialects/mysql/base.py | 38 | ||||
-rw-r--r-- | test/dialect/mysql/test_dialect.py | 20 |
3 files changed, 57 insertions, 12 deletions
diff --git a/doc/build/changelog/changelog_11.rst b/doc/build/changelog/changelog_11.rst index f111c930a..77b7f510c 100644 --- a/doc/build/changelog/changelog_11.rst +++ b/doc/build/changelog/changelog_11.rst @@ -66,6 +66,17 @@ features a collation would fail to produce the correct syntax within CREATE TABLE. + .. change:: 4007 + :tags: bug, mysql + :tickets: 4007 + :versions: 1.2.0b1 + + MySQL 5.7 has introduced permission limiting for the "SHOW VARIABLES" + command; the MySQL dialect will now handle when SHOW returns no + row, in particular for the initial fetch of SQL_MODE, and will + emit a warning that user permissions should be modified to allow the + row to be present. + .. change:: 3994 :tags: bug, mssql :tickets: 3994 diff --git a/lib/sqlalchemy/dialects/mysql/base.py b/lib/sqlalchemy/dialects/mysql/base.py index 277ae5815..c19253478 100644 --- a/lib/sqlalchemy/dialects/mysql/base.py +++ b/lib/sqlalchemy/dialects/mysql/base.py @@ -1673,13 +1673,21 @@ class MySQLDialect(default.DefaultDialect): """Proxy a result row to smooth over MySQL-Python driver inconsistencies.""" - return _DecodingRowProxy(rp.fetchone(), charset) + row = rp.fetchone() + if row: + return _DecodingRowProxy(row, charset) + else: + return None def _compat_first(self, rp, charset=None): """Proxy a result row to smooth over MySQL-Python driver inconsistencies.""" - return _DecodingRowProxy(rp.first(), charset) + row = rp.first() + if row: + return _DecodingRowProxy(row, charset) + else: + return None def _extract_error_code(self, exception): raise NotImplementedError() @@ -1720,6 +1728,7 @@ class MySQLDialect(default.DefaultDialect): def initialize(self, connection): self._connection_charset = self._detect_charset(connection) + self._detect_sql_mode(connection) self._detect_ansiquotes(connection) if self._server_ansiquotes: # if ansiquotes == True, build a new IdentifierPreparer @@ -1993,21 +2002,28 @@ class MySQLDialect(default.DefaultDialect): collations[row[0]] = row[1] return collations - def _detect_ansiquotes(self, connection): - """Detect and adjust for the ANSI_QUOTES sql mode.""" - + def _detect_sql_mode(self, connection): row = self._compat_first( connection.execute("SHOW VARIABLES LIKE 'sql_mode'"), charset=self._connection_charset) if not row: - mode = '' + util.warn( + "Could not retrieve SQL_MODE; please ensure the " + "MySQL user has permissions to SHOW VARIABLES") + self._sql_mode = '' else: - mode = row[1] or '' - # 4.0 - if mode.isdigit(): - mode_no = int(mode) - mode = (mode_no | 4 == mode_no) and 'ANSI_QUOTES' or '' + self._sql_mode = row[1] or '' + + def _detect_ansiquotes(self, connection): + """Detect and adjust for the ANSI_QUOTES sql mode.""" + + mode = self._sql_mode + if not mode: + mode = '' + elif mode.isdigit(): + mode_no = int(mode) + mode = (mode_no | 4 == mode_no) and 'ANSI_QUOTES' or '' self._server_ansiquotes = 'ANSI_QUOTES' in mode diff --git a/test/dialect/mysql/test_dialect.py b/test/dialect/mysql/test_dialect.py index e6bff3553..cf8641ddc 100644 --- a/test/dialect/mysql/test_dialect.py +++ b/test/dialect/mysql/test_dialect.py @@ -3,7 +3,7 @@ from sqlalchemy.testing import eq_ from sqlalchemy import * from sqlalchemy.engine.url import make_url -from sqlalchemy.testing import fixtures +from sqlalchemy.testing import fixtures, expect_warnings from sqlalchemy import testing from sqlalchemy.testing import engines from ...engine import test_execute @@ -102,6 +102,24 @@ class DialectTest(fixtures.TestBase): conn = eng.connect() eq_(conn.dialect._connection_charset, enc) + def test_no_show_variables(self): + from sqlalchemy.testing import mock + engine = engines.testing_engine() + + def my_execute(self, statement, *args, **kw): + if statement.startswith("SHOW VARIABLES"): + statement = "SELECT 1 FROM DUAL WHERE 1=0" + return real_exec(self, statement, *args, **kw) + + real_exec = engine._connection_cls._execute_text + with mock.patch.object( + engine._connection_cls, "_execute_text", my_execute): + with expect_warnings( + "Could not retrieve SQL_MODE; please ensure the " + "MySQL user has permissions to SHOW VARIABLES" + ): + engine.connect() + def test_autocommit_isolation_level(self): c = testing.db.connect().execution_options( isolation_level='AUTOCOMMIT' |