connections.py | connections.py | |||
---|---|---|---|---|
""" | """ | |||
This module implements connections for MySQLdb. Presently there is | This module implements connections for MySQLdb. Presently there is | |||
only one class: Connection. Others are unlikely. However, you might | only one class: Connection. Others are unlikely. However, you might | |||
want to make your own subclasses. In most cases, you will probably | want to make your own subclasses. In most cases, you will probably | |||
override Connection.default_cursor with a non-standard Cursor class. | override Connection.default_cursor with a non-standard Cursor class. | |||
""" | """ | |||
import re | ||||
import sys | ||||
from MySQLdb import cursors | from MySQLdb import cursors | |||
from MySQLdb.compat import unicode, PY2 | from MySQLdb.compat import unicode, PY2 | |||
from _mysql_exceptions import Warning, Error, InterfaceError, DataError, \ | from _mysql_exceptions import ( | |||
DatabaseError, OperationalError, IntegrityError, InternalError, \ | Warning, Error, InterfaceError, DataError, | |||
NotSupportedError, ProgrammingError | DatabaseError, OperationalError, IntegrityError, InternalError, | |||
NotSupportedError, ProgrammingError, | ||||
) | ||||
import _mysql | import _mysql | |||
import re | ||||
if not PY2: | ||||
if sys.version_info[:2] < (3, 6): | ||||
# See http://bugs.python.org/issue24870 | ||||
_surrogateescape_table = [chr(i) if i < 0x80 else chr(i + 0xdc00) f | ||||
or i in range(256)] | ||||
def _fast_surrogateescape(s): | ||||
return s.decode('latin1').translate(_surrogateescape_table) | ||||
else: | ||||
def _fast_surrogateescape(s): | ||||
return s.decode('ascii', 'surrogateescape') | ||||
def defaulterrorhandler(connection, cursor, errorclass, errorvalue): | def defaulterrorhandler(connection, cursor, errorclass, errorvalue): | |||
""" | """ | |||
If cursor is not None, (errorclass, errorvalue) is appended to | If cursor is not None, (errorclass, errorvalue) is appended to | |||
cursor.messages; otherwise it is appended to | cursor.messages; otherwise it is appended to | |||
connection.messages. Then errorclass is raised with errorvalue as | connection.messages. Then errorclass is raised with errorvalue as | |||
the value. | the value. | |||
You can override this with your own error handler by assigning it | You can override this with your own error handler by assigning it | |||
to the instance. | to the instance. | |||
skipping to change at line 59 | skipping to change at line 72 | |||
>>> numeric_part("16b") | >>> numeric_part("16b") | |||
16 | 16 | |||
""" | """ | |||
m = re_numeric_part.match(s) | m = re_numeric_part.match(s) | |||
if m: | if m: | |||
return int(m.group(1)) | return int(m.group(1)) | |||
return None | return None | |||
class Connection(_mysql.connection): | class Connection(_mysql.connection): | |||
"""MySQL Database Connection Object""" | """MySQL Database Connection Object""" | |||
default_cursor = cursors.Cursor | default_cursor = cursors.Cursor | |||
waiter = None | waiter = None | |||
def __init__(self, *args, **kwargs): | def __init__(self, *args, **kwargs): | |||
""" | """ | |||
Create a connection to the database. It is strongly recommended | Create a connection to the database. It is strongly recommended | |||
that you only use keyword parameters. Consult the MySQL C API | that you only use keyword parameters. Consult the MySQL C API | |||
documentation for more information. | documentation for more information. | |||
host | :param str host: host to connect | |||
string, host to connect | :param str user: user to connect as | |||
:param str password: password to use | ||||
user | :param str passwd: alias of password, for backward compatibili | |||
string, user to connect as | ty | |||
:param str database: database to use | ||||
passwd | :param str db: alias of database, for backward compatibili | |||
string, password to use | ty | |||
:param int port: TCP/IP port to connect to | ||||
db | :param str unix_socket: location of unix_socket to use | |||
string, database to use | :param dict conv: conversion dictionary, see MySQLdb.converte | |||
rs | ||||
port | :param int connect_timeout: | |||
integer, TCP/IP port to connect to | number of seconds to wait before the connection attempt fails. | |||
unix_socket | :param bool compress: if set, compression is enabled | |||
string, location of unix_socket to use | :param str named_pipe: if set, a named pipe is used to connect (Wi | |||
ndows only) | ||||
conv | :param str init_command: | |||
conversion dictionary, see MySQLdb.converters | command which is run once the connection is created | |||
connect_timeout | :param str read_default_file: | |||
number of seconds to wait before the connection attempt | file from which default client values are read | |||
fails. | ||||
:param str read_default_group: | ||||
compress | configuration group to use from the default file | |||
if set, compression is enabled | ||||
:param type cursorclass: | ||||
named_pipe | class object, used to create cursors (keyword only) | |||
if set, a named pipe is used to connect (Windows only) | ||||
:param str use_unicode: | ||||
init_command | If True, text-like columns are returned as unicode objects | |||
command which is run once the connection is created | using the connection's character set. Otherwise, text-like | |||
columns are returned as strings. columns are returned as | ||||
read_default_file | normal strings. Unicode objects will always be encoded to | |||
file from which default client values are read | the connection's character set regardless of this setting. | |||
Default to False on Python 2 and True on Python 3. | ||||
read_default_group | ||||
configuration group to use from the default file | :param str charset: | |||
If supplied, the connection character set will be changed | ||||
cursorclass | to this character set (MySQL-4.1 and newer). This implies | |||
class object, used to create cursors (keyword only) | use_unicode=True. | |||
use_unicode | :param str sql_mode: | |||
If True, text-like columns are returned as unicode objects | If supplied, the session SQL mode will be changed to this | |||
using the connection's character set. Otherwise, text-like | setting (MySQL-4.1 and newer). For more details and legal | |||
columns are returned as strings. columns are returned as | values, see the MySQL documentation. | |||
normal strings. Unicode objects will always be encoded to | ||||
the connection's character set regardless of this setting. | :param int client_flag: | |||
Default to False on Python 2 and True on Python 3. | flags to use or 0 (see MySQL docs or constants/CLIENTS.py) | |||
charset | :param dict ssl: | |||
If supplied, the connection character set will be changed | dictionary or mapping contains SSL connection parameters; | |||
to this character set (MySQL-4.1 and newer). This implies | see the MySQL documentation for more details | |||
use_unicode=True. | (mysql_ssl_set()). If this is set, and the client does not | |||
support SSL, NotSupportedError will be raised. | ||||
sql_mode | ||||
If supplied, the session SQL mode will be changed to this | :param bool local_infile: | |||
setting (MySQL-4.1 and newer). For more details and legal | enables LOAD LOCAL INFILE; zero disables | |||
values, see the MySQL documentation. | ||||
:param bool autocommit: | ||||
client_flag | If False (default), autocommit is disabled. | |||
integer, flags to use or 0 | If True, autocommit is enabled. | |||
(see MySQL docs or constants/CLIENTS.py) | If None, autocommit isn't set and server default is used. | |||
ssl | :param bool binary_prefix: | |||
dictionary or mapping, contains SSL connection parameters; | If set, the '_binary' prefix will be used for raw byte query | |||
see the MySQL documentation for more details | arguments (e.g. Binary). This is disabled by default. | |||
(mysql_ssl_set()). If this is set, and the client does not | ||||
support SSL, NotSupportedError will be raised. | ||||
local_infile | ||||
integer, non-zero enables LOAD LOCAL INFILE; zero disables | ||||
autocommit | ||||
If False (default), autocommit is disabled. | ||||
If True, autocommit is enabled. | ||||
If None, autocommit isn't set and server default is used. | ||||
waiter | ||||
Callable accepts fd as an argument. It is called after sending | ||||
query and before reading response. | ||||
This is useful when using with greenlet and async io. | ||||
There are a number of undocumented, non-standard methods. See the | There are a number of undocumented, non-standard methods. See the | |||
documentation for the MySQL C API for some hints on what they do. | documentation for the MySQL C API for some hints on what they do. | |||
""" | """ | |||
from MySQLdb.constants import CLIENT, FIELD_TYPE | from MySQLdb.constants import CLIENT, FIELD_TYPE | |||
from MySQLdb.converters import conversions | from MySQLdb.converters import conversions | |||
from weakref import proxy | from weakref import proxy | |||
kwargs2 = kwargs.copy() | kwargs2 = kwargs.copy() | |||
if 'database' in kwargs2: | ||||
kwargs2['db'] = kwargs2.pop('database') | ||||
if 'password' in kwargs2: | ||||
kwargs2['passwd'] = kwargs2.pop('password') | ||||
if 'conv' in kwargs: | if 'conv' in kwargs: | |||
conv = kwargs['conv'] | conv = kwargs['conv'] | |||
else: | else: | |||
conv = conversions | conv = conversions | |||
conv2 = {} | conv2 = {} | |||
for k, v in conv.items(): | for k, v in conv.items(): | |||
if isinstance(k, int) and isinstance(v, list): | if isinstance(k, int) and isinstance(v, list): | |||
conv2[k] = v[:] | conv2[k] = v[:] | |||
else: | else: | |||
skipping to change at line 187 | skipping to change at line 185 | |||
cursorclass = kwargs2.pop('cursorclass', self.default_cursor) | cursorclass = kwargs2.pop('cursorclass', self.default_cursor) | |||
charset = kwargs2.pop('charset', '') | charset = kwargs2.pop('charset', '') | |||
if charset or not PY2: | if charset or not PY2: | |||
use_unicode = True | use_unicode = True | |||
else: | else: | |||
use_unicode = False | use_unicode = False | |||
use_unicode = kwargs2.pop('use_unicode', use_unicode) | use_unicode = kwargs2.pop('use_unicode', use_unicode) | |||
sql_mode = kwargs2.pop('sql_mode', '') | sql_mode = kwargs2.pop('sql_mode', '') | |||
binary_prefix = kwargs2.pop('binary_prefix', False) | ||||
client_flag = kwargs.get('client_flag', 0) | client_flag = kwargs.get('client_flag', 0) | |||
client_version = tuple([ numeric_part(n) for n in _mysql.get_client _info().split('.')[:2] ]) | client_version = tuple([ numeric_part(n) for n in _mysql.get_client _info().split('.')[:2] ]) | |||
if client_version >= (4, 1): | if client_version >= (4, 1): | |||
client_flag |= CLIENT.MULTI_STATEMENTS | client_flag |= CLIENT.MULTI_STATEMENTS | |||
if client_version >= (5, 0): | if client_version >= (5, 0): | |||
client_flag |= CLIENT.MULTI_RESULTS | client_flag |= CLIENT.MULTI_RESULTS | |||
kwargs2['client_flag'] = client_flag | kwargs2['client_flag'] = client_flag | |||
skipping to change at line 210 | skipping to change at line 209 | |||
super(Connection, self).__init__(*args, **kwargs2) | super(Connection, self).__init__(*args, **kwargs2) | |||
self.cursorclass = cursorclass | self.cursorclass = cursorclass | |||
self.encoders = dict([ (k, v) for k, v in conv.items() | self.encoders = dict([ (k, v) for k, v in conv.items() | |||
if type(k) is not int ]) | if type(k) is not int ]) | |||
self._server_version = tuple([ numeric_part(n) for n in self.get_se rver_info().split('.')[:2] ]) | self._server_version = tuple([ numeric_part(n) for n in self.get_se rver_info().split('.')[:2] ]) | |||
db = proxy(self) | db = proxy(self) | |||
def _get_string_literal(): | def _get_string_literal(): | |||
# Note: string_literal() is called for bytes object on Python 3 . | # Note: string_literal() is called for bytes object on Python 3 (via bytes_literal) | |||
def string_literal(obj, dummy=None): | def string_literal(obj, dummy=None): | |||
return db.string_literal(obj) | return db.string_literal(obj) | |||
return string_literal | return string_literal | |||
def _get_unicode_literal(): | def _get_unicode_literal(): | |||
if PY2: | if PY2: | |||
# unicode_literal is called for only unicode object. | # unicode_literal is called for only unicode object. | |||
def unicode_literal(u, dummy=None): | def unicode_literal(u, dummy=None): | |||
return db.literal(u.encode(unicode_literal.charset)) | return db.string_literal(u.encode(unicode_literal.chars et)) | |||
else: | else: | |||
# unicode_literal() is called for arbitrary object. | # unicode_literal() is called for arbitrary object. | |||
def unicode_literal(u, dummy=None): | def unicode_literal(u, dummy=None): | |||
return db.literal(str(u).encode(unicode_literal.charset )) | return db.string_literal(str(u).encode(unicode_literal. charset)) | |||
return unicode_literal | return unicode_literal | |||
def _get_bytes_literal(): | ||||
def bytes_literal(obj, dummy=None): | ||||
return b'_binary' + db.string_literal(obj) | ||||
return bytes_literal | ||||
def _get_string_decoder(): | def _get_string_decoder(): | |||
def string_decoder(s): | def string_decoder(s): | |||
return s.decode(string_decoder.charset) | return s.decode(string_decoder.charset) | |||
return string_decoder | return string_decoder | |||
string_literal = _get_string_literal() | string_literal = _get_string_literal() | |||
self.unicode_literal = unicode_literal = _get_unicode_literal() | self.unicode_literal = unicode_literal = _get_unicode_literal() | |||
bytes_literal = _get_bytes_literal() | ||||
self.string_decoder = string_decoder = _get_string_decoder() | self.string_decoder = string_decoder = _get_string_decoder() | |||
if not charset: | if not charset: | |||
charset = self.character_set_name() | charset = self.character_set_name() | |||
self.set_character_set(charset) | self.set_character_set(charset) | |||
if sql_mode: | if sql_mode: | |||
self.set_sql_mode(sql_mode) | self.set_sql_mode(sql_mode) | |||
if use_unicode: | if use_unicode: | |||
self.converter[FIELD_TYPE.STRING].append((None, string_decoder) ) | self.converter[FIELD_TYPE.STRING].append((None, string_decoder) ) | |||
self.converter[FIELD_TYPE.VAR_STRING].append((None, string_deco der)) | self.converter[FIELD_TYPE.VAR_STRING].append((None, string_deco der)) | |||
self.converter[FIELD_TYPE.VARCHAR].append((None, string_decoder )) | self.converter[FIELD_TYPE.VARCHAR].append((None, string_decoder )) | |||
self.converter[FIELD_TYPE.BLOB].append((None, string_decoder)) | self.converter[FIELD_TYPE.BLOB].append((None, string_decoder)) | |||
self.encoders[bytes] = string_literal | if binary_prefix: | |||
self.encoders[bytes] = string_literal if PY2 else bytes_literal | ||||
self.encoders[bytearray] = bytes_literal | ||||
else: | ||||
self.encoders[bytes] = string_literal | ||||
self.encoders[unicode] = unicode_literal | self.encoders[unicode] = unicode_literal | |||
self._transactional = self.server_capabilities & CLIENT.TRANSACTION S | self._transactional = self.server_capabilities & CLIENT.TRANSACTION S | |||
if self._transactional: | if self._transactional: | |||
if autocommit is not None: | if autocommit is not None: | |||
self.autocommit(autocommit) | self.autocommit(autocommit) | |||
self.messages = [] | self.messages = [] | |||
def autocommit(self, on): | def autocommit(self, on): | |||
on = bool(on) | on = bool(on) | |||
if self.get_autocommit() != on: | if self.get_autocommit() != on: | |||
_mysql.connection.autocommit(self, on) | _mysql.connection.autocommit(self, on) | |||
def cursor(self, cursorclass=None): | def cursor(self, cursorclass=None): | |||
""" | """ | |||
Create a cursor on which queries may be performed. The | Create a cursor on which queries may be performed. The | |||
optional cursorclass parameter is used to create the | optional cursorclass parameter is used to create the | |||
Cursor. By default, self.cursorclass=cursors.Cursor is | Cursor. By default, self.cursorclass=cursors.Cursor is | |||
used. | used. | |||
""" | """ | |||
return (cursorclass or self.cursorclass)(self) | return (cursorclass or self.cursorclass)(self) | |||
def query(self, query): | def query(self, query): | |||
# Since _mysql releases GIL while querying, we need immutable buffe | ||||
r. | ||||
if isinstance(query, bytearray): | ||||
query = bytes(query) | ||||
if self.waiter is not None: | if self.waiter is not None: | |||
self.send_query(query) | self.send_query(query) | |||
self.waiter(self.fileno()) | self.waiter(self.fileno()) | |||
self.read_query_result() | self.read_query_result() | |||
else: | else: | |||
_mysql.connection.query(self, query) | _mysql.connection.query(self, query) | |||
def __enter__(self): | def __enter__(self): | |||
from warnings import warn | ||||
warn("context interface will be changed. Use explicit conn.commit( | ||||
) or conn.rollback().", | ||||
DeprecationWarning, 2) | ||||
if self.get_autocommit(): | if self.get_autocommit(): | |||
self.query("BEGIN") | self.query("BEGIN") | |||
return self.cursor() | return self.cursor() | |||
def __exit__(self, exc, value, tb): | def __exit__(self, exc, value, tb): | |||
if exc: | if exc: | |||
self.rollback() | self.rollback() | |||
else: | else: | |||
self.commit() | self.commit() | |||
def literal(self, o): | def literal(self, o): | |||
""" | """If o is a single object, returns an SQL literal as a string. | |||
If o is a single object, returns an SQL literal as a string. | ||||
If o is a non-string sequence, the items of the sequence are | If o is a non-string sequence, the items of the sequence are | |||
converted and returned as a sequence. | converted and returned as a sequence. | |||
Non-standard. For internal use; do not use this in your | Non-standard. For internal use; do not use this in your | |||
applications. | applications. | |||
""" | """ | |||
s = self.escape(o, self.encoders) | s = self.escape(o, self.encoders) | |||
# Python 3 doesn't support % operation for bytes object. | # Python 3(~3.4) doesn't support % operation for bytes object. | |||
# We should decode it before using %. | # We should decode it before using %. | |||
# Decoding with ascii and surrogateescape allows convert arbitrary | # Decoding with ascii and surrogateescape allows convert arbitrary | |||
# bytes to unicode and back again. | # bytes to unicode and back again. | |||
# See http://python.org/dev/peps/pep-0383/ | # See http://python.org/dev/peps/pep-0383/ | |||
if not PY2 and isinstance(s, bytes): | if not PY2 and isinstance(s, (bytes, bytearray)): | |||
return s.decode('ascii', 'surrogateescape') | return _fast_surrogateescape(s) | |||
return s | return s | |||
def begin(self): | def begin(self): | |||
"""Explicitly begin a connection. Non-standard. | """Explicitly begin a connection. Non-standard. | |||
DEPRECATED: Will be removed in 1.3. | DEPRECATED: Will be removed in 1.3. | |||
Use an SQL BEGIN statement instead.""" | Use an SQL BEGIN statement instead.""" | |||
from warnings import warn | from warnings import warn | |||
warn("begin() is non-standard and will be removed in 1.3", | warn("begin() is non-standard and will be removed in 1.4", | |||
DeprecationWarning, 2) | DeprecationWarning, 2) | |||
self.query("BEGIN") | self.query("BEGIN") | |||
if not hasattr(_mysql.connection, 'warning_count'): | if not hasattr(_mysql.connection, 'warning_count'): | |||
def warning_count(self): | def warning_count(self): | |||
"""Return the number of warnings generated from the | """Return the number of warnings generated from the | |||
last query. This is derived from the info() method.""" | last query. This is derived from the info() method.""" | |||
info = self.info() | info = self.info() | |||
if info: | if info: | |||
skipping to change at line 350 | skipping to change at line 361 | |||
if self.character_set_name() != charset: | if self.character_set_name() != charset: | |||
try: | try: | |||
super(Connection, self).set_character_set(charset) | super(Connection, self).set_character_set(charset) | |||
except AttributeError: | except AttributeError: | |||
if self._server_version < (4, 1): | if self._server_version < (4, 1): | |||
raise NotSupportedError("server is too old to set chars et") | raise NotSupportedError("server is too old to set chars et") | |||
self.query('SET NAMES %s' % charset) | self.query('SET NAMES %s' % charset) | |||
self.store_result() | self.store_result() | |||
self.string_decoder.charset = py_charset | self.string_decoder.charset = py_charset | |||
self.unicode_literal.charset = py_charset | self.unicode_literal.charset = py_charset | |||
self.encoding = py_charset | ||||
def set_sql_mode(self, sql_mode): | def set_sql_mode(self, sql_mode): | |||
"""Set the connection sql_mode. See MySQL documentation for | """Set the connection sql_mode. See MySQL documentation for | |||
legal values.""" | legal values.""" | |||
if self._server_version < (4, 1): | if self._server_version < (4, 1): | |||
raise NotSupportedError("server is too old to set sql_mode") | raise NotSupportedError("server is too old to set sql_mode") | |||
self.query("SET SESSION sql_mode='%s'" % sql_mode) | self.query("SET SESSION sql_mode='%s'" % sql_mode) | |||
self.store_result() | self.store_result() | |||
def show_warnings(self): | def show_warnings(self): | |||
skipping to change at line 382 | skipping to change at line 394 | |||
InterfaceError = InterfaceError | InterfaceError = InterfaceError | |||
DatabaseError = DatabaseError | DatabaseError = DatabaseError | |||
DataError = DataError | DataError = DataError | |||
OperationalError = OperationalError | OperationalError = OperationalError | |||
IntegrityError = IntegrityError | IntegrityError = IntegrityError | |||
InternalError = InternalError | InternalError = InternalError | |||
ProgrammingError = ProgrammingError | ProgrammingError = ProgrammingError | |||
NotSupportedError = NotSupportedError | NotSupportedError = NotSupportedError | |||
errorhandler = defaulterrorhandler | errorhandler = defaulterrorhandler | |||
# vim: colorcolumn=100 | ||||
End of changes. 26 change blocks. | ||||
104 lines changed or deleted | 123 lines changed or added | |||
This html diff was produced by rfcdiff 1.41. The latest version is available from http://tools.ietf.org/tools/rfcdiff/ |