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/