SQLAlchemy 2.0.47__cp313-cp313t-win_amd64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- sqlalchemy/__init__.py +283 -0
- sqlalchemy/connectors/__init__.py +18 -0
- sqlalchemy/connectors/aioodbc.py +184 -0
- sqlalchemy/connectors/asyncio.py +429 -0
- sqlalchemy/connectors/pyodbc.py +250 -0
- sqlalchemy/cyextension/__init__.py +6 -0
- sqlalchemy/cyextension/collections.cp313t-win_amd64.pyd +0 -0
- sqlalchemy/cyextension/collections.pyx +409 -0
- sqlalchemy/cyextension/immutabledict.cp313t-win_amd64.pyd +0 -0
- sqlalchemy/cyextension/immutabledict.pxd +8 -0
- sqlalchemy/cyextension/immutabledict.pyx +133 -0
- sqlalchemy/cyextension/processors.cp313t-win_amd64.pyd +0 -0
- sqlalchemy/cyextension/processors.pyx +68 -0
- sqlalchemy/cyextension/resultproxy.cp313t-win_amd64.pyd +0 -0
- sqlalchemy/cyextension/resultproxy.pyx +102 -0
- sqlalchemy/cyextension/util.cp313t-win_amd64.pyd +0 -0
- sqlalchemy/cyextension/util.pyx +90 -0
- sqlalchemy/dialects/__init__.py +62 -0
- sqlalchemy/dialects/_typing.py +30 -0
- sqlalchemy/dialects/mssql/__init__.py +88 -0
- sqlalchemy/dialects/mssql/aioodbc.py +63 -0
- sqlalchemy/dialects/mssql/base.py +4093 -0
- sqlalchemy/dialects/mssql/information_schema.py +285 -0
- sqlalchemy/dialects/mssql/json.py +129 -0
- sqlalchemy/dialects/mssql/provision.py +185 -0
- sqlalchemy/dialects/mssql/pymssql.py +126 -0
- sqlalchemy/dialects/mssql/pyodbc.py +760 -0
- sqlalchemy/dialects/mysql/__init__.py +104 -0
- sqlalchemy/dialects/mysql/aiomysql.py +250 -0
- sqlalchemy/dialects/mysql/asyncmy.py +231 -0
- sqlalchemy/dialects/mysql/base.py +3949 -0
- sqlalchemy/dialects/mysql/cymysql.py +106 -0
- sqlalchemy/dialects/mysql/dml.py +225 -0
- sqlalchemy/dialects/mysql/enumerated.py +282 -0
- sqlalchemy/dialects/mysql/expression.py +146 -0
- sqlalchemy/dialects/mysql/json.py +91 -0
- sqlalchemy/dialects/mysql/mariadb.py +72 -0
- sqlalchemy/dialects/mysql/mariadbconnector.py +322 -0
- sqlalchemy/dialects/mysql/mysqlconnector.py +302 -0
- sqlalchemy/dialects/mysql/mysqldb.py +314 -0
- sqlalchemy/dialects/mysql/provision.py +153 -0
- sqlalchemy/dialects/mysql/pymysql.py +158 -0
- sqlalchemy/dialects/mysql/pyodbc.py +157 -0
- sqlalchemy/dialects/mysql/reflection.py +727 -0
- sqlalchemy/dialects/mysql/reserved_words.py +570 -0
- sqlalchemy/dialects/mysql/types.py +835 -0
- sqlalchemy/dialects/oracle/__init__.py +81 -0
- sqlalchemy/dialects/oracle/base.py +3802 -0
- sqlalchemy/dialects/oracle/cx_oracle.py +1555 -0
- sqlalchemy/dialects/oracle/dictionary.py +507 -0
- sqlalchemy/dialects/oracle/oracledb.py +941 -0
- sqlalchemy/dialects/oracle/provision.py +297 -0
- sqlalchemy/dialects/oracle/types.py +316 -0
- sqlalchemy/dialects/oracle/vector.py +365 -0
- sqlalchemy/dialects/postgresql/__init__.py +167 -0
- sqlalchemy/dialects/postgresql/_psycopg_common.py +189 -0
- sqlalchemy/dialects/postgresql/array.py +519 -0
- sqlalchemy/dialects/postgresql/asyncpg.py +1284 -0
- sqlalchemy/dialects/postgresql/base.py +5378 -0
- sqlalchemy/dialects/postgresql/dml.py +339 -0
- sqlalchemy/dialects/postgresql/ext.py +540 -0
- sqlalchemy/dialects/postgresql/hstore.py +406 -0
- sqlalchemy/dialects/postgresql/json.py +404 -0
- sqlalchemy/dialects/postgresql/named_types.py +524 -0
- sqlalchemy/dialects/postgresql/operators.py +129 -0
- sqlalchemy/dialects/postgresql/pg8000.py +669 -0
- sqlalchemy/dialects/postgresql/pg_catalog.py +326 -0
- sqlalchemy/dialects/postgresql/provision.py +183 -0
- sqlalchemy/dialects/postgresql/psycopg.py +862 -0
- sqlalchemy/dialects/postgresql/psycopg2.py +892 -0
- sqlalchemy/dialects/postgresql/psycopg2cffi.py +61 -0
- sqlalchemy/dialects/postgresql/ranges.py +1031 -0
- sqlalchemy/dialects/postgresql/types.py +313 -0
- sqlalchemy/dialects/sqlite/__init__.py +57 -0
- sqlalchemy/dialects/sqlite/aiosqlite.py +482 -0
- sqlalchemy/dialects/sqlite/base.py +3056 -0
- sqlalchemy/dialects/sqlite/dml.py +263 -0
- sqlalchemy/dialects/sqlite/json.py +92 -0
- sqlalchemy/dialects/sqlite/provision.py +229 -0
- sqlalchemy/dialects/sqlite/pysqlcipher.py +157 -0
- sqlalchemy/dialects/sqlite/pysqlite.py +756 -0
- sqlalchemy/dialects/type_migration_guidelines.txt +145 -0
- sqlalchemy/engine/__init__.py +62 -0
- sqlalchemy/engine/_py_processors.py +136 -0
- sqlalchemy/engine/_py_row.py +128 -0
- sqlalchemy/engine/_py_util.py +74 -0
- sqlalchemy/engine/base.py +3390 -0
- sqlalchemy/engine/characteristics.py +155 -0
- sqlalchemy/engine/create.py +893 -0
- sqlalchemy/engine/cursor.py +2298 -0
- sqlalchemy/engine/default.py +2394 -0
- sqlalchemy/engine/events.py +965 -0
- sqlalchemy/engine/interfaces.py +3471 -0
- sqlalchemy/engine/mock.py +134 -0
- sqlalchemy/engine/processors.py +61 -0
- sqlalchemy/engine/reflection.py +2102 -0
- sqlalchemy/engine/result.py +2399 -0
- sqlalchemy/engine/row.py +400 -0
- sqlalchemy/engine/strategies.py +16 -0
- sqlalchemy/engine/url.py +924 -0
- sqlalchemy/engine/util.py +167 -0
- sqlalchemy/event/__init__.py +26 -0
- sqlalchemy/event/api.py +220 -0
- sqlalchemy/event/attr.py +676 -0
- sqlalchemy/event/base.py +472 -0
- sqlalchemy/event/legacy.py +258 -0
- sqlalchemy/event/registry.py +390 -0
- sqlalchemy/events.py +17 -0
- sqlalchemy/exc.py +832 -0
- sqlalchemy/ext/__init__.py +11 -0
- sqlalchemy/ext/associationproxy.py +2027 -0
- sqlalchemy/ext/asyncio/__init__.py +25 -0
- sqlalchemy/ext/asyncio/base.py +281 -0
- sqlalchemy/ext/asyncio/engine.py +1471 -0
- sqlalchemy/ext/asyncio/exc.py +21 -0
- sqlalchemy/ext/asyncio/result.py +965 -0
- sqlalchemy/ext/asyncio/scoping.py +1599 -0
- sqlalchemy/ext/asyncio/session.py +1947 -0
- sqlalchemy/ext/automap.py +1701 -0
- sqlalchemy/ext/baked.py +570 -0
- sqlalchemy/ext/compiler.py +600 -0
- sqlalchemy/ext/declarative/__init__.py +65 -0
- sqlalchemy/ext/declarative/extensions.py +564 -0
- sqlalchemy/ext/horizontal_shard.py +478 -0
- sqlalchemy/ext/hybrid.py +1535 -0
- sqlalchemy/ext/indexable.py +364 -0
- sqlalchemy/ext/instrumentation.py +450 -0
- sqlalchemy/ext/mutable.py +1085 -0
- sqlalchemy/ext/mypy/__init__.py +6 -0
- sqlalchemy/ext/mypy/apply.py +324 -0
- sqlalchemy/ext/mypy/decl_class.py +515 -0
- sqlalchemy/ext/mypy/infer.py +590 -0
- sqlalchemy/ext/mypy/names.py +335 -0
- sqlalchemy/ext/mypy/plugin.py +303 -0
- sqlalchemy/ext/mypy/util.py +357 -0
- sqlalchemy/ext/orderinglist.py +439 -0
- sqlalchemy/ext/serializer.py +185 -0
- sqlalchemy/future/__init__.py +16 -0
- sqlalchemy/future/engine.py +15 -0
- sqlalchemy/inspection.py +174 -0
- sqlalchemy/log.py +288 -0
- sqlalchemy/orm/__init__.py +171 -0
- sqlalchemy/orm/_orm_constructors.py +2661 -0
- sqlalchemy/orm/_typing.py +179 -0
- sqlalchemy/orm/attributes.py +2845 -0
- sqlalchemy/orm/base.py +971 -0
- sqlalchemy/orm/bulk_persistence.py +2135 -0
- sqlalchemy/orm/clsregistry.py +571 -0
- sqlalchemy/orm/collections.py +1627 -0
- sqlalchemy/orm/context.py +3334 -0
- sqlalchemy/orm/decl_api.py +2004 -0
- sqlalchemy/orm/decl_base.py +2192 -0
- sqlalchemy/orm/dependency.py +1302 -0
- sqlalchemy/orm/descriptor_props.py +1092 -0
- sqlalchemy/orm/dynamic.py +300 -0
- sqlalchemy/orm/evaluator.py +379 -0
- sqlalchemy/orm/events.py +3252 -0
- sqlalchemy/orm/exc.py +237 -0
- sqlalchemy/orm/identity.py +302 -0
- sqlalchemy/orm/instrumentation.py +754 -0
- sqlalchemy/orm/interfaces.py +1496 -0
- sqlalchemy/orm/loading.py +1686 -0
- sqlalchemy/orm/mapped_collection.py +557 -0
- sqlalchemy/orm/mapper.py +4444 -0
- sqlalchemy/orm/path_registry.py +809 -0
- sqlalchemy/orm/persistence.py +1788 -0
- sqlalchemy/orm/properties.py +935 -0
- sqlalchemy/orm/query.py +3459 -0
- sqlalchemy/orm/relationships.py +3508 -0
- sqlalchemy/orm/scoping.py +2148 -0
- sqlalchemy/orm/session.py +5280 -0
- sqlalchemy/orm/state.py +1168 -0
- sqlalchemy/orm/state_changes.py +196 -0
- sqlalchemy/orm/strategies.py +3470 -0
- sqlalchemy/orm/strategy_options.py +2568 -0
- sqlalchemy/orm/sync.py +164 -0
- sqlalchemy/orm/unitofwork.py +796 -0
- sqlalchemy/orm/util.py +2403 -0
- sqlalchemy/orm/writeonly.py +674 -0
- sqlalchemy/pool/__init__.py +44 -0
- sqlalchemy/pool/base.py +1524 -0
- sqlalchemy/pool/events.py +375 -0
- sqlalchemy/pool/impl.py +588 -0
- sqlalchemy/py.typed +0 -0
- sqlalchemy/schema.py +69 -0
- sqlalchemy/sql/__init__.py +145 -0
- sqlalchemy/sql/_dml_constructors.py +132 -0
- sqlalchemy/sql/_elements_constructors.py +1872 -0
- sqlalchemy/sql/_orm_types.py +20 -0
- sqlalchemy/sql/_py_util.py +75 -0
- sqlalchemy/sql/_selectable_constructors.py +763 -0
- sqlalchemy/sql/_typing.py +482 -0
- sqlalchemy/sql/annotation.py +587 -0
- sqlalchemy/sql/base.py +2293 -0
- sqlalchemy/sql/cache_key.py +1057 -0
- sqlalchemy/sql/coercions.py +1404 -0
- sqlalchemy/sql/compiler.py +8081 -0
- sqlalchemy/sql/crud.py +1752 -0
- sqlalchemy/sql/ddl.py +1444 -0
- sqlalchemy/sql/default_comparator.py +551 -0
- sqlalchemy/sql/dml.py +1850 -0
- sqlalchemy/sql/elements.py +5589 -0
- sqlalchemy/sql/events.py +458 -0
- sqlalchemy/sql/expression.py +159 -0
- sqlalchemy/sql/functions.py +2158 -0
- sqlalchemy/sql/lambdas.py +1442 -0
- sqlalchemy/sql/naming.py +209 -0
- sqlalchemy/sql/operators.py +2623 -0
- sqlalchemy/sql/roles.py +323 -0
- sqlalchemy/sql/schema.py +6222 -0
- sqlalchemy/sql/selectable.py +7265 -0
- sqlalchemy/sql/sqltypes.py +3930 -0
- sqlalchemy/sql/traversals.py +1024 -0
- sqlalchemy/sql/type_api.py +2368 -0
- sqlalchemy/sql/util.py +1485 -0
- sqlalchemy/sql/visitors.py +1164 -0
- sqlalchemy/testing/__init__.py +96 -0
- sqlalchemy/testing/assertions.py +994 -0
- sqlalchemy/testing/assertsql.py +520 -0
- sqlalchemy/testing/asyncio.py +135 -0
- sqlalchemy/testing/config.py +434 -0
- sqlalchemy/testing/engines.py +483 -0
- sqlalchemy/testing/entities.py +117 -0
- sqlalchemy/testing/exclusions.py +476 -0
- sqlalchemy/testing/fixtures/__init__.py +28 -0
- sqlalchemy/testing/fixtures/base.py +384 -0
- sqlalchemy/testing/fixtures/mypy.py +332 -0
- sqlalchemy/testing/fixtures/orm.py +227 -0
- sqlalchemy/testing/fixtures/sql.py +482 -0
- sqlalchemy/testing/pickleable.py +155 -0
- sqlalchemy/testing/plugin/__init__.py +6 -0
- sqlalchemy/testing/plugin/bootstrap.py +51 -0
- sqlalchemy/testing/plugin/plugin_base.py +828 -0
- sqlalchemy/testing/plugin/pytestplugin.py +892 -0
- sqlalchemy/testing/profiling.py +329 -0
- sqlalchemy/testing/provision.py +603 -0
- sqlalchemy/testing/requirements.py +1945 -0
- sqlalchemy/testing/schema.py +198 -0
- sqlalchemy/testing/suite/__init__.py +19 -0
- sqlalchemy/testing/suite/test_cte.py +237 -0
- sqlalchemy/testing/suite/test_ddl.py +389 -0
- sqlalchemy/testing/suite/test_deprecations.py +153 -0
- sqlalchemy/testing/suite/test_dialect.py +776 -0
- sqlalchemy/testing/suite/test_insert.py +630 -0
- sqlalchemy/testing/suite/test_reflection.py +3557 -0
- sqlalchemy/testing/suite/test_results.py +504 -0
- sqlalchemy/testing/suite/test_rowcount.py +258 -0
- sqlalchemy/testing/suite/test_select.py +2010 -0
- sqlalchemy/testing/suite/test_sequence.py +317 -0
- sqlalchemy/testing/suite/test_types.py +2147 -0
- sqlalchemy/testing/suite/test_unicode_ddl.py +189 -0
- sqlalchemy/testing/suite/test_update_delete.py +139 -0
- sqlalchemy/testing/util.py +535 -0
- sqlalchemy/testing/warnings.py +52 -0
- sqlalchemy/types.py +74 -0
- sqlalchemy/util/__init__.py +162 -0
- sqlalchemy/util/_collections.py +712 -0
- sqlalchemy/util/_concurrency_py3k.py +288 -0
- sqlalchemy/util/_has_cy.py +40 -0
- sqlalchemy/util/_py_collections.py +541 -0
- sqlalchemy/util/compat.py +421 -0
- sqlalchemy/util/concurrency.py +110 -0
- sqlalchemy/util/deprecations.py +401 -0
- sqlalchemy/util/langhelpers.py +2203 -0
- sqlalchemy/util/preloaded.py +150 -0
- sqlalchemy/util/queue.py +322 -0
- sqlalchemy/util/tool_support.py +201 -0
- sqlalchemy/util/topological.py +120 -0
- sqlalchemy/util/typing.py +734 -0
- sqlalchemy-2.0.47.dist-info/METADATA +243 -0
- sqlalchemy-2.0.47.dist-info/RECORD +274 -0
- sqlalchemy-2.0.47.dist-info/WHEEL +5 -0
- sqlalchemy-2.0.47.dist-info/licenses/LICENSE +19 -0
- sqlalchemy-2.0.47.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
# dialects/mysql/mysqlconnector.py
|
|
2
|
+
# Copyright (C) 2005-2026 the SQLAlchemy authors and contributors
|
|
3
|
+
# <see AUTHORS file>
|
|
4
|
+
#
|
|
5
|
+
# This module is part of SQLAlchemy and is released under
|
|
6
|
+
# the MIT License: https://www.opensource.org/licenses/mit-license.php
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
r"""
|
|
10
|
+
.. dialect:: mysql+mysqlconnector
|
|
11
|
+
:name: MySQL Connector/Python
|
|
12
|
+
:dbapi: myconnpy
|
|
13
|
+
:connectstring: mysql+mysqlconnector://<user>:<password>@<host>[:<port>]/<dbname>
|
|
14
|
+
:url: https://pypi.org/project/mysql-connector-python/
|
|
15
|
+
|
|
16
|
+
Driver Status
|
|
17
|
+
-------------
|
|
18
|
+
|
|
19
|
+
MySQL Connector/Python is supported as of SQLAlchemy 2.0.39 to the
|
|
20
|
+
degree which the driver is functional. There are still ongoing issues
|
|
21
|
+
with features such as server side cursors which remain disabled until
|
|
22
|
+
upstream issues are repaired.
|
|
23
|
+
|
|
24
|
+
.. warning:: The MySQL Connector/Python driver published by Oracle is subject
|
|
25
|
+
to frequent, major regressions of essential functionality such as being able
|
|
26
|
+
to correctly persist simple binary strings which indicate it is not well
|
|
27
|
+
tested. The SQLAlchemy project is not able to maintain this dialect fully as
|
|
28
|
+
regressions in the driver prevent it from being included in continuous
|
|
29
|
+
integration.
|
|
30
|
+
|
|
31
|
+
.. versionchanged:: 2.0.39
|
|
32
|
+
|
|
33
|
+
The MySQL Connector/Python dialect has been updated to support the
|
|
34
|
+
latest version of this DBAPI. Previously, MySQL Connector/Python
|
|
35
|
+
was not fully supported. However, support remains limited due to ongoing
|
|
36
|
+
regressions introduced in this driver.
|
|
37
|
+
|
|
38
|
+
Connecting to MariaDB with MySQL Connector/Python
|
|
39
|
+
--------------------------------------------------
|
|
40
|
+
|
|
41
|
+
MySQL Connector/Python may attempt to pass an incompatible collation to the
|
|
42
|
+
database when connecting to MariaDB. Experimentation has shown that using
|
|
43
|
+
``?charset=utf8mb4&collation=utfmb4_general_ci`` or similar MariaDB-compatible
|
|
44
|
+
charset/collation will allow connectivity.
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
""" # noqa
|
|
48
|
+
from __future__ import annotations
|
|
49
|
+
|
|
50
|
+
import re
|
|
51
|
+
from typing import Any
|
|
52
|
+
from typing import cast
|
|
53
|
+
from typing import Optional
|
|
54
|
+
from typing import Sequence
|
|
55
|
+
from typing import Tuple
|
|
56
|
+
from typing import TYPE_CHECKING
|
|
57
|
+
from typing import Union
|
|
58
|
+
|
|
59
|
+
from .base import MariaDBIdentifierPreparer
|
|
60
|
+
from .base import MySQLCompiler
|
|
61
|
+
from .base import MySQLDialect
|
|
62
|
+
from .base import MySQLExecutionContext
|
|
63
|
+
from .base import MySQLIdentifierPreparer
|
|
64
|
+
from .mariadb import MariaDBDialect
|
|
65
|
+
from .types import BIT
|
|
66
|
+
from ... import util
|
|
67
|
+
|
|
68
|
+
if TYPE_CHECKING:
|
|
69
|
+
|
|
70
|
+
from ...engine.base import Connection
|
|
71
|
+
from ...engine.cursor import CursorResult
|
|
72
|
+
from ...engine.interfaces import ConnectArgsType
|
|
73
|
+
from ...engine.interfaces import DBAPIConnection
|
|
74
|
+
from ...engine.interfaces import DBAPICursor
|
|
75
|
+
from ...engine.interfaces import DBAPIModule
|
|
76
|
+
from ...engine.interfaces import IsolationLevel
|
|
77
|
+
from ...engine.interfaces import PoolProxiedConnection
|
|
78
|
+
from ...engine.row import Row
|
|
79
|
+
from ...engine.url import URL
|
|
80
|
+
from ...sql.elements import BinaryExpression
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
class MySQLExecutionContext_mysqlconnector(MySQLExecutionContext):
|
|
84
|
+
def create_server_side_cursor(self) -> DBAPICursor:
|
|
85
|
+
return self._dbapi_connection.cursor(buffered=False)
|
|
86
|
+
|
|
87
|
+
def create_default_cursor(self) -> DBAPICursor:
|
|
88
|
+
return self._dbapi_connection.cursor(buffered=True)
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
class MySQLCompiler_mysqlconnector(MySQLCompiler):
|
|
92
|
+
def visit_mod_binary(
|
|
93
|
+
self, binary: BinaryExpression[Any], operator: Any, **kw: Any
|
|
94
|
+
) -> str:
|
|
95
|
+
return (
|
|
96
|
+
self.process(binary.left, **kw)
|
|
97
|
+
+ " % "
|
|
98
|
+
+ self.process(binary.right, **kw)
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
class IdentifierPreparerCommon_mysqlconnector:
|
|
103
|
+
@property
|
|
104
|
+
def _double_percents(self) -> bool:
|
|
105
|
+
return False
|
|
106
|
+
|
|
107
|
+
@_double_percents.setter
|
|
108
|
+
def _double_percents(self, value: Any) -> None:
|
|
109
|
+
pass
|
|
110
|
+
|
|
111
|
+
def _escape_identifier(self, value: str) -> str:
|
|
112
|
+
value = value.replace(
|
|
113
|
+
self.escape_quote, # type:ignore[attr-defined]
|
|
114
|
+
self.escape_to_quote, # type:ignore[attr-defined]
|
|
115
|
+
)
|
|
116
|
+
return value
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
class MySQLIdentifierPreparer_mysqlconnector(
|
|
120
|
+
IdentifierPreparerCommon_mysqlconnector, MySQLIdentifierPreparer
|
|
121
|
+
):
|
|
122
|
+
pass
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
class MariaDBIdentifierPreparer_mysqlconnector(
|
|
126
|
+
IdentifierPreparerCommon_mysqlconnector, MariaDBIdentifierPreparer
|
|
127
|
+
):
|
|
128
|
+
pass
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
class _myconnpyBIT(BIT):
|
|
132
|
+
def result_processor(self, dialect: Any, coltype: Any) -> None:
|
|
133
|
+
"""MySQL-connector already converts mysql bits, so."""
|
|
134
|
+
|
|
135
|
+
return None
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
class MySQLDialect_mysqlconnector(MySQLDialect):
|
|
139
|
+
driver = "mysqlconnector"
|
|
140
|
+
supports_statement_cache = True
|
|
141
|
+
|
|
142
|
+
supports_sane_rowcount = True
|
|
143
|
+
supports_sane_multi_rowcount = True
|
|
144
|
+
|
|
145
|
+
supports_native_decimal = True
|
|
146
|
+
|
|
147
|
+
supports_native_bit = True
|
|
148
|
+
|
|
149
|
+
# not until https://bugs.mysql.com/bug.php?id=117548
|
|
150
|
+
supports_server_side_cursors = False
|
|
151
|
+
|
|
152
|
+
default_paramstyle = "format"
|
|
153
|
+
statement_compiler = MySQLCompiler_mysqlconnector
|
|
154
|
+
|
|
155
|
+
execution_ctx_cls = MySQLExecutionContext_mysqlconnector
|
|
156
|
+
|
|
157
|
+
preparer: type[MySQLIdentifierPreparer] = (
|
|
158
|
+
MySQLIdentifierPreparer_mysqlconnector
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
colspecs = util.update_copy(MySQLDialect.colspecs, {BIT: _myconnpyBIT})
|
|
162
|
+
|
|
163
|
+
@classmethod
|
|
164
|
+
def import_dbapi(cls) -> DBAPIModule:
|
|
165
|
+
return cast("DBAPIModule", __import__("mysql.connector").connector)
|
|
166
|
+
|
|
167
|
+
def do_ping(self, dbapi_connection: DBAPIConnection) -> bool:
|
|
168
|
+
dbapi_connection.ping(False)
|
|
169
|
+
return True
|
|
170
|
+
|
|
171
|
+
def create_connect_args(self, url: URL) -> ConnectArgsType:
|
|
172
|
+
opts = url.translate_connect_args(username="user")
|
|
173
|
+
|
|
174
|
+
opts.update(url.query)
|
|
175
|
+
|
|
176
|
+
util.coerce_kw_type(opts, "allow_local_infile", bool)
|
|
177
|
+
util.coerce_kw_type(opts, "autocommit", bool)
|
|
178
|
+
util.coerce_kw_type(opts, "buffered", bool)
|
|
179
|
+
util.coerce_kw_type(opts, "client_flag", int)
|
|
180
|
+
util.coerce_kw_type(opts, "compress", bool)
|
|
181
|
+
util.coerce_kw_type(opts, "connection_timeout", int)
|
|
182
|
+
util.coerce_kw_type(opts, "connect_timeout", int)
|
|
183
|
+
util.coerce_kw_type(opts, "consume_results", bool)
|
|
184
|
+
util.coerce_kw_type(opts, "force_ipv6", bool)
|
|
185
|
+
util.coerce_kw_type(opts, "get_warnings", bool)
|
|
186
|
+
util.coerce_kw_type(opts, "pool_reset_session", bool)
|
|
187
|
+
util.coerce_kw_type(opts, "pool_size", int)
|
|
188
|
+
util.coerce_kw_type(opts, "raise_on_warnings", bool)
|
|
189
|
+
util.coerce_kw_type(opts, "raw", bool)
|
|
190
|
+
util.coerce_kw_type(opts, "ssl_verify_cert", bool)
|
|
191
|
+
util.coerce_kw_type(opts, "use_pure", bool)
|
|
192
|
+
util.coerce_kw_type(opts, "use_unicode", bool)
|
|
193
|
+
|
|
194
|
+
# note that "buffered" is set to False by default in MySQL/connector
|
|
195
|
+
# python. If you set it to True, then there is no way to get a server
|
|
196
|
+
# side cursor because the logic is written to disallow that.
|
|
197
|
+
|
|
198
|
+
# leaving this at True until
|
|
199
|
+
# https://bugs.mysql.com/bug.php?id=117548 can be fixed
|
|
200
|
+
opts["buffered"] = True
|
|
201
|
+
|
|
202
|
+
# FOUND_ROWS must be set in ClientFlag to enable
|
|
203
|
+
# supports_sane_rowcount.
|
|
204
|
+
if self.dbapi is not None:
|
|
205
|
+
try:
|
|
206
|
+
from mysql.connector import constants # type: ignore
|
|
207
|
+
|
|
208
|
+
ClientFlag = constants.ClientFlag
|
|
209
|
+
|
|
210
|
+
client_flags = opts.get(
|
|
211
|
+
"client_flags", ClientFlag.get_default()
|
|
212
|
+
)
|
|
213
|
+
client_flags |= ClientFlag.FOUND_ROWS
|
|
214
|
+
opts["client_flags"] = client_flags
|
|
215
|
+
except Exception:
|
|
216
|
+
pass
|
|
217
|
+
|
|
218
|
+
return [], opts
|
|
219
|
+
|
|
220
|
+
@util.memoized_property
|
|
221
|
+
def _mysqlconnector_version_info(self) -> Optional[Tuple[int, ...]]:
|
|
222
|
+
if self.dbapi and hasattr(self.dbapi, "__version__"):
|
|
223
|
+
m = re.match(r"(\d+)\.(\d+)(?:\.(\d+))?", self.dbapi.__version__)
|
|
224
|
+
if m:
|
|
225
|
+
return tuple(int(x) for x in m.group(1, 2, 3) if x is not None)
|
|
226
|
+
return None
|
|
227
|
+
|
|
228
|
+
def _detect_charset(self, connection: Connection) -> str:
|
|
229
|
+
return connection.connection.charset # type: ignore
|
|
230
|
+
|
|
231
|
+
def _extract_error_code(self, exception: BaseException) -> int:
|
|
232
|
+
return exception.errno # type: ignore
|
|
233
|
+
|
|
234
|
+
def is_disconnect(
|
|
235
|
+
self,
|
|
236
|
+
e: Exception,
|
|
237
|
+
connection: Optional[Union[PoolProxiedConnection, DBAPIConnection]],
|
|
238
|
+
cursor: Optional[DBAPICursor],
|
|
239
|
+
) -> bool:
|
|
240
|
+
errnos = (2006, 2013, 2014, 2045, 2055, 2048)
|
|
241
|
+
exceptions = (
|
|
242
|
+
self.loaded_dbapi.OperationalError, #
|
|
243
|
+
self.loaded_dbapi.InterfaceError,
|
|
244
|
+
self.loaded_dbapi.ProgrammingError,
|
|
245
|
+
)
|
|
246
|
+
if isinstance(e, exceptions):
|
|
247
|
+
return (
|
|
248
|
+
e.errno in errnos
|
|
249
|
+
or "MySQL Connection not available." in str(e)
|
|
250
|
+
or "Connection to MySQL is not available" in str(e)
|
|
251
|
+
)
|
|
252
|
+
else:
|
|
253
|
+
return False
|
|
254
|
+
|
|
255
|
+
def _compat_fetchall(
|
|
256
|
+
self,
|
|
257
|
+
rp: CursorResult[Tuple[Any, ...]],
|
|
258
|
+
charset: Optional[str] = None,
|
|
259
|
+
) -> Sequence[Row[Tuple[Any, ...]]]:
|
|
260
|
+
return rp.fetchall()
|
|
261
|
+
|
|
262
|
+
def _compat_fetchone(
|
|
263
|
+
self,
|
|
264
|
+
rp: CursorResult[Tuple[Any, ...]],
|
|
265
|
+
charset: Optional[str] = None,
|
|
266
|
+
) -> Optional[Row[Tuple[Any, ...]]]:
|
|
267
|
+
return rp.fetchone()
|
|
268
|
+
|
|
269
|
+
def get_isolation_level_values(
|
|
270
|
+
self, dbapi_conn: DBAPIConnection
|
|
271
|
+
) -> Sequence[IsolationLevel]:
|
|
272
|
+
return (
|
|
273
|
+
"SERIALIZABLE",
|
|
274
|
+
"READ UNCOMMITTED",
|
|
275
|
+
"READ COMMITTED",
|
|
276
|
+
"REPEATABLE READ",
|
|
277
|
+
"AUTOCOMMIT",
|
|
278
|
+
)
|
|
279
|
+
|
|
280
|
+
def detect_autocommit_setting(self, dbapi_conn: DBAPIConnection) -> bool:
|
|
281
|
+
return bool(dbapi_conn.autocommit)
|
|
282
|
+
|
|
283
|
+
def set_isolation_level(
|
|
284
|
+
self, dbapi_connection: DBAPIConnection, level: IsolationLevel
|
|
285
|
+
) -> None:
|
|
286
|
+
if level == "AUTOCOMMIT":
|
|
287
|
+
dbapi_connection.autocommit = True
|
|
288
|
+
else:
|
|
289
|
+
dbapi_connection.autocommit = False
|
|
290
|
+
super().set_isolation_level(dbapi_connection, level)
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
class MariaDBDialect_mysqlconnector(
|
|
294
|
+
MariaDBDialect, MySQLDialect_mysqlconnector
|
|
295
|
+
):
|
|
296
|
+
supports_statement_cache = True
|
|
297
|
+
_allows_uuid_binds = False
|
|
298
|
+
preparer = MariaDBIdentifierPreparer_mysqlconnector
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
dialect = MySQLDialect_mysqlconnector
|
|
302
|
+
mariadb_dialect = MariaDBDialect_mysqlconnector
|
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
# dialects/mysql/mysqldb.py
|
|
2
|
+
# Copyright (C) 2005-2026 the SQLAlchemy authors and contributors
|
|
3
|
+
# <see AUTHORS file>
|
|
4
|
+
#
|
|
5
|
+
# This module is part of SQLAlchemy and is released under
|
|
6
|
+
# the MIT License: https://www.opensource.org/licenses/mit-license.php
|
|
7
|
+
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
.. dialect:: mysql+mysqldb
|
|
11
|
+
:name: mysqlclient (maintained fork of MySQL-Python)
|
|
12
|
+
:dbapi: mysqldb
|
|
13
|
+
:connectstring: mysql+mysqldb://<user>:<password>@<host>[:<port>]/<dbname>
|
|
14
|
+
:url: https://pypi.org/project/mysqlclient/
|
|
15
|
+
|
|
16
|
+
Driver Status
|
|
17
|
+
-------------
|
|
18
|
+
|
|
19
|
+
The mysqlclient DBAPI is a maintained fork of the
|
|
20
|
+
`MySQL-Python <https://sourceforge.net/projects/mysql-python>`_ DBAPI
|
|
21
|
+
that is no longer maintained. `mysqlclient`_ supports Python 2 and Python 3
|
|
22
|
+
and is very stable.
|
|
23
|
+
|
|
24
|
+
.. _mysqlclient: https://github.com/PyMySQL/mysqlclient-python
|
|
25
|
+
|
|
26
|
+
.. _mysqldb_unicode:
|
|
27
|
+
|
|
28
|
+
Unicode
|
|
29
|
+
-------
|
|
30
|
+
|
|
31
|
+
Please see :ref:`mysql_unicode` for current recommendations on unicode
|
|
32
|
+
handling.
|
|
33
|
+
|
|
34
|
+
.. _mysqldb_ssl:
|
|
35
|
+
|
|
36
|
+
SSL Connections
|
|
37
|
+
----------------
|
|
38
|
+
|
|
39
|
+
The mysqlclient and PyMySQL DBAPIs accept an additional dictionary under the
|
|
40
|
+
key "ssl", which may be specified using the
|
|
41
|
+
:paramref:`_sa.create_engine.connect_args` dictionary::
|
|
42
|
+
|
|
43
|
+
engine = create_engine(
|
|
44
|
+
"mysql+mysqldb://scott:tiger@192.168.0.134/test",
|
|
45
|
+
connect_args={
|
|
46
|
+
"ssl": {
|
|
47
|
+
"ca": "/home/gord/client-ssl/ca.pem",
|
|
48
|
+
"cert": "/home/gord/client-ssl/client-cert.pem",
|
|
49
|
+
"key": "/home/gord/client-ssl/client-key.pem",
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
For convenience, the following keys may also be specified inline within the URL
|
|
55
|
+
where they will be interpreted into the "ssl" dictionary automatically:
|
|
56
|
+
"ssl_ca", "ssl_cert", "ssl_key", "ssl_capath", "ssl_cipher",
|
|
57
|
+
"ssl_check_hostname". An example is as follows::
|
|
58
|
+
|
|
59
|
+
connection_uri = (
|
|
60
|
+
"mysql+mysqldb://scott:tiger@192.168.0.134/test"
|
|
61
|
+
"?ssl_ca=/home/gord/client-ssl/ca.pem"
|
|
62
|
+
"&ssl_cert=/home/gord/client-ssl/client-cert.pem"
|
|
63
|
+
"&ssl_key=/home/gord/client-ssl/client-key.pem"
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
.. seealso::
|
|
67
|
+
|
|
68
|
+
:ref:`pymysql_ssl` in the PyMySQL dialect
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
Using MySQLdb with Google Cloud SQL
|
|
72
|
+
-----------------------------------
|
|
73
|
+
|
|
74
|
+
Google Cloud SQL now recommends use of the MySQLdb dialect. Connect
|
|
75
|
+
using a URL like the following:
|
|
76
|
+
|
|
77
|
+
.. sourcecode:: text
|
|
78
|
+
|
|
79
|
+
mysql+mysqldb://root@/<dbname>?unix_socket=/cloudsql/<projectid>:<instancename>
|
|
80
|
+
|
|
81
|
+
Server Side Cursors
|
|
82
|
+
-------------------
|
|
83
|
+
|
|
84
|
+
The mysqldb dialect supports server-side cursors. See :ref:`mysql_ss_cursors`.
|
|
85
|
+
|
|
86
|
+
"""
|
|
87
|
+
from __future__ import annotations
|
|
88
|
+
|
|
89
|
+
import re
|
|
90
|
+
from typing import Any
|
|
91
|
+
from typing import Callable
|
|
92
|
+
from typing import cast
|
|
93
|
+
from typing import Dict
|
|
94
|
+
from typing import Optional
|
|
95
|
+
from typing import Tuple
|
|
96
|
+
from typing import TYPE_CHECKING
|
|
97
|
+
|
|
98
|
+
from .base import MySQLCompiler
|
|
99
|
+
from .base import MySQLDialect
|
|
100
|
+
from .base import MySQLExecutionContext
|
|
101
|
+
from .base import MySQLIdentifierPreparer
|
|
102
|
+
from ... import util
|
|
103
|
+
from ...util.typing import Literal
|
|
104
|
+
|
|
105
|
+
if TYPE_CHECKING:
|
|
106
|
+
|
|
107
|
+
from ...engine.base import Connection
|
|
108
|
+
from ...engine.interfaces import _DBAPIMultiExecuteParams
|
|
109
|
+
from ...engine.interfaces import ConnectArgsType
|
|
110
|
+
from ...engine.interfaces import DBAPIConnection
|
|
111
|
+
from ...engine.interfaces import DBAPICursor
|
|
112
|
+
from ...engine.interfaces import DBAPIModule
|
|
113
|
+
from ...engine.interfaces import ExecutionContext
|
|
114
|
+
from ...engine.interfaces import IsolationLevel
|
|
115
|
+
from ...engine.url import URL
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
class MySQLExecutionContext_mysqldb(MySQLExecutionContext):
|
|
119
|
+
pass
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
class MySQLCompiler_mysqldb(MySQLCompiler):
|
|
123
|
+
pass
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
class MySQLDialect_mysqldb(MySQLDialect):
|
|
127
|
+
driver = "mysqldb"
|
|
128
|
+
supports_statement_cache = True
|
|
129
|
+
supports_unicode_statements = True
|
|
130
|
+
supports_sane_rowcount = True
|
|
131
|
+
supports_sane_multi_rowcount = True
|
|
132
|
+
|
|
133
|
+
supports_native_decimal = True
|
|
134
|
+
|
|
135
|
+
default_paramstyle = "format"
|
|
136
|
+
execution_ctx_cls = MySQLExecutionContext_mysqldb
|
|
137
|
+
statement_compiler = MySQLCompiler_mysqldb
|
|
138
|
+
preparer = MySQLIdentifierPreparer
|
|
139
|
+
server_version_info: Tuple[int, ...]
|
|
140
|
+
|
|
141
|
+
def __init__(self, **kwargs: Any):
|
|
142
|
+
super().__init__(**kwargs)
|
|
143
|
+
self._mysql_dbapi_version = (
|
|
144
|
+
self._parse_dbapi_version(self.dbapi.__version__)
|
|
145
|
+
if self.dbapi is not None and hasattr(self.dbapi, "__version__")
|
|
146
|
+
else (0, 0, 0)
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
def _parse_dbapi_version(self, version: str) -> Tuple[int, ...]:
|
|
150
|
+
m = re.match(r"(\d+)\.(\d+)(?:\.(\d+))?", version)
|
|
151
|
+
if m:
|
|
152
|
+
return tuple(int(x) for x in m.group(1, 2, 3) if x is not None)
|
|
153
|
+
else:
|
|
154
|
+
return (0, 0, 0)
|
|
155
|
+
|
|
156
|
+
@util.langhelpers.memoized_property
|
|
157
|
+
def supports_server_side_cursors(self) -> bool:
|
|
158
|
+
try:
|
|
159
|
+
cursors = __import__("MySQLdb.cursors").cursors
|
|
160
|
+
self._sscursor = cursors.SSCursor
|
|
161
|
+
return True
|
|
162
|
+
except (ImportError, AttributeError):
|
|
163
|
+
return False
|
|
164
|
+
|
|
165
|
+
@classmethod
|
|
166
|
+
def import_dbapi(cls) -> DBAPIModule:
|
|
167
|
+
return __import__("MySQLdb")
|
|
168
|
+
|
|
169
|
+
def on_connect(self) -> Callable[[DBAPIConnection], None]:
|
|
170
|
+
super_ = super().on_connect()
|
|
171
|
+
|
|
172
|
+
def on_connect(conn: DBAPIConnection) -> None:
|
|
173
|
+
if super_ is not None:
|
|
174
|
+
super_(conn)
|
|
175
|
+
|
|
176
|
+
charset_name = conn.character_set_name()
|
|
177
|
+
|
|
178
|
+
if charset_name is not None:
|
|
179
|
+
cursor = conn.cursor()
|
|
180
|
+
cursor.execute("SET NAMES %s" % charset_name)
|
|
181
|
+
cursor.close()
|
|
182
|
+
|
|
183
|
+
return on_connect
|
|
184
|
+
|
|
185
|
+
def do_ping(self, dbapi_connection: DBAPIConnection) -> Literal[True]:
|
|
186
|
+
dbapi_connection.ping()
|
|
187
|
+
return True
|
|
188
|
+
|
|
189
|
+
def do_executemany(
|
|
190
|
+
self,
|
|
191
|
+
cursor: DBAPICursor,
|
|
192
|
+
statement: str,
|
|
193
|
+
parameters: _DBAPIMultiExecuteParams,
|
|
194
|
+
context: Optional[ExecutionContext] = None,
|
|
195
|
+
) -> None:
|
|
196
|
+
rowcount = cursor.executemany(statement, parameters)
|
|
197
|
+
if context is not None:
|
|
198
|
+
cast(MySQLExecutionContext, context)._rowcount = rowcount
|
|
199
|
+
|
|
200
|
+
def create_connect_args(
|
|
201
|
+
self, url: URL, _translate_args: Optional[Dict[str, Any]] = None
|
|
202
|
+
) -> ConnectArgsType:
|
|
203
|
+
if _translate_args is None:
|
|
204
|
+
_translate_args = dict(
|
|
205
|
+
database="db", username="user", password="passwd"
|
|
206
|
+
)
|
|
207
|
+
|
|
208
|
+
opts = url.translate_connect_args(**_translate_args)
|
|
209
|
+
opts.update(url.query)
|
|
210
|
+
|
|
211
|
+
util.coerce_kw_type(opts, "compress", bool)
|
|
212
|
+
util.coerce_kw_type(opts, "connect_timeout", int)
|
|
213
|
+
util.coerce_kw_type(opts, "read_timeout", int)
|
|
214
|
+
util.coerce_kw_type(opts, "write_timeout", int)
|
|
215
|
+
util.coerce_kw_type(opts, "client_flag", int)
|
|
216
|
+
util.coerce_kw_type(opts, "local_infile", bool)
|
|
217
|
+
# Note: using either of the below will cause all strings to be
|
|
218
|
+
# returned as Unicode, both in raw SQL operations and with column
|
|
219
|
+
# types like String and MSString.
|
|
220
|
+
util.coerce_kw_type(opts, "use_unicode", bool)
|
|
221
|
+
util.coerce_kw_type(opts, "charset", str)
|
|
222
|
+
|
|
223
|
+
# Rich values 'cursorclass' and 'conv' are not supported via
|
|
224
|
+
# query string.
|
|
225
|
+
|
|
226
|
+
ssl = {}
|
|
227
|
+
keys = [
|
|
228
|
+
("ssl_ca", str),
|
|
229
|
+
("ssl_key", str),
|
|
230
|
+
("ssl_cert", str),
|
|
231
|
+
("ssl_capath", str),
|
|
232
|
+
("ssl_cipher", str),
|
|
233
|
+
("ssl_check_hostname", bool),
|
|
234
|
+
]
|
|
235
|
+
for key, kw_type in keys:
|
|
236
|
+
if key in opts:
|
|
237
|
+
ssl[key[4:]] = opts[key]
|
|
238
|
+
util.coerce_kw_type(ssl, key[4:], kw_type)
|
|
239
|
+
del opts[key]
|
|
240
|
+
if ssl:
|
|
241
|
+
opts["ssl"] = ssl
|
|
242
|
+
|
|
243
|
+
# FOUND_ROWS must be set in CLIENT_FLAGS to enable
|
|
244
|
+
# supports_sane_rowcount.
|
|
245
|
+
client_flag = opts.get("client_flag", 0)
|
|
246
|
+
|
|
247
|
+
client_flag_found_rows = self._found_rows_client_flag()
|
|
248
|
+
if client_flag_found_rows is not None:
|
|
249
|
+
client_flag |= client_flag_found_rows
|
|
250
|
+
opts["client_flag"] = client_flag
|
|
251
|
+
return [], opts
|
|
252
|
+
|
|
253
|
+
def _found_rows_client_flag(self) -> Optional[int]:
|
|
254
|
+
if self.dbapi is not None:
|
|
255
|
+
try:
|
|
256
|
+
CLIENT_FLAGS = __import__(
|
|
257
|
+
self.dbapi.__name__ + ".constants.CLIENT"
|
|
258
|
+
).constants.CLIENT
|
|
259
|
+
except (AttributeError, ImportError):
|
|
260
|
+
return None
|
|
261
|
+
else:
|
|
262
|
+
return CLIENT_FLAGS.FOUND_ROWS # type: ignore
|
|
263
|
+
else:
|
|
264
|
+
return None
|
|
265
|
+
|
|
266
|
+
def _extract_error_code(self, exception: DBAPIModule.Error) -> int:
|
|
267
|
+
return exception.args[0] # type: ignore[no-any-return]
|
|
268
|
+
|
|
269
|
+
def _detect_charset(self, connection: Connection) -> str:
|
|
270
|
+
"""Sniff out the character set in use for connection results."""
|
|
271
|
+
|
|
272
|
+
try:
|
|
273
|
+
# note: the SQL here would be
|
|
274
|
+
# "SHOW VARIABLES LIKE 'character_set%%'"
|
|
275
|
+
|
|
276
|
+
cset_name: Callable[[], str] = (
|
|
277
|
+
connection.connection.character_set_name
|
|
278
|
+
)
|
|
279
|
+
except AttributeError:
|
|
280
|
+
util.warn(
|
|
281
|
+
"No 'character_set_name' can be detected with "
|
|
282
|
+
"this MySQL-Python version; "
|
|
283
|
+
"please upgrade to a recent version of MySQL-Python. "
|
|
284
|
+
"Assuming latin1."
|
|
285
|
+
)
|
|
286
|
+
return "latin1"
|
|
287
|
+
else:
|
|
288
|
+
return cset_name()
|
|
289
|
+
|
|
290
|
+
def get_isolation_level_values(
|
|
291
|
+
self, dbapi_conn: DBAPIConnection
|
|
292
|
+
) -> Tuple[IsolationLevel, ...]:
|
|
293
|
+
return (
|
|
294
|
+
"SERIALIZABLE",
|
|
295
|
+
"READ UNCOMMITTED",
|
|
296
|
+
"READ COMMITTED",
|
|
297
|
+
"REPEATABLE READ",
|
|
298
|
+
"AUTOCOMMIT",
|
|
299
|
+
)
|
|
300
|
+
|
|
301
|
+
def detect_autocommit_setting(self, dbapi_conn: DBAPIConnection) -> bool:
|
|
302
|
+
return dbapi_conn.get_autocommit() # type: ignore[no-any-return]
|
|
303
|
+
|
|
304
|
+
def set_isolation_level(
|
|
305
|
+
self, dbapi_connection: DBAPIConnection, level: IsolationLevel
|
|
306
|
+
) -> None:
|
|
307
|
+
if level == "AUTOCOMMIT":
|
|
308
|
+
dbapi_connection.autocommit(True)
|
|
309
|
+
else:
|
|
310
|
+
dbapi_connection.autocommit(False)
|
|
311
|
+
super().set_isolation_level(dbapi_connection, level)
|
|
312
|
+
|
|
313
|
+
|
|
314
|
+
dialect = MySQLDialect_mysqldb
|