| Viewing file:  connections.py (12.61 KB)      -rw-r--r-- Select action/file-type:
 
  (+) |  (+) |  (+) | Code (+) | Session (+) |  (+) | SDB (+) |  (+) |  (+) |  (+) |  (+) |  (+) | 
 
"""
 This module implements connections for MySQLdb. Presently there is
 only one class: Connection. Others are unlikely. However, you might
 want to make your own subclasses. In most cases, you will probably
 override Connection.default_cursor with a non-standard Cursor class.
 
 """
 from MySQLdb import cursors
 from MySQLdb.compat import unicode, PY2
 from _mysql_exceptions import Warning, Error, InterfaceError, DataError, \
 DatabaseError, OperationalError, IntegrityError, InternalError, \
 NotSupportedError, ProgrammingError
 import _mysql
 import re
 
 
 def defaulterrorhandler(connection, cursor, errorclass, errorvalue):
 """
 If cursor is not None, (errorclass, errorvalue) is appended to
 cursor.messages; otherwise it is appended to
 connection.messages. Then errorclass is raised with errorvalue as
 the value.
 
 You can override this with your own error handler by assigning it
 to the instance.
 """
 error = errorclass, errorvalue
 if cursor:
 cursor.messages.append(error)
 else:
 connection.messages.append(error)
 del cursor
 del connection
 if isinstance(errorvalue, BaseException):
 raise errorvalue
 if errorclass is not None:
 raise errorclass(errorvalue)
 else:
 raise Exception(errorvalue)
 
 
 re_numeric_part = re.compile(r"^(\d+)")
 
 def numeric_part(s):
 """Returns the leading numeric part of a string.
 
 >>> numeric_part("20-alpha")
 20
 >>> numeric_part("foo")
 >>> numeric_part("16b")
 16
 """
 
 m = re_numeric_part.match(s)
 if m:
 return int(m.group(1))
 return None
 
 
 class Connection(_mysql.connection):
 
 """MySQL Database Connection Object"""
 
 default_cursor = cursors.Cursor
 waiter = None
 
 def __init__(self, *args, **kwargs):
 """
 Create a connection to the database. It is strongly recommended
 that you only use keyword parameters. Consult the MySQL C API
 documentation for more information.
 
 host
 string, host to connect
 
 user
 string, user to connect as
 
 passwd
 string, password to use
 
 db
 string, database to use
 
 port
 integer, TCP/IP port to connect to
 
 unix_socket
 string, location of unix_socket to use
 
 conv
 conversion dictionary, see MySQLdb.converters
 
 connect_timeout
 number of seconds to wait before the connection attempt
 fails.
 
 compress
 if set, compression is enabled
 
 named_pipe
 if set, a named pipe is used to connect (Windows only)
 
 init_command
 command which is run once the connection is created
 
 read_default_file
 file from which default client values are read
 
 read_default_group
 configuration group to use from the default file
 
 cursorclass
 class object, used to create cursors (keyword only)
 
 use_unicode
 If True, text-like columns are returned as unicode objects
 using the connection's character set.  Otherwise, text-like
 columns are returned as strings.  columns are returned as
 normal strings. Unicode objects will always be encoded to
 the connection's character set regardless of this setting.
 Default to False on Python 2 and True on Python 3.
 
 charset
 If supplied, the connection character set will be changed
 to this character set (MySQL-4.1 and newer). This implies
 use_unicode=True.
 
 sql_mode
 If supplied, the session SQL mode will be changed to this
 setting (MySQL-4.1 and newer). For more details and legal
 values, see the MySQL documentation.
 
 client_flag
 integer, flags to use or 0
 (see MySQL docs or constants/CLIENTS.py)
 
 ssl
 dictionary or mapping, contains SSL connection parameters;
 see the MySQL documentation for more details
 (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
 documentation for the MySQL C API for some hints on what they do.
 """
 from MySQLdb.constants import CLIENT, FIELD_TYPE
 from MySQLdb.converters import conversions
 from weakref import proxy
 
 kwargs2 = kwargs.copy()
 
 if 'conv' in kwargs:
 conv = kwargs['conv']
 else:
 conv = conversions
 
 conv2 = {}
 for k, v in conv.items():
 if isinstance(k, int) and isinstance(v, list):
 conv2[k] = v[:]
 else:
 conv2[k] = v
 kwargs2['conv'] = conv2
 
 cursorclass = kwargs2.pop('cursorclass', self.default_cursor)
 charset = kwargs2.pop('charset', '')
 
 if charset or not PY2:
 use_unicode = True
 else:
 use_unicode = False
 
 use_unicode = kwargs2.pop('use_unicode', use_unicode)
 sql_mode = kwargs2.pop('sql_mode', '')
 
 client_flag = kwargs.get('client_flag', 0)
 client_version = tuple([ numeric_part(n) for n in _mysql.get_client_info().split('.')[:2] ])
 if client_version >= (4, 1):
 client_flag |= CLIENT.MULTI_STATEMENTS
 if client_version >= (5, 0):
 client_flag |= CLIENT.MULTI_RESULTS
 
 kwargs2['client_flag'] = client_flag
 
 # PEP-249 requires autocommit to be initially off
 autocommit = kwargs2.pop('autocommit', False)
 self.waiter = kwargs2.pop('waiter', None)
 
 super(Connection, self).__init__(*args, **kwargs2)
 self.cursorclass = cursorclass
 self.encoders = dict([ (k, v) for k, v in conv.items()
 if type(k) is not int ])
 
 self._server_version = tuple([ numeric_part(n) for n in self.get_server_info().split('.')[:2] ])
 
 db = proxy(self)
 def _get_string_literal():
 # Note: string_literal() is called for bytes object on Python 3.
 def string_literal(obj, dummy=None):
 return db.string_literal(obj)
 return string_literal
 
 def _get_unicode_literal():
 if PY2:
 # unicode_literal is called for only unicode object.
 def unicode_literal(u, dummy=None):
 return db.literal(u.encode(unicode_literal.charset))
 else:
 # unicode_literal() is called for arbitrary object.
 def unicode_literal(u, dummy=None):
 return db.literal(str(u).encode(unicode_literal.charset))
 return unicode_literal
 
 def _get_string_decoder():
 def string_decoder(s):
 return s.decode(string_decoder.charset)
 return string_decoder
 
 string_literal = _get_string_literal()
 self.unicode_literal = unicode_literal = _get_unicode_literal()
 self.string_decoder = string_decoder = _get_string_decoder()
 if not charset:
 charset = self.character_set_name()
 self.set_character_set(charset)
 
 if sql_mode:
 self.set_sql_mode(sql_mode)
 
 if use_unicode:
 self.converter[FIELD_TYPE.STRING].append((None, string_decoder))
 self.converter[FIELD_TYPE.VAR_STRING].append((None, string_decoder))
 self.converter[FIELD_TYPE.VARCHAR].append((None, string_decoder))
 self.converter[FIELD_TYPE.BLOB].append((None, string_decoder))
 
 self.encoders[bytes] = string_literal
 self.encoders[unicode] = unicode_literal
 self._transactional = self.server_capabilities & CLIENT.TRANSACTIONS
 if self._transactional:
 if autocommit is not None:
 self.autocommit(autocommit)
 self.messages = []
 
 def autocommit(self, on):
 on = bool(on)
 if self.get_autocommit() != on:
 _mysql.connection.autocommit(self, on)
 
 def cursor(self, cursorclass=None):
 """
 
 Create a cursor on which queries may be performed. The
 optional cursorclass parameter is used to create the
 Cursor. By default, self.cursorclass=cursors.Cursor is
 used.
 
 """
 return (cursorclass or self.cursorclass)(self)
 
 def query(self, query):
 if self.waiter is not None:
 self.send_query(query)
 self.waiter(self.fileno())
 self.read_query_result()
 else:
 _mysql.connection.query(self, query)
 
 def __enter__(self):
 if self.get_autocommit():
 self.query("BEGIN")
 return self.cursor()
 
 def __exit__(self, exc, value, tb):
 if exc:
 self.rollback()
 else:
 self.commit()
 
 def literal(self, o):
 """
 
 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
 converted and returned as a sequence.
 
 Non-standard. For internal use; do not use this in your
 applications.
 
 """
 s = self.escape(o, self.encoders)
 # Python 3 doesn't support % operation for bytes object.
 # We should decode it before using %.
 # Decoding with ascii and surrogateescape allows convert arbitrary
 # bytes to unicode and back again.
 # See http://python.org/dev/peps/pep-0383/
 if not PY2 and isinstance(s, bytes):
 return s.decode('ascii', 'surrogateescape')
 return s
 
 def begin(self):
 """Explicitly begin a connection. Non-standard.
 DEPRECATED: Will be removed in 1.3.
 Use an SQL BEGIN statement instead."""
 from warnings import warn
 warn("begin() is non-standard and will be removed in 1.3",
 DeprecationWarning, 2)
 self.query("BEGIN")
 
 if not hasattr(_mysql.connection, 'warning_count'):
 
 def warning_count(self):
 """Return the number of warnings generated from the
 last query. This is derived from the info() method."""
 info = self.info()
 if info:
 return int(info.split()[-1])
 else:
 return 0
 
 def set_character_set(self, charset):
 """Set the connection character set to charset. The character
 set can only be changed in MySQL-4.1 and newer. If you try
 to change the character set from the current value in an
 older version, NotSupportedError will be raised."""
 if charset == "utf8mb4":
 py_charset = "utf8"
 else:
 py_charset = charset
 if self.character_set_name() != charset:
 try:
 super(Connection, self).set_character_set(charset)
 except AttributeError:
 if self._server_version < (4, 1):
 raise NotSupportedError("server is too old to set charset")
 self.query('SET NAMES %s' % charset)
 self.store_result()
 self.string_decoder.charset = py_charset
 self.unicode_literal.charset = py_charset
 
 def set_sql_mode(self, sql_mode):
 """Set the connection sql_mode. See MySQL documentation for
 legal values."""
 if self._server_version < (4, 1):
 raise NotSupportedError("server is too old to set sql_mode")
 self.query("SET SESSION sql_mode='%s'" % sql_mode)
 self.store_result()
 
 def show_warnings(self):
 """Return detailed information about warnings as a
 sequence of tuples of (Level, Code, Message). This
 is only supported in MySQL-4.1 and up. If your server
 is an earlier version, an empty sequence is returned."""
 if self._server_version < (4,1): return ()
 self.query("SHOW WARNINGS")
 r = self.store_result()
 warnings = r.fetch_row(0)
 return warnings
 
 Warning = Warning
 Error = Error
 InterfaceError = InterfaceError
 DatabaseError = DatabaseError
 DataError = DataError
 OperationalError = OperationalError
 IntegrityError = IntegrityError
 InternalError = InternalError
 ProgrammingError = ProgrammingError
 NotSupportedError = NotSupportedError
 
 errorhandler = defaulterrorhandler
 
 |