Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/sqlalchemy/dialects/mysql/pyodbc.py: 42%
57 statements
« prev ^ index » next coverage.py v7.2.7, created at 2023-06-07 06:35 +0000
« prev ^ index » next coverage.py v7.2.7, created at 2023-06-07 06:35 +0000
1# mysql/pyodbc.py
2# Copyright (C) 2005-2023 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
8r"""
11.. dialect:: mysql+pyodbc
12 :name: PyODBC
13 :dbapi: pyodbc
14 :connectstring: mysql+pyodbc://<username>:<password>@<dsnname>
15 :url: https://pypi.org/project/pyodbc/
17.. note::
19 The PyODBC for MySQL dialect is **not tested as part of
20 SQLAlchemy's continuous integration**.
21 The recommended MySQL dialects are mysqlclient and PyMySQL.
22 However, if you want to use the mysql+pyodbc dialect and require
23 full support for ``utf8mb4`` characters (including supplementary
24 characters like emoji) be sure to use a current release of
25 MySQL Connector/ODBC and specify the "ANSI" (**not** "Unicode")
26 version of the driver in your DSN or connection string.
28Pass through exact pyodbc connection string::
30 import urllib
31 connection_string = (
32 'DRIVER=MySQL ODBC 8.0 ANSI Driver;'
33 'SERVER=localhost;'
34 'PORT=3307;'
35 'DATABASE=mydb;'
36 'UID=root;'
37 'PWD=(whatever);'
38 'charset=utf8mb4;'
39 )
40 params = urllib.parse.quote_plus(connection_string)
41 connection_uri = "mysql+pyodbc:///?odbc_connect=%s" % params
43""" # noqa
45import re
47from .base import MySQLDialect
48from .base import MySQLExecutionContext
49from .types import TIME
50from ... import exc
51from ... import util
52from ...connectors.pyodbc import PyODBCConnector
53from ...sql.sqltypes import Time
56class _pyodbcTIME(TIME):
57 def result_processor(self, dialect, coltype):
58 def process(value):
59 # pyodbc returns a datetime.time object; no need to convert
60 return value
62 return process
65class MySQLExecutionContext_pyodbc(MySQLExecutionContext):
66 def get_lastrowid(self):
67 cursor = self.create_cursor()
68 cursor.execute("SELECT LAST_INSERT_ID()")
69 lastrowid = cursor.fetchone()[0]
70 cursor.close()
71 return lastrowid
74class MySQLDialect_pyodbc(PyODBCConnector, MySQLDialect):
75 supports_statement_cache = True
76 colspecs = util.update_copy(MySQLDialect.colspecs, {Time: _pyodbcTIME})
77 supports_unicode_statements = True
78 execution_ctx_cls = MySQLExecutionContext_pyodbc
80 pyodbc_driver_name = "MySQL"
82 def _detect_charset(self, connection):
83 """Sniff out the character set in use for connection results."""
85 # Prefer 'character_set_results' for the current connection over the
86 # value in the driver. SET NAMES or individual variable SETs will
87 # change the charset without updating the driver's view of the world.
88 #
89 # If it's decided that issuing that sort of SQL leaves you SOL, then
90 # this can prefer the driver value.
92 # set this to None as _fetch_setting attempts to use it (None is OK)
93 self._connection_charset = None
94 try:
95 value = self._fetch_setting(connection, "character_set_client")
96 if value:
97 return value
98 except exc.DBAPIError:
99 pass
101 util.warn(
102 "Could not detect the connection character set. "
103 "Assuming latin1."
104 )
105 return "latin1"
107 def _get_server_version_info(self, connection):
108 return MySQLDialect._get_server_version_info(self, connection)
110 def _extract_error_code(self, exception):
111 m = re.compile(r"\((\d+)\)").search(str(exception.args))
112 c = m.group(1)
113 if c:
114 return int(c)
115 else:
116 return None
118 def on_connect(self):
119 super_ = super(MySQLDialect_pyodbc, self).on_connect()
121 def on_connect(conn):
122 if super_ is not None:
123 super_(conn)
125 # declare Unicode encoding for pyodbc as per
126 # https://github.com/mkleehammer/pyodbc/wiki/Unicode
127 pyodbc_SQL_CHAR = 1 # pyodbc.SQL_CHAR
128 pyodbc_SQL_WCHAR = -8 # pyodbc.SQL_WCHAR
129 conn.setdecoding(pyodbc_SQL_CHAR, encoding="utf-8")
130 conn.setdecoding(pyodbc_SQL_WCHAR, encoding="utf-8")
131 conn.setencoding(encoding="utf-8")
133 return on_connect
136dialect = MySQLDialect_pyodbc