summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormike bayer <mike_mp@zzzcomputing.com>2017-06-16 18:40:13 -0400
committerGerrit Code Review <gerrit@awstats.zzzcomputing.com>2017-06-16 18:40:13 -0400
commit139cbe4f72e587228965bbb338387842fb1cf47b (patch)
tree5954e5be21a8fc2ef8d35ff770732ce79c19e3f2
parent6d8d89042b32078a846c67a4d33d93b0cd0e645d (diff)
parent5650a0c306391216a9c9ce1961c5b548e534b5eb (diff)
downloadsqlalchemy-139cbe4f72e587228965bbb338387842fb1cf47b.tar.gz
Merge "Handle SHOW VARIABLES returning no row"
-rw-r--r--doc/build/changelog/changelog_11.rst11
-rw-r--r--lib/sqlalchemy/dialects/mysql/base.py38
-rw-r--r--test/dialect/mysql/test_dialect.py20
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'