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
"""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()
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
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
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
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'