summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2016-03-15 17:11:08 -0400
committerMike Bayer <mike_mp@zzzcomputing.com>2016-03-15 17:17:21 -0400
commit31f96c27a5fea302358ba580313a2f742c12b83d (patch)
tree5ba8ebb50ead2ef07c9bf9b5ec1871ce1564aba8
parent224b03f9c006b12e3bbae9190ca9d0132e843208 (diff)
downloadsqlalchemy-31f96c27a5fea302358ba580313a2f742c12b83d.tar.gz
- changelog and docs for #3332, fixes #3332
- make docs for isolation level more consistent between postgresql and mysql - move mysql autocommit tests
-rw-r--r--doc/build/changelog/changelog_11.rst12
-rw-r--r--doc/build/changelog/migration_11.rst19
-rw-r--r--lib/sqlalchemy/dialects/mysql/base.py42
-rw-r--r--lib/sqlalchemy/dialects/postgresql/base.py10
-rw-r--r--test/dialect/mysql/test_dialect.py47
5 files changed, 94 insertions, 36 deletions
diff --git a/doc/build/changelog/changelog_11.rst b/doc/build/changelog/changelog_11.rst
index ef52c4bbe..e6dac9265 100644
--- a/doc/build/changelog/changelog_11.rst
+++ b/doc/build/changelog/changelog_11.rst
@@ -22,6 +22,18 @@
:version: 1.1.0b1
.. change::
+ :tags: feature, mysql
+ :tickets: 3332
+
+ Added support for "autocommit" on MySQL drivers, via the
+ AUTOCOMMIT isolation level setting. Pull request courtesy
+ Roman Podoliaka.
+
+ .. seealso::
+
+ :ref:`change_3332`
+
+ .. change::
:tags: bug, orm
:tickets: 3677
diff --git a/doc/build/changelog/migration_11.rst b/doc/build/changelog/migration_11.rst
index cbf213d44..3f40c7278 100644
--- a/doc/build/changelog/migration_11.rst
+++ b/doc/build/changelog/migration_11.rst
@@ -1861,6 +1861,25 @@ common to both MySQL and Postgresql.
:ticket:`3547`
+.. _change_3332:
+
+Added support for AUTOCOMMIT "isolation level"
+----------------------------------------------
+
+The MySQL dialect now accepts the value "AUTOCOMMIT" for the
+:paramref:`.create_engine.isolation_level` and
+:paramref:`.Connection.execution_options.isolation_level`
+parameters::
+
+ connection = engine.connect()
+ connection = connection.execution_options(
+ isolation_level="AUTOCOMMIT"
+ )
+
+The isolation level makes use of the various "autocommit" attributes
+provided by most MySQL DBAPIs.
+
+:ticket:`3332`
.. _change_mysql_3216:
diff --git a/lib/sqlalchemy/dialects/mysql/base.py b/lib/sqlalchemy/dialects/mysql/base.py
index b04070162..b85e32db0 100644
--- a/lib/sqlalchemy/dialects/mysql/base.py
+++ b/lib/sqlalchemy/dialects/mysql/base.py
@@ -111,19 +111,45 @@ to be used.
Transaction Isolation Level
---------------------------
-:func:`.create_engine` accepts an :paramref:`.create_engine.isolation_level`
-parameter which results in the command ``SET SESSION
-TRANSACTION ISOLATION LEVEL <level>`` being invoked for
-every new connection. Valid values for this parameter are
-``READ COMMITTED``, ``READ UNCOMMITTED``,
-``REPEATABLE READ``, and ``SERIALIZABLE``::
+All MySQL dialects support setting of transaction isolation level
+both via a dialect-specific parameter :paramref:`.create_engine.isolation_level`
+accepted by :func:`.create_engine`,
+as well as the :paramref:`.Connection.execution_options.isolation_level`
+argument as passed to :meth:`.Connection.execution_options`.
+This feature works by issuing the command
+``SET SESSION TRANSACTION ISOLATION LEVEL <level>`` for
+each new connection. For the special AUTOCOMMIT isolation level, DBAPI-specific
+techniques are used.
+
+To set isolation level using :func:`.create_engine`::
engine = create_engine(
"mysql://scott:tiger@localhost/test",
isolation_level="READ UNCOMMITTED"
)
-.. versionadded:: 0.7.6
+To set using per-connection execution options::
+
+ connection = engine.connect()
+ connection = connection.execution_options(
+ isolation_level="READ COMMITTED"
+ )
+
+Valid values for ``isolation_level`` include:
+
+* ``READ COMMITTED``
+* ``READ UNCOMMITTED``
+* ``REPEATABLE READ``
+* ``SERIALIZABLE``
+* ``AUTOCOMMIT``
+
+The special ``AUTOCOMMIT`` value makes use of the various "autocommit"
+attributes provided by specific DBAPIs, and is currently supported by
+MySQLdb, MySQL-Client, MySQL-Connector Python, and PyMySQL. Using it,
+the MySQL connection will return true for the value of
+``SELECT @@autocommit;``.
+
+.. versionadded:: 1.1 - added support for the AUTOCOMMIT isolation level.
AUTO_INCREMENT Behavior
-----------------------
@@ -1439,6 +1465,8 @@ class MySQLDialect(default.DefaultDialect):
level = level.replace('_', ' ')
# adjust for ConnectionFairy being present
+ # allows attribute set e.g. "connection.autocommit = True"
+ # to work properly
if hasattr(connection, 'connection'):
connection = connection.connection
diff --git a/lib/sqlalchemy/dialects/postgresql/base.py b/lib/sqlalchemy/dialects/postgresql/base.py
index b16a82e04..c0a3708d4 100644
--- a/lib/sqlalchemy/dialects/postgresql/base.py
+++ b/lib/sqlalchemy/dialects/postgresql/base.py
@@ -50,11 +50,12 @@ Transaction Isolation Level
All Postgresql dialects support setting of transaction isolation level
both via a dialect-specific parameter :paramref:`.create_engine.isolation_level`
accepted by :func:`.create_engine`,
-as well as the ``isolation_level`` argument as passed to
+as well as the :paramref:`.Connection.execution_options.isolation_level` argument as passed to
:meth:`.Connection.execution_options`. When using a non-psycopg2 dialect,
this feature works by issuing the command
``SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL <level>`` for
-each new connection.
+each new connection. For the special AUTOCOMMIT isolation level, DBAPI-specific
+techniques are used.
To set isolation level using :func:`.create_engine`::
@@ -76,10 +77,7 @@ Valid values for ``isolation_level`` include:
* ``READ UNCOMMITTED``
* ``REPEATABLE READ``
* ``SERIALIZABLE``
-
-The :mod:`~sqlalchemy.dialects.postgresql.psycopg2` and
-:mod:`~sqlalchemy.dialects.postgresql.pg8000` dialects also offer the
-special level ``AUTOCOMMIT``.
+* ``AUTOCOMMIT`` - on psycopg2 / pg8000 only
.. seealso::
diff --git a/test/dialect/mysql/test_dialect.py b/test/dialect/mysql/test_dialect.py
index 1288b50d7..ab719b368 100644
--- a/test/dialect/mysql/test_dialect.py
+++ b/test/dialect/mysql/test_dialect.py
@@ -11,6 +11,7 @@ import datetime
class DialectTest(fixtures.TestBase):
__backend__ = True
+ __only_on__ = 'mysql'
def test_ssl_arguments_mysqldb(self):
from sqlalchemy.dialects.mysql import mysqldb
@@ -97,6 +98,29 @@ class DialectTest(fixtures.TestBase):
conn = eng.connect()
eq_(conn.dialect._connection_charset, enc)
+ def test_autocommit_isolation_level(self):
+ c = testing.db.connect().execution_options(
+ isolation_level='AUTOCOMMIT'
+ )
+ assert c.execute('SELECT @@autocommit;').scalar()
+
+ c = c.execution_options(isolation_level='READ COMMITTED')
+ assert not c.execute('SELECT @@autocommit;').scalar()
+
+ def test_isolation_level(self):
+ values = {
+ # sqlalchemy -> mysql
+ 'READ UNCOMMITTED': 'READ-UNCOMMITTED',
+ 'READ COMMITTED': 'READ-COMMITTED',
+ 'REPEATABLE READ': 'REPEATABLE-READ',
+ 'SERIALIZABLE': 'SERIALIZABLE'
+ }
+ for sa_value, mysql_value in values.items():
+ c = testing.db.connect().execution_options(
+ isolation_level=sa_value
+ )
+ assert c.execute('SELECT @@tx_isolation;').scalar() == mysql_value
+
class SQLModeDetectionTest(fixtures.TestBase):
__only_on__ = 'mysql'
__backend__ = True
@@ -163,26 +187,3 @@ class ExecutionTest(fixtures.TestBase):
d = testing.db.scalar(func.sysdate())
assert isinstance(d, datetime.datetime)
- @testing.only_on(['mysql+mysqldb',
- 'mysql+mysqlconnector',
- 'mysql+pymysql',
- 'mysql+cymysql'])
- def test_autocommit_isolation_level(self):
- c = testing.db.connect().execution_options(
- isolation_level='AUTOCOMMIT'
- )
- assert c.execute('SELECT @@autocommit;').scalar()
-
- def test_isolation_level(self):
- values = {
- # sqlalchemy -> mysql
- 'READ UNCOMMITTED': 'READ-UNCOMMITTED',
- 'READ COMMITTED': 'READ-COMMITTED',
- 'REPEATABLE READ': 'REPEATABLE-READ',
- 'SERIALIZABLE': 'SERIALIZABLE'
- }
- for sa_value, mysql_value in values.items():
- c = testing.db.connect().execution_options(
- isolation_level=sa_value
- )
- assert c.execute('SELECT @@tx_isolation;').scalar() == mysql_value