| 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/ | ||||