Coverage for /home/martinb/.local/share/virtualenvs/camcops/lib/python3.6/site-packages/sqlalchemy/dialects/mysql/oursql.py : 40%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1# mysql/oursql.py
2# Copyright (C) 2005-2020 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: http://www.opensource.org/licenses/mit-license.php
8"""
10.. dialect:: mysql+oursql
11 :name: OurSQL
12 :dbapi: oursql
13 :connectstring: mysql+oursql://<user>:<password>@<host>[:<port>]/<dbname>
14 :url: http://packages.python.org/oursql/
16.. note::
18 The OurSQL MySQL dialect is legacy and is no longer supported upstream,
19 and is **not tested as part of SQLAlchemy's continuous integration**.
20 The recommended MySQL dialects are mysqlclient and PyMySQL.
22Unicode
23-------
25Please see :ref:`mysql_unicode` for current recommendations on unicode
26handling.
29"""
32from .base import BIT
33from .base import MySQLDialect
34from .base import MySQLExecutionContext
35from ... import types as sqltypes
36from ... import util
39class _oursqlBIT(BIT):
40 def result_processor(self, dialect, coltype):
41 """oursql already converts mysql bits, so."""
43 return None
46class MySQLExecutionContext_oursql(MySQLExecutionContext):
47 @property
48 def plain_query(self):
49 return self.execution_options.get("_oursql_plain_query", False)
52class MySQLDialect_oursql(MySQLDialect):
53 driver = "oursql"
55 if util.py2k:
56 supports_unicode_binds = True
57 supports_unicode_statements = True
59 supports_native_decimal = True
61 supports_sane_rowcount = True
62 supports_sane_multi_rowcount = True
63 execution_ctx_cls = MySQLExecutionContext_oursql
65 colspecs = util.update_copy(
66 MySQLDialect.colspecs, {sqltypes.Time: sqltypes.Time, BIT: _oursqlBIT}
67 )
69 @classmethod
70 def dbapi(cls):
71 return __import__("oursql")
73 def do_execute(self, cursor, statement, parameters, context=None):
74 """Provide an implementation of
75 *cursor.execute(statement, parameters)*."""
77 if context and context.plain_query:
78 cursor.execute(statement, plain_query=True)
79 else:
80 cursor.execute(statement, parameters)
82 def do_begin(self, connection):
83 connection.cursor().execute("BEGIN", plain_query=True)
85 def _xa_query(self, connection, query, xid):
86 if util.py2k:
87 arg = connection.connection._escape_string(xid)
88 else:
89 charset = self._connection_charset
90 arg = connection.connection._escape_string(
91 xid.encode(charset)
92 ).decode(charset)
93 arg = "'%s'" % arg
94 connection.execution_options(_oursql_plain_query=True).execute(
95 query % arg
96 )
98 # Because mysql is bad, these methods have to be
99 # reimplemented to use _PlainQuery. Basically, some queries
100 # refuse to return any data if they're run through
101 # the parameterized query API, or refuse to be parameterized
102 # in the first place.
103 def do_begin_twophase(self, connection, xid):
104 self._xa_query(connection, "XA BEGIN %s", xid)
106 def do_prepare_twophase(self, connection, xid):
107 self._xa_query(connection, "XA END %s", xid)
108 self._xa_query(connection, "XA PREPARE %s", xid)
110 def do_rollback_twophase(
111 self, connection, xid, is_prepared=True, recover=False
112 ):
113 if not is_prepared:
114 self._xa_query(connection, "XA END %s", xid)
115 self._xa_query(connection, "XA ROLLBACK %s", xid)
117 def do_commit_twophase(
118 self, connection, xid, is_prepared=True, recover=False
119 ):
120 if not is_prepared:
121 self.do_prepare_twophase(connection, xid)
122 self._xa_query(connection, "XA COMMIT %s", xid)
124 # Q: why didn't we need all these "plain_query" overrides earlier ?
125 # am i on a newer/older version of OurSQL ?
126 def has_table(self, connection, table_name, schema=None):
127 return MySQLDialect.has_table(
128 self,
129 connection.connect().execution_options(_oursql_plain_query=True),
130 table_name,
131 schema,
132 )
134 def get_table_options(self, connection, table_name, schema=None, **kw):
135 return MySQLDialect.get_table_options(
136 self,
137 connection.connect().execution_options(_oursql_plain_query=True),
138 table_name,
139 schema=schema,
140 **kw
141 )
143 def get_columns(self, connection, table_name, schema=None, **kw):
144 return MySQLDialect.get_columns(
145 self,
146 connection.connect().execution_options(_oursql_plain_query=True),
147 table_name,
148 schema=schema,
149 **kw
150 )
152 def get_view_names(self, connection, schema=None, **kw):
153 return MySQLDialect.get_view_names(
154 self,
155 connection.connect().execution_options(_oursql_plain_query=True),
156 schema=schema,
157 **kw
158 )
160 def get_table_names(self, connection, schema=None, **kw):
161 return MySQLDialect.get_table_names(
162 self,
163 connection.connect().execution_options(_oursql_plain_query=True),
164 schema,
165 )
167 def get_schema_names(self, connection, **kw):
168 return MySQLDialect.get_schema_names(
169 self,
170 connection.connect().execution_options(_oursql_plain_query=True),
171 **kw
172 )
174 def initialize(self, connection):
175 return MySQLDialect.initialize(
176 self, connection.execution_options(_oursql_plain_query=True)
177 )
179 def _show_create_table(
180 self, connection, table, charset=None, full_name=None
181 ):
182 return MySQLDialect._show_create_table(
183 self,
184 connection._contextual_connect(
185 close_with_result=True
186 ).execution_options(_oursql_plain_query=True),
187 table,
188 charset,
189 full_name,
190 )
192 def is_disconnect(self, e, connection, cursor):
193 if isinstance(e, self.dbapi.ProgrammingError):
194 return (
195 e.errno is None
196 and "cursor" not in e.args[1]
197 and e.args[1].endswith("closed")
198 )
199 else:
200 return e.errno in (2006, 2013, 2014, 2045, 2055)
202 def create_connect_args(self, url):
203 opts = url.translate_connect_args(
204 database="db", username="user", password="passwd"
205 )
206 opts.update(url.query)
208 util.coerce_kw_type(opts, "port", int)
209 util.coerce_kw_type(opts, "compress", bool)
210 util.coerce_kw_type(opts, "autoping", bool)
211 util.coerce_kw_type(opts, "raise_on_warnings", bool)
213 util.coerce_kw_type(opts, "default_charset", bool)
214 if opts.pop("default_charset", False):
215 opts["charset"] = None
216 else:
217 util.coerce_kw_type(opts, "charset", str)
218 opts["use_unicode"] = opts.get("use_unicode", True)
219 util.coerce_kw_type(opts, "use_unicode", bool)
221 # FOUND_ROWS must be set in CLIENT_FLAGS to enable
222 # supports_sane_rowcount.
223 opts.setdefault("found_rows", True)
225 ssl = {}
226 for key in [
227 "ssl_ca",
228 "ssl_key",
229 "ssl_cert",
230 "ssl_capath",
231 "ssl_cipher",
232 ]:
233 if key in opts:
234 ssl[key[4:]] = opts[key]
235 util.coerce_kw_type(ssl, key[4:], str)
236 del opts[key]
237 if ssl:
238 opts["ssl"] = ssl
240 return [[], opts]
242 def _extract_error_code(self, exception):
243 return exception.errno
245 def _detect_charset(self, connection):
246 """Sniff out the character set in use for connection results."""
248 return connection.connection.charset
250 def _compat_fetchall(self, rp, charset=None):
251 """oursql isn't super-broken like MySQLdb, yaaay."""
252 return rp.fetchall()
254 def _compat_fetchone(self, rp, charset=None):
255 """oursql isn't super-broken like MySQLdb, yaaay."""
256 return rp.fetchone()
258 def _compat_first(self, rp, charset=None):
259 return rp.first()
262dialect = MySQLDialect_oursql