mirror of
https://github.com/PyMySQL/mysqlclient.git
synced 2025-08-16 20:33:57 +08:00

Raise IntegrityError for a couple types of relatively new errors. (Bug 1327679) Add BIT column support. (Bug 1468725) Return BINARY columns as normal strings, not arrays. (Bug 1495765) Add support for a new VARCHAR type; behaves like other CHAR types. Defer issuing warnings when using SSCursors. (Bug 1495782) Do not try to encode query strings unless they are unicode instances. (Bug 1521274) Fix problem with callproc() when it is used before execute() (which is legal). (Bug 1541124) Fix formatting of datetime.timedelta values. (Bug 1527801) Fix connect_timeout documentation bug. (Bug 1523883)
303 lines
10 KiB
Python
303 lines
10 KiB
Python
"""
|
|
|
|
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.
|
|
|
|
"""
|
|
import cursors
|
|
from _mysql_exceptions import Warning, Error, InterfaceError, DataError, \
|
|
DatabaseError, OperationalError, IntegrityError, InternalError, \
|
|
NotSupportedError, ProgrammingError
|
|
import types, _mysql
|
|
|
|
|
|
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
|
|
raise errorclass, errorvalue
|
|
|
|
|
|
class Connection(_mysql.connection):
|
|
|
|
"""MySQL Database Connection Object"""
|
|
|
|
default_cursor = cursors.Cursor
|
|
|
|
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.
|
|
|
|
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
|
|
|
|
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 constants import CLIENT, FIELD_TYPE
|
|
from converters import conversions
|
|
from weakref import proxy, WeakValueDictionary
|
|
|
|
import types
|
|
|
|
kwargs2 = kwargs.copy()
|
|
|
|
if kwargs.has_key('conv'):
|
|
conv = kwargs['conv']
|
|
else:
|
|
conv = conversions
|
|
|
|
kwargs2['conv'] = dict([ (k, v) for k, v in conv.items()
|
|
if type(k) is int ])
|
|
|
|
self.cursorclass = kwargs2.pop('cursorclass', self.default_cursor)
|
|
charset = kwargs2.pop('charset', '')
|
|
|
|
if charset:
|
|
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([ int(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
|
|
|
|
super(Connection, self).__init__(*args, **kwargs2)
|
|
|
|
self.encoders = dict([ (k, v) for k, v in conv.items()
|
|
if type(k) is not int ])
|
|
|
|
self._server_version = tuple([ int(n) for n in self.get_server_info().split('.')[:2] ])
|
|
|
|
db = proxy(self)
|
|
def _get_string_literal():
|
|
def string_literal(obj, dummy=None):
|
|
return db.string_literal(obj)
|
|
return string_literal
|
|
|
|
def _get_unicode_literal():
|
|
def unicode_literal(u, dummy=None):
|
|
return db.literal(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[types.StringType] = string_literal
|
|
self.encoders[types.UnicodeType] = unicode_literal
|
|
self._transactional = self.server_capabilities & CLIENT.TRANSACTIONS
|
|
if self._transactional:
|
|
# PEP-249 requires autocommit to be initially off
|
|
self.autocommit(False)
|
|
self.messages = []
|
|
|
|
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 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.
|
|
|
|
"""
|
|
return self.escape(o, self.encoders)
|
|
|
|
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."""
|
|
from string import atoi
|
|
info = self.info()
|
|
if info:
|
|
return atoi(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 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 = charset
|
|
self.unicode_literal.charset = 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
|