summaryrefslogtreecommitdiff
path: root/MySQLdb
diff options
context:
space:
mode:
authorAndy Dustman <farcepest@gmail.com>2012-09-25 21:08:56 -0400
committerfarcepest <farcepest@gmail.com>2012-09-25 21:08:56 -0400
commitcdc221a8078382f3a0d97b8b43b155a4f6246297 (patch)
tree3770d54a384913aa5fb0d236c2b8aad7c6b0cc50 /MySQLdb
parentc16bc33f16da156ef8daddcc54039a55bc816843 (diff)
downloadmysqldb1-cdc221a8078382f3a0d97b8b43b155a4f6246297.tar.gz
Hopefully this is just a very minor spacing cleanup.
Diffstat (limited to 'MySQLdb')
-rw-r--r--MySQLdb/.cvsignore6
-rw-r--r--MySQLdb/HISTORY232
-rw-r--r--MySQLdb/MANIFEST.in28
-rw-r--r--MySQLdb/MySQLdb/.cvsignore1
-rw-r--r--MySQLdb/MySQLdb/__init__.py196
-rw-r--r--MySQLdb/MySQLdb/connections.py666
-rw-r--r--MySQLdb/MySQLdb/constants/.cvsignore2
-rw-r--r--MySQLdb/MySQLdb/constants/CLIENT.py58
-rw-r--r--MySQLdb/MySQLdb/constants/CR.py60
-rw-r--r--MySQLdb/MySQLdb/constants/ER.py934
-rw-r--r--MySQLdb/MySQLdb/constants/FIELD_TYPE.py74
-rw-r--r--MySQLdb/MySQLdb/constants/FLAG.py46
-rw-r--r--MySQLdb/MySQLdb/constants/REFRESH.py34
-rw-r--r--MySQLdb/MySQLdb/constants/__init__.py2
-rw-r--r--MySQLdb/MySQLdb/converters.py362
-rw-r--r--MySQLdb/MySQLdb/cursors.py1020
-rw-r--r--MySQLdb/MySQLdb/times.py202
-rw-r--r--MySQLdb/README506
-rw-r--r--MySQLdb/_mysql.c6158
-rw-r--r--MySQLdb/_mysql_exceptions.py174
-rw-r--r--MySQLdb/distribute_setup.py1030
-rw-r--r--MySQLdb/doc/.cvsignore2
-rw-r--r--MySQLdb/doc/FAQ.txt286
-rw-r--r--MySQLdb/doc/MySQLdb.txt1436
-rw-r--r--MySQLdb/ez_setup.py568
-rw-r--r--MySQLdb/metadata.cfg120
-rw-r--r--MySQLdb/pymemcompat.h174
-rw-r--r--MySQLdb/setup.cfg40
-rw-r--r--MySQLdb/setup.py42
-rw-r--r--MySQLdb/setup_common.py74
-rw-r--r--MySQLdb/setup_posix.py204
-rw-r--r--MySQLdb/setup_windows.py92
-rw-r--r--MySQLdb/site.cfg32
-rw-r--r--MySQLdb/tests/capabilities.py560
-rw-r--r--MySQLdb/tests/dbapi20.py1706
-rw-r--r--MySQLdb/tests/test_MySQLdb_capabilities.py206
-rw-r--r--MySQLdb/tests/test_MySQLdb_dbapi20.py410
-rw-r--r--MySQLdb/tests/test_MySQLdb_nonstandard.py170
38 files changed, 8952 insertions, 8961 deletions
diff --git a/MySQLdb/.cvsignore b/MySQLdb/.cvsignore
deleted file mode 100644
index d562f69..0000000
--- a/MySQLdb/.cvsignore
+++ /dev/null
@@ -1,6 +0,0 @@
-dist
-build
-regress.py
-test.py
-PKG-INFO
-*.pyc
diff --git a/MySQLdb/HISTORY b/MySQLdb/HISTORY
index 4ca7e5a..1b899c3 100644
--- a/MySQLdb/HISTORY
+++ b/MySQLdb/HISTORY
@@ -1,116 +1,116 @@
-=====================
- What's new in 1.2.3
-=====================
-
-ez_setup.py has been update to include various fixes that affect the build.
-
-Better Python version and dependency detection as well as eliminate exception
-warnings under Python 2.6.
-
-Eliminated memory leaks related to Unicode and failed connections.
-
-Corrected connection .escape() functionality.
-
-Miscellaneous cleanups and and expanded testing suite to ensure ongoing release
-quality.
-
-=====================
- What's new in 1.2.2
-=====================
-
-The build system has been completely redone and should now build
-on Windows without any patching; uses setuptools.
-
-Added compatibility for Python 2.5, including support for with statement.
-
-connection.ping() now takes an optional boolean argument which can
-enable (or disable) automatic reconnection.
-
-Support returning SET columns as Python sets was removed due to an
-API bug in MySQL; corresponding test removed.
-
-Added a test for single-character CHAR columns.
-
-BLOB columns are now returned as Python strings instead of byte arrays.
-
-BINARY character columns are always returned as Python strings, and not
-unicode.
-
-Fixed a bug introduced in 1.2.1 where the new SHOW WARNINGS support broke
-SSCursor.
-
-Only encode the query (convert to a string) when it is a unicode instance;
-re-encoding encoded strings would break things.
-
-Make a deep copy of conv when connecting, since it can be modified.
-
-Added support for new VARCHAR and BIT column types.
-
-DBAPISet objects were broken, but nobody noticed.
-
-
-========================
- What's new in 1.2.1_p2
-========================
-
-There are some minor build fixes which probably only affect MySQL
-older than 4.0.
-
-If you had MySQL older than 4.1, the new charset and sql_mode
-parameters didn't work right. In fact, it was impossible to create
-a connection due to the charset problem.
-
-If you are using MySQL-4.1 or newer, there is no practical difference
-between 1.2.1 and 1.2.1_p2, and you don't need to upgrade.
-
-
-=====================
- What's new in 1.2.1
-=====================
-
-Switched to Subversion. Was going to do this for 1.3, but a
-SourceForge CVS outage has forced the issue.
-
-Mapped a lot of new 4.1 and 5.0 error codes to Python exceptions
-
-Added an API call for mysql_set_character_set(charset) (MySQL > 5.0.7)
-
-Added an API call for mysql_get_character_set_info() (MySQL > 5.0.10)
-
-Revamped the build system. Edit site.cfg if necessary (probably not
-in most cases)
-
-Python-2.3 is now the minimum version.
-
-Dropped support for mx.Datetime and stringtimes; always uses Python
-datetime module now.
-
-Improved unit tests
-
-New connect() options:
-* charset: sets character set, implies use_unicode
-* sql_mode: sets SQL mode (i.e. ANSI, etc.; see MySQL docs)
-
-When using MySQL-4.1 or newer, enables MULTI_STATEMENTS
-
-When using MySQL-5.0 or newer, enables MULTI_RESULTS
-
-When using MySQL-4.1 or newer, more detailed warning messages
-are produced
-
-SET columns returned as Python Set types; you can pass a Set as
-a parameter to cursor.execute().
-
-Support for the new MySQL-5.0 DECIMAL implementation
-
-Support for Python Decimal type
-
-Some use of weak references internally. Cursors no longer leak
-if you don't close them. Connections still do, unfortunately.
-
-ursor.fetchXXXDict() methods raise DeprecationWarning
-
-cursor.begin() is making a brief reappearence.
-
-cursor.callproc() now works, with some limitations.
-
+=====================
+ What's new in 1.2.3
+=====================
+
+ez_setup.py has been update to include various fixes that affect the build.
+
+Better Python version and dependency detection as well as eliminate exception
+warnings under Python 2.6.
+
+Eliminated memory leaks related to Unicode and failed connections.
+
+Corrected connection .escape() functionality.
+
+Miscellaneous cleanups and and expanded testing suite to ensure ongoing release
+quality.
+
+=====================
+ What's new in 1.2.2
+=====================
+
+The build system has been completely redone and should now build
+on Windows without any patching; uses setuptools.
+
+Added compatibility for Python 2.5, including support for with statement.
+
+connection.ping() now takes an optional boolean argument which can
+enable (or disable) automatic reconnection.
+
+Support returning SET columns as Python sets was removed due to an
+API bug in MySQL; corresponding test removed.
+
+Added a test for single-character CHAR columns.
+
+BLOB columns are now returned as Python strings instead of byte arrays.
+
+BINARY character columns are always returned as Python strings, and not
+unicode.
+
+Fixed a bug introduced in 1.2.1 where the new SHOW WARNINGS support broke
+SSCursor.
+
+Only encode the query (convert to a string) when it is a unicode instance;
+re-encoding encoded strings would break things.
+
+Make a deep copy of conv when connecting, since it can be modified.
+
+Added support for new VARCHAR and BIT column types.
+
+DBAPISet objects were broken, but nobody noticed.
+
+
+========================
+ What's new in 1.2.1_p2
+========================
+
+There are some minor build fixes which probably only affect MySQL
+older than 4.0.
+
+If you had MySQL older than 4.1, the new charset and sql_mode
+parameters didn't work right. In fact, it was impossible to create
+a connection due to the charset problem.
+
+If you are using MySQL-4.1 or newer, there is no practical difference
+between 1.2.1 and 1.2.1_p2, and you don't need to upgrade.
+
+
+=====================
+ What's new in 1.2.1
+=====================
+
+Switched to Subversion. Was going to do this for 1.3, but a
+SourceForge CVS outage has forced the issue.
+
+Mapped a lot of new 4.1 and 5.0 error codes to Python exceptions
+
+Added an API call for mysql_set_character_set(charset) (MySQL > 5.0.7)
+
+Added an API call for mysql_get_character_set_info() (MySQL > 5.0.10)
+
+Revamped the build system. Edit site.cfg if necessary (probably not
+in most cases)
+
+Python-2.3 is now the minimum version.
+
+Dropped support for mx.Datetime and stringtimes; always uses Python
+datetime module now.
+
+Improved unit tests
+
+New connect() options:
+* charset: sets character set, implies use_unicode
+* sql_mode: sets SQL mode (i.e. ANSI, etc.; see MySQL docs)
+
+When using MySQL-4.1 or newer, enables MULTI_STATEMENTS
+
+When using MySQL-5.0 or newer, enables MULTI_RESULTS
+
+When using MySQL-4.1 or newer, more detailed warning messages
+are produced
+
+SET columns returned as Python Set types; you can pass a Set as
+a parameter to cursor.execute().
+
+Support for the new MySQL-5.0 DECIMAL implementation
+
+Support for Python Decimal type
+
+Some use of weak references internally. Cursors no longer leak
+if you don't close them. Connections still do, unfortunately.
+
+ursor.fetchXXXDict() methods raise DeprecationWarning
+
+cursor.begin() is making a brief reappearence.
+
+cursor.callproc() now works, with some limitations.
+
diff --git a/MySQLdb/MANIFEST.in b/MySQLdb/MANIFEST.in
index 24165bc..a4df31e 100644
--- a/MySQLdb/MANIFEST.in
+++ b/MySQLdb/MANIFEST.in
@@ -1,14 +1,14 @@
-recursive-include doc *.txt
-recursive-include tests *.py
-include MANIFEST.in
-include MANIFEST
-include ChangeLog
-include HISTORY
-include GPL
-include pymemcompat.h
-include metadata.cfg
-include site.cfg
-include distribute_setup.py
-include setup_common.py
-include setup_posix.py
-include setup_windows.py
+recursive-include doc *.txt
+recursive-include tests *.py
+include MANIFEST.in
+include MANIFEST
+include ChangeLog
+include HISTORY
+include GPL
+include pymemcompat.h
+include metadata.cfg
+include site.cfg
+include distribute_setup.py
+include setup_common.py
+include setup_posix.py
+include setup_windows.py
diff --git a/MySQLdb/MySQLdb/.cvsignore b/MySQLdb/MySQLdb/.cvsignore
deleted file mode 100644
index 0d20b64..0000000
--- a/MySQLdb/MySQLdb/.cvsignore
+++ /dev/null
@@ -1 +0,0 @@
-*.pyc
diff --git a/MySQLdb/MySQLdb/__init__.py b/MySQLdb/MySQLdb/__init__.py
index 8761671..dc18e87 100644
--- a/MySQLdb/MySQLdb/__init__.py
+++ b/MySQLdb/MySQLdb/__init__.py
@@ -1,98 +1,98 @@
-"""MySQLdb - A DB API v2.0 compatible interface to MySQL.
-
-This package is a wrapper around _mysql, which mostly implements the
-MySQL C API.
-
-connect() -- connects to server
-
-See the C API specification and the MySQL documentation for more info
-on other items.
-
-For information on how MySQLdb handles type conversion, see the
-MySQLdb.converters module.
-
-"""
-
-__revision__ = """$Revision$"""[11:-2]
-from MySQLdb.release import __version__, version_info, __author__
-
-import _mysql
-
-if version_info != _mysql.version_info:
- raise ImportError("this is MySQLdb version %s, but _mysql is version %r" %
- (version_info, _mysql.version_info))
-
-threadsafety = 1
-apilevel = "2.0"
-paramstyle = "format"
-
-from _mysql import *
-from MySQLdb.constants import FIELD_TYPE
-from MySQLdb.times import Date, Time, Timestamp, \
- DateFromTicks, TimeFromTicks, TimestampFromTicks
-
-try:
- frozenset
-except NameError:
- from sets import ImmutableSet as frozenset
-
-class DBAPISet(frozenset):
-
- """A special type of set for which A == x is true if A is a
- DBAPISet and x is a member of that set."""
-
- def __eq__(self, other):
- if isinstance(other, DBAPISet):
- return not self.difference(other)
- return other in self
-
-
-STRING = DBAPISet([FIELD_TYPE.ENUM, FIELD_TYPE.STRING,
- FIELD_TYPE.VAR_STRING])
-BINARY = DBAPISet([FIELD_TYPE.BLOB, FIELD_TYPE.LONG_BLOB,
- FIELD_TYPE.MEDIUM_BLOB, FIELD_TYPE.TINY_BLOB])
-NUMBER = DBAPISet([FIELD_TYPE.DECIMAL, FIELD_TYPE.DOUBLE, FIELD_TYPE.FLOAT,
- FIELD_TYPE.INT24, FIELD_TYPE.LONG, FIELD_TYPE.LONGLONG,
- FIELD_TYPE.TINY, FIELD_TYPE.YEAR])
-DATE = DBAPISet([FIELD_TYPE.DATE, FIELD_TYPE.NEWDATE])
-TIME = DBAPISet([FIELD_TYPE.TIME])
-TIMESTAMP = DBAPISet([FIELD_TYPE.TIMESTAMP, FIELD_TYPE.DATETIME])
-DATETIME = TIMESTAMP
-ROWID = DBAPISet()
-
-def test_DBAPISet_set_equality():
- assert STRING == STRING
-
-def test_DBAPISet_set_inequality():
- assert STRING != NUMBER
-
-def test_DBAPISet_set_equality_membership():
- assert FIELD_TYPE.VAR_STRING == STRING
-
-def test_DBAPISet_set_inequality_membership():
- assert FIELD_TYPE.DATE != STRING
-
-def Binary(x):
- return str(x)
-
-def Connect(*args, **kwargs):
- """Factory function for connections.Connection."""
- from MySQLdb.connections import Connection
- return Connection(*args, **kwargs)
-
-connect = Connection = Connect
-
-__all__ = [ 'BINARY', 'Binary', 'Connect', 'Connection', 'DATE',
- 'Date', 'Time', 'Timestamp', 'DateFromTicks', 'TimeFromTicks',
- 'TimestampFromTicks', 'DataError', 'DatabaseError', 'Error',
- 'FIELD_TYPE', 'IntegrityError', 'InterfaceError', 'InternalError',
- 'MySQLError', 'NULL', 'NUMBER', 'NotSupportedError', 'DBAPISet',
- 'OperationalError', 'ProgrammingError', 'ROWID', 'STRING', 'TIME',
- 'TIMESTAMP', 'Warning', 'apilevel', 'connect', 'connections',
- 'constants', 'converters', 'cursors', 'debug', 'escape', 'escape_dict',
- 'escape_sequence', 'escape_string', 'get_client_info',
- 'paramstyle', 'string_literal', 'threadsafety', 'version_info']
-
-
-
-
+"""MySQLdb - A DB API v2.0 compatible interface to MySQL.
+
+This package is a wrapper around _mysql, which mostly implements the
+MySQL C API.
+
+connect() -- connects to server
+
+See the C API specification and the MySQL documentation for more info
+on other items.
+
+For information on how MySQLdb handles type conversion, see the
+MySQLdb.converters module.
+
+"""
+
+__revision__ = """$Revision$"""[11:-2]
+from MySQLdb.release import __version__, version_info, __author__
+
+import _mysql
+
+if version_info != _mysql.version_info:
+ raise ImportError("this is MySQLdb version %s, but _mysql is version %r" %
+ (version_info, _mysql.version_info))
+
+threadsafety = 1
+apilevel = "2.0"
+paramstyle = "format"
+
+from _mysql import *
+from MySQLdb.constants import FIELD_TYPE
+from MySQLdb.times import Date, Time, Timestamp, \
+ DateFromTicks, TimeFromTicks, TimestampFromTicks
+
+try:
+ frozenset
+except NameError:
+ from sets import ImmutableSet as frozenset
+
+class DBAPISet(frozenset):
+
+ """A special type of set for which A == x is true if A is a
+ DBAPISet and x is a member of that set."""
+
+ def __eq__(self, other):
+ if isinstance(other, DBAPISet):
+ return not self.difference(other)
+ return other in self
+
+
+STRING = DBAPISet([FIELD_TYPE.ENUM, FIELD_TYPE.STRING,
+ FIELD_TYPE.VAR_STRING])
+BINARY = DBAPISet([FIELD_TYPE.BLOB, FIELD_TYPE.LONG_BLOB,
+ FIELD_TYPE.MEDIUM_BLOB, FIELD_TYPE.TINY_BLOB])
+NUMBER = DBAPISet([FIELD_TYPE.DECIMAL, FIELD_TYPE.DOUBLE, FIELD_TYPE.FLOAT,
+ FIELD_TYPE.INT24, FIELD_TYPE.LONG, FIELD_TYPE.LONGLONG,
+ FIELD_TYPE.TINY, FIELD_TYPE.YEAR])
+DATE = DBAPISet([FIELD_TYPE.DATE, FIELD_TYPE.NEWDATE])
+TIME = DBAPISet([FIELD_TYPE.TIME])
+TIMESTAMP = DBAPISet([FIELD_TYPE.TIMESTAMP, FIELD_TYPE.DATETIME])
+DATETIME = TIMESTAMP
+ROWID = DBAPISet()
+
+def test_DBAPISet_set_equality():
+ assert STRING == STRING
+
+def test_DBAPISet_set_inequality():
+ assert STRING != NUMBER
+
+def test_DBAPISet_set_equality_membership():
+ assert FIELD_TYPE.VAR_STRING == STRING
+
+def test_DBAPISet_set_inequality_membership():
+ assert FIELD_TYPE.DATE != STRING
+
+def Binary(x):
+ return str(x)
+
+def Connect(*args, **kwargs):
+ """Factory function for connections.Connection."""
+ from MySQLdb.connections import Connection
+ return Connection(*args, **kwargs)
+
+connect = Connection = Connect
+
+__all__ = [ 'BINARY', 'Binary', 'Connect', 'Connection', 'DATE',
+ 'Date', 'Time', 'Timestamp', 'DateFromTicks', 'TimeFromTicks',
+ 'TimestampFromTicks', 'DataError', 'DatabaseError', 'Error',
+ 'FIELD_TYPE', 'IntegrityError', 'InterfaceError', 'InternalError',
+ 'MySQLError', 'NULL', 'NUMBER', 'NotSupportedError', 'DBAPISet',
+ 'OperationalError', 'ProgrammingError', 'ROWID', 'STRING', 'TIME',
+ 'TIMESTAMP', 'Warning', 'apilevel', 'connect', 'connections',
+ 'constants', 'converters', 'cursors', 'debug', 'escape', 'escape_dict',
+ 'escape_sequence', 'escape_string', 'get_client_info',
+ 'paramstyle', 'string_literal', 'threadsafety', 'version_info']
+
+
+
+
diff --git a/MySQLdb/MySQLdb/connections.py b/MySQLdb/MySQLdb/connections.py
index d281cbd..e567227 100644
--- a/MySQLdb/MySQLdb/connections.py
+++ b/MySQLdb/MySQLdb/connections.py
@@ -1,333 +1,333 @@
-"""
-
-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 _mysql_exceptions import Warning, Error, InterfaceError, DataError, \
- DatabaseError, OperationalError, IntegrityError, InternalError, \
- NotSupportedError, ProgrammingError
-import types, _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
- raise errorclass(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
-
- 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 MySQLdb.constants import CLIENT, FIELD_TYPE
- from MySQLdb.converters import conversions
- from weakref import proxy, WeakValueDictionary
-
- import types
-
- 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:
- 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
-
- 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():
- 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 __enter__(self): 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.
-
- """
- 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
+"""
+
+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 _mysql_exceptions import Warning, Error, InterfaceError, DataError, \
+ DatabaseError, OperationalError, IntegrityError, InternalError, \
+ NotSupportedError, ProgrammingError
+import types, _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
+ raise errorclass(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
+
+ 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 MySQLdb.constants import CLIENT, FIELD_TYPE
+ from MySQLdb.converters import conversions
+ from weakref import proxy, WeakValueDictionary
+
+ import types
+
+ 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:
+ 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
+
+ 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():
+ 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 __enter__(self): 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.
+
+ """
+ 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
diff --git a/MySQLdb/MySQLdb/constants/.cvsignore b/MySQLdb/MySQLdb/constants/.cvsignore
index 0d20b64..94487b9 100644
--- a/MySQLdb/MySQLdb/constants/.cvsignore
+++ b/MySQLdb/MySQLdb/constants/.cvsignore
@@ -1 +1 @@
-*.pyc
+*.pyc
diff --git a/MySQLdb/MySQLdb/constants/CLIENT.py b/MySQLdb/MySQLdb/constants/CLIENT.py
index 6559917..22b1317 100644
--- a/MySQLdb/MySQLdb/constants/CLIENT.py
+++ b/MySQLdb/MySQLdb/constants/CLIENT.py
@@ -1,29 +1,29 @@
-"""MySQL CLIENT constants
-
-These constants are used when creating the connection. Use bitwise-OR
-(|) to combine options together, and pass them as the client_flags
-parameter to MySQLdb.Connection. For more information on these flags,
-see the MySQL C API documentation for mysql_real_connect().
-
-"""
-
-LONG_PASSWORD = 1
-FOUND_ROWS = 2
-LONG_FLAG = 4
-CONNECT_WITH_DB = 8
-NO_SCHEMA = 16
-COMPRESS = 32
-ODBC = 64
-LOCAL_FILES = 128
-IGNORE_SPACE = 256
-CHANGE_USER = 512
-INTERACTIVE = 1024
-SSL = 2048
-IGNORE_SIGPIPE = 4096
-TRANSACTIONS = 8192 # mysql_com.h was WRONG prior to 3.23.35
-RESERVED = 16384
-SECURE_CONNECTION = 32768
-MULTI_STATEMENTS = 65536
-MULTI_RESULTS = 131072
-
-
+"""MySQL CLIENT constants
+
+These constants are used when creating the connection. Use bitwise-OR
+(|) to combine options together, and pass them as the client_flags
+parameter to MySQLdb.Connection. For more information on these flags,
+see the MySQL C API documentation for mysql_real_connect().
+
+"""
+
+LONG_PASSWORD = 1
+FOUND_ROWS = 2
+LONG_FLAG = 4
+CONNECT_WITH_DB = 8
+NO_SCHEMA = 16
+COMPRESS = 32
+ODBC = 64
+LOCAL_FILES = 128
+IGNORE_SPACE = 256
+CHANGE_USER = 512
+INTERACTIVE = 1024
+SSL = 2048
+IGNORE_SIGPIPE = 4096
+TRANSACTIONS = 8192 # mysql_com.h was WRONG prior to 3.23.35
+RESERVED = 16384
+SECURE_CONNECTION = 32768
+MULTI_STATEMENTS = 65536
+MULTI_RESULTS = 131072
+
+
diff --git a/MySQLdb/MySQLdb/constants/CR.py b/MySQLdb/MySQLdb/constants/CR.py
index 249dfec..2d48733 100644
--- a/MySQLdb/MySQLdb/constants/CR.py
+++ b/MySQLdb/MySQLdb/constants/CR.py
@@ -1,30 +1,30 @@
-"""MySQL Connection Errors
-
-Nearly all of these raise OperationalError. COMMANDS_OUT_OF_SYNC
-raises ProgrammingError.
-
-"""
-
-MIN_ERROR = 2000
-MAX_ERROR = 2999
-UNKNOWN_ERROR = 2000
-SOCKET_CREATE_ERROR = 2001
-CONNECTION_ERROR = 2002
-CONN_HOST_ERROR = 2003
-IPSOCK_ERROR = 2004
-UNKNOWN_HOST = 2005
-SERVER_GONE_ERROR = 2006
-VERSION_ERROR = 2007
-OUT_OF_MEMORY = 2008
-WRONG_HOST_INFO = 2009
-LOCALHOST_CONNECTION = 2010
-TCP_CONNECTION = 2011
-SERVER_HANDSHAKE_ERR = 2012
-SERVER_LOST = 2013
-COMMANDS_OUT_OF_SYNC = 2014
-NAMEDPIPE_CONNECTION = 2015
-NAMEDPIPEWAIT_ERROR = 2016
-NAMEDPIPEOPEN_ERROR = 2017
-NAMEDPIPESETSTATE_ERROR = 2018
-CANT_READ_CHARSET = 2019
-NET_PACKET_TOO_LARGE = 2020
+"""MySQL Connection Errors
+
+Nearly all of these raise OperationalError. COMMANDS_OUT_OF_SYNC
+raises ProgrammingError.
+
+"""
+
+MIN_ERROR = 2000
+MAX_ERROR = 2999
+UNKNOWN_ERROR = 2000
+SOCKET_CREATE_ERROR = 2001
+CONNECTION_ERROR = 2002
+CONN_HOST_ERROR = 2003
+IPSOCK_ERROR = 2004
+UNKNOWN_HOST = 2005
+SERVER_GONE_ERROR = 2006
+VERSION_ERROR = 2007
+OUT_OF_MEMORY = 2008
+WRONG_HOST_INFO = 2009
+LOCALHOST_CONNECTION = 2010
+TCP_CONNECTION = 2011
+SERVER_HANDSHAKE_ERR = 2012
+SERVER_LOST = 2013
+COMMANDS_OUT_OF_SYNC = 2014
+NAMEDPIPE_CONNECTION = 2015
+NAMEDPIPEWAIT_ERROR = 2016
+NAMEDPIPEOPEN_ERROR = 2017
+NAMEDPIPESETSTATE_ERROR = 2018
+CANT_READ_CHARSET = 2019
+NET_PACKET_TOO_LARGE = 2020
diff --git a/MySQLdb/MySQLdb/constants/ER.py b/MySQLdb/MySQLdb/constants/ER.py
index ed45f3a..0756e1c 100644
--- a/MySQLdb/MySQLdb/constants/ER.py
+++ b/MySQLdb/MySQLdb/constants/ER.py
@@ -1,467 +1,467 @@
-"""MySQL ER Constants
-
-These constants are error codes for the bulk of the error conditions
-that may occur.
-
-"""
-
-HASHCHK = 1000
-NISAMCHK = 1001
-NO = 1002
-YES = 1003
-CANT_CREATE_FILE = 1004
-CANT_CREATE_TABLE = 1005
-CANT_CREATE_DB = 1006
-DB_CREATE_EXISTS = 1007
-DB_DROP_EXISTS = 1008
-DB_DROP_DELETE = 1009
-DB_DROP_RMDIR = 1010
-CANT_DELETE_FILE = 1011
-CANT_FIND_SYSTEM_REC = 1012
-CANT_GET_STAT = 1013
-CANT_GET_WD = 1014
-CANT_LOCK = 1015
-CANT_OPEN_FILE = 1016
-FILE_NOT_FOUND = 1017
-CANT_READ_DIR = 1018
-CANT_SET_WD = 1019
-CHECKREAD = 1020
-DISK_FULL = 1021
-DUP_KEY = 1022
-ERROR_ON_CLOSE = 1023
-ERROR_ON_READ = 1024
-ERROR_ON_RENAME = 1025
-ERROR_ON_WRITE = 1026
-FILE_USED = 1027
-FILSORT_ABORT = 1028
-FORM_NOT_FOUND = 1029
-GET_ERRNO = 1030
-ILLEGAL_HA = 1031
-KEY_NOT_FOUND = 1032
-NOT_FORM_FILE = 1033
-NOT_KEYFILE = 1034
-OLD_KEYFILE = 1035
-OPEN_AS_READONLY = 1036
-OUTOFMEMORY = 1037
-OUT_OF_SORTMEMORY = 1038
-UNEXPECTED_EOF = 1039
-CON_COUNT_ERROR = 1040
-OUT_OF_RESOURCES = 1041
-BAD_HOST_ERROR = 1042
-HANDSHAKE_ERROR = 1043
-DBACCESS_DENIED_ERROR = 1044
-ACCESS_DENIED_ERROR = 1045
-NO_DB_ERROR = 1046
-UNKNOWN_COM_ERROR = 1047
-BAD_NULL_ERROR = 1048
-BAD_DB_ERROR = 1049
-TABLE_EXISTS_ERROR = 1050
-BAD_TABLE_ERROR = 1051
-NON_UNIQ_ERROR = 1052
-SERVER_SHUTDOWN = 1053
-BAD_FIELD_ERROR = 1054
-WRONG_FIELD_WITH_GROUP = 1055
-WRONG_GROUP_FIELD = 1056
-WRONG_SUM_SELECT = 1057
-WRONG_VALUE_COUNT = 1058
-TOO_LONG_IDENT = 1059
-DUP_FIELDNAME = 1060
-DUP_KEYNAME = 1061
-DUP_ENTRY = 1062
-WRONG_FIELD_SPEC = 1063
-PARSE_ERROR = 1064
-EMPTY_QUERY = 1065
-NONUNIQ_TABLE = 1066
-INVALID_DEFAULT = 1067
-MULTIPLE_PRI_KEY = 1068
-TOO_MANY_KEYS = 1069
-TOO_MANY_KEY_PARTS = 1070
-TOO_LONG_KEY = 1071
-KEY_COLUMN_DOES_NOT_EXITS = 1072
-BLOB_USED_AS_KEY = 1073
-TOO_BIG_FIELDLENGTH = 1074
-WRONG_AUTO_KEY = 1075
-READY = 1076
-NORMAL_SHUTDOWN = 1077
-GOT_SIGNAL = 1078
-SHUTDOWN_COMPLETE = 1079
-FORCING_CLOSE = 1080
-IPSOCK_ERROR = 1081
-NO_SUCH_INDEX = 1082
-WRONG_FIELD_TERMINATORS = 1083
-BLOBS_AND_NO_TERMINATED = 1084
-TEXTFILE_NOT_READABLE = 1085
-FILE_EXISTS_ERROR = 1086
-LOAD_INFO = 1087
-ALTER_INFO = 1088
-WRONG_SUB_KEY = 1089
-CANT_REMOVE_ALL_FIELDS = 1090
-CANT_DROP_FIELD_OR_KEY = 1091
-INSERT_INFO = 1092
-INSERT_TABLE_USED = 1093
-NO_SUCH_THREAD = 1094
-KILL_DENIED_ERROR = 1095
-NO_TABLES_USED = 1096
-TOO_BIG_SET = 1097
-NO_UNIQUE_LOGFILE = 1098
-TABLE_NOT_LOCKED_FOR_WRITE = 1099
-TABLE_NOT_LOCKED = 1100
-BLOB_CANT_HAVE_DEFAULT = 1101
-WRONG_DB_NAME = 1102
-WRONG_TABLE_NAME = 1103
-TOO_BIG_SELECT = 1104
-UNKNOWN_ERROR = 1105
-UNKNOWN_PROCEDURE = 1106
-WRONG_PARAMCOUNT_TO_PROCEDURE = 1107
-WRONG_PARAMETERS_TO_PROCEDURE = 1108
-UNKNOWN_TABLE = 1109
-FIELD_SPECIFIED_TWICE = 1110
-INVALID_GROUP_FUNC_USE = 1111
-UNSUPPORTED_EXTENSION = 1112
-TABLE_MUST_HAVE_COLUMNS = 1113
-RECORD_FILE_FULL = 1114
-UNKNOWN_CHARACTER_SET = 1115
-TOO_MANY_TABLES = 1116
-TOO_MANY_FIELDS = 1117
-TOO_BIG_ROWSIZE = 1118
-STACK_OVERRUN = 1119
-WRONG_OUTER_JOIN = 1120
-NULL_COLUMN_IN_INDEX = 1121
-CANT_FIND_UDF = 1122
-CANT_INITIALIZE_UDF = 1123
-UDF_NO_PATHS = 1124
-UDF_EXISTS = 1125
-CANT_OPEN_LIBRARY = 1126
-CANT_FIND_DL_ENTRY = 1127
-FUNCTION_NOT_DEFINED = 1128
-HOST_IS_BLOCKED = 1129
-HOST_NOT_PRIVILEGED = 1130
-PASSWORD_ANONYMOUS_USER = 1131
-PASSWORD_NOT_ALLOWED = 1132
-PASSWORD_NO_MATCH = 1133
-UPDATE_INFO = 1134
-CANT_CREATE_THREAD = 1135
-WRONG_VALUE_COUNT_ON_ROW = 1136
-CANT_REOPEN_TABLE = 1137
-INVALID_USE_OF_NULL = 1138
-REGEXP_ERROR = 1139
-MIX_OF_GROUP_FUNC_AND_FIELDS = 1140
-NONEXISTING_GRANT = 1141
-TABLEACCESS_DENIED_ERROR = 1142
-COLUMNACCESS_DENIED_ERROR = 1143
-ILLEGAL_GRANT_FOR_TABLE = 1144
-GRANT_WRONG_HOST_OR_USER = 1145
-NO_SUCH_TABLE = 1146
-NONEXISTING_TABLE_GRANT = 1147
-NOT_ALLOWED_COMMAND = 1148
-SYNTAX_ERROR = 1149
-DELAYED_CANT_CHANGE_LOCK = 1150
-TOO_MANY_DELAYED_THREADS = 1151
-ABORTING_CONNECTION = 1152
-NET_PACKET_TOO_LARGE = 1153
-NET_READ_ERROR_FROM_PIPE = 1154
-NET_FCNTL_ERROR = 1155
-NET_PACKETS_OUT_OF_ORDER = 1156
-NET_UNCOMPRESS_ERROR = 1157
-NET_READ_ERROR = 1158
-NET_READ_INTERRUPTED = 1159
-NET_ERROR_ON_WRITE = 1160
-NET_WRITE_INTERRUPTED = 1161
-TOO_LONG_STRING = 1162
-TABLE_CANT_HANDLE_BLOB = 1163
-TABLE_CANT_HANDLE_AUTO_INCREMENT = 1164
-DELAYED_INSERT_TABLE_LOCKED = 1165
-WRONG_COLUMN_NAME = 1166
-WRONG_KEY_COLUMN = 1167
-WRONG_MRG_TABLE = 1168
-DUP_UNIQUE = 1169
-BLOB_KEY_WITHOUT_LENGTH = 1170
-PRIMARY_CANT_HAVE_NULL = 1171
-TOO_MANY_ROWS = 1172
-REQUIRES_PRIMARY_KEY = 1173
-NO_RAID_COMPILED = 1174
-UPDATE_WITHOUT_KEY_IN_SAFE_MODE = 1175
-KEY_DOES_NOT_EXITS = 1176
-CHECK_NO_SUCH_TABLE = 1177
-CHECK_NOT_IMPLEMENTED = 1178
-CANT_DO_THIS_DURING_AN_TRANSACTION = 1179
-ERROR_DURING_COMMIT = 1180
-ERROR_DURING_ROLLBACK = 1181
-ERROR_DURING_FLUSH_LOGS = 1182
-ERROR_DURING_CHECKPOINT = 1183
-NEW_ABORTING_CONNECTION = 1184
-DUMP_NOT_IMPLEMENTED = 1185
-FLUSH_MASTER_BINLOG_CLOSED = 1186
-INDEX_REBUILD = 1187
-MASTER = 1188
-MASTER_NET_READ = 1189
-MASTER_NET_WRITE = 1190
-FT_MATCHING_KEY_NOT_FOUND = 1191
-LOCK_OR_ACTIVE_TRANSACTION = 1192
-UNKNOWN_SYSTEM_VARIABLE = 1193
-CRASHED_ON_USAGE = 1194
-CRASHED_ON_REPAIR = 1195
-WARNING_NOT_COMPLETE_ROLLBACK = 1196
-TRANS_CACHE_FULL = 1197
-SLAVE_MUST_STOP = 1198
-SLAVE_NOT_RUNNING = 1199
-BAD_SLAVE = 1200
-MASTER_INFO = 1201
-SLAVE_THREAD = 1202
-TOO_MANY_USER_CONNECTIONS = 1203
-SET_CONSTANTS_ONLY = 1204
-LOCK_WAIT_TIMEOUT = 1205
-LOCK_TABLE_FULL = 1206
-READ_ONLY_TRANSACTION = 1207
-DROP_DB_WITH_READ_LOCK = 1208
-CREATE_DB_WITH_READ_LOCK = 1209
-WRONG_ARGUMENTS = 1210
-NO_PERMISSION_TO_CREATE_USER = 1211
-UNION_TABLES_IN_DIFFERENT_DIR = 1212
-LOCK_DEADLOCK = 1213
-TABLE_CANT_HANDLE_FT = 1214
-CANNOT_ADD_FOREIGN = 1215
-NO_REFERENCED_ROW = 1216
-ROW_IS_REFERENCED = 1217
-CONNECT_TO_MASTER = 1218
-QUERY_ON_MASTER = 1219
-ERROR_WHEN_EXECUTING_COMMAND = 1220
-WRONG_USAGE = 1221
-WRONG_NUMBER_OF_COLUMNS_IN_SELECT = 1222
-CANT_UPDATE_WITH_READLOCK = 1223
-MIXING_NOT_ALLOWED = 1224
-DUP_ARGUMENT = 1225
-USER_LIMIT_REACHED = 1226
-SPECIFIC_ACCESS_DENIED_ERROR = 1227
-LOCAL_VARIABLE = 1228
-GLOBAL_VARIABLE = 1229
-NO_DEFAULT = 1230
-WRONG_VALUE_FOR_VAR = 1231
-WRONG_TYPE_FOR_VAR = 1232
-VAR_CANT_BE_READ = 1233
-CANT_USE_OPTION_HERE = 1234
-NOT_SUPPORTED_YET = 1235
-MASTER_FATAL_ERROR_READING_BINLOG = 1236
-SLAVE_IGNORED_TABLE = 1237
-INCORRECT_GLOBAL_LOCAL_VAR = 1238
-WRONG_FK_DEF = 1239
-KEY_REF_DO_NOT_MATCH_TABLE_REF = 1240
-OPERAND_COLUMNS = 1241
-SUBQUERY_NO_1_ROW = 1242
-UNKNOWN_STMT_HANDLER = 1243
-CORRUPT_HELP_DB = 1244
-CYCLIC_REFERENCE = 1245
-AUTO_CONVERT = 1246
-ILLEGAL_REFERENCE = 1247
-DERIVED_MUST_HAVE_ALIAS = 1248
-SELECT_REDUCED = 1249
-TABLENAME_NOT_ALLOWED_HERE = 1250
-NOT_SUPPORTED_AUTH_MODE = 1251
-SPATIAL_CANT_HAVE_NULL = 1252
-COLLATION_CHARSET_MISMATCH = 1253
-SLAVE_WAS_RUNNING = 1254
-SLAVE_WAS_NOT_RUNNING = 1255
-TOO_BIG_FOR_UNCOMPRESS = 1256
-ZLIB_Z_MEM_ERROR = 1257
-ZLIB_Z_BUF_ERROR = 1258
-ZLIB_Z_DATA_ERROR = 1259
-CUT_VALUE_GROUP_CONCAT = 1260
-WARN_TOO_FEW_RECORDS = 1261
-WARN_TOO_MANY_RECORDS = 1262
-WARN_NULL_TO_NOTNULL = 1263
-WARN_DATA_OUT_OF_RANGE = 1264
-WARN_DATA_TRUNCATED = 1265
-WARN_USING_OTHER_HANDLER = 1266
-CANT_AGGREGATE_2COLLATIONS = 1267
-DROP_USER = 1268
-REVOKE_GRANTS = 1269
-CANT_AGGREGATE_3COLLATIONS = 1270
-CANT_AGGREGATE_NCOLLATIONS = 1271
-VARIABLE_IS_NOT_STRUCT = 1272
-UNKNOWN_COLLATION = 1273
-SLAVE_IGNORED_SSL_PARAMS = 1274
-SERVER_IS_IN_SECURE_AUTH_MODE = 1275
-WARN_FIELD_RESOLVED = 1276
-BAD_SLAVE_UNTIL_COND = 1277
-MISSING_SKIP_SLAVE = 1278
-UNTIL_COND_IGNORED = 1279
-WRONG_NAME_FOR_INDEX = 1280
-WRONG_NAME_FOR_CATALOG = 1281
-WARN_QC_RESIZE = 1282
-BAD_FT_COLUMN = 1283
-UNKNOWN_KEY_CACHE = 1284
-WARN_HOSTNAME_WONT_WORK = 1285
-UNKNOWN_STORAGE_ENGINE = 1286
-WARN_DEPRECATED_SYNTAX = 1287
-NON_UPDATABLE_TABLE = 1288
-FEATURE_DISABLED = 1289
-OPTION_PREVENTS_STATEMENT = 1290
-DUPLICATED_VALUE_IN_TYPE = 1291
-TRUNCATED_WRONG_VALUE = 1292
-TOO_MUCH_AUTO_TIMESTAMP_COLS = 1293
-INVALID_ON_UPDATE = 1294
-UNSUPPORTED_PS = 1295
-GET_ERRMSG = 1296
-GET_TEMPORARY_ERRMSG = 1297
-UNKNOWN_TIME_ZONE = 1298
-WARN_INVALID_TIMESTAMP = 1299
-INVALID_CHARACTER_STRING = 1300
-WARN_ALLOWED_PACKET_OVERFLOWED = 1301
-CONFLICTING_DECLARATIONS = 1302
-SP_NO_RECURSIVE_CREATE = 1303
-SP_ALREADY_EXISTS = 1304
-SP_DOES_NOT_EXIST = 1305
-SP_DROP_FAILED = 1306
-SP_STORE_FAILED = 1307
-SP_LILABEL_MISMATCH = 1308
-SP_LABEL_REDEFINE = 1309
-SP_LABEL_MISMATCH = 1310
-SP_UNINIT_VAR = 1311
-SP_BADSELECT = 1312
-SP_BADRETURN = 1313
-SP_BADSTATEMENT = 1314
-UPDATE_LOG_DEPRECATED_IGNORED = 1315
-UPDATE_LOG_DEPRECATED_TRANSLATED = 1316
-QUERY_INTERRUPTED = 1317
-SP_WRONG_NO_OF_ARGS = 1318
-SP_COND_MISMATCH = 1319
-SP_NORETURN = 1320
-SP_NORETURNEND = 1321
-SP_BAD_CURSOR_QUERY = 1322
-SP_BAD_CURSOR_SELECT = 1323
-SP_CURSOR_MISMATCH = 1324
-SP_CURSOR_ALREADY_OPEN = 1325
-SP_CURSOR_NOT_OPEN = 1326
-SP_UNDECLARED_VAR = 1327
-SP_WRONG_NO_OF_FETCH_ARGS = 1328
-SP_FETCH_NO_DATA = 1329
-SP_DUP_PARAM = 1330
-SP_DUP_VAR = 1331
-SP_DUP_COND = 1332
-SP_DUP_CURS = 1333
-SP_CANT_ALTER = 1334
-SP_SUBSELECT_NYI = 1335
-STMT_NOT_ALLOWED_IN_SF_OR_TRG = 1336
-SP_VARCOND_AFTER_CURSHNDLR = 1337
-SP_CURSOR_AFTER_HANDLER = 1338
-SP_CASE_NOT_FOUND = 1339
-FPARSER_TOO_BIG_FILE = 1340
-FPARSER_BAD_HEADER = 1341
-FPARSER_EOF_IN_COMMENT = 1342
-FPARSER_ERROR_IN_PARAMETER = 1343
-FPARSER_EOF_IN_UNKNOWN_PARAMETER = 1344
-VIEW_NO_EXPLAIN = 1345
-FRM_UNKNOWN_TYPE = 1346
-WRONG_OBJECT = 1347
-NONUPDATEABLE_COLUMN = 1348
-VIEW_SELECT_DERIVED = 1349
-VIEW_SELECT_CLAUSE = 1350
-VIEW_SELECT_VARIABLE = 1351
-VIEW_SELECT_TMPTABLE = 1352
-VIEW_WRONG_LIST = 1353
-WARN_VIEW_MERGE = 1354
-WARN_VIEW_WITHOUT_KEY = 1355
-VIEW_INVALID = 1356
-SP_NO_DROP_SP = 1357
-SP_GOTO_IN_HNDLR = 1358
-TRG_ALREADY_EXISTS = 1359
-TRG_DOES_NOT_EXIST = 1360
-TRG_ON_VIEW_OR_TEMP_TABLE = 1361
-TRG_CANT_CHANGE_ROW = 1362
-TRG_NO_SUCH_ROW_IN_TRG = 1363
-NO_DEFAULT_FOR_FIELD = 1364
-DIVISION_BY_ZERO = 1365
-TRUNCATED_WRONG_VALUE_FOR_FIELD = 1366
-ILLEGAL_VALUE_FOR_TYPE = 1367
-VIEW_NONUPD_CHECK = 1368
-VIEW_CHECK_FAILED = 1369
-PROCACCESS_DENIED_ERROR = 1370
-RELAY_LOG_FAIL = 1371
-PASSWD_LENGTH = 1372
-UNKNOWN_TARGET_BINLOG = 1373
-IO_ERR_LOG_INDEX_READ = 1374
-BINLOG_PURGE_PROHIBITED = 1375
-FSEEK_FAIL = 1376
-BINLOG_PURGE_FATAL_ERR = 1377
-LOG_IN_USE = 1378
-LOG_PURGE_UNKNOWN_ERR = 1379
-RELAY_LOG_INIT = 1380
-NO_BINARY_LOGGING = 1381
-RESERVED_SYNTAX = 1382
-WSAS_FAILED = 1383
-DIFF_GROUPS_PROC = 1384
-NO_GROUP_FOR_PROC = 1385
-ORDER_WITH_PROC = 1386
-LOGGING_PROHIBIT_CHANGING_OF = 1387
-NO_FILE_MAPPING = 1388
-WRONG_MAGIC = 1389
-PS_MANY_PARAM = 1390
-KEY_PART_0 = 1391
-VIEW_CHECKSUM = 1392
-VIEW_MULTIUPDATE = 1393
-VIEW_NO_INSERT_FIELD_LIST = 1394
-VIEW_DELETE_MERGE_VIEW = 1395
-CANNOT_USER = 1396
-XAER_NOTA = 1397
-XAER_INVAL = 1398
-XAER_RMFAIL = 1399
-XAER_OUTSIDE = 1400
-XAER_RMERR = 1401
-XA_RBROLLBACK = 1402
-NONEXISTING_PROC_GRANT = 1403
-PROC_AUTO_GRANT_FAIL = 1404
-PROC_AUTO_REVOKE_FAIL = 1405
-DATA_TOO_LONG = 1406
-SP_BAD_SQLSTATE = 1407
-STARTUP = 1408
-LOAD_FROM_FIXED_SIZE_ROWS_TO_VAR = 1409
-CANT_CREATE_USER_WITH_GRANT = 1410
-WRONG_VALUE_FOR_TYPE = 1411
-TABLE_DEF_CHANGED = 1412
-SP_DUP_HANDLER = 1413
-SP_NOT_VAR_ARG = 1414
-SP_NO_RETSET = 1415
-CANT_CREATE_GEOMETRY_OBJECT = 1416
-FAILED_ROUTINE_BREAK_BINLOG = 1417
-BINLOG_UNSAFE_ROUTINE = 1418
-BINLOG_CREATE_ROUTINE_NEED_SUPER = 1419
-EXEC_STMT_WITH_OPEN_CURSOR = 1420
-STMT_HAS_NO_OPEN_CURSOR = 1421
-COMMIT_NOT_ALLOWED_IN_SF_OR_TRG = 1422
-NO_DEFAULT_FOR_VIEW_FIELD = 1423
-SP_NO_RECURSION = 1424
-TOO_BIG_SCALE = 1425
-TOO_BIG_PRECISION = 1426
-M_BIGGER_THAN_D = 1427
-WRONG_LOCK_OF_SYSTEM_TABLE = 1428
-CONNECT_TO_FOREIGN_DATA_SOURCE = 1429
-QUERY_ON_FOREIGN_DATA_SOURCE = 1430
-FOREIGN_DATA_SOURCE_DOESNT_EXIST = 1431
-FOREIGN_DATA_STRING_INVALID_CANT_CREATE = 1432
-FOREIGN_DATA_STRING_INVALID = 1433
-CANT_CREATE_FEDERATED_TABLE = 1434
-TRG_IN_WRONG_SCHEMA = 1435
-STACK_OVERRUN_NEED_MORE = 1436
-TOO_LONG_BODY = 1437
-WARN_CANT_DROP_DEFAULT_KEYCACHE = 1438
-TOO_BIG_DISPLAYWIDTH = 1439
-XAER_DUPID = 1440
-DATETIME_FUNCTION_OVERFLOW = 1441
-CANT_UPDATE_USED_TABLE_IN_SF_OR_TRG = 1442
-VIEW_PREVENT_UPDATE = 1443
-PS_NO_RECURSION = 1444
-SP_CANT_SET_AUTOCOMMIT = 1445
-MALFORMED_DEFINER = 1446
-VIEW_FRM_NO_USER = 1447
-VIEW_OTHER_USER = 1448
-NO_SUCH_USER = 1449
-FORBID_SCHEMA_CHANGE = 1450
-ROW_IS_REFERENCED_2 = 1451
-NO_REFERENCED_ROW_2 = 1452
-SP_BAD_VAR_SHADOW = 1453
-TRG_NO_DEFINER = 1454
-OLD_FILE_FORMAT = 1455
-SP_RECURSION_LIMIT = 1456
-SP_PROC_TABLE_CORRUPT = 1457
-ERROR_LAST = 1457
-
+"""MySQL ER Constants
+
+These constants are error codes for the bulk of the error conditions
+that may occur.
+
+"""
+
+HASHCHK = 1000
+NISAMCHK = 1001
+NO = 1002
+YES = 1003
+CANT_CREATE_FILE = 1004
+CANT_CREATE_TABLE = 1005
+CANT_CREATE_DB = 1006
+DB_CREATE_EXISTS = 1007
+DB_DROP_EXISTS = 1008
+DB_DROP_DELETE = 1009
+DB_DROP_RMDIR = 1010
+CANT_DELETE_FILE = 1011
+CANT_FIND_SYSTEM_REC = 1012
+CANT_GET_STAT = 1013
+CANT_GET_WD = 1014
+CANT_LOCK = 1015
+CANT_OPEN_FILE = 1016
+FILE_NOT_FOUND = 1017
+CANT_READ_DIR = 1018
+CANT_SET_WD = 1019
+CHECKREAD = 1020
+DISK_FULL = 1021
+DUP_KEY = 1022
+ERROR_ON_CLOSE = 1023
+ERROR_ON_READ = 1024
+ERROR_ON_RENAME = 1025
+ERROR_ON_WRITE = 1026
+FILE_USED = 1027
+FILSORT_ABORT = 1028
+FORM_NOT_FOUND = 1029
+GET_ERRNO = 1030
+ILLEGAL_HA = 1031
+KEY_NOT_FOUND = 1032
+NOT_FORM_FILE = 1033
+NOT_KEYFILE = 1034
+OLD_KEYFILE = 1035
+OPEN_AS_READONLY = 1036
+OUTOFMEMORY = 1037
+OUT_OF_SORTMEMORY = 1038
+UNEXPECTED_EOF = 1039
+CON_COUNT_ERROR = 1040
+OUT_OF_RESOURCES = 1041
+BAD_HOST_ERROR = 1042
+HANDSHAKE_ERROR = 1043
+DBACCESS_DENIED_ERROR = 1044
+ACCESS_DENIED_ERROR = 1045
+NO_DB_ERROR = 1046
+UNKNOWN_COM_ERROR = 1047
+BAD_NULL_ERROR = 1048
+BAD_DB_ERROR = 1049
+TABLE_EXISTS_ERROR = 1050
+BAD_TABLE_ERROR = 1051
+NON_UNIQ_ERROR = 1052
+SERVER_SHUTDOWN = 1053
+BAD_FIELD_ERROR = 1054
+WRONG_FIELD_WITH_GROUP = 1055
+WRONG_GROUP_FIELD = 1056
+WRONG_SUM_SELECT = 1057
+WRONG_VALUE_COUNT = 1058
+TOO_LONG_IDENT = 1059
+DUP_FIELDNAME = 1060
+DUP_KEYNAME = 1061
+DUP_ENTRY = 1062
+WRONG_FIELD_SPEC = 1063
+PARSE_ERROR = 1064
+EMPTY_QUERY = 1065
+NONUNIQ_TABLE = 1066
+INVALID_DEFAULT = 1067
+MULTIPLE_PRI_KEY = 1068
+TOO_MANY_KEYS = 1069
+TOO_MANY_KEY_PARTS = 1070
+TOO_LONG_KEY = 1071
+KEY_COLUMN_DOES_NOT_EXITS = 1072
+BLOB_USED_AS_KEY = 1073
+TOO_BIG_FIELDLENGTH = 1074
+WRONG_AUTO_KEY = 1075
+READY = 1076
+NORMAL_SHUTDOWN = 1077
+GOT_SIGNAL = 1078
+SHUTDOWN_COMPLETE = 1079
+FORCING_CLOSE = 1080
+IPSOCK_ERROR = 1081
+NO_SUCH_INDEX = 1082
+WRONG_FIELD_TERMINATORS = 1083
+BLOBS_AND_NO_TERMINATED = 1084
+TEXTFILE_NOT_READABLE = 1085
+FILE_EXISTS_ERROR = 1086
+LOAD_INFO = 1087
+ALTER_INFO = 1088
+WRONG_SUB_KEY = 1089
+CANT_REMOVE_ALL_FIELDS = 1090
+CANT_DROP_FIELD_OR_KEY = 1091
+INSERT_INFO = 1092
+INSERT_TABLE_USED = 1093
+NO_SUCH_THREAD = 1094
+KILL_DENIED_ERROR = 1095
+NO_TABLES_USED = 1096
+TOO_BIG_SET = 1097
+NO_UNIQUE_LOGFILE = 1098
+TABLE_NOT_LOCKED_FOR_WRITE = 1099
+TABLE_NOT_LOCKED = 1100
+BLOB_CANT_HAVE_DEFAULT = 1101
+WRONG_DB_NAME = 1102
+WRONG_TABLE_NAME = 1103
+TOO_BIG_SELECT = 1104
+UNKNOWN_ERROR = 1105
+UNKNOWN_PROCEDURE = 1106
+WRONG_PARAMCOUNT_TO_PROCEDURE = 1107
+WRONG_PARAMETERS_TO_PROCEDURE = 1108
+UNKNOWN_TABLE = 1109
+FIELD_SPECIFIED_TWICE = 1110
+INVALID_GROUP_FUNC_USE = 1111
+UNSUPPORTED_EXTENSION = 1112
+TABLE_MUST_HAVE_COLUMNS = 1113
+RECORD_FILE_FULL = 1114
+UNKNOWN_CHARACTER_SET = 1115
+TOO_MANY_TABLES = 1116
+TOO_MANY_FIELDS = 1117
+TOO_BIG_ROWSIZE = 1118
+STACK_OVERRUN = 1119
+WRONG_OUTER_JOIN = 1120
+NULL_COLUMN_IN_INDEX = 1121
+CANT_FIND_UDF = 1122
+CANT_INITIALIZE_UDF = 1123
+UDF_NO_PATHS = 1124
+UDF_EXISTS = 1125
+CANT_OPEN_LIBRARY = 1126
+CANT_FIND_DL_ENTRY = 1127
+FUNCTION_NOT_DEFINED = 1128
+HOST_IS_BLOCKED = 1129
+HOST_NOT_PRIVILEGED = 1130
+PASSWORD_ANONYMOUS_USER = 1131
+PASSWORD_NOT_ALLOWED = 1132
+PASSWORD_NO_MATCH = 1133
+UPDATE_INFO = 1134
+CANT_CREATE_THREAD = 1135
+WRONG_VALUE_COUNT_ON_ROW = 1136
+CANT_REOPEN_TABLE = 1137
+INVALID_USE_OF_NULL = 1138
+REGEXP_ERROR = 1139
+MIX_OF_GROUP_FUNC_AND_FIELDS = 1140
+NONEXISTING_GRANT = 1141
+TABLEACCESS_DENIED_ERROR = 1142
+COLUMNACCESS_DENIED_ERROR = 1143
+ILLEGAL_GRANT_FOR_TABLE = 1144
+GRANT_WRONG_HOST_OR_USER = 1145
+NO_SUCH_TABLE = 1146
+NONEXISTING_TABLE_GRANT = 1147
+NOT_ALLOWED_COMMAND = 1148
+SYNTAX_ERROR = 1149
+DELAYED_CANT_CHANGE_LOCK = 1150
+TOO_MANY_DELAYED_THREADS = 1151
+ABORTING_CONNECTION = 1152
+NET_PACKET_TOO_LARGE = 1153
+NET_READ_ERROR_FROM_PIPE = 1154
+NET_FCNTL_ERROR = 1155
+NET_PACKETS_OUT_OF_ORDER = 1156
+NET_UNCOMPRESS_ERROR = 1157
+NET_READ_ERROR = 1158
+NET_READ_INTERRUPTED = 1159
+NET_ERROR_ON_WRITE = 1160
+NET_WRITE_INTERRUPTED = 1161
+TOO_LONG_STRING = 1162
+TABLE_CANT_HANDLE_BLOB = 1163
+TABLE_CANT_HANDLE_AUTO_INCREMENT = 1164
+DELAYED_INSERT_TABLE_LOCKED = 1165
+WRONG_COLUMN_NAME = 1166
+WRONG_KEY_COLUMN = 1167
+WRONG_MRG_TABLE = 1168
+DUP_UNIQUE = 1169
+BLOB_KEY_WITHOUT_LENGTH = 1170
+PRIMARY_CANT_HAVE_NULL = 1171
+TOO_MANY_ROWS = 1172
+REQUIRES_PRIMARY_KEY = 1173
+NO_RAID_COMPILED = 1174
+UPDATE_WITHOUT_KEY_IN_SAFE_MODE = 1175
+KEY_DOES_NOT_EXITS = 1176
+CHECK_NO_SUCH_TABLE = 1177
+CHECK_NOT_IMPLEMENTED = 1178
+CANT_DO_THIS_DURING_AN_TRANSACTION = 1179
+ERROR_DURING_COMMIT = 1180
+ERROR_DURING_ROLLBACK = 1181
+ERROR_DURING_FLUSH_LOGS = 1182
+ERROR_DURING_CHECKPOINT = 1183
+NEW_ABORTING_CONNECTION = 1184
+DUMP_NOT_IMPLEMENTED = 1185
+FLUSH_MASTER_BINLOG_CLOSED = 1186
+INDEX_REBUILD = 1187
+MASTER = 1188
+MASTER_NET_READ = 1189
+MASTER_NET_WRITE = 1190
+FT_MATCHING_KEY_NOT_FOUND = 1191
+LOCK_OR_ACTIVE_TRANSACTION = 1192
+UNKNOWN_SYSTEM_VARIABLE = 1193
+CRASHED_ON_USAGE = 1194
+CRASHED_ON_REPAIR = 1195
+WARNING_NOT_COMPLETE_ROLLBACK = 1196
+TRANS_CACHE_FULL = 1197
+SLAVE_MUST_STOP = 1198
+SLAVE_NOT_RUNNING = 1199
+BAD_SLAVE = 1200
+MASTER_INFO = 1201
+SLAVE_THREAD = 1202
+TOO_MANY_USER_CONNECTIONS = 1203
+SET_CONSTANTS_ONLY = 1204
+LOCK_WAIT_TIMEOUT = 1205
+LOCK_TABLE_FULL = 1206
+READ_ONLY_TRANSACTION = 1207
+DROP_DB_WITH_READ_LOCK = 1208
+CREATE_DB_WITH_READ_LOCK = 1209
+WRONG_ARGUMENTS = 1210
+NO_PERMISSION_TO_CREATE_USER = 1211
+UNION_TABLES_IN_DIFFERENT_DIR = 1212
+LOCK_DEADLOCK = 1213
+TABLE_CANT_HANDLE_FT = 1214
+CANNOT_ADD_FOREIGN = 1215
+NO_REFERENCED_ROW = 1216
+ROW_IS_REFERENCED = 1217
+CONNECT_TO_MASTER = 1218
+QUERY_ON_MASTER = 1219
+ERROR_WHEN_EXECUTING_COMMAND = 1220
+WRONG_USAGE = 1221
+WRONG_NUMBER_OF_COLUMNS_IN_SELECT = 1222
+CANT_UPDATE_WITH_READLOCK = 1223
+MIXING_NOT_ALLOWED = 1224
+DUP_ARGUMENT = 1225
+USER_LIMIT_REACHED = 1226
+SPECIFIC_ACCESS_DENIED_ERROR = 1227
+LOCAL_VARIABLE = 1228
+GLOBAL_VARIABLE = 1229
+NO_DEFAULT = 1230
+WRONG_VALUE_FOR_VAR = 1231
+WRONG_TYPE_FOR_VAR = 1232
+VAR_CANT_BE_READ = 1233
+CANT_USE_OPTION_HERE = 1234
+NOT_SUPPORTED_YET = 1235
+MASTER_FATAL_ERROR_READING_BINLOG = 1236
+SLAVE_IGNORED_TABLE = 1237
+INCORRECT_GLOBAL_LOCAL_VAR = 1238
+WRONG_FK_DEF = 1239
+KEY_REF_DO_NOT_MATCH_TABLE_REF = 1240
+OPERAND_COLUMNS = 1241
+SUBQUERY_NO_1_ROW = 1242
+UNKNOWN_STMT_HANDLER = 1243
+CORRUPT_HELP_DB = 1244
+CYCLIC_REFERENCE = 1245
+AUTO_CONVERT = 1246
+ILLEGAL_REFERENCE = 1247
+DERIVED_MUST_HAVE_ALIAS = 1248
+SELECT_REDUCED = 1249
+TABLENAME_NOT_ALLOWED_HERE = 1250
+NOT_SUPPORTED_AUTH_MODE = 1251
+SPATIAL_CANT_HAVE_NULL = 1252
+COLLATION_CHARSET_MISMATCH = 1253
+SLAVE_WAS_RUNNING = 1254
+SLAVE_WAS_NOT_RUNNING = 1255
+TOO_BIG_FOR_UNCOMPRESS = 1256
+ZLIB_Z_MEM_ERROR = 1257
+ZLIB_Z_BUF_ERROR = 1258
+ZLIB_Z_DATA_ERROR = 1259
+CUT_VALUE_GROUP_CONCAT = 1260
+WARN_TOO_FEW_RECORDS = 1261
+WARN_TOO_MANY_RECORDS = 1262
+WARN_NULL_TO_NOTNULL = 1263
+WARN_DATA_OUT_OF_RANGE = 1264
+WARN_DATA_TRUNCATED = 1265
+WARN_USING_OTHER_HANDLER = 1266
+CANT_AGGREGATE_2COLLATIONS = 1267
+DROP_USER = 1268
+REVOKE_GRANTS = 1269
+CANT_AGGREGATE_3COLLATIONS = 1270
+CANT_AGGREGATE_NCOLLATIONS = 1271
+VARIABLE_IS_NOT_STRUCT = 1272
+UNKNOWN_COLLATION = 1273
+SLAVE_IGNORED_SSL_PARAMS = 1274
+SERVER_IS_IN_SECURE_AUTH_MODE = 1275
+WARN_FIELD_RESOLVED = 1276
+BAD_SLAVE_UNTIL_COND = 1277
+MISSING_SKIP_SLAVE = 1278
+UNTIL_COND_IGNORED = 1279
+WRONG_NAME_FOR_INDEX = 1280
+WRONG_NAME_FOR_CATALOG = 1281
+WARN_QC_RESIZE = 1282
+BAD_FT_COLUMN = 1283
+UNKNOWN_KEY_CACHE = 1284
+WARN_HOSTNAME_WONT_WORK = 1285
+UNKNOWN_STORAGE_ENGINE = 1286
+WARN_DEPRECATED_SYNTAX = 1287
+NON_UPDATABLE_TABLE = 1288
+FEATURE_DISABLED = 1289
+OPTION_PREVENTS_STATEMENT = 1290
+DUPLICATED_VALUE_IN_TYPE = 1291
+TRUNCATED_WRONG_VALUE = 1292
+TOO_MUCH_AUTO_TIMESTAMP_COLS = 1293
+INVALID_ON_UPDATE = 1294
+UNSUPPORTED_PS = 1295
+GET_ERRMSG = 1296
+GET_TEMPORARY_ERRMSG = 1297
+UNKNOWN_TIME_ZONE = 1298
+WARN_INVALID_TIMESTAMP = 1299
+INVALID_CHARACTER_STRING = 1300
+WARN_ALLOWED_PACKET_OVERFLOWED = 1301
+CONFLICTING_DECLARATIONS = 1302
+SP_NO_RECURSIVE_CREATE = 1303
+SP_ALREADY_EXISTS = 1304
+SP_DOES_NOT_EXIST = 1305
+SP_DROP_FAILED = 1306
+SP_STORE_FAILED = 1307
+SP_LILABEL_MISMATCH = 1308
+SP_LABEL_REDEFINE = 1309
+SP_LABEL_MISMATCH = 1310
+SP_UNINIT_VAR = 1311
+SP_BADSELECT = 1312
+SP_BADRETURN = 1313
+SP_BADSTATEMENT = 1314
+UPDATE_LOG_DEPRECATED_IGNORED = 1315
+UPDATE_LOG_DEPRECATED_TRANSLATED = 1316
+QUERY_INTERRUPTED = 1317
+SP_WRONG_NO_OF_ARGS = 1318
+SP_COND_MISMATCH = 1319
+SP_NORETURN = 1320
+SP_NORETURNEND = 1321
+SP_BAD_CURSOR_QUERY = 1322
+SP_BAD_CURSOR_SELECT = 1323
+SP_CURSOR_MISMATCH = 1324
+SP_CURSOR_ALREADY_OPEN = 1325
+SP_CURSOR_NOT_OPEN = 1326
+SP_UNDECLARED_VAR = 1327
+SP_WRONG_NO_OF_FETCH_ARGS = 1328
+SP_FETCH_NO_DATA = 1329
+SP_DUP_PARAM = 1330
+SP_DUP_VAR = 1331
+SP_DUP_COND = 1332
+SP_DUP_CURS = 1333
+SP_CANT_ALTER = 1334
+SP_SUBSELECT_NYI = 1335
+STMT_NOT_ALLOWED_IN_SF_OR_TRG = 1336
+SP_VARCOND_AFTER_CURSHNDLR = 1337
+SP_CURSOR_AFTER_HANDLER = 1338
+SP_CASE_NOT_FOUND = 1339
+FPARSER_TOO_BIG_FILE = 1340
+FPARSER_BAD_HEADER = 1341
+FPARSER_EOF_IN_COMMENT = 1342
+FPARSER_ERROR_IN_PARAMETER = 1343
+FPARSER_EOF_IN_UNKNOWN_PARAMETER = 1344
+VIEW_NO_EXPLAIN = 1345
+FRM_UNKNOWN_TYPE = 1346
+WRONG_OBJECT = 1347
+NONUPDATEABLE_COLUMN = 1348
+VIEW_SELECT_DERIVED = 1349
+VIEW_SELECT_CLAUSE = 1350
+VIEW_SELECT_VARIABLE = 1351
+VIEW_SELECT_TMPTABLE = 1352
+VIEW_WRONG_LIST = 1353
+WARN_VIEW_MERGE = 1354
+WARN_VIEW_WITHOUT_KEY = 1355
+VIEW_INVALID = 1356
+SP_NO_DROP_SP = 1357
+SP_GOTO_IN_HNDLR = 1358
+TRG_ALREADY_EXISTS = 1359
+TRG_DOES_NOT_EXIST = 1360
+TRG_ON_VIEW_OR_TEMP_TABLE = 1361
+TRG_CANT_CHANGE_ROW = 1362
+TRG_NO_SUCH_ROW_IN_TRG = 1363
+NO_DEFAULT_FOR_FIELD = 1364
+DIVISION_BY_ZERO = 1365
+TRUNCATED_WRONG_VALUE_FOR_FIELD = 1366
+ILLEGAL_VALUE_FOR_TYPE = 1367
+VIEW_NONUPD_CHECK = 1368
+VIEW_CHECK_FAILED = 1369
+PROCACCESS_DENIED_ERROR = 1370
+RELAY_LOG_FAIL = 1371
+PASSWD_LENGTH = 1372
+UNKNOWN_TARGET_BINLOG = 1373
+IO_ERR_LOG_INDEX_READ = 1374
+BINLOG_PURGE_PROHIBITED = 1375
+FSEEK_FAIL = 1376
+BINLOG_PURGE_FATAL_ERR = 1377
+LOG_IN_USE = 1378
+LOG_PURGE_UNKNOWN_ERR = 1379
+RELAY_LOG_INIT = 1380
+NO_BINARY_LOGGING = 1381
+RESERVED_SYNTAX = 1382
+WSAS_FAILED = 1383
+DIFF_GROUPS_PROC = 1384
+NO_GROUP_FOR_PROC = 1385
+ORDER_WITH_PROC = 1386
+LOGGING_PROHIBIT_CHANGING_OF = 1387
+NO_FILE_MAPPING = 1388
+WRONG_MAGIC = 1389
+PS_MANY_PARAM = 1390
+KEY_PART_0 = 1391
+VIEW_CHECKSUM = 1392
+VIEW_MULTIUPDATE = 1393
+VIEW_NO_INSERT_FIELD_LIST = 1394
+VIEW_DELETE_MERGE_VIEW = 1395
+CANNOT_USER = 1396
+XAER_NOTA = 1397
+XAER_INVAL = 1398
+XAER_RMFAIL = 1399
+XAER_OUTSIDE = 1400
+XAER_RMERR = 1401
+XA_RBROLLBACK = 1402
+NONEXISTING_PROC_GRANT = 1403
+PROC_AUTO_GRANT_FAIL = 1404
+PROC_AUTO_REVOKE_FAIL = 1405
+DATA_TOO_LONG = 1406
+SP_BAD_SQLSTATE = 1407
+STARTUP = 1408
+LOAD_FROM_FIXED_SIZE_ROWS_TO_VAR = 1409
+CANT_CREATE_USER_WITH_GRANT = 1410
+WRONG_VALUE_FOR_TYPE = 1411
+TABLE_DEF_CHANGED = 1412
+SP_DUP_HANDLER = 1413
+SP_NOT_VAR_ARG = 1414
+SP_NO_RETSET = 1415
+CANT_CREATE_GEOMETRY_OBJECT = 1416
+FAILED_ROUTINE_BREAK_BINLOG = 1417
+BINLOG_UNSAFE_ROUTINE = 1418
+BINLOG_CREATE_ROUTINE_NEED_SUPER = 1419
+EXEC_STMT_WITH_OPEN_CURSOR = 1420
+STMT_HAS_NO_OPEN_CURSOR = 1421
+COMMIT_NOT_ALLOWED_IN_SF_OR_TRG = 1422
+NO_DEFAULT_FOR_VIEW_FIELD = 1423
+SP_NO_RECURSION = 1424
+TOO_BIG_SCALE = 1425
+TOO_BIG_PRECISION = 1426
+M_BIGGER_THAN_D = 1427
+WRONG_LOCK_OF_SYSTEM_TABLE = 1428
+CONNECT_TO_FOREIGN_DATA_SOURCE = 1429
+QUERY_ON_FOREIGN_DATA_SOURCE = 1430
+FOREIGN_DATA_SOURCE_DOESNT_EXIST = 1431
+FOREIGN_DATA_STRING_INVALID_CANT_CREATE = 1432
+FOREIGN_DATA_STRING_INVALID = 1433
+CANT_CREATE_FEDERATED_TABLE = 1434
+TRG_IN_WRONG_SCHEMA = 1435
+STACK_OVERRUN_NEED_MORE = 1436
+TOO_LONG_BODY = 1437
+WARN_CANT_DROP_DEFAULT_KEYCACHE = 1438
+TOO_BIG_DISPLAYWIDTH = 1439
+XAER_DUPID = 1440
+DATETIME_FUNCTION_OVERFLOW = 1441
+CANT_UPDATE_USED_TABLE_IN_SF_OR_TRG = 1442
+VIEW_PREVENT_UPDATE = 1443
+PS_NO_RECURSION = 1444
+SP_CANT_SET_AUTOCOMMIT = 1445
+MALFORMED_DEFINER = 1446
+VIEW_FRM_NO_USER = 1447
+VIEW_OTHER_USER = 1448
+NO_SUCH_USER = 1449
+FORBID_SCHEMA_CHANGE = 1450
+ROW_IS_REFERENCED_2 = 1451
+NO_REFERENCED_ROW_2 = 1452
+SP_BAD_VAR_SHADOW = 1453
+TRG_NO_DEFINER = 1454
+OLD_FILE_FORMAT = 1455
+SP_RECURSION_LIMIT = 1456
+SP_PROC_TABLE_CORRUPT = 1457
+ERROR_LAST = 1457
+
diff --git a/MySQLdb/MySQLdb/constants/FIELD_TYPE.py b/MySQLdb/MySQLdb/constants/FIELD_TYPE.py
index 8a57b17..429f2c8 100644
--- a/MySQLdb/MySQLdb/constants/FIELD_TYPE.py
+++ b/MySQLdb/MySQLdb/constants/FIELD_TYPE.py
@@ -1,37 +1,37 @@
-"""MySQL FIELD_TYPE Constants
-
-These constants represent the various column (field) types that are
-supported by MySQL.
-
-"""
-
-DECIMAL = 0
-TINY = 1
-SHORT = 2
-LONG = 3
-FLOAT = 4
-DOUBLE = 5
-NULL = 6
-TIMESTAMP = 7
-LONGLONG = 8
-INT24 = 9
-DATE = 10
-TIME = 11
-DATETIME = 12
-YEAR = 13
-NEWDATE = 14
-VARCHAR = 15
-BIT = 16
-NEWDECIMAL = 246
-ENUM = 247
-SET = 248
-TINY_BLOB = 249
-MEDIUM_BLOB = 250
-LONG_BLOB = 251
-BLOB = 252
-VAR_STRING = 253
-STRING = 254
-GEOMETRY = 255
-
-CHAR = TINY
-INTERVAL = ENUM
+"""MySQL FIELD_TYPE Constants
+
+These constants represent the various column (field) types that are
+supported by MySQL.
+
+"""
+
+DECIMAL = 0
+TINY = 1
+SHORT = 2
+LONG = 3
+FLOAT = 4
+DOUBLE = 5
+NULL = 6
+TIMESTAMP = 7
+LONGLONG = 8
+INT24 = 9
+DATE = 10
+TIME = 11
+DATETIME = 12
+YEAR = 13
+NEWDATE = 14
+VARCHAR = 15
+BIT = 16
+NEWDECIMAL = 246
+ENUM = 247
+SET = 248
+TINY_BLOB = 249
+MEDIUM_BLOB = 250
+LONG_BLOB = 251
+BLOB = 252
+VAR_STRING = 253
+STRING = 254
+GEOMETRY = 255
+
+CHAR = TINY
+INTERVAL = ENUM
diff --git a/MySQLdb/MySQLdb/constants/FLAG.py b/MySQLdb/MySQLdb/constants/FLAG.py
index 00e6c7c..49a7a0d 100644
--- a/MySQLdb/MySQLdb/constants/FLAG.py
+++ b/MySQLdb/MySQLdb/constants/FLAG.py
@@ -1,23 +1,23 @@
-"""MySQL FLAG Constants
-
-These flags are used along with the FIELD_TYPE to indicate various
-properties of columns in a result set.
-
-"""
-
-NOT_NULL = 1
-PRI_KEY = 2
-UNIQUE_KEY = 4
-MULTIPLE_KEY = 8
-BLOB = 16
-UNSIGNED = 32
-ZEROFILL = 64
-BINARY = 128
-ENUM = 256
-AUTO_INCREMENT = 512
-TIMESTAMP = 1024
-SET = 2048
-NUM = 32768
-PART_KEY = 16384
-GROUP = 32768
-UNIQUE = 65536
+"""MySQL FLAG Constants
+
+These flags are used along with the FIELD_TYPE to indicate various
+properties of columns in a result set.
+
+"""
+
+NOT_NULL = 1
+PRI_KEY = 2
+UNIQUE_KEY = 4
+MULTIPLE_KEY = 8
+BLOB = 16
+UNSIGNED = 32
+ZEROFILL = 64
+BINARY = 128
+ENUM = 256
+AUTO_INCREMENT = 512
+TIMESTAMP = 1024
+SET = 2048
+NUM = 32768
+PART_KEY = 16384
+GROUP = 32768
+UNIQUE = 65536
diff --git a/MySQLdb/MySQLdb/constants/REFRESH.py b/MySQLdb/MySQLdb/constants/REFRESH.py
index 4a08b94..8e25048 100644
--- a/MySQLdb/MySQLdb/constants/REFRESH.py
+++ b/MySQLdb/MySQLdb/constants/REFRESH.py
@@ -1,17 +1,17 @@
-"""MySQL REFRESH Constants
-
-These constants seem to mostly deal with things internal to the
-MySQL server. Forget you saw this.
-
-"""
-
-GRANT = 1
-LOG = 2
-TABLES = 4
-HOSTS = 8
-STATUS = 16
-THREADS = 32
-SLAVE = 64
-MASTER = 128
-READ_LOCK = 16384
-FAST = 32768
+"""MySQL REFRESH Constants
+
+These constants seem to mostly deal with things internal to the
+MySQL server. Forget you saw this.
+
+"""
+
+GRANT = 1
+LOG = 2
+TABLES = 4
+HOSTS = 8
+STATUS = 16
+THREADS = 32
+SLAVE = 64
+MASTER = 128
+READ_LOCK = 16384
+FAST = 32768
diff --git a/MySQLdb/MySQLdb/constants/__init__.py b/MySQLdb/MySQLdb/constants/__init__.py
index 3da4a0e..15d7de2 100644
--- a/MySQLdb/MySQLdb/constants/__init__.py
+++ b/MySQLdb/MySQLdb/constants/__init__.py
@@ -1 +1 @@
-__all__ = ['CR', 'FIELD_TYPE','CLIENT','REFRESH','ER','FLAG']
+__all__ = ['CR', 'FIELD_TYPE','CLIENT','REFRESH','ER','FLAG']
diff --git a/MySQLdb/MySQLdb/converters.py b/MySQLdb/MySQLdb/converters.py
index 14b1f52..a04dd1b 100644
--- a/MySQLdb/MySQLdb/converters.py
+++ b/MySQLdb/MySQLdb/converters.py
@@ -1,181 +1,181 @@
-"""MySQLdb type conversion module
-
-This module handles all the type conversions for MySQL. If the default
-type conversions aren't what you need, you can make your own. The
-dictionary conversions maps some kind of type to a conversion function
-which returns the corresponding value:
-
-Key: FIELD_TYPE.* (from MySQLdb.constants)
-
-Conversion function:
-
- Arguments: string
-
- Returns: Python object
-
-Key: Python type object (from types) or class
-
-Conversion function:
-
- Arguments: Python object of indicated type or class AND
- conversion dictionary
-
- Returns: SQL literal value
-
- Notes: Most conversion functions can ignore the dictionary, but
- it is a required parameter. It is necessary for converting
- things like sequences and instances.
-
-Don't modify conversions if you can avoid it. Instead, make copies
-(with the copy() method), modify the copies, and then pass them to
-MySQL.connect().
-
-"""
-
-from _mysql import string_literal, escape_sequence, escape_dict, escape, NULL
-from MySQLdb.constants import FIELD_TYPE, FLAG
-from MySQLdb.times import *
-
-try:
- from types import IntType, LongType, FloatType, NoneType, TupleType, ListType, DictType, InstanceType, \
- StringType, UnicodeType, ObjectType, BooleanType, ClassType, TypeType
-except ImportError:
- # Python 3
- long = int
- IntType, LongType, FloatType, NoneType = int, long, float, type(None)
- TupleType, ListType, DictType, InstanceType = tuple, list, dict, None
- StringType, UnicodeType, ObjectType, BooleanType = bytes, str, object, bool
-
-import array
-
-try:
- set
-except NameError:
- from sets import Set as set
-
-def Bool2Str(s, d): return str(int(s))
-
-def Str2Set(s):
- return set([ i for i in s.split(',') if i ])
-
-def Set2Str(s, d):
- return string_literal(','.join(s), d)
-
-def Thing2Str(s, d):
- """Convert something into a string via str()."""
- return str(s)
-
-def Unicode2Str(s, d):
- """Convert a unicode object to a string using the default encoding.
- This is only used as a placeholder for the real function, which
- is connection-dependent."""
- return s.encode()
-
-Long2Int = Thing2Str
-
-def Float2Str(o, d):
- return '%.15g' % o
-
-def None2NULL(o, d):
- """Convert None to NULL."""
- return NULL # duh
-
-def Thing2Literal(o, d):
-
- """Convert something into a SQL string literal. If using
- MySQL-3.23 or newer, string_literal() is a method of the
- _mysql.MYSQL object, and this function will be overridden with
- that method when the connection is created."""
-
- return string_literal(o, d)
-
-
-def Instance2Str(o, d):
-
- """
-
- Convert an Instance to a string representation. If the __str__()
- method produces acceptable output, then you don't need to add the
- class to conversions; it will be handled by the default
- converter. If the exact class is not found in d, it will use the
- first class it can find for which o is an instance.
-
- """
-
- if o.__class__ in d:
- return d[o.__class__](o, d)
- cl = filter(lambda x,o=o:
- type(x) is ClassType
- and isinstance(o, x), d.keys())
- if not cl and hasattr(types, 'ObjectType'):
- cl = filter(lambda x,o=o:
- type(x) is TypeType
- and isinstance(o, x)
- and d[x] is not Instance2Str,
- d.keys())
- if not cl:
- return d[types.StringType](o,d)
- d[o.__class__] = d[cl[0]]
- return d[cl[0]](o, d)
-
-def char_array(s):
- return array.array('c', s)
-
-def array2Str(o, d):
- return Thing2Literal(o.tostring(), d)
-
-conversions = {
- IntType: Thing2Str,
- LongType: Long2Int,
- FloatType: Float2Str,
- NoneType: None2NULL,
- TupleType: escape_sequence,
- ListType: escape_sequence,
- DictType: escape_dict,
- InstanceType: Instance2Str,
- array.ArrayType: array2Str,
- StringType: Thing2Literal, # default
- UnicodeType: Unicode2Str,
- ObjectType: Instance2Str,
- BooleanType: Bool2Str,
- DateTimeType: DateTime2literal,
- DateTimeDeltaType: DateTimeDelta2literal,
- set: Set2Str,
- FIELD_TYPE.TINY: int,
- FIELD_TYPE.SHORT: int,
- FIELD_TYPE.LONG: long,
- FIELD_TYPE.FLOAT: float,
- FIELD_TYPE.DOUBLE: float,
- FIELD_TYPE.DECIMAL: float,
- FIELD_TYPE.NEWDECIMAL: float,
- FIELD_TYPE.LONGLONG: long,
- FIELD_TYPE.INT24: int,
- FIELD_TYPE.YEAR: int,
- FIELD_TYPE.SET: Str2Set,
- FIELD_TYPE.TIMESTAMP: mysql_timestamp_converter,
- FIELD_TYPE.DATETIME: DateTime_or_None,
- FIELD_TYPE.TIME: TimeDelta_or_None,
- FIELD_TYPE.DATE: Date_or_None,
- FIELD_TYPE.BLOB: [
- (FLAG.BINARY, str),
- ],
- FIELD_TYPE.STRING: [
- (FLAG.BINARY, str),
- ],
- FIELD_TYPE.VAR_STRING: [
- (FLAG.BINARY, str),
- ],
- FIELD_TYPE.VARCHAR: [
- (FLAG.BINARY, str),
- ],
- }
-
-try:
- from decimal import Decimal
- conversions[FIELD_TYPE.DECIMAL] = Decimal
- conversions[FIELD_TYPE.NEWDECIMAL] = Decimal
-except ImportError:
- pass
-
-
-
+"""MySQLdb type conversion module
+
+This module handles all the type conversions for MySQL. If the default
+type conversions aren't what you need, you can make your own. The
+dictionary conversions maps some kind of type to a conversion function
+which returns the corresponding value:
+
+Key: FIELD_TYPE.* (from MySQLdb.constants)
+
+Conversion function:
+
+ Arguments: string
+
+ Returns: Python object
+
+Key: Python type object (from types) or class
+
+Conversion function:
+
+ Arguments: Python object of indicated type or class AND
+ conversion dictionary
+
+ Returns: SQL literal value
+
+ Notes: Most conversion functions can ignore the dictionary, but
+ it is a required parameter. It is necessary for converting
+ things like sequences and instances.
+
+Don't modify conversions if you can avoid it. Instead, make copies
+(with the copy() method), modify the copies, and then pass them to
+MySQL.connect().
+
+"""
+
+from _mysql import string_literal, escape_sequence, escape_dict, escape, NULL
+from MySQLdb.constants import FIELD_TYPE, FLAG
+from MySQLdb.times import *
+
+try:
+ from types import IntType, LongType, FloatType, NoneType, TupleType, ListType, DictType, InstanceType, \
+ StringType, UnicodeType, ObjectType, BooleanType, ClassType, TypeType
+except ImportError:
+ # Python 3
+ long = int
+ IntType, LongType, FloatType, NoneType = int, long, float, type(None)
+ TupleType, ListType, DictType, InstanceType = tuple, list, dict, None
+ StringType, UnicodeType, ObjectType, BooleanType = bytes, str, object, bool
+
+import array
+
+try:
+ set
+except NameError:
+ from sets import Set as set
+
+def Bool2Str(s, d): return str(int(s))
+
+def Str2Set(s):
+ return set([ i for i in s.split(',') if i ])
+
+def Set2Str(s, d):
+ return string_literal(','.join(s), d)
+
+def Thing2Str(s, d):
+ """Convert something into a string via str()."""
+ return str(s)
+
+def Unicode2Str(s, d):
+ """Convert a unicode object to a string using the default encoding.
+ This is only used as a placeholder for the real function, which
+ is connection-dependent."""
+ return s.encode()
+
+Long2Int = Thing2Str
+
+def Float2Str(o, d):
+ return '%.15g' % o
+
+def None2NULL(o, d):
+ """Convert None to NULL."""
+ return NULL # duh
+
+def Thing2Literal(o, d):
+
+ """Convert something into a SQL string literal. If using
+ MySQL-3.23 or newer, string_literal() is a method of the
+ _mysql.MYSQL object, and this function will be overridden with
+ that method when the connection is created."""
+
+ return string_literal(o, d)
+
+
+def Instance2Str(o, d):
+
+ """
+
+ Convert an Instance to a string representation. If the __str__()
+ method produces acceptable output, then you don't need to add the
+ class to conversions; it will be handled by the default
+ converter. If the exact class is not found in d, it will use the
+ first class it can find for which o is an instance.
+
+ """
+
+ if o.__class__ in d:
+ return d[o.__class__](o, d)
+ cl = filter(lambda x,o=o:
+ type(x) is ClassType
+ and isinstance(o, x), d.keys())
+ if not cl and hasattr(types, 'ObjectType'):
+ cl = filter(lambda x,o=o:
+ type(x) is TypeType
+ and isinstance(o, x)
+ and d[x] is not Instance2Str,
+ d.keys())
+ if not cl:
+ return d[types.StringType](o,d)
+ d[o.__class__] = d[cl[0]]
+ return d[cl[0]](o, d)
+
+def char_array(s):
+ return array.array('c', s)
+
+def array2Str(o, d):
+ return Thing2Literal(o.tostring(), d)
+
+conversions = {
+ IntType: Thing2Str,
+ LongType: Long2Int,
+ FloatType: Float2Str,
+ NoneType: None2NULL,
+ TupleType: escape_sequence,
+ ListType: escape_sequence,
+ DictType: escape_dict,
+ InstanceType: Instance2Str,
+ array.ArrayType: array2Str,
+ StringType: Thing2Literal, # default
+ UnicodeType: Unicode2Str,
+ ObjectType: Instance2Str,
+ BooleanType: Bool2Str,
+ DateTimeType: DateTime2literal,
+ DateTimeDeltaType: DateTimeDelta2literal,
+ set: Set2Str,
+ FIELD_TYPE.TINY: int,
+ FIELD_TYPE.SHORT: int,
+ FIELD_TYPE.LONG: long,
+ FIELD_TYPE.FLOAT: float,
+ FIELD_TYPE.DOUBLE: float,
+ FIELD_TYPE.DECIMAL: float,
+ FIELD_TYPE.NEWDECIMAL: float,
+ FIELD_TYPE.LONGLONG: long,
+ FIELD_TYPE.INT24: int,
+ FIELD_TYPE.YEAR: int,
+ FIELD_TYPE.SET: Str2Set,
+ FIELD_TYPE.TIMESTAMP: mysql_timestamp_converter,
+ FIELD_TYPE.DATETIME: DateTime_or_None,
+ FIELD_TYPE.TIME: TimeDelta_or_None,
+ FIELD_TYPE.DATE: Date_or_None,
+ FIELD_TYPE.BLOB: [
+ (FLAG.BINARY, str),
+ ],
+ FIELD_TYPE.STRING: [
+ (FLAG.BINARY, str),
+ ],
+ FIELD_TYPE.VAR_STRING: [
+ (FLAG.BINARY, str),
+ ],
+ FIELD_TYPE.VARCHAR: [
+ (FLAG.BINARY, str),
+ ],
+ }
+
+try:
+ from decimal import Decimal
+ conversions[FIELD_TYPE.DECIMAL] = Decimal
+ conversions[FIELD_TYPE.NEWDECIMAL] = Decimal
+except ImportError:
+ pass
+
+
+
diff --git a/MySQLdb/MySQLdb/cursors.py b/MySQLdb/MySQLdb/cursors.py
index 53960ae..696f44a 100644
--- a/MySQLdb/MySQLdb/cursors.py
+++ b/MySQLdb/MySQLdb/cursors.py
@@ -1,510 +1,510 @@
-"""MySQLdb Cursors
-
-This module implements Cursors of various types for MySQLdb. By
-default, MySQLdb uses the Cursor class.
-
-"""
-
-import re
-import sys
-try:
- from types import ListType, TupleType, UnicodeType
-except ImportError:
- # Python 3
- ListType = list
- TupleType = tuple
- UnicodeType = str
-
-restr = (r"\svalues\s*"
- r"(\(((?<!\\)'[^\)]*?\)[^\)]*(?<!\\)?'"
- r"|[^\(\)]|"
- r"(?:\([^\)]*\))"
- r")+\))")
-
-insert_values = re.compile(restr, re.I)
-
-from _mysql_exceptions import Warning, Error, InterfaceError, DataError, \
- DatabaseError, OperationalError, IntegrityError, InternalError, \
- NotSupportedError, ProgrammingError
-
-
-class BaseCursor(object):
-
- """A base for Cursor classes. Useful attributes:
-
- description
- A tuple of DB API 7-tuples describing the columns in
- the last executed query; see PEP-249 for details.
-
- description_flags
- Tuple of column flags for last query, one entry per column
- in the result set. Values correspond to those in
- MySQLdb.constants.FLAG. See MySQL documentation (C API)
- for more information. Non-standard extension.
-
- arraysize
- default number of rows fetchmany() will fetch
-
- """
-
- from _mysql_exceptions import MySQLError, Warning, Error, InterfaceError, \
- DatabaseError, DataError, OperationalError, IntegrityError, \
- InternalError, ProgrammingError, NotSupportedError
-
- _defer_warnings = False
-
- def __init__(self, connection):
- from weakref import proxy
-
- self.connection = proxy(connection)
- self.description = None
- self.description_flags = None
- self.rowcount = -1
- self.arraysize = 1
- self._executed = None
- self.lastrowid = None
- self.messages = []
- self.errorhandler = connection.errorhandler
- self._result = None
- self._warnings = 0
- self._info = None
- self.rownumber = None
-
- def __del__(self):
- self.close()
- self.errorhandler = None
- self._result = None
-
- def close(self):
- """Close the cursor. No further queries will be possible."""
- if not self.connection: return
- while self.nextset(): pass
- self.connection = None
-
- def _check_executed(self):
- if not self._executed:
- self.errorhandler(self, ProgrammingError, "execute() first")
-
- def _warning_check(self):
- from warnings import warn
- if self._warnings:
- warnings = self._get_db().show_warnings()
- if warnings:
- # This is done in two loops in case
- # Warnings are set to raise exceptions.
- for w in warnings:
- self.messages.append((self.Warning, w))
- for w in warnings:
- warn(w[-1], self.Warning, 3)
- elif self._info:
- self.messages.append((self.Warning, self._info))
- warn(self._info, self.Warning, 3)
-
- def nextset(self):
- """Advance to the next result set.
-
- Returns None if there are no more result sets.
- """
- if self._executed:
- self.fetchall()
- del self.messages[:]
-
- db = self._get_db()
- nr = db.next_result()
- if nr == -1:
- return None
- self._do_get_result()
- self._post_get_result()
- self._warning_check()
- return 1
-
- def _post_get_result(self): pass
-
- def _do_get_result(self):
- db = self._get_db()
- self._result = self._get_result()
- self.rowcount = db.affected_rows()
- self.rownumber = 0
- self.description = self._result and self._result.describe() or None
- self.description_flags = self._result and self._result.field_flags() or None
- self.lastrowid = db.insert_id()
- self._warnings = db.warning_count()
- self._info = db.info()
-
- def setinputsizes(self, *args):
- """Does nothing, required by DB API."""
-
- def setoutputsizes(self, *args):
- """Does nothing, required by DB API."""
-
- def _get_db(self):
- if not self.connection:
- self.errorhandler(self, ProgrammingError, "cursor closed")
- return self.connection
-
- def execute(self, query, args=None):
-
- """Execute a query.
-
- query -- string, query to execute on server
- args -- optional sequence or mapping, parameters to use with query.
-
- Note: If args is a sequence, then %s must be used as the
- parameter placeholder in the query. If a mapping is used,
- %(key)s must be used as the placeholder.
-
- Returns long integer rows affected, if any
-
- """
- del self.messages[:]
- db = self._get_db()
- charset = db.character_set_name()
- if isinstance(query, unicode):
- query = query.encode(charset)
- if args is not None:
- query = query % db.literal(args)
- try:
- r = None
- r = self._query(query)
- except TypeError as m:
- if m.args[0] in ("not enough arguments for format string",
- "not all arguments converted"):
- self.messages.append((ProgrammingError, m.args[0]))
- self.errorhandler(self, ProgrammingError, m.args[0])
- else:
- self.messages.append((TypeError, m))
- self.errorhandler(self, TypeError, m)
- except:
- exc, value, tb = sys.exc_info()
- del tb
- self.messages.append((exc, value))
- self.errorhandler(self, exc, value)
- self._executed = query
- if not self._defer_warnings: self._warning_check()
- return r
-
- def executemany(self, query, args):
-
- """Execute a multi-row query.
-
- query -- string, query to execute on server
-
- args
-
- Sequence of sequences or mappings, parameters to use with
- query.
-
- Returns long integer rows affected, if any.
-
- This method improves performance on multiple-row INSERT and
- REPLACE. Otherwise it is equivalent to looping over args with
- execute().
-
- """
- del self.messages[:]
- db = self._get_db()
- if not args: return
- charset = db.character_set_name()
- if isinstance(query, unicode): query = query.encode(charset)
- m = insert_values.search(query)
- if not m:
- r = 0
- for a in args:
- r = r + self.execute(query, a)
- return r
- p = m.start(1)
- e = m.end(1)
- qv = m.group(1)
- try:
- q = [ qv % db.literal(a) for a in args ]
- except TypeError as msg:
- if msg.args[0] in ("not enough arguments for format string",
- "not all arguments converted"):
- self.errorhandler(self, ProgrammingError, msg.args[0])
- else:
- self.errorhandler(self, TypeError, msg)
- except:
- exc, value, tb = sys.exc_info()
- del tb
- self.errorhandler(self, exc, value)
- r = self._query('\n'.join([query[:p], ',\n'.join(q), query[e:]]))
- if not self._defer_warnings: self._warning_check()
- return r
-
- def callproc(self, procname, args=()):
-
- """Execute stored procedure procname with args
-
- procname -- string, name of procedure to execute on server
-
- args -- Sequence of parameters to use with procedure
-
- Returns the original args.
-
- Compatibility warning: PEP-249 specifies that any modified
- parameters must be returned. This is currently impossible
- as they are only available by storing them in a server
- variable and then retrieved by a query. Since stored
- procedures return zero or more result sets, there is no
- reliable way to get at OUT or INOUT parameters via callproc.
- The server variables are named @_procname_n, where procname
- is the parameter above and n is the position of the parameter
- (from zero). Once all result sets generated by the procedure
- have been fetched, you can issue a SELECT @_procname_0, ...
- query using .execute() to get any OUT or INOUT values.
-
- Compatibility warning: The act of calling a stored procedure
- itself creates an empty result set. This appears after any
- result sets generated by the procedure. This is non-standard
- behavior with respect to the DB-API. Be sure to use nextset()
- to advance through all result sets; otherwise you may get
- disconnected.
- """
-
- db = self._get_db()
- charset = db.character_set_name()
- for index, arg in enumerate(args):
- q = "SET @_%s_%d=%s" % (procname, index,
- db.literal(arg))
- if isinstance(q, unicode):
- q = q.encode(charset)
- self._query(q)
- self.nextset()
-
- q = "CALL %s(%s)" % (procname,
- ','.join(['@_%s_%d' % (procname, i)
- for i in range(len(args))]))
- if type(q) is UnicodeType:
- q = q.encode(charset)
- self._query(q)
- self._executed = q
- if not self._defer_warnings: self._warning_check()
- return args
-
- def _do_query(self, q):
- db = self._get_db()
- self._last_executed = q
- db.query(q)
- self._do_get_result()
- return self.rowcount
-
- def _query(self, q): return self._do_query(q)
-
- def _fetch_row(self, size=1):
- if not self._result:
- return ()
- return self._result.fetch_row(size, self._fetch_type)
-
- def __iter__(self):
- return iter(self.fetchone, None)
-
- Warning = Warning
- Error = Error
- InterfaceError = InterfaceError
- DatabaseError = DatabaseError
- DataError = DataError
- OperationalError = OperationalError
- IntegrityError = IntegrityError
- InternalError = InternalError
- ProgrammingError = ProgrammingError
- NotSupportedError = NotSupportedError
-
-
-class CursorStoreResultMixIn(object):
-
- """This is a MixIn class which causes the entire result set to be
- stored on the client side, i.e. it uses mysql_store_result(). If the
- result set can be very large, consider adding a LIMIT clause to your
- query, or using CursorUseResultMixIn instead."""
-
- def _get_result(self): return self._get_db().store_result()
-
- def _query(self, q):
- rowcount = self._do_query(q)
- self._post_get_result()
- return rowcount
-
- def _post_get_result(self):
- self._rows = self._fetch_row(0)
- self._result = None
-
- def fetchone(self):
- """Fetches a single row from the cursor. None indicates that
- no more rows are available."""
- self._check_executed()
- if self.rownumber >= len(self._rows): return None
- result = self._rows[self.rownumber]
- self.rownumber = self.rownumber+1
- return result
-
- def fetchmany(self, size=None):
- """Fetch up to size rows from the cursor. Result set may be smaller
- than size. If size is not defined, cursor.arraysize is used."""
- self._check_executed()
- end = self.rownumber + (size or self.arraysize)
- result = self._rows[self.rownumber:end]
- self.rownumber = min(end, len(self._rows))
- return result
-
- def fetchall(self):
- """Fetchs all available rows from the cursor."""
- self._check_executed()
- if self.rownumber:
- result = self._rows[self.rownumber:]
- else:
- result = self._rows
- self.rownumber = len(self._rows)
- return result
-
- def scroll(self, value, mode='relative'):
- """Scroll the cursor in the result set to a new position according
- to mode.
-
- If mode is 'relative' (default), value is taken as offset to
- the current position in the result set, if set to 'absolute',
- value states an absolute target position."""
- self._check_executed()
- if mode == 'relative':
- r = self.rownumber + value
- elif mode == 'absolute':
- r = value
- else:
- self.errorhandler(self, ProgrammingError,
- "unknown scroll mode %s" % repr(mode))
- if r < 0 or r >= len(self._rows):
- self.errorhandler(self, IndexError, "out of range")
- self.rownumber = r
-
- def __iter__(self):
- self._check_executed()
- result = self.rownumber and self._rows[self.rownumber:] or self._rows
- return iter(result)
-
-
-class CursorUseResultMixIn(object):
-
- """This is a MixIn class which causes the result set to be stored
- in the server and sent row-by-row to client side, i.e. it uses
- mysql_use_result(). You MUST retrieve the entire result set and
- close() the cursor before additional queries can be peformed on
- the connection."""
-
- _defer_warnings = True
-
- def _get_result(self): return self._get_db().use_result()
-
- def fetchone(self):
- """Fetches a single row from the cursor."""
- self._check_executed()
- r = self._fetch_row(1)
- if not r:
- self._warning_check()
- return None
- self.rownumber = self.rownumber + 1
- return r[0]
-
- def fetchmany(self, size=None):
- """Fetch up to size rows from the cursor. Result set may be smaller
- than size. If size is not defined, cursor.arraysize is used."""
- self._check_executed()
- r = self._fetch_row(size or self.arraysize)
- self.rownumber = self.rownumber + len(r)
- if not r:
- self._warning_check()
- return r
-
- def fetchall(self):
- """Fetchs all available rows from the cursor."""
- self._check_executed()
- r = self._fetch_row(0)
- self.rownumber = self.rownumber + len(r)
- self._warning_check()
- return r
-
- def __iter__(self):
- return self
-
- def next(self):
- row = self.fetchone()
- if row is None:
- raise StopIteration
- return row
-
-
-class CursorTupleRowsMixIn(object):
-
- """This is a MixIn class that causes all rows to be returned as tuples,
- which is the standard form required by DB API."""
-
- _fetch_type = 0
-
-
-class CursorDictRowsMixIn(object):
-
- """This is a MixIn class that causes all rows to be returned as
- dictionaries. This is a non-standard feature."""
-
- _fetch_type = 1
-
- def fetchoneDict(self):
- """Fetch a single row as a dictionary. Deprecated:
- Use fetchone() instead. Will be removed in 1.3."""
- from warnings import warn
- warn("fetchoneDict() is non-standard and will be removed in 1.3",
- DeprecationWarning, 2)
- return self.fetchone()
-
- def fetchmanyDict(self, size=None):
- """Fetch several rows as a list of dictionaries. Deprecated:
- Use fetchmany() instead. Will be removed in 1.3."""
- from warnings import warn
- warn("fetchmanyDict() is non-standard and will be removed in 1.3",
- DeprecationWarning, 2)
- return self.fetchmany(size)
-
- def fetchallDict(self):
- """Fetch all available rows as a list of dictionaries. Deprecated:
- Use fetchall() instead. Will be removed in 1.3."""
- from warnings import warn
- warn("fetchallDict() is non-standard and will be removed in 1.3",
- DeprecationWarning, 2)
- return self.fetchall()
-
-
-class CursorOldDictRowsMixIn(CursorDictRowsMixIn):
-
- """This is a MixIn class that returns rows as dictionaries with
- the same key convention as the old Mysqldb (MySQLmodule). Don't
- use this."""
-
- _fetch_type = 2
-
-
-class Cursor(CursorStoreResultMixIn, CursorTupleRowsMixIn,
- BaseCursor):
-
- """This is the standard Cursor class that returns rows as tuples
- and stores the result set in the client."""
-
-
-class DictCursor(CursorStoreResultMixIn, CursorDictRowsMixIn,
- BaseCursor):
-
- """This is a Cursor class that returns rows as dictionaries and
- stores the result set in the client."""
-
-
-class SSCursor(CursorUseResultMixIn, CursorTupleRowsMixIn,
- BaseCursor):
-
- """This is a Cursor class that returns rows as tuples and stores
- the result set in the server."""
-
-
-class SSDictCursor(CursorUseResultMixIn, CursorDictRowsMixIn,
- BaseCursor):
-
- """This is a Cursor class that returns rows as dictionaries and
- stores the result set in the server."""
-
-
+"""MySQLdb Cursors
+
+This module implements Cursors of various types for MySQLdb. By
+default, MySQLdb uses the Cursor class.
+
+"""
+
+import re
+import sys
+try:
+ from types import ListType, TupleType, UnicodeType
+except ImportError:
+ # Python 3
+ ListType = list
+ TupleType = tuple
+ UnicodeType = str
+
+restr = (r"\svalues\s*"
+ r"(\(((?<!\\)'[^\)]*?\)[^\)]*(?<!\\)?'"
+ r"|[^\(\)]|"
+ r"(?:\([^\)]*\))"
+ r")+\))")
+
+insert_values = re.compile(restr, re.I)
+
+from _mysql_exceptions import Warning, Error, InterfaceError, DataError, \
+ DatabaseError, OperationalError, IntegrityError, InternalError, \
+ NotSupportedError, ProgrammingError
+
+
+class BaseCursor(object):
+
+ """A base for Cursor classes. Useful attributes:
+
+ description
+ A tuple of DB API 7-tuples describing the columns in
+ the last executed query; see PEP-249 for details.
+
+ description_flags
+ Tuple of column flags for last query, one entry per column
+ in the result set. Values correspond to those in
+ MySQLdb.constants.FLAG. See MySQL documentation (C API)
+ for more information. Non-standard extension.
+
+ arraysize
+ default number of rows fetchmany() will fetch
+
+ """
+
+ from _mysql_exceptions import MySQLError, Warning, Error, InterfaceError, \
+ DatabaseError, DataError, OperationalError, IntegrityError, \
+ InternalError, ProgrammingError, NotSupportedError
+
+ _defer_warnings = False
+
+ def __init__(self, connection):
+ from weakref import proxy
+
+ self.connection = proxy(connection)
+ self.description = None
+ self.description_flags = None
+ self.rowcount = -1
+ self.arraysize = 1
+ self._executed = None
+ self.lastrowid = None
+ self.messages = []
+ self.errorhandler = connection.errorhandler
+ self._result = None
+ self._warnings = 0
+ self._info = None
+ self.rownumber = None
+
+ def __del__(self):
+ self.close()
+ self.errorhandler = None
+ self._result = None
+
+ def close(self):
+ """Close the cursor. No further queries will be possible."""
+ if not self.connection: return
+ while self.nextset(): pass
+ self.connection = None
+
+ def _check_executed(self):
+ if not self._executed:
+ self.errorhandler(self, ProgrammingError, "execute() first")
+
+ def _warning_check(self):
+ from warnings import warn
+ if self._warnings:
+ warnings = self._get_db().show_warnings()
+ if warnings:
+ # This is done in two loops in case
+ # Warnings are set to raise exceptions.
+ for w in warnings:
+ self.messages.append((self.Warning, w))
+ for w in warnings:
+ warn(w[-1], self.Warning, 3)
+ elif self._info:
+ self.messages.append((self.Warning, self._info))
+ warn(self._info, self.Warning, 3)
+
+ def nextset(self):
+ """Advance to the next result set.
+
+ Returns None if there are no more result sets.
+ """
+ if self._executed:
+ self.fetchall()
+ del self.messages[:]
+
+ db = self._get_db()
+ nr = db.next_result()
+ if nr == -1:
+ return None
+ self._do_get_result()
+ self._post_get_result()
+ self._warning_check()
+ return 1
+
+ def _post_get_result(self): pass
+
+ def _do_get_result(self):
+ db = self._get_db()
+ self._result = self._get_result()
+ self.rowcount = db.affected_rows()
+ self.rownumber = 0
+ self.description = self._result and self._result.describe() or None
+ self.description_flags = self._result and self._result.field_flags() or None
+ self.lastrowid = db.insert_id()
+ self._warnings = db.warning_count()
+ self._info = db.info()
+
+ def setinputsizes(self, *args):
+ """Does nothing, required by DB API."""
+
+ def setoutputsizes(self, *args):
+ """Does nothing, required by DB API."""
+
+ def _get_db(self):
+ if not self.connection:
+ self.errorhandler(self, ProgrammingError, "cursor closed")
+ return self.connection
+
+ def execute(self, query, args=None):
+
+ """Execute a query.
+
+ query -- string, query to execute on server
+ args -- optional sequence or mapping, parameters to use with query.
+
+ Note: If args is a sequence, then %s must be used as the
+ parameter placeholder in the query. If a mapping is used,
+ %(key)s must be used as the placeholder.
+
+ Returns long integer rows affected, if any
+
+ """
+ del self.messages[:]
+ db = self._get_db()
+ charset = db.character_set_name()
+ if isinstance(query, unicode):
+ query = query.encode(charset)
+ if args is not None:
+ query = query % db.literal(args)
+ try:
+ r = None
+ r = self._query(query)
+ except TypeError as m:
+ if m.args[0] in ("not enough arguments for format string",
+ "not all arguments converted"):
+ self.messages.append((ProgrammingError, m.args[0]))
+ self.errorhandler(self, ProgrammingError, m.args[0])
+ else:
+ self.messages.append((TypeError, m))
+ self.errorhandler(self, TypeError, m)
+ except:
+ exc, value, tb = sys.exc_info()
+ del tb
+ self.messages.append((exc, value))
+ self.errorhandler(self, exc, value)
+ self._executed = query
+ if not self._defer_warnings: self._warning_check()
+ return r
+
+ def executemany(self, query, args):
+
+ """Execute a multi-row query.
+
+ query -- string, query to execute on server
+
+ args
+
+ Sequence of sequences or mappings, parameters to use with
+ query.
+
+ Returns long integer rows affected, if any.
+
+ This method improves performance on multiple-row INSERT and
+ REPLACE. Otherwise it is equivalent to looping over args with
+ execute().
+
+ """
+ del self.messages[:]
+ db = self._get_db()
+ if not args: return
+ charset = db.character_set_name()
+ if isinstance(query, unicode): query = query.encode(charset)
+ m = insert_values.search(query)
+ if not m:
+ r = 0
+ for a in args:
+ r = r + self.execute(query, a)
+ return r
+ p = m.start(1)
+ e = m.end(1)
+ qv = m.group(1)
+ try:
+ q = [ qv % db.literal(a) for a in args ]
+ except TypeError as msg:
+ if msg.args[0] in ("not enough arguments for format string",
+ "not all arguments converted"):
+ self.errorhandler(self, ProgrammingError, msg.args[0])
+ else:
+ self.errorhandler(self, TypeError, msg)
+ except:
+ exc, value, tb = sys.exc_info()
+ del tb
+ self.errorhandler(self, exc, value)
+ r = self._query('\n'.join([query[:p], ',\n'.join(q), query[e:]]))
+ if not self._defer_warnings: self._warning_check()
+ return r
+
+ def callproc(self, procname, args=()):
+
+ """Execute stored procedure procname with args
+
+ procname -- string, name of procedure to execute on server
+
+ args -- Sequence of parameters to use with procedure
+
+ Returns the original args.
+
+ Compatibility warning: PEP-249 specifies that any modified
+ parameters must be returned. This is currently impossible
+ as they are only available by storing them in a server
+ variable and then retrieved by a query. Since stored
+ procedures return zero or more result sets, there is no
+ reliable way to get at OUT or INOUT parameters via callproc.
+ The server variables are named @_procname_n, where procname
+ is the parameter above and n is the position of the parameter
+ (from zero). Once all result sets generated by the procedure
+ have been fetched, you can issue a SELECT @_procname_0, ...
+ query using .execute() to get any OUT or INOUT values.
+
+ Compatibility warning: The act of calling a stored procedure
+ itself creates an empty result set. This appears after any
+ result sets generated by the procedure. This is non-standard
+ behavior with respect to the DB-API. Be sure to use nextset()
+ to advance through all result sets; otherwise you may get
+ disconnected.
+ """
+
+ db = self._get_db()
+ charset = db.character_set_name()
+ for index, arg in enumerate(args):
+ q = "SET @_%s_%d=%s" % (procname, index,
+ db.literal(arg))
+ if isinstance(q, unicode):
+ q = q.encode(charset)
+ self._query(q)
+ self.nextset()
+
+ q = "CALL %s(%s)" % (procname,
+ ','.join(['@_%s_%d' % (procname, i)
+ for i in range(len(args))]))
+ if type(q) is UnicodeType:
+ q = q.encode(charset)
+ self._query(q)
+ self._executed = q
+ if not self._defer_warnings: self._warning_check()
+ return args
+
+ def _do_query(self, q):
+ db = self._get_db()
+ self._last_executed = q
+ db.query(q)
+ self._do_get_result()
+ return self.rowcount
+
+ def _query(self, q): return self._do_query(q)
+
+ def _fetch_row(self, size=1):
+ if not self._result:
+ return ()
+ return self._result.fetch_row(size, self._fetch_type)
+
+ def __iter__(self):
+ return iter(self.fetchone, None)
+
+ Warning = Warning
+ Error = Error
+ InterfaceError = InterfaceError
+ DatabaseError = DatabaseError
+ DataError = DataError
+ OperationalError = OperationalError
+ IntegrityError = IntegrityError
+ InternalError = InternalError
+ ProgrammingError = ProgrammingError
+ NotSupportedError = NotSupportedError
+
+
+class CursorStoreResultMixIn(object):
+
+ """This is a MixIn class which causes the entire result set to be
+ stored on the client side, i.e. it uses mysql_store_result(). If the
+ result set can be very large, consider adding a LIMIT clause to your
+ query, or using CursorUseResultMixIn instead."""
+
+ def _get_result(self): return self._get_db().store_result()
+
+ def _query(self, q):
+ rowcount = self._do_query(q)
+ self._post_get_result()
+ return rowcount
+
+ def _post_get_result(self):
+ self._rows = self._fetch_row(0)
+ self._result = None
+
+ def fetchone(self):
+ """Fetches a single row from the cursor. None indicates that
+ no more rows are available."""
+ self._check_executed()
+ if self.rownumber >= len(self._rows): return None
+ result = self._rows[self.rownumber]
+ self.rownumber = self.rownumber+1
+ return result
+
+ def fetchmany(self, size=None):
+ """Fetch up to size rows from the cursor. Result set may be smaller
+ than size. If size is not defined, cursor.arraysize is used."""
+ self._check_executed()
+ end = self.rownumber + (size or self.arraysize)
+ result = self._rows[self.rownumber:end]
+ self.rownumber = min(end, len(self._rows))
+ return result
+
+ def fetchall(self):
+ """Fetchs all available rows from the cursor."""
+ self._check_executed()
+ if self.rownumber:
+ result = self._rows[self.rownumber:]
+ else:
+ result = self._rows
+ self.rownumber = len(self._rows)
+ return result
+
+ def scroll(self, value, mode='relative'):
+ """Scroll the cursor in the result set to a new position according
+ to mode.
+
+ If mode is 'relative' (default), value is taken as offset to
+ the current position in the result set, if set to 'absolute',
+ value states an absolute target position."""
+ self._check_executed()
+ if mode == 'relative':
+ r = self.rownumber + value
+ elif mode == 'absolute':
+ r = value
+ else:
+ self.errorhandler(self, ProgrammingError,
+ "unknown scroll mode %s" % repr(mode))
+ if r < 0 or r >= len(self._rows):
+ self.errorhandler(self, IndexError, "out of range")
+ self.rownumber = r
+
+ def __iter__(self):
+ self._check_executed()
+ result = self.rownumber and self._rows[self.rownumber:] or self._rows
+ return iter(result)
+
+
+class CursorUseResultMixIn(object):
+
+ """This is a MixIn class which causes the result set to be stored
+ in the server and sent row-by-row to client side, i.e. it uses
+ mysql_use_result(). You MUST retrieve the entire result set and
+ close() the cursor before additional queries can be peformed on
+ the connection."""
+
+ _defer_warnings = True
+
+ def _get_result(self): return self._get_db().use_result()
+
+ def fetchone(self):
+ """Fetches a single row from the cursor."""
+ self._check_executed()
+ r = self._fetch_row(1)
+ if not r:
+ self._warning_check()
+ return None
+ self.rownumber = self.rownumber + 1
+ return r[0]
+
+ def fetchmany(self, size=None):
+ """Fetch up to size rows from the cursor. Result set may be smaller
+ than size. If size is not defined, cursor.arraysize is used."""
+ self._check_executed()
+ r = self._fetch_row(size or self.arraysize)
+ self.rownumber = self.rownumber + len(r)
+ if not r:
+ self._warning_check()
+ return r
+
+ def fetchall(self):
+ """Fetchs all available rows from the cursor."""
+ self._check_executed()
+ r = self._fetch_row(0)
+ self.rownumber = self.rownumber + len(r)
+ self._warning_check()
+ return r
+
+ def __iter__(self):
+ return self
+
+ def next(self):
+ row = self.fetchone()
+ if row is None:
+ raise StopIteration
+ return row
+
+
+class CursorTupleRowsMixIn(object):
+
+ """This is a MixIn class that causes all rows to be returned as tuples,
+ which is the standard form required by DB API."""
+
+ _fetch_type = 0
+
+
+class CursorDictRowsMixIn(object):
+
+ """This is a MixIn class that causes all rows to be returned as
+ dictionaries. This is a non-standard feature."""
+
+ _fetch_type = 1
+
+ def fetchoneDict(self):
+ """Fetch a single row as a dictionary. Deprecated:
+ Use fetchone() instead. Will be removed in 1.3."""
+ from warnings import warn
+ warn("fetchoneDict() is non-standard and will be removed in 1.3",
+ DeprecationWarning, 2)
+ return self.fetchone()
+
+ def fetchmanyDict(self, size=None):
+ """Fetch several rows as a list of dictionaries. Deprecated:
+ Use fetchmany() instead. Will be removed in 1.3."""
+ from warnings import warn
+ warn("fetchmanyDict() is non-standard and will be removed in 1.3",
+ DeprecationWarning, 2)
+ return self.fetchmany(size)
+
+ def fetchallDict(self):
+ """Fetch all available rows as a list of dictionaries. Deprecated:
+ Use fetchall() instead. Will be removed in 1.3."""
+ from warnings import warn
+ warn("fetchallDict() is non-standard and will be removed in 1.3",
+ DeprecationWarning, 2)
+ return self.fetchall()
+
+
+class CursorOldDictRowsMixIn(CursorDictRowsMixIn):
+
+ """This is a MixIn class that returns rows as dictionaries with
+ the same key convention as the old Mysqldb (MySQLmodule). Don't
+ use this."""
+
+ _fetch_type = 2
+
+
+class Cursor(CursorStoreResultMixIn, CursorTupleRowsMixIn,
+ BaseCursor):
+
+ """This is the standard Cursor class that returns rows as tuples
+ and stores the result set in the client."""
+
+
+class DictCursor(CursorStoreResultMixIn, CursorDictRowsMixIn,
+ BaseCursor):
+
+ """This is a Cursor class that returns rows as dictionaries and
+ stores the result set in the client."""
+
+
+class SSCursor(CursorUseResultMixIn, CursorTupleRowsMixIn,
+ BaseCursor):
+
+ """This is a Cursor class that returns rows as tuples and stores
+ the result set in the server."""
+
+
+class SSDictCursor(CursorUseResultMixIn, CursorDictRowsMixIn,
+ BaseCursor):
+
+ """This is a Cursor class that returns rows as dictionaries and
+ stores the result set in the server."""
+
+
diff --git a/MySQLdb/MySQLdb/times.py b/MySQLdb/MySQLdb/times.py
index 35adc7b..be7b89c 100644
--- a/MySQLdb/MySQLdb/times.py
+++ b/MySQLdb/MySQLdb/times.py
@@ -1,101 +1,101 @@
-"""times module
-
-This module provides some Date and Time classes for dealing with MySQL data.
-
-Use Python datetime module to handle date and time columns."""
-
-import math
-from time import localtime
-from datetime import date, datetime, time, timedelta
-from _mysql import string_literal
-
-Date = date
-Time = time
-TimeDelta = timedelta
-Timestamp = datetime
-
-DateTimeDeltaType = timedelta
-DateTimeType = datetime
-
-def DateFromTicks(ticks):
- """Convert UNIX ticks into a date instance."""
- return date(*localtime(ticks)[:3])
-
-def TimeFromTicks(ticks):
- """Convert UNIX ticks into a time instance."""
- return time(*localtime(ticks)[3:6])
-
-def TimestampFromTicks(ticks):
- """Convert UNIX ticks into a datetime instance."""
- return datetime(*localtime(ticks)[:6])
-
-format_TIME = format_DATE = str
-
-def format_TIMEDELTA(v):
- seconds = int(v.seconds) % 60
- minutes = int(v.seconds / 60) % 60
- hours = int(v.seconds / 3600) % 24
- return '%d %d:%d:%d' % (v.days, hours, minutes, seconds)
-
-def format_TIMESTAMP(d):
- return d.isoformat(" ")
-
-
-def DateTime_or_None(s):
- if ' ' in s:
- sep = ' '
- elif 'T' in s:
- sep = 'T'
- else:
- return Date_or_None(s)
-
- try:
- d, t = s.split(sep, 1)
- return datetime(*[ int(x) for x in d.split('-')+t.split(':') ])
- except:
- return Date_or_None(s)
-
-def TimeDelta_or_None(s):
- try:
- h, m, s = s.split(':')
- h, m, s = int(h), int(m), float(s)
- td = timedelta(hours=abs(h), minutes=m, seconds=int(s),
- microseconds=int(math.modf(s)[0] * 1000000))
- if h < 0:
- return -td
- else:
- return td
- except ValueError:
- # unpacking or int/float conversion failed
- return None
-
-def Time_or_None(s):
- try:
- h, m, s = s.split(':')
- h, m, s = int(h), int(m), float(s)
- return time(hour=h, minute=m, second=int(s),
- microsecond=int(math.modf(s)[0] * 1000000))
- except ValueError:
- return None
-
-def Date_or_None(s):
- try: return date(*[ int(x) for x in s.split('-',2)])
- except: return None
-
-def DateTime2literal(d, c):
- """Format a DateTime object as an ISO timestamp."""
- return string_literal(format_TIMESTAMP(d),c)
-
-def DateTimeDelta2literal(d, c):
- """Format a DateTimeDelta object as a time."""
- return string_literal(format_TIMEDELTA(d),c)
-
-def mysql_timestamp_converter(s):
- """Convert a MySQL TIMESTAMP to a Timestamp object."""
- # MySQL>4.1 returns TIMESTAMP in the same format as DATETIME
- if s[4] == '-': return DateTime_or_None(s)
- s = s + "0"*(14-len(s)) # padding
- parts = map(int, filter(None, (s[:4],s[4:6],s[6:8],
- s[8:10],s[10:12],s[12:14])))
- try: return Timestamp(*parts)
- except: return None
+"""times module
+
+This module provides some Date and Time classes for dealing with MySQL data.
+
+Use Python datetime module to handle date and time columns."""
+
+import math
+from time import localtime
+from datetime import date, datetime, time, timedelta
+from _mysql import string_literal
+
+Date = date
+Time = time
+TimeDelta = timedelta
+Timestamp = datetime
+
+DateTimeDeltaType = timedelta
+DateTimeType = datetime
+
+def DateFromTicks(ticks):
+ """Convert UNIX ticks into a date instance."""
+ return date(*localtime(ticks)[:3])
+
+def TimeFromTicks(ticks):
+ """Convert UNIX ticks into a time instance."""
+ return time(*localtime(ticks)[3:6])
+
+def TimestampFromTicks(ticks):
+ """Convert UNIX ticks into a datetime instance."""
+ return datetime(*localtime(ticks)[:6])
+
+format_TIME = format_DATE = str
+
+def format_TIMEDELTA(v):
+ seconds = int(v.seconds) % 60
+ minutes = int(v.seconds / 60) % 60
+ hours = int(v.seconds / 3600) % 24
+ return '%d %d:%d:%d' % (v.days, hours, minutes, seconds)
+
+def format_TIMESTAMP(d):
+ return d.isoformat(" ")
+
+
+def DateTime_or_None(s):
+ if ' ' in s:
+ sep = ' '
+ elif 'T' in s:
+ sep = 'T'
+ else:
+ return Date_or_None(s)
+
+ try:
+ d, t = s.split(sep, 1)
+ return datetime(*[ int(x) for x in d.split('-')+t.split(':') ])
+ except:
+ return Date_or_None(s)
+
+def TimeDelta_or_None(s):
+ try:
+ h, m, s = s.split(':')
+ h, m, s = int(h), int(m), float(s)
+ td = timedelta(hours=abs(h), minutes=m, seconds=int(s),
+ microseconds=int(math.modf(s)[0] * 1000000))
+ if h < 0:
+ return -td
+ else:
+ return td
+ except ValueError:
+ # unpacking or int/float conversion failed
+ return None
+
+def Time_or_None(s):
+ try:
+ h, m, s = s.split(':')
+ h, m, s = int(h), int(m), float(s)
+ return time(hour=h, minute=m, second=int(s),
+ microsecond=int(math.modf(s)[0] * 1000000))
+ except ValueError:
+ return None
+
+def Date_or_None(s):
+ try: return date(*[ int(x) for x in s.split('-',2)])
+ except: return None
+
+def DateTime2literal(d, c):
+ """Format a DateTime object as an ISO timestamp."""
+ return string_literal(format_TIMESTAMP(d),c)
+
+def DateTimeDelta2literal(d, c):
+ """Format a DateTimeDelta object as a time."""
+ return string_literal(format_TIMEDELTA(d),c)
+
+def mysql_timestamp_converter(s):
+ """Convert a MySQL TIMESTAMP to a Timestamp object."""
+ # MySQL>4.1 returns TIMESTAMP in the same format as DATETIME
+ if s[4] == '-': return DateTime_or_None(s)
+ s = s + "0"*(14-len(s)) # padding
+ parts = map(int, filter(None, (s[:4],s[4:6],s[6:8],
+ s[8:10],s[10:12],s[12:14])))
+ try: return Timestamp(*parts)
+ except: return None
diff --git a/MySQLdb/README b/MySQLdb/README
index f44b410..322ae6d 100644
--- a/MySQLdb/README
+++ b/MySQLdb/README
@@ -1,253 +1,253 @@
-====================
-MySQLdb Installation
-====================
-
-.. contents::
-..
-
-Prerequisites
--------------
-
-+ Python 2.3.4 or higher
-
- * http://www.python.org/
-
- * Versions lower than 2.3 WON'T WORK.
-
- * 2.4 is the primary test environment.
-
- * Red Hat Linux:
-
- - Make sure you have the Python development headers and libraries
- (python-devel).
-
-+ setuptools
-
- * http://pypi.python.org/pypi/setuptools
-
-+ MySQL 3.23.32 or higher
-
- * http://www.mysql.com/downloads/
-
- * Versions lower than 3.22 definitely WON'T WORK.
-
- * Versions lower than 3.22.19 might not work.
-
- * MySQL-3.22 might work but isn't supported anymore. It's very old.
-
- * MySQL-3.23 ought to work, but it's pretty elderly.
-
- * MySQL-4.0 is supported, but not tested and slightly discouraged.
-
- * MySQL-4.1 is supported. The prepared statements API is not
- supported, and won't be until MySQLdb-1.3 or 2.0, if ever.
-
- * MySQL-5.0 is supported and tested, including stored procedures.
-
- * MySQL-5.1 is supported (currently a release candidate) but untested.
- It should work.
-
- * MySQL-6.0 is sorta-kinda-supported (currently alpha) but untested.
- It should work.
-
- * Drizzle <https://launchpad.net/drizzle> is a fork of MySQL. So far
- the C API looks really similar except everything is renamed.
- Drizzle support probably won't happen in 1.2. There may be have to
- be an entirely different module, but still using DB-API.
-
- * MaxDB, formerly known as SAP DB (and maybe Adabas D?), is a
- completely different animal. Use the sapdb.sql module that comes
- with MaxDB.
-
- * Red Hat Linux packages:
-
- - mysql-devel to compile
-
- - mysql and/or mysql-devel to run
-
- * MySQL.com RPM packages:
-
- - MySQL-devel to compile
-
- - MySQL-shared if you want to use their shared
- library. Otherwise you'll get a statically-linked module,
- which may or may not be what you want.
-
- - MySQL-shared to run if you compiled with MySQL-shared installed
-
- * Transactions (particularly InnoDB tables) are supported for
- MySQL-3.23 and up. You may need a special package from your vendor
- with this support turned on.
-
-+ zlib
-
- * Required for MySQL-3.23 and newer.
-
- * Red Hat Linux
-
- - zlib-devel to compile
-
- - zlib to run
-
-+ openssl
-
- * May be needed for MySQL-4.0 or newer, depending on compilation
- options. If you need it, you probably already have it.
-
- - you may need openssl-devel on some platforms
-
-+ C compiler
-
- * Most free software-based systems already have this, usually gcc.
-
- * Most commercial UNIX platforms also come with a C compiler, or
- you can also use gcc.
-
- * If you have some Windows flavor, you usually have to pay extra
- for this, or you can use Cygwin_.
-
-.. _Cygwin: http://www.cygwin.com/
-
-
-Building and installing
------------------------
-
-The setup.py script uses mysql_config to find all compiler and linker
-options, and should work as is on any POSIX-like platform, so long as
-mysql_config is in your path.
-
-Depending on which version of MySQL you have, you may have the option
-of using three different client libraries. To select the client library,
-edit the [options] section of site.cfg:
-
- embedded
- use embedded server library (libmysqld) if True; otherwise use
- one of the client libraries (default).
-
- threadsafe
- thread-safe client library (libmysqlclient_r) if True (default);
- otherwise use non-thread-safe (libmysqlclient). You should
- always use the thread-safe library if you have the option;
- otherwise you *may* have problems.
-
- static
- if True, try to link against a static library; otherwise link
- against dynamic libraries (default). You may need static linking
- to use the embedded server.
-
-
-Finally, putting it together::
-
- $ tar xfz MySQL-python-1.2.1.tar.gz
- $ cd MySQL-python-1.2.1
- $ # edit site.cfg if necessary
- $ python setup.py build
- $ sudo python setup.py install # or su first
-
-
-Windows
-.......
-
-I don't do Windows. However if someone provides me with a package for
-Windows, I'll make it available. Don't ask me for help with Windows
-because I can't help you.
-
-Generally, though, running setup.py is similar to above::
-
- C:\...> python setup.py install
- C:\...> python setup.py bdist_wininst
-
-The latter example should build a Windows installer package, if you
-have the correct tools. In any event, you *must* have a C compiler.
-Additionally, you have to set an environment variable (mysqlroot)
-which is the path to your MySQL installation. In theory, it would be
-possible to get this information out of the registry, but like I said,
-I don't do Windows, but I'll accept a patch that does this.
-
-On Windows, you will definitely have to edit site.cfg since there is
-no mysql_config in the MySQL package.
-
-
-Zope
-....
-
-If you are using a binary package of Zope, you need run setup.py with
-the python executable that came with Zope. Otherwise, you'll install
-into the wrong Python tree and Zope (ZMySQLDA) will not be able to
-find _mysql.
-
-
-Binary Packages
----------------
-
-I don't plan to make binary packages any more. However, if someone
-contributes one, I will make it available. Several OS vendors have
-their own packages available.
-
-
-RPMs
-....
-
-If you prefer to install RPMs, you can use the bdist_rpm command with
-setup.py. This only builds the RPM; it does not install it. You may
-want to use the --python=XXX option, where XXX is the name of the
-Python executable, i.e. python, python2, python2.4; the default is
-python. Using this will incorporate the Python executable name into
-the package name for the RPM so you have install the package multiple
-times if you need to support more than one version of Python. You can
-also set this in setup.cfg.
-
-
-Red Hat Linux
-.............
-
-MySQL-python is pre-packaged in Red Hat Linux 7.x and newer. This
-includes Fedora Core and Red Hat Enterprise Linux. You can also
-build your own RPM packages as described above.
-
-
-Debian GNU/Linux
-................
-
-Packaged as `python-mysqldb`_::
-
- # apt-get install python-mysqldb
-
-Or use Synaptic.
-
-.. _`python-mysqldb`: http://packages.debian.org/python-mysqldb
-
-
-Ubuntu
-......
-
-Same as with Debian.
-
-
-Gentoo Linux
-............
-
-Packaged as `mysql-python`_. ::
-
- # emerge sync
- # emerge mysql-python
- # emerge zmysqlda # if you use Zope
-
-.. _`mysql-python`: http://packages.gentoo.org/search/?sstring=mysql-python
-
-
-BSD
-...
-
-MySQL-python is a ported package in FreeBSD, NetBSD, and OpenBSD,
-although the name may vary to match OS conventions.
-
-
-License
--------
-
-GPL or the original license based on Python 1.5.2's license.
-
-
-:Author: Andy Dustman <andy@dustman.net>
-:Revision: $Id$
+====================
+MySQLdb Installation
+====================
+
+.. contents::
+..
+
+Prerequisites
+-------------
+
++ Python 2.3.4 or higher
+
+ * http://www.python.org/
+
+ * Versions lower than 2.3 WON'T WORK.
+
+ * 2.4 is the primary test environment.
+
+ * Red Hat Linux:
+
+ - Make sure you have the Python development headers and libraries
+ (python-devel).
+
++ setuptools
+
+ * http://pypi.python.org/pypi/setuptools
+
++ MySQL 3.23.32 or higher
+
+ * http://www.mysql.com/downloads/
+
+ * Versions lower than 3.22 definitely WON'T WORK.
+
+ * Versions lower than 3.22.19 might not work.
+
+ * MySQL-3.22 might work but isn't supported anymore. It's very old.
+
+ * MySQL-3.23 ought to work, but it's pretty elderly.
+
+ * MySQL-4.0 is supported, but not tested and slightly discouraged.
+
+ * MySQL-4.1 is supported. The prepared statements API is not
+ supported, and won't be until MySQLdb-1.3 or 2.0, if ever.
+
+ * MySQL-5.0 is supported and tested, including stored procedures.
+
+ * MySQL-5.1 is supported (currently a release candidate) but untested.
+ It should work.
+
+ * MySQL-6.0 is sorta-kinda-supported (currently alpha) but untested.
+ It should work.
+
+ * Drizzle <https://launchpad.net/drizzle> is a fork of MySQL. So far
+ the C API looks really similar except everything is renamed.
+ Drizzle support probably won't happen in 1.2. There may be have to
+ be an entirely different module, but still using DB-API.
+
+ * MaxDB, formerly known as SAP DB (and maybe Adabas D?), is a
+ completely different animal. Use the sapdb.sql module that comes
+ with MaxDB.
+
+ * Red Hat Linux packages:
+
+ - mysql-devel to compile
+
+ - mysql and/or mysql-devel to run
+
+ * MySQL.com RPM packages:
+
+ - MySQL-devel to compile
+
+ - MySQL-shared if you want to use their shared
+ library. Otherwise you'll get a statically-linked module,
+ which may or may not be what you want.
+
+ - MySQL-shared to run if you compiled with MySQL-shared installed
+
+ * Transactions (particularly InnoDB tables) are supported for
+ MySQL-3.23 and up. You may need a special package from your vendor
+ with this support turned on.
+
++ zlib
+
+ * Required for MySQL-3.23 and newer.
+
+ * Red Hat Linux
+
+ - zlib-devel to compile
+
+ - zlib to run
+
++ openssl
+
+ * May be needed for MySQL-4.0 or newer, depending on compilation
+ options. If you need it, you probably already have it.
+
+ - you may need openssl-devel on some platforms
+
++ C compiler
+
+ * Most free software-based systems already have this, usually gcc.
+
+ * Most commercial UNIX platforms also come with a C compiler, or
+ you can also use gcc.
+
+ * If you have some Windows flavor, you usually have to pay extra
+ for this, or you can use Cygwin_.
+
+.. _Cygwin: http://www.cygwin.com/
+
+
+Building and installing
+-----------------------
+
+The setup.py script uses mysql_config to find all compiler and linker
+options, and should work as is on any POSIX-like platform, so long as
+mysql_config is in your path.
+
+Depending on which version of MySQL you have, you may have the option
+of using three different client libraries. To select the client library,
+edit the [options] section of site.cfg:
+
+ embedded
+ use embedded server library (libmysqld) if True; otherwise use
+ one of the client libraries (default).
+
+ threadsafe
+ thread-safe client library (libmysqlclient_r) if True (default);
+ otherwise use non-thread-safe (libmysqlclient). You should
+ always use the thread-safe library if you have the option;
+ otherwise you *may* have problems.
+
+ static
+ if True, try to link against a static library; otherwise link
+ against dynamic libraries (default). You may need static linking
+ to use the embedded server.
+
+
+Finally, putting it together::
+
+ $ tar xfz MySQL-python-1.2.1.tar.gz
+ $ cd MySQL-python-1.2.1
+ $ # edit site.cfg if necessary
+ $ python setup.py build
+ $ sudo python setup.py install # or su first
+
+
+Windows
+.......
+
+I don't do Windows. However if someone provides me with a package for
+Windows, I'll make it available. Don't ask me for help with Windows
+because I can't help you.
+
+Generally, though, running setup.py is similar to above::
+
+ C:\...> python setup.py install
+ C:\...> python setup.py bdist_wininst
+
+The latter example should build a Windows installer package, if you
+have the correct tools. In any event, you *must* have a C compiler.
+Additionally, you have to set an environment variable (mysqlroot)
+which is the path to your MySQL installation. In theory, it would be
+possible to get this information out of the registry, but like I said,
+I don't do Windows, but I'll accept a patch that does this.
+
+On Windows, you will definitely have to edit site.cfg since there is
+no mysql_config in the MySQL package.
+
+
+Zope
+....
+
+If you are using a binary package of Zope, you need run setup.py with
+the python executable that came with Zope. Otherwise, you'll install
+into the wrong Python tree and Zope (ZMySQLDA) will not be able to
+find _mysql.
+
+
+Binary Packages
+---------------
+
+I don't plan to make binary packages any more. However, if someone
+contributes one, I will make it available. Several OS vendors have
+their own packages available.
+
+
+RPMs
+....
+
+If you prefer to install RPMs, you can use the bdist_rpm command with
+setup.py. This only builds the RPM; it does not install it. You may
+want to use the --python=XXX option, where XXX is the name of the
+Python executable, i.e. python, python2, python2.4; the default is
+python. Using this will incorporate the Python executable name into
+the package name for the RPM so you have install the package multiple
+times if you need to support more than one version of Python. You can
+also set this in setup.cfg.
+
+
+Red Hat Linux
+.............
+
+MySQL-python is pre-packaged in Red Hat Linux 7.x and newer. This
+includes Fedora Core and Red Hat Enterprise Linux. You can also
+build your own RPM packages as described above.
+
+
+Debian GNU/Linux
+................
+
+Packaged as `python-mysqldb`_::
+
+ # apt-get install python-mysqldb
+
+Or use Synaptic.
+
+.. _`python-mysqldb`: http://packages.debian.org/python-mysqldb
+
+
+Ubuntu
+......
+
+Same as with Debian.
+
+
+Gentoo Linux
+............
+
+Packaged as `mysql-python`_. ::
+
+ # emerge sync
+ # emerge mysql-python
+ # emerge zmysqlda # if you use Zope
+
+.. _`mysql-python`: http://packages.gentoo.org/search/?sstring=mysql-python
+
+
+BSD
+...
+
+MySQL-python is a ported package in FreeBSD, NetBSD, and OpenBSD,
+although the name may vary to match OS conventions.
+
+
+License
+-------
+
+GPL or the original license based on Python 1.5.2's license.
+
+
+:Author: Andy Dustman <andy@dustman.net>
+:Revision: $Id$
diff --git a/MySQLdb/_mysql.c b/MySQLdb/_mysql.c
index 63e990f..2e75415 100644
--- a/MySQLdb/_mysql.c
+++ b/MySQLdb/_mysql.c
@@ -1,3079 +1,3079 @@
-/*
-This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version. Alternatively, you may use the original license
-reproduced below.
-
-Copyright 1999 by Comstar.net, Inc., Atlanta, GA, US.
-
- All Rights Reserved
-
-Permission to use, copy, modify, and distribute this software and its
-documentation for any purpose and without fee is hereby granted,
-provided that the above copyright notice appear in all copies and that
-both that copyright notice and this permission notice appear in
-supporting documentation, and that the name of Comstar.net, Inc.
-or COMSTAR not be used in advertising or publicity pertaining to
-distribution of the software without specific, written prior permission.
-
-COMSTAR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
-INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
-EVENT SHALL COMSTAR BE LIABLE FOR ANY SPECIAL, INDIRECT OR
-CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
-USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
-OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-PERFORMANCE OF THIS SOFTWARE.
-*/
-
-#include "Python.h"
-#if PY_MAJOR_VERSION >= 3
-#define IS_PY3K
-#define PyInt_FromLong(n) PyLong_FromLong(n)
-#define PyInt_Check(n) PyLong_Check(n)
-#define PyInt_AS_LONG(n) PyLong_AS_LONG(n)
-#endif
-#if PY_VERSION_HEX > 0x02060000
-#include "bytesobject.h"
-#endif
-#include "pymemcompat.h"
-#include "structmember.h"
-#if defined(MS_WINDOWS)
-#include <config-win.h>
-#else
-#include "my_config.h"
-#endif
-#include "mysql.h"
-#include "mysqld_error.h"
-#include "errmsg.h"
-
-#if PY_VERSION_HEX < 0x02020000
-# define MyTuple_Resize(t,n,d) _PyTuple_Resize(t, n, d)
-# define MyMember(a,b,c,d,e) {a,b,c,d}
-# define MyMemberlist(x) struct memberlist x
-# define MyAlloc(s,t) PyObject_New(s,&t)
-# define MyFree(o) PyObject_Del(o)
-#else
-# define MyTuple_Resize(t,n,d) _PyTuple_Resize(t, n)
-# define MyMember(a,b,c,d,e) {a,b,c,d,e}
-# define MyMemberlist(x) struct PyMemberDef x
-# define MyAlloc(s,t) (s *) t.tp_alloc(&t,0)
-#ifdef IS_PY3K
-# define MyFree(o) PyObject_Del(o)
-#else
-# define MyFree(ob) ob->ob_type->tp_free((PyObject *)ob)
-#endif
-#endif
-
-#if PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN)
-typedef int Py_ssize_t;
-#define PY_SSIZE_T_MAX INT_MAX
-#define PY_SSIZE_T_MIN INT_MIN
-#endif
-
-static PyObject *_mysql_MySQLError;
-static PyObject *_mysql_Warning;
-static PyObject *_mysql_Error;
-static PyObject *_mysql_DatabaseError;
-static PyObject *_mysql_InterfaceError;
-static PyObject *_mysql_DataError;
-static PyObject *_mysql_OperationalError;
-static PyObject *_mysql_IntegrityError;
-static PyObject *_mysql_InternalError;
-static PyObject *_mysql_ProgrammingError;
-static PyObject *_mysql_NotSupportedError;
-
-typedef struct {
- PyObject_HEAD
- MYSQL connection;
- int open;
- PyObject *converter;
-} _mysql_ConnectionObject;
-
-#define check_connection(c) if (!(c->open)) return _mysql_Exception(c)
-#define result_connection(r) ((_mysql_ConnectionObject *)r->conn)
-#define check_result_connection(r) check_connection(result_connection(r))
-
-extern PyTypeObject _mysql_ConnectionObject_Type;
-
-typedef struct {
- PyObject_HEAD
- PyObject *conn;
- MYSQL_RES *result;
- int nfields;
- int use;
- PyObject *converter;
-} _mysql_ResultObject;
-
-extern PyTypeObject _mysql_ResultObject_Type;
-
-static int _mysql_server_init_done = 0;
-#if MYSQL_VERSION_ID >= 40000
-#define check_server_init(x) if (!_mysql_server_init_done) { if (mysql_server_init(0, NULL, NULL)) { _mysql_Exception(NULL); return x; } else { _mysql_server_init_done = 1;} }
-#else
-#define check_server_init(x) if (!_mysql_server_init_done) _mysql_server_init_done = 1
-#endif
-
-#if MYSQL_VERSION_ID >= 50500
-#define HAVE_OPENSSL 1
-#endif
-
-PyObject *
-_mysql_Exception(_mysql_ConnectionObject *c)
-{
- PyObject *t, *e;
- int merr;
-
- if (!(t = PyTuple_New(2))) return NULL;
- if (!_mysql_server_init_done) {
- e = _mysql_InternalError;
- PyTuple_SET_ITEM(t, 0, PyInt_FromLong(-1L));
-#ifdef IS_PY3K
- PyTuple_SET_ITEM(t, 1, PyUnicode_FromString("server not initialized"));
-#else
- PyTuple_SET_ITEM(t, 1, PyString_FromString("server not initialized"));
-#endif
- PyErr_SetObject(e, t);
- Py_DECREF(t);
- return NULL;
- }
- merr = mysql_errno(&(c->connection));
- if (!merr)
- e = _mysql_InterfaceError;
- else if (merr > CR_MAX_ERROR) {
- PyTuple_SET_ITEM(t, 0, PyInt_FromLong(-1L));
-#ifdef IS_PY3K
- PyTuple_SET_ITEM(t, 1, PyUnicode_FromString("error totally whack"));
-#else
- PyTuple_SET_ITEM(t, 1, PyString_FromString("error totally whack"));
-#endif
- PyErr_SetObject(_mysql_InterfaceError, t);
- Py_DECREF(t);
- return NULL;
- }
- else switch (merr) {
- case CR_COMMANDS_OUT_OF_SYNC:
- case ER_DB_CREATE_EXISTS:
- case ER_SYNTAX_ERROR:
- case ER_PARSE_ERROR:
- case ER_NO_SUCH_TABLE:
- case ER_WRONG_DB_NAME:
- case ER_WRONG_TABLE_NAME:
- case ER_FIELD_SPECIFIED_TWICE:
- case ER_INVALID_GROUP_FUNC_USE:
- case ER_UNSUPPORTED_EXTENSION:
- case ER_TABLE_MUST_HAVE_COLUMNS:
-#ifdef ER_CANT_DO_THIS_DURING_AN_TRANSACTION
- case ER_CANT_DO_THIS_DURING_AN_TRANSACTION:
-#endif
- e = _mysql_ProgrammingError;
- break;
-#ifdef WARN_DATA_TRUNCATED
- case WARN_DATA_TRUNCATED:
-#ifdef WARN_NULL_TO_NOTNULL
- case WARN_NULL_TO_NOTNULL:
-#endif
-#ifdef ER_WARN_DATA_OUT_OF_RANGE
- case ER_WARN_DATA_OUT_OF_RANGE:
-#endif
-#ifdef ER_NO_DEFAULT
- case ER_NO_DEFAULT:
-#endif
-#ifdef ER_PRIMARY_CANT_HAVE_NULL
- case ER_PRIMARY_CANT_HAVE_NULL:
-#endif
-#ifdef ER_DATA_TOO_LONG
- case ER_DATA_TOO_LONG:
-#endif
-#ifdef ER_DATETIME_FUNCTION_OVERFLOW
- case ER_DATETIME_FUNCTION_OVERFLOW:
-#endif
- e = _mysql_DataError;
- break;
-#endif
- case ER_DUP_ENTRY:
-#ifdef ER_DUP_UNIQUE
- case ER_DUP_UNIQUE:
-#endif
-#ifdef ER_NO_REFERENCED_ROW
- case ER_NO_REFERENCED_ROW:
-#endif
-#ifdef ER_NO_REFERENCED_ROW_2
- case ER_NO_REFERENCED_ROW_2:
-#endif
-#ifdef ER_ROW_IS_REFERENCED
- case ER_ROW_IS_REFERENCED:
-#endif
-#ifdef ER_ROW_IS_REFERENCED_2
- case ER_ROW_IS_REFERENCED_2:
-#endif
-#ifdef ER_CANNOT_ADD_FOREIGN
- case ER_CANNOT_ADD_FOREIGN:
-#endif
- e = _mysql_IntegrityError;
- break;
-#ifdef ER_WARNING_NOT_COMPLETE_ROLLBACK
- case ER_WARNING_NOT_COMPLETE_ROLLBACK:
-#endif
-#ifdef ER_NOT_SUPPORTED_YET
- case ER_NOT_SUPPORTED_YET:
-#endif
-#ifdef ER_FEATURE_DISABLED
- case ER_FEATURE_DISABLED:
-#endif
-#ifdef ER_UNKNOWN_STORAGE_ENGINE
- case ER_UNKNOWN_STORAGE_ENGINE:
-#endif
- e = _mysql_NotSupportedError;
- break;
- default:
- if (merr < 1000)
- e = _mysql_InternalError;
- else
- e = _mysql_OperationalError;
- break;
- }
- PyTuple_SET_ITEM(t, 0, PyInt_FromLong((long)merr));
-#ifdef IS_PY3K
- PyTuple_SET_ITEM(t, 1, PyUnicode_FromString(mysql_error(&(c->connection))));
-#else
- PyTuple_SET_ITEM(t, 1, PyString_FromString(mysql_error(&(c->connection))));
-#endif
- PyErr_SetObject(e, t);
- Py_DECREF(t);
- return NULL;
-}
-
-static char _mysql_server_init__doc__[] =
-"Initialize embedded server. If this client is not linked against\n\
-the embedded server library, this function does nothing.\n\
-\n\
-args -- sequence of command-line arguments\n\
-groups -- sequence of groups to use in defaults files\n\
-";
-
-static PyObject *_mysql_server_init(
- PyObject *self,
- PyObject *args,
- PyObject *kwargs) {
- static char *kwlist[] = {"args", "groups", NULL};
- char **cmd_args_c=NULL, **groups_c=NULL, *s;
- int cmd_argc=0, i, groupc;
- PyObject *cmd_args=NULL, *groups=NULL, *ret=NULL, *item;
-
- if (_mysql_server_init_done) {
- PyErr_SetString(_mysql_ProgrammingError,
- "already initialized");
- return NULL;
- }
-
- if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OO", kwlist,
- &cmd_args, &groups))
- return NULL;
-
-#if MYSQL_VERSION_ID >= 40000
- if (cmd_args) {
- if (!PySequence_Check(cmd_args)) {
- PyErr_SetString(PyExc_TypeError,
- "args must be a sequence");
- goto finish;
- }
- cmd_argc = PySequence_Size(cmd_args);
- if (cmd_argc == -1) {
- PyErr_SetString(PyExc_TypeError,
- "args could not be sized");
- goto finish;
- }
- cmd_args_c = (char **) PyMem_Malloc(cmd_argc*sizeof(char *));
- for (i=0; i< cmd_argc; i++) {
- item = PySequence_GetItem(cmd_args, i);
-#ifdef IS_PY3K
- s = PyUnicode_AS_DATA(item);
-#else
- s = PyString_AsString(item);
-#endif
-
- Py_DECREF(item);
- if (!s) {
- PyErr_SetString(PyExc_TypeError,
- "args must contain strings");
- goto finish;
- }
- cmd_args_c[i] = s;
- }
- }
- if (groups) {
- if (!PySequence_Check(groups)) {
- PyErr_SetString(PyExc_TypeError,
- "groups must be a sequence");
- goto finish;
- }
- groupc = PySequence_Size(groups);
- if (groupc == -1) {
- PyErr_SetString(PyExc_TypeError,
- "groups could not be sized");
- goto finish;
- }
- groups_c = (char **) PyMem_Malloc((1+groupc)*sizeof(char *));
- for (i=0; i< groupc; i++) {
- item = PySequence_GetItem(groups, i);
-#ifdef IS_PY3K
- s = PyUnicode_AS_DATA(item);
-#else
- s = PyString_AsString(item);
-#endif
- Py_DECREF(item);
- if (!s) {
- PyErr_SetString(PyExc_TypeError,
- "groups must contain strings");
- goto finish;
- }
- groups_c[i] = s;
- }
- groups_c[groupc] = (char *)NULL;
- }
- /* even though this may block, don't give up the interpreter lock
- so that the server can't be initialized multiple times. */
- if (mysql_server_init(cmd_argc, cmd_args_c, groups_c)) {
- _mysql_Exception(NULL);
- goto finish;
- }
-#endif
- ret = Py_None;
- Py_INCREF(Py_None);
- _mysql_server_init_done = 1;
- finish:
- PyMem_Free(groups_c);
- PyMem_Free(cmd_args_c);
- return ret;
-}
-
-static char _mysql_server_end__doc__[] =
-"Shut down embedded server. If not using an embedded server, this\n\
-does nothing.";
-
-static PyObject *_mysql_server_end(
- PyObject *self,
- PyObject *args) {
- if (_mysql_server_init_done) {
-#if MYSQL_VERSION_ID >= 40000
- mysql_server_end();
-#endif
- _mysql_server_init_done = 0;
- Py_INCREF(Py_None);
- return Py_None;
- }
- return _mysql_Exception(NULL);
-}
-
-#if MYSQL_VERSION_ID >= 32314
-static char _mysql_thread_safe__doc__[] =
-"Indicates whether the client is compiled as thread-safe.";
-
-static PyObject *_mysql_thread_safe(
- PyObject *self,
- PyObject *args) {
- PyObject *flag;
- if (!PyArg_ParseTuple(args, "")) return NULL;
- check_server_init(NULL);
- if (!(flag=PyInt_FromLong((long)mysql_thread_safe()))) return NULL;
- return flag;
-}
-#endif
-
-static char _mysql_ResultObject__doc__[] =
-"result(connection, use=0, converter={}) -- Result set from a query.\n\
-\n\
-Creating instances of this class directly is an excellent way to\n\
-shoot yourself in the foot. If using _mysql.connection directly,\n\
-use connection.store_result() or connection.use_result() instead.\n\
-If using MySQLdb.Connection, this is done by the cursor class.\n\
-Just forget you ever saw this. Forget... FOR-GET...";
-
-static int
-_mysql_ResultObject_Initialize(
- _mysql_ResultObject *self,
- PyObject *args,
- PyObject *kwargs)
-{
- static char *kwlist[] = {"connection", "use", "converter", NULL};
- MYSQL_RES *result;
- _mysql_ConnectionObject *conn=NULL;
- int use=0;
- PyObject *conv=NULL;
- int n, i;
- MYSQL_FIELD *fields;
-
- if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|iO", kwlist,
- &conn, &use, &conv))
- return -1;
- if (!conv) conv = PyDict_New();
- if (!conv) return -1;
- self->conn = (PyObject *) conn;
- Py_INCREF(conn);
- self->use = use;
- Py_BEGIN_ALLOW_THREADS ;
- if (use)
- result = mysql_use_result(&(conn->connection));
- else
- result = mysql_store_result(&(conn->connection));
- self->result = result;
- Py_END_ALLOW_THREADS ;
- if (!result) {
- if (mysql_field_count(&(conn->connection)) > 0) {
- _mysql_Exception(conn);
- return -1;
- }
- self->converter = PyTuple_New(0);
- return 0;
- }
- n = mysql_num_fields(result);
- self->nfields = n;
- if (!(self->converter = PyTuple_New(n))) return -1;
- fields = mysql_fetch_fields(result);
- for (i=0; i<n; i++) {
- PyObject *tmp, *fun;
- tmp = PyInt_FromLong((long) fields[i].type);
- if (!tmp) return -1;
- fun = PyObject_GetItem(conv, tmp);
- Py_DECREF(tmp);
- if (!fun) {
- PyErr_Clear();
- fun = Py_None;
- Py_INCREF(Py_None);
- }
- if (PySequence_Check(fun)) {
- int j, n2=PySequence_Size(fun);
- PyObject *fun2=NULL;
- for (j=0; j<n2; j++) {
- PyObject *t = PySequence_GetItem(fun, j);
- if (!t) continue;
- if (!PyTuple_Check(t)) goto cleanup;
- if (PyTuple_GET_SIZE(t) == 2) {
- long mask;
- PyObject *pmask=NULL;
- pmask = PyTuple_GET_ITEM(t, 0);
- fun2 = PyTuple_GET_ITEM(t, 1);
- if (PyInt_Check(pmask)) {
- mask = PyInt_AS_LONG(pmask);
- if (mask & fields[i].flags) {
- Py_DECREF(t);
- break;
- }
- else {
- goto cleanup;
- }
- } else {
- Py_DECREF(t);
- break;
- }
- }
- cleanup:
- Py_DECREF(t);
- }
- if (!fun2) fun2 = Py_None;
- Py_INCREF(fun2);
- Py_DECREF(fun);
- fun = fun2;
- }
- PyTuple_SET_ITEM(self->converter, i, fun);
- }
- return 0;
-}
-
-#if PY_VERSION_HEX >= 0x02020000
-static int _mysql_ResultObject_traverse(
- _mysql_ResultObject *self,
- visitproc visit,
- void *arg)
-{
- int r;
- if (self->converter) {
- if (!(r = visit(self->converter, arg))) return r;
- }
- if (self->conn)
- return visit(self->conn, arg);
- return 0;
-}
-#endif
-
-static int _mysql_ResultObject_clear(
- _mysql_ResultObject *self)
-{
- Py_XDECREF(self->converter);
- self->converter = NULL;
- Py_XDECREF(self->conn);
- self->conn = NULL;
- return 0;
-}
-
-static int
-_mysql_ConnectionObject_Initialize(
- _mysql_ConnectionObject *self,
- PyObject *args,
- PyObject *kwargs)
-{
- MYSQL *conn = NULL;
- PyObject *conv = NULL;
- PyObject *ssl = NULL;
-#if HAVE_OPENSSL
- char *key = NULL, *cert = NULL, *ca = NULL,
- *capath = NULL, *cipher = NULL;
-#endif
- char *host = NULL, *user = NULL, *passwd = NULL,
- *db = NULL, *unix_socket = NULL;
- unsigned int port = 0;
- unsigned int client_flag = 0;
- static char *kwlist[] = { "host", "user", "passwd", "db", "port",
- "unix_socket", "conv",
- "connect_timeout", "compress",
- "named_pipe", "init_command",
- "read_default_file", "read_default_group",
- "client_flag", "ssl",
- "local_infile",
- NULL } ;
- int connect_timeout = 0;
- int compress = -1, named_pipe = -1, local_infile = -1;
- char *init_command=NULL,
- *read_default_file=NULL,
- *read_default_group=NULL;
-
- self->converter = NULL;
- self->open = 0;
- check_server_init(-1);
- if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|ssssisOiiisssiOi:connect",
- kwlist,
- &host, &user, &passwd, &db,
- &port, &unix_socket, &conv,
- &connect_timeout,
- &compress, &named_pipe,
- &init_command, &read_default_file,
- &read_default_group,
- &client_flag, &ssl,
- &local_infile /* DO NOT PATCH FOR RECONNECT, IDIOTS
- IF YOU DO THIS, I WILL NOT SUPPORT YOUR PACKAGES. */
- ))
- return -1;
-
-#ifdef IS_PY3K
-#define _stringsuck(d,t,s) {t=PyMapping_GetItemString(s,#d);\
- if(t){d=PyUnicode_AS_DATA(t);Py_DECREF(t);}\
- PyErr_Clear();}
-#else
-#define _stringsuck(d,t,s) {t=PyMapping_GetItemString(s,#d);\
- if(t){d=PyString_AsString(t);Py_DECREF(t);}\
- PyErr_Clear();}
-#endif
-
- if (ssl) {
-#if HAVE_OPENSSL
- PyObject *value = NULL;
- _stringsuck(ca, value, ssl);
- _stringsuck(capath, value, ssl);
- _stringsuck(cert, value, ssl);
- _stringsuck(key, value, ssl);
- _stringsuck(cipher, value, ssl);
-#else
- PyErr_SetString(_mysql_NotSupportedError,
- "client library does not have SSL support");
- return -1;
-#endif
- }
-
- Py_BEGIN_ALLOW_THREADS ;
- conn = mysql_init(&(self->connection));
- if (connect_timeout) {
- unsigned int timeout = connect_timeout;
- mysql_options(&(self->connection), MYSQL_OPT_CONNECT_TIMEOUT,
- (char *)&timeout);
- }
- if (compress != -1) {
- mysql_options(&(self->connection), MYSQL_OPT_COMPRESS, 0);
- client_flag |= CLIENT_COMPRESS;
- }
- if (named_pipe != -1)
- mysql_options(&(self->connection), MYSQL_OPT_NAMED_PIPE, 0);
- if (init_command != NULL)
- mysql_options(&(self->connection), MYSQL_INIT_COMMAND, init_command);
- if (read_default_file != NULL)
- mysql_options(&(self->connection), MYSQL_READ_DEFAULT_FILE, read_default_file);
- if (read_default_group != NULL)
- mysql_options(&(self->connection), MYSQL_READ_DEFAULT_GROUP, read_default_group);
-
- if (local_infile != -1)
- mysql_options(&(self->connection), MYSQL_OPT_LOCAL_INFILE, (char *) &local_infile);
-
-#if HAVE_OPENSSL
- if (ssl)
- mysql_ssl_set(&(self->connection),
- key, cert, ca, capath, cipher);
-#endif
-
- conn = mysql_real_connect(&(self->connection), host, user, passwd, db,
- port, unix_socket, client_flag);
-
- Py_END_ALLOW_THREADS ;
-
- if (!conn) {
- _mysql_Exception(self);
- return -1;
- }
-
- /* Internal references to python-land objects */
- if (!conv)
- conv = PyDict_New();
- else
- Py_INCREF(conv);
-
- if (!conv)
- return -1;
- self->converter = conv;
-
- /*
- PyType_GenericAlloc() automatically sets up GC allocation and
- tracking for GC objects, at least in 2.2.1, so it does not need to
- be done here. tp_dealloc still needs to call PyObject_GC_UnTrack(),
- however.
- */
- self->open = 1;
- return 0;
-}
-
-static char _mysql_connect__doc__[] =
-"Returns a MYSQL connection object. Exclusive use of\n\
-keyword parameters strongly recommended. Consult the\n\
-MySQL C API documentation for more details.\n\
-\n\
-host\n\
- string, host to connect\n\
-\n\
-user\n\
- string, user to connect as\n\
-\n\
-passwd\n\
- string, password to use\n\
-\n\
-db\n\
- string, database to use\n\
-\n\
-port\n\
- integer, TCP/IP port to connect to\n\
-\n\
-unix_socket\n\
- string, location of unix_socket (UNIX-ish only)\n\
-\n\
-conv\n\
- mapping, maps MySQL FIELD_TYPE.* to Python functions which\n\
- convert a string to the appropriate Python type\n\
-\n\
-connect_timeout\n\
- number of seconds to wait before the connection\n\
- attempt fails.\n\
-\n\
-compress\n\
- if set, gzip compression is enabled\n\
-\n\
-named_pipe\n\
- if set, connect to server via named pipe (Windows only)\n\
-\n\
-init_command\n\
- command which is run once the connection is created\n\
-\n\
-read_default_file\n\
- see the MySQL documentation for mysql_options()\n\
-\n\
-read_default_group\n\
- see the MySQL documentation for mysql_options()\n\
-\n\
-client_flag\n\
- client flags from MySQLdb.constants.CLIENT\n\
-\n\
-load_infile\n\
- int, non-zero enables LOAD LOCAL INFILE, zero disables\n\
-\n\
-";
-
-static PyObject *
-_mysql_connect(
- PyObject *self,
- PyObject *args,
- PyObject *kwargs)
-{
- _mysql_ConnectionObject *c=NULL;
-
- c = MyAlloc(_mysql_ConnectionObject, _mysql_ConnectionObject_Type);
- if (c == NULL) return NULL;
- if (_mysql_ConnectionObject_Initialize(c, args, kwargs)) {
- Py_DECREF(c);
- c = NULL;
- }
- return (PyObject *) c;
-}
-
-#if PY_VERSION_HEX >= 0x02020000
-static int _mysql_ConnectionObject_traverse(
- _mysql_ConnectionObject *self,
- visitproc visit,
- void *arg)
-{
- if (self->converter)
- return visit(self->converter, arg);
- return 0;
-}
-#endif
-
-static int _mysql_ConnectionObject_clear(
- _mysql_ConnectionObject *self)
-{
- Py_XDECREF(self->converter);
- self->converter = NULL;
- return 0;
-}
-
-static char _mysql_ConnectionObject_close__doc__[] =
-"Close the connection. No further activity possible.";
-
-static PyObject *
-_mysql_ConnectionObject_close(
- _mysql_ConnectionObject *self,
- PyObject *args)
-{
- if (args) {
- if (!PyArg_ParseTuple(args, "")) return NULL;
- }
- if (self->open) {
- Py_BEGIN_ALLOW_THREADS
- mysql_close(&(self->connection));
- Py_END_ALLOW_THREADS
- self->open = 0;
- } else {
- PyErr_SetString(_mysql_ProgrammingError,
- "closing a closed connection");
- return NULL;
- }
- _mysql_ConnectionObject_clear(self);
- Py_INCREF(Py_None);
- return Py_None;
-}
-
-static char _mysql_ConnectionObject_affected_rows__doc__ [] =
-"Return number of rows affected by the last query.\n\
-Non-standard. Use Cursor.rowcount.\n\
-";
-
-static PyObject *
-_mysql_ConnectionObject_affected_rows(
- _mysql_ConnectionObject *self,
- PyObject *args)
-{
- if (!PyArg_ParseTuple(args, "")) return NULL;
- check_connection(self);
- return PyLong_FromUnsignedLongLong(mysql_affected_rows(&(self->connection)));
-}
-
-static char _mysql_debug__doc__[] =
-"Does a DBUG_PUSH with the given string.\n\
-mysql_debug() uses the Fred Fish debug library.\n\
-To use this function, you must compile the client library to\n\
-support debugging.\n\
-";
-static PyObject *
-_mysql_debug(
- PyObject *self,
- PyObject *args)
-{
- char *debug;
- if (!PyArg_ParseTuple(args, "s", &debug)) return NULL;
- mysql_debug(debug);
- Py_INCREF(Py_None);
- return Py_None;
-}
-
-static char _mysql_ConnectionObject_dump_debug_info__doc__[] =
-"Instructs the server to write some debug information to the\n\
-log. The connected user must have the process privilege for\n\
-this to work. Non-standard.\n\
-";
-
-static PyObject *
-_mysql_ConnectionObject_dump_debug_info(
- _mysql_ConnectionObject *self,
- PyObject *args)
-{
- int err;
- if (!PyArg_ParseTuple(args, "")) return NULL;
- check_connection(self);
- Py_BEGIN_ALLOW_THREADS
- err = mysql_dump_debug_info(&(self->connection));
- Py_END_ALLOW_THREADS
- if (err) return _mysql_Exception(self);
- Py_INCREF(Py_None);
- return Py_None;
-}
-
-static char _mysql_ConnectionObject_autocommit__doc__[] =
-"Set the autocommit mode. True values enable; False value disable.\n\
-";
-static PyObject *
-_mysql_ConnectionObject_autocommit(
- _mysql_ConnectionObject *self,
- PyObject *args)
-{
- int flag, err;
- if (!PyArg_ParseTuple(args, "i", &flag)) return NULL;
- Py_BEGIN_ALLOW_THREADS
-#if MYSQL_VERSION_ID >= 40100
- err = mysql_autocommit(&(self->connection), flag);
-#else
- {
- char query[256];
- snprintf(query, 256, "SET AUTOCOMMIT=%d", flag);
- err = mysql_query(&(self->connection), query);
- }
-#endif
- Py_END_ALLOW_THREADS
- if (err) return _mysql_Exception(self);
- Py_INCREF(Py_None);
- return Py_None;
-}
-
-static char _mysql_ConnectionObject_commit__doc__[] =
-"Commits the current transaction\n\
-";
-static PyObject *
-_mysql_ConnectionObject_commit(
- _mysql_ConnectionObject *self,
- PyObject *args)
-{
- int err;
- if (!PyArg_ParseTuple(args, "")) return NULL;
- Py_BEGIN_ALLOW_THREADS
-#if MYSQL_VERSION_ID >= 40100
- err = mysql_commit(&(self->connection));
-#else
- err = mysql_query(&(self->connection), "COMMIT");
-#endif
- Py_END_ALLOW_THREADS
- if (err) return _mysql_Exception(self);
- Py_INCREF(Py_None);
- return Py_None;
-}
-
-static char _mysql_ConnectionObject_rollback__doc__[] =
-"Rolls backs the current transaction\n\
-";
-static PyObject *
-_mysql_ConnectionObject_rollback(
- _mysql_ConnectionObject *self,
- PyObject *args)
-{
- int err;
- if (!PyArg_ParseTuple(args, "")) return NULL;
- Py_BEGIN_ALLOW_THREADS
-#if MYSQL_VERSION_ID >= 40100
- err = mysql_rollback(&(self->connection));
-#else
- err = mysql_query(&(self->connection), "ROLLBACK");
-#endif
- Py_END_ALLOW_THREADS
- if (err) return _mysql_Exception(self);
- Py_INCREF(Py_None);
- return Py_None;
-}
-
-static char _mysql_ConnectionObject_next_result__doc__[] =
-"If more query results exist, next_result() reads the next query\n\
-results and returns the status back to application.\n\
-\n\
-After calling next_result() the state of the connection is as if\n\
-you had called query() for the next query. This means that you can\n\
-now call store_result(), warning_count(), affected_rows()\n\
-, and so forth. \n\
-\n\
-Returns 0 if there are more results; -1 if there are no more results\n\
-\n\
-Non-standard.\n\
-";
-static PyObject *
-_mysql_ConnectionObject_next_result(
- _mysql_ConnectionObject *self,
- PyObject *args)
-{
- int err;
- if (!PyArg_ParseTuple(args, "")) return NULL;
- Py_BEGIN_ALLOW_THREADS
-#if MYSQL_VERSION_ID >= 40100
- err = mysql_next_result(&(self->connection));
-#else
- err = -1;
-#endif
- Py_END_ALLOW_THREADS
- if (err > 0) return _mysql_Exception(self);
- return PyInt_FromLong(err);
-}
-
-#if MYSQL_VERSION_ID >= 40100
-
-static char _mysql_ConnectionObject_set_server_option__doc__[] =
-"set_server_option(option) -- Enables or disables an option\n\
-for the connection.\n\
-\n\
-Non-standard.\n\
-";
-static PyObject *
-_mysql_ConnectionObject_set_server_option(
- _mysql_ConnectionObject *self,
- PyObject *args)
-{
- int err, flags=0;
- if (!PyArg_ParseTuple(args, "i", &flags))
- return NULL;
- Py_BEGIN_ALLOW_THREADS
- err = mysql_set_server_option(&(self->connection), flags);
- Py_END_ALLOW_THREADS
- if (err) return _mysql_Exception(self);
- return PyInt_FromLong(err);
-}
-
-static char _mysql_ConnectionObject_sqlstate__doc__[] =
-"Returns a string containing the SQLSTATE error code\n\
-for the last error. The error code consists of five characters.\n\
-'00000' means \"no error.\" The values are specified by ANSI SQL\n\
-and ODBC. For a list of possible values, see section 23\n\
-Error Handling in MySQL in the MySQL Manual.\n\
-\n\
-Note that not all MySQL errors are yet mapped to SQLSTATE's.\n\
-The value 'HY000' (general error) is used for unmapped errors.\n\
-\n\
-Non-standard.\n\
-";
-static PyObject *
-_mysql_ConnectionObject_sqlstate(
- _mysql_ConnectionObject *self,
- PyObject *args)
-{
- if (!PyArg_ParseTuple(args, "")) return NULL;
-#ifdef IS_PY3K
- return PyUnicode_FromString(mysql_sqlstate(&(self->connection)));
-#else
- return PyString_FromString(mysql_sqlstate(&(self->connection)));
-#endif
-}
-
-static char _mysql_ConnectionObject_warning_count__doc__[] =
-"Returns the number of warnings generated during execution\n\
-of the previous SQL statement.\n\
-\n\
-Non-standard.\n\
-";
-static PyObject *
-_mysql_ConnectionObject_warning_count(
- _mysql_ConnectionObject *self,
- PyObject *args)
-{
- if (!PyArg_ParseTuple(args, "")) return NULL;
- return PyInt_FromLong(mysql_warning_count(&(self->connection)));
-}
-
-#endif
-
-static char _mysql_ConnectionObject_errno__doc__[] =
-"Returns the error code for the most recently invoked API function\n\
-that can succeed or fail. A return value of zero means that no error\n\
-occurred.\n\
-";
-
-static PyObject *
-_mysql_ConnectionObject_errno(
- _mysql_ConnectionObject *self,
- PyObject *args)
-{
- if (!PyArg_ParseTuple(args, "")) return NULL;
- check_connection(self);
- return PyInt_FromLong((long)mysql_errno(&(self->connection)));
-}
-
-static char _mysql_ConnectionObject_error__doc__[] =
-"Returns the error message for the most recently invoked API function\n\
-that can succeed or fail. An empty string ("") is returned if no error\n\
-occurred.\n\
-";
-
-static PyObject *
-_mysql_ConnectionObject_error(
- _mysql_ConnectionObject *self,
- PyObject *args)
-{
- if (!PyArg_ParseTuple(args, "")) return NULL;
- check_connection(self);
-#ifdef IS_PY3K
- return PyUnicode_FromString(mysql_error(&(self->connection)));
-#else
- return PyString_FromString(mysql_error(&(self->connection)));
-#endif
-}
-
-static char _mysql_escape_string__doc__[] =
-"escape_string(s) -- quote any SQL-interpreted characters in string s.\n\
-\n\
-Use connection.escape_string(s), if you use it at all.\n\
-_mysql.escape_string(s) cannot handle character sets. You are\n\
-probably better off using connection.escape(o) instead, since\n\
-it will escape entire sequences as well as strings.";
-
-static PyObject *
-_mysql_escape_string(
- _mysql_ConnectionObject *self,
- PyObject *args)
-{
- PyObject *str;
- char *in, *out;
- int len, size;
- if (!PyArg_ParseTuple(args, "s#:escape_string", &in, &size)) return NULL;
-#ifdef IS_PY3K
- str = PyUnicode_FromStringAndSize((char *) NULL, size*2+1);
-#else
- str = PyString_FromStringAndSize((char *) NULL, size*2+1);
-#endif
- if (!str) return PyErr_NoMemory();
-#ifdef IS_PY3K
- out = PyUnicode_AS_DATA(str);
-#else
- out = PyString_AS_STRING(str);
-#endif
-#if MYSQL_VERSION_ID < 32321
- len = mysql_escape_string(out, in, size);
-#else
- check_server_init(NULL);
- if (self && self->open)
- len = mysql_real_escape_string(&(self->connection), out, in, size);
- else
- len = mysql_escape_string(out, in, size);
-#endif
-#ifdef IS_PY3K
- if (PyUnicode_Resize(&str, len) < 0) return NULL;
-#else
- if (_PyString_Resize(&str, len) < 0) return NULL;
-#endif
- return (str);
-}
-
-static char _mysql_string_literal__doc__[] =
-"string_literal(obj) -- converts object obj into a SQL string literal.\n\
-This means, any special SQL characters are escaped, and it is enclosed\n\
-within single quotes. In other words, it performs:\n\
-\n\
-\"'%s'\" % escape_string(str(obj))\n\
-\n\
-Use connection.string_literal(obj), if you use it at all.\n\
-_mysql.string_literal(obj) cannot handle character sets.";
-
-static PyObject *
-_mysql_string_literal(
- _mysql_ConnectionObject *self,
- PyObject *args)
-{
- PyObject *str, *s, *o, *d;
- char *in, *out;
- int len, size;
- if (!PyArg_ParseTuple(args, "O|O:string_literal", &o, &d)) return NULL;
- s = PyObject_Str(o);
- if (!s) return NULL;
-#ifdef IS_PY3K
- in = PyUnicode_AS_DATA(s);
- size = PyUnicode_GetSize(s);
- str = PyUnicode_FromStringAndSize((char *) NULL, size*2+3);
- if (!str) return PyErr_NoMemory();
- out = PyUnicode_AS_DATA(str);
-#else
- in = PyString_AsString(s);
- size = PyString_GET_SIZE(s);
- str = PyString_FromStringAndSize((char *) NULL, size*2+3);
- if (!str) return PyErr_NoMemory();
- out = PyString_AS_STRING(str);
-#endif
-#if MYSQL_VERSION_ID < 32321
- len = mysql_escape_string(out+1, in, size);
-#else
- check_server_init(NULL);
- if (self && self->open)
- len = mysql_real_escape_string(&(self->connection), out+1, in, size);
- else
- len = mysql_escape_string(out+1, in, size);
-#endif
- *out = *(out+len+1) = '\'';
-#ifdef IS_PY3K
- if (PyUnicode_Resize(&str, len+2) < 0) return NULL;
-#else
- if (_PyString_Resize(&str, len+2) < 0) return NULL;
-#endif
- Py_DECREF(s);
- return (str);
-}
-
-static PyObject *_mysql_NULL;
-
-static PyObject *
-_escape_item(
- PyObject *item,
- PyObject *d)
-{
- PyObject *quoted=NULL, *itemtype, *itemconv;
- if (!(itemtype = PyObject_Type(item)))
- goto error;
- itemconv = PyObject_GetItem(d, itemtype);
- Py_DECREF(itemtype);
- if (!itemconv) {
- PyErr_Clear();
- itemconv = PyObject_GetItem(d,
-#ifdef IS_PY3K
- (PyObject *) &PyUnicode_Type);
-#else
- (PyObject *) &PyString_Type);
-#endif
- }
- if (!itemconv) {
- PyErr_SetString(PyExc_TypeError,
- "no default type converter defined");
- goto error;
- }
- quoted = PyObject_CallFunction(itemconv, "OO", item, d);
- Py_DECREF(itemconv);
-error:
- return quoted;
-}
-
-static char _mysql_escape__doc__[] =
-"escape(obj, dict) -- escape any special characters in object obj\n\
-using mapping dict to provide quoting functions for each type.\n\
-Returns a SQL literal string.";
-static PyObject *
-_mysql_escape(
- PyObject *self,
- PyObject *args)
-{
- PyObject *o=NULL, *d=NULL;
- if (!PyArg_ParseTuple(args, "O|O:escape", &o, &d))
- return NULL;
- if (d) {
- if (!PyMapping_Check(d)) {
- PyErr_SetString(PyExc_TypeError,
- "argument 2 must be a mapping");
- return NULL;
- }
- return _escape_item(o, d);
- } else {
- if (!self) {
- PyErr_SetString(PyExc_TypeError,
- "argument 2 must be a mapping");
- return NULL;
- }
- return _escape_item(o,
- ((_mysql_ConnectionObject *) self)->converter);
- }
-}
-
-static char _mysql_escape_sequence__doc__[] =
-"escape_sequence(seq, dict) -- escape any special characters in sequence\n\
-seq using mapping dict to provide quoting functions for each type.\n\
-Returns a tuple of escaped items.";
-static PyObject *
-_mysql_escape_sequence(
- PyObject *self,
- PyObject *args)
-{
- PyObject *o=NULL, *d=NULL, *r=NULL, *item, *quoted;
- int i, n;
- if (!PyArg_ParseTuple(args, "OO:escape_sequence", &o, &d))
- goto error;
- if (!PyMapping_Check(d)) {
- PyErr_SetString(PyExc_TypeError,
- "argument 2 must be a mapping");
- return NULL;
- }
- if ((n = PyObject_Length(o)) == -1) goto error;
- if (!(r = PyTuple_New(n))) goto error;
- for (i=0; i<n; i++) {
- item = PySequence_GetItem(o, i);
- if (!item) goto error;
- quoted = _escape_item(item, d);
- Py_DECREF(item);
- if (!quoted) goto error;
- PyTuple_SET_ITEM(r, i, quoted);
- }
- return r;
- error:
- Py_XDECREF(r);
- return NULL;
-}
-
-static char _mysql_escape_dict__doc__[] =
-"escape_sequence(d, dict) -- escape any special characters in\n\
-dictionary d using mapping dict to provide quoting functions for each type.\n\
-Returns a dictionary of escaped items.";
-static PyObject *
-_mysql_escape_dict(
- PyObject *self,
- PyObject *args)
-{
- PyObject *o=NULL, *d=NULL, *r=NULL, *item, *quoted, *pkey;
- Py_ssize_t ppos = 0;
- if (!PyArg_ParseTuple(args, "O!O:escape_dict", &PyDict_Type, &o, &d))
- goto error;
- if (!PyMapping_Check(d)) {
- PyErr_SetString(PyExc_TypeError,
- "argument 2 must be a mapping");
- return NULL;
- }
- if (!(r = PyDict_New())) goto error;
- while (PyDict_Next(o, &ppos, &pkey, &item)) {
- quoted = _escape_item(item, d);
- if (!quoted) goto error;
- if (PyDict_SetItem(r, pkey, quoted)==-1) goto error;
- Py_DECREF(quoted);
- }
- return r;
- error:
- Py_XDECREF(r);
- return NULL;
-}
-
-static char _mysql_ResultObject_describe__doc__[] =
-"Returns the sequence of 7-tuples required by the DB-API for\n\
-the Cursor.description attribute.\n\
-";
-
-static PyObject *
-_mysql_ResultObject_describe(
- _mysql_ResultObject *self,
- PyObject *args)
-{
- PyObject *d;
- MYSQL_FIELD *fields;
- unsigned int i, n;
- if (!PyArg_ParseTuple(args, "")) return NULL;
- check_result_connection(self);
- n = mysql_num_fields(self->result);
- fields = mysql_fetch_fields(self->result);
- if (!(d = PyTuple_New(n))) return NULL;
- for (i=0; i<n; i++) {
- PyObject *t;
- t = Py_BuildValue("(siiiiii)",
- fields[i].name,
- (long) fields[i].type,
- (long) fields[i].max_length,
- (long) fields[i].length,
- (long) fields[i].length,
- (long) fields[i].decimals,
- (long) !(IS_NOT_NULL(fields[i].flags)));
- if (!t) goto error;
- PyTuple_SET_ITEM(d, i, t);
- }
- return d;
- error:
- Py_XDECREF(d);
- return NULL;
-}
-
-static char _mysql_ResultObject_field_flags__doc__[] =
-"Returns a tuple of field flags, one for each column in the result.\n\
-" ;
-
-static PyObject *
-_mysql_ResultObject_field_flags(
- _mysql_ResultObject *self,
- PyObject *args)
-{
- PyObject *d;
- MYSQL_FIELD *fields;
- unsigned int i, n;
- if (!PyArg_ParseTuple(args, "")) return NULL;
- check_result_connection(self);
- n = mysql_num_fields(self->result);
- fields = mysql_fetch_fields(self->result);
- if (!(d = PyTuple_New(n))) return NULL;
- for (i=0; i<n; i++) {
- PyObject *f;
- if (!(f = PyInt_FromLong((long)fields[i].flags))) goto error;
- PyTuple_SET_ITEM(d, i, f);
- }
- return d;
- error:
- Py_XDECREF(d);
- return NULL;
-}
-
-static PyObject *
-_mysql_field_to_python(
- PyObject *converter,
- char *rowitem,
- unsigned long length)
-{
- PyObject *v;
- if (rowitem) {
- if (converter != Py_None)
- v = PyObject_CallFunction(converter,
- "s#",
- rowitem,
- (int)length);
- else
-#ifdef IS_PY3K
- v = PyUnicode_FromStringAndSize(rowitem,
- (int)length);
-#else
- v = PyString_FromStringAndSize(rowitem,
- (int)length);
-#endif
- if (!v)
- return NULL;
- } else {
- Py_INCREF(Py_None);
- v = Py_None;
- }
- return v;
-}
-
-static PyObject *
-_mysql_row_to_tuple(
- _mysql_ResultObject *self,
- MYSQL_ROW row)
-{
- unsigned int n, i;
- unsigned long *length;
- PyObject *r, *c;
-
- n = mysql_num_fields(self->result);
- if (!(r = PyTuple_New(n))) return NULL;
- length = mysql_fetch_lengths(self->result);
- for (i=0; i<n; i++) {
- PyObject *v;
- c = PyTuple_GET_ITEM(self->converter, i);
- v = _mysql_field_to_python(c, row[i], length[i]);
- if (!v) goto error;
- PyTuple_SET_ITEM(r, i, v);
- }
- return r;
- error:
- Py_XDECREF(r);
- return NULL;
-}
-
-static PyObject *
-_mysql_row_to_dict(
- _mysql_ResultObject *self,
- MYSQL_ROW row)
-{
- unsigned int n, i;
- unsigned long *length;
- PyObject *r, *c;
- MYSQL_FIELD *fields;
-
- n = mysql_num_fields(self->result);
- if (!(r = PyDict_New())) return NULL;
- length = mysql_fetch_lengths(self->result);
- fields = mysql_fetch_fields(self->result);
- for (i=0; i<n; i++) {
- PyObject *v;
- c = PyTuple_GET_ITEM(self->converter, i);
- v = _mysql_field_to_python(c, row[i], length[i]);
- if (!v) goto error;
- if (!PyMapping_HasKeyString(r, fields[i].name)) {
- PyMapping_SetItemString(r, fields[i].name, v);
- } else {
- int len;
- char buf[256];
- strncpy(buf, fields[i].table, 256);
- len = strlen(buf);
- strncat(buf, ".", 256-len);
- len = strlen(buf);
- strncat(buf, fields[i].name, 256-len);
- PyMapping_SetItemString(r, buf, v);
- }
- Py_DECREF(v);
- }
- return r;
- error:
- Py_XDECREF(r);
- return NULL;
-}
-
-static PyObject *
-_mysql_row_to_dict_old(
- _mysql_ResultObject *self,
- MYSQL_ROW row)
-{
- unsigned int n, i;
- unsigned long *length;
- PyObject *r, *c;
- MYSQL_FIELD *fields;
-
- n = mysql_num_fields(self->result);
- if (!(r = PyDict_New())) return NULL;
- length = mysql_fetch_lengths(self->result);
- fields = mysql_fetch_fields(self->result);
- for (i=0; i<n; i++) {
- PyObject *v;
- c = PyTuple_GET_ITEM(self->converter, i);
- v = _mysql_field_to_python(c, row[i], length[i]);
- if (!v) goto error;
- {
- int len=0;
- char buf[256]="";
- if (strlen(fields[i].table)) {
- strncpy(buf, fields[i].table, 256);
- len = strlen(buf);
- strncat(buf, ".", 256-len);
- len = strlen(buf);
- }
- strncat(buf, fields[i].name, 256-len);
- PyMapping_SetItemString(r, buf, v);
- }
- Py_DECREF(v);
- }
- return r;
- error:
- Py_XDECREF(r);
- return NULL;
-}
-
-typedef PyObject *_PYFUNC(_mysql_ResultObject *, MYSQL_ROW);
-
-int
-_mysql__fetch_row(
- _mysql_ResultObject *self,
- PyObject **r,
- int skiprows,
- int maxrows,
- _PYFUNC *convert_row)
-{
- unsigned int i;
- MYSQL_ROW row;
-
- for (i = skiprows; i<(skiprows+maxrows); i++) {
- PyObject *v;
- if (!self->use)
- row = mysql_fetch_row(self->result);
- else {
- Py_BEGIN_ALLOW_THREADS;
- row = mysql_fetch_row(self->result);
- Py_END_ALLOW_THREADS;
- }
- if (!row && mysql_errno(&(((_mysql_ConnectionObject *)(self->conn))->connection))) {
- _mysql_Exception((_mysql_ConnectionObject *)self->conn);
- goto error;
- }
- if (!row) {
- if (MyTuple_Resize(r, i, 0) == -1) goto error;
- break;
- }
- v = convert_row(self, row);
- if (!v) goto error;
- PyTuple_SET_ITEM(*r, i, v);
- }
- return i-skiprows;
- error:
- return -1;
-}
-
-static char _mysql_ResultObject_fetch_row__doc__[] =
-"fetch_row([maxrows, how]) -- Fetches up to maxrows as a tuple.\n\
-The rows are formatted according to how:\n\
-\n\
- 0 -- tuples (default)\n\
- 1 -- dictionaries, key=column or table.column if duplicated\n\
- 2 -- dictionaries, key=table.column\n\
-";
-
-static PyObject *
-_mysql_ResultObject_fetch_row(
- _mysql_ResultObject *self,
- PyObject *args,
- PyObject *kwargs)
-{
- typedef PyObject *_PYFUNC(_mysql_ResultObject *, MYSQL_ROW);
- static char *kwlist[] = { "maxrows", "how", NULL };
- static _PYFUNC *row_converters[] =
- {
- _mysql_row_to_tuple,
- _mysql_row_to_dict,
- _mysql_row_to_dict_old
- };
- _PYFUNC *convert_row;
- unsigned int maxrows=1, how=0, skiprows=0, rowsadded;
- PyObject *r=NULL;
-
- if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|ii:fetch_row", kwlist,
- &maxrows, &how))
- return NULL;
- check_result_connection(self);
- if (how < 0 || how >= sizeof(row_converters)) {
- PyErr_SetString(PyExc_ValueError, "how out of range");
- return NULL;
- }
- convert_row = row_converters[how];
- if (maxrows) {
- if (!(r = PyTuple_New(maxrows))) goto error;
- rowsadded = _mysql__fetch_row(self, &r, skiprows, maxrows,
- convert_row);
- if (rowsadded == -1) goto error;
- } else {
- if (self->use) {
- maxrows = 1000;
- if (!(r = PyTuple_New(maxrows))) goto error;
- while (1) {
- rowsadded = _mysql__fetch_row(self, &r, skiprows,
- maxrows, convert_row);
- if (rowsadded == -1) goto error;
- skiprows += rowsadded;
- if (rowsadded < maxrows) break;
- if (MyTuple_Resize(&r, skiprows+maxrows, 0) == -1)
- goto error;
- }
- } else {
- /* XXX if overflow, maxrows<0? */
- maxrows = (int) mysql_num_rows(self->result);
- if (!(r = PyTuple_New(maxrows))) goto error;
- rowsadded = _mysql__fetch_row(self, &r, 0,
- maxrows, convert_row);
- if (rowsadded == -1) goto error;
- }
- }
- return r;
- error:
- Py_XDECREF(r);
- return NULL;
-}
-
-#if MYSQL_VERSION_ID >= 32303
-
-static char _mysql_ConnectionObject_change_user__doc__[] =
-"Changes the user and causes the database specified by db to\n\
-become the default (current) database on the connection\n\
-specified by mysql. In subsequent queries, this database is\n\
-the default for table references that do not include an\n\
-explicit database specifier.\n\
-\n\
-This function was introduced in MySQL Version 3.23.3.\n\
-\n\
-Fails unless the connected user can be authenticated or if he\n\
-doesn't have permission to use the database. In this case the\n\
-user and database are not changed.\n\
-\n\
-The db parameter may be set to None if you don't want to have\n\
-a default database.\n\
-";
-
-static PyObject *
-_mysql_ConnectionObject_change_user(
- _mysql_ConnectionObject *self,
- PyObject *args,
- PyObject *kwargs)
-{
- char *user, *pwd=NULL, *db=NULL;
- int r;
- static char *kwlist[] = { "user", "passwd", "db", NULL } ;
-
- if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|ss:change_user",
- kwlist, &user, &pwd, &db))
- return NULL;
- check_connection(self);
- Py_BEGIN_ALLOW_THREADS
- r = mysql_change_user(&(self->connection), user, pwd, db);
- Py_END_ALLOW_THREADS
- if (r) return _mysql_Exception(self);
- Py_INCREF(Py_None);
- return Py_None;
-}
-#endif
-
-static char _mysql_ConnectionObject_character_set_name__doc__[] =
-"Returns the default character set for the current connection.\n\
-Non-standard.\n\
-";
-
-static PyObject *
-_mysql_ConnectionObject_character_set_name(
- _mysql_ConnectionObject *self,
- PyObject *args)
-{
- const char *s;
- if (!PyArg_ParseTuple(args, "")) return NULL;
- check_connection(self);
-#if MYSQL_VERSION_ID >= 32321
- s = mysql_character_set_name(&(self->connection));
-#else
- s = "latin1";
-#endif
-#ifdef IS_PY3K
- return PyUnicode_FromString(s);
-#else
- return PyString_FromString(s);
-#endif
-}
-
-#if MYSQL_VERSION_ID >= 50007
-static char _mysql_ConnectionObject_set_character_set__doc__[] =
-"Sets the default character set for the current connection.\n\
-Non-standard.\n\
-";
-
-static PyObject *
-_mysql_ConnectionObject_set_character_set(
- _mysql_ConnectionObject *self,
- PyObject *args)
-{
- const char *s;
- int err;
- if (!PyArg_ParseTuple(args, "s", &s)) return NULL;
- check_connection(self);
- Py_BEGIN_ALLOW_THREADS
- err = mysql_set_character_set(&(self->connection), s);
- Py_END_ALLOW_THREADS
- if (err) return _mysql_Exception(self);
- Py_INCREF(Py_None);
- return Py_None;
-}
-#endif
-
-#if MYSQL_VERSION_ID >= 50010
-static char _mysql_ConnectionObject_get_character_set_info__doc__[] =
-"Returns a dict with information about the current character set:\n\
-\n\
-collation\n\
- collation name\n\
-name\n\
- character set name\n\
-comment\n\
- comment or descriptive name\n\
-dir\n\
- character set directory\n\
-mbminlen\n\
- min. length for multibyte string\n\
-mbmaxlen\n\
- max. length for multibyte string\n\
-\n\
-Not all keys may be present, particularly dir.\n\
-\n\
-Non-standard.\n\
-";
-
-static PyObject *
-_mysql_ConnectionObject_get_character_set_info(
- _mysql_ConnectionObject *self,
- PyObject *args)
-{
- PyObject *result;
- MY_CHARSET_INFO cs;
-
- if (!PyArg_ParseTuple(args, "")) return NULL;
- check_connection(self);
- mysql_get_character_set_info(&(self->connection), &cs);
- if (!(result = PyDict_New())) return NULL;
-#ifdef IS_PY3K
- if (cs.csname)
- PyDict_SetItemString(result, "name", PyUnicode_FromString(cs.csname));
- if (cs.name)
- PyDict_SetItemString(result, "collation", PyUnicode_FromString(cs.name));
- if (cs.comment)
- PyDict_SetItemString(result, "comment", PyUnicode_FromString(cs.comment));
- if (cs.dir)
- PyDict_SetItemString(result, "dir", PyUnicode_FromString(cs.dir));
- PyDict_SetItemString(result, "mbminlen", PyInt_FromLong(cs.mbminlen));
- PyDict_SetItemString(result, "mbmaxlen", PyInt_FromLong(cs.mbmaxlen));
-#else
- if (cs.csname)
- PyDict_SetItemString(result, "name", PyString_FromString(cs.csname));
- if (cs.name)
- PyDict_SetItemString(result, "collation", PyString_FromString(cs.name));
- if (cs.comment)
- PyDict_SetItemString(result, "comment", PyString_FromString(cs.comment));
- if (cs.dir)
- PyDict_SetItemString(result, "dir", PyString_FromString(cs.dir));
- PyDict_SetItemString(result, "mbminlen", PyInt_FromLong(cs.mbminlen));
- PyDict_SetItemString(result, "mbmaxlen", PyInt_FromLong(cs.mbmaxlen));
-#endif
- return result;
-}
-#endif
-
-static char _mysql_get_client_info__doc__[] =
-"get_client_info() -- Returns a string that represents\n\
-the client library version.";
-static PyObject *
-_mysql_get_client_info(
- PyObject *self,
- PyObject *args)
-{
- if (!PyArg_ParseTuple(args, "")) return NULL;
- check_server_init(NULL);
-#ifdef IS_PY3K
- return PyUnicode_FromString(mysql_get_client_info());
-#else
- return PyString_FromString(mysql_get_client_info());
-#endif
-}
-
-static char _mysql_ConnectionObject_get_host_info__doc__[] =
-"Returns a string that represents the MySQL client library\n\
-version. Non-standard.\n\
-";
-
-static PyObject *
-_mysql_ConnectionObject_get_host_info(
- _mysql_ConnectionObject *self,
- PyObject *args)
-{
- if (!PyArg_ParseTuple(args, "")) return NULL;
- check_connection(self);
-#ifdef IS_PY3K
- return PyUnicode_FromString(mysql_get_host_info(&(self->connection)));
-#else
- return PyString_FromString(mysql_get_host_info(&(self->connection)));
-#endif
-}
-
-static char _mysql_ConnectionObject_get_proto_info__doc__[] =
-"Returns an unsigned integer representing the protocol version\n\
-used by the current connection. Non-standard.\n\
-";
-
-static PyObject *
-_mysql_ConnectionObject_get_proto_info(
- _mysql_ConnectionObject *self,
- PyObject *args)
-{
- if (!PyArg_ParseTuple(args, "")) return NULL;
- check_connection(self);
- return PyInt_FromLong((long)mysql_get_proto_info(&(self->connection)));
-}
-
-static char _mysql_ConnectionObject_get_server_info__doc__[] =
-"Returns a string that represents the server version number.\n\
-Non-standard.\n\
-";
-
-static PyObject *
-_mysql_ConnectionObject_get_server_info(
- _mysql_ConnectionObject *self,
- PyObject *args)
-{
- if (!PyArg_ParseTuple(args, "")) return NULL;
- check_connection(self);
-#ifdef IS_PY3K
- return PyUnicode_FromString(mysql_get_server_info(&(self->connection)));
-#else
- return PyString_FromString(mysql_get_server_info(&(self->connection)));
-#endif
-}
-
-static char _mysql_ConnectionObject_info__doc__[] =
-"Retrieves a string providing information about the most\n\
-recently executed query. Non-standard. Use messages or\n\
-Cursor.messages.\n\
-";
-
-static PyObject *
-_mysql_ConnectionObject_info(
- _mysql_ConnectionObject *self,
- PyObject *args)
-{
- const char *s;
- if (!PyArg_ParseTuple(args, "")) return NULL;
- check_connection(self);
- s = mysql_info(&(self->connection));
-#ifdef IS_PY3K
- if (s) return PyUnicode_FromString(s);
-#else
- if (s) return PyString_FromString(s);
-#endif
- Py_INCREF(Py_None);
- return Py_None;
-}
-
-static char _mysql_ConnectionObject_insert_id__doc__[] =
-"Returns the ID generated for an AUTO_INCREMENT column by the previous\n\
-query. Use this function after you have performed an INSERT query into a\n\
-table that contains an AUTO_INCREMENT field.\n\
-\n\
-Note that this returns 0 if the previous query does not\n\
-generate an AUTO_INCREMENT value. If you need to save the value for\n\
-later, be sure to call this immediately after the query\n\
-that generates the value.\n\
-\n\
-The ID is updated after INSERT and UPDATE statements that generate\n\
-an AUTO_INCREMENT value or that set a column value to\n\
-LAST_INSERT_ID(expr). See section 6.3.5.2 Miscellaneous Functions\n\
-in the MySQL documentation.\n\
-\n\
-Also note that the value of the SQL LAST_INSERT_ID() function always\n\
-contains the most recently generated AUTO_INCREMENT value, and is not\n\
-reset between queries because the value of that function is maintained\n\
-in the server.\n\
-" ;
-
-static PyObject *
-_mysql_ConnectionObject_insert_id(
- _mysql_ConnectionObject *self,
- PyObject *args)
-{
- my_ulonglong r;
- if (!PyArg_ParseTuple(args, "")) return NULL;
- check_connection(self);
- Py_BEGIN_ALLOW_THREADS
- r = mysql_insert_id(&(self->connection));
- Py_END_ALLOW_THREADS
- return PyLong_FromUnsignedLongLong(r);
-}
-
-static char _mysql_ConnectionObject_kill__doc__[] =
-"Asks the server to kill the thread specified by pid.\n\
-Non-standard.";
-
-static PyObject *
-_mysql_ConnectionObject_kill(
- _mysql_ConnectionObject *self,
- PyObject *args)
-{
- unsigned long pid;
- int r;
- if (!PyArg_ParseTuple(args, "k:kill", &pid)) return NULL;
- check_connection(self);
- Py_BEGIN_ALLOW_THREADS
- r = mysql_kill(&(self->connection), pid);
- Py_END_ALLOW_THREADS
- if (r) return _mysql_Exception(self);
- Py_INCREF(Py_None);
- return Py_None;
-}
-
-static char _mysql_ConnectionObject_field_count__doc__[] =
-"Returns the number of columns for the most recent query on the\n\
-connection. Non-standard. Will probably give you bogus results\n\
-on most cursor classes. Use Cursor.rowcount.\n\
-";
-
-static PyObject *
-_mysql_ConnectionObject_field_count(
- _mysql_ConnectionObject *self,
- PyObject *args)
-{
- if (!PyArg_ParseTuple(args, "")) return NULL;
- check_connection(self);
-#if MYSQL_VERSION_ID < 32224
- return PyInt_FromLong((long)mysql_num_fields(&(self->connection)));
-#else
- return PyInt_FromLong((long)mysql_field_count(&(self->connection)));
-#endif
-}
-
-static char _mysql_ResultObject_num_fields__doc__[] =
-"Returns the number of fields (column) in the result." ;
-
-static PyObject *
-_mysql_ResultObject_num_fields(
- _mysql_ResultObject *self,
- PyObject *args)
-{
- if (!PyArg_ParseTuple(args, "")) return NULL;
- check_result_connection(self);
- return PyInt_FromLong((long)mysql_num_fields(self->result));
-}
-
-static char _mysql_ResultObject_num_rows__doc__[] =
-"Returns the number of rows in the result set. Note that if\n\
-use=1, this will not return a valid value until the entire result\n\
-set has been read.\n\
-";
-
-static PyObject *
-_mysql_ResultObject_num_rows(
- _mysql_ResultObject *self,
- PyObject *args)
-{
- if (!PyArg_ParseTuple(args, "")) return NULL;
- check_result_connection(self);
- return PyLong_FromUnsignedLongLong(mysql_num_rows(self->result));
-}
-
-static char _mysql_ConnectionObject_ping__doc__[] =
-"Checks whether or not the connection to the server is\n\
-working. If it has gone down, an automatic reconnection is\n\
-attempted.\n\
-\n\
-This function can be used by clients that remain idle for a\n\
-long while, to check whether or not the server has closed the\n\
-connection and reconnect if necessary.\n\
-\n\
-New in 1.2.2: Accepts an optional reconnect parameter. If True,\n\
-then the client will attempt reconnection. Note that this setting\n\
-is persistent. By default, this is on in MySQL<5.0.3, and off\n\
-thereafter.\n\
-\n\
-Non-standard. You should assume that ping() performs an\n\
-implicit rollback; use only when starting a new transaction.\n\
-You have been warned.\n\
-";
-
-static PyObject *
-_mysql_ConnectionObject_ping(
- _mysql_ConnectionObject *self,
- PyObject *args)
-{
- int r, reconnect = -1;
- if (!PyArg_ParseTuple(args, "|I", &reconnect)) return NULL;
- check_connection(self);
- if ( reconnect != -1 ) self->connection.reconnect = reconnect;
- Py_BEGIN_ALLOW_THREADS
- r = mysql_ping(&(self->connection));
- Py_END_ALLOW_THREADS
- if (r) return _mysql_Exception(self);
- Py_INCREF(Py_None);
- return Py_None;
-}
-
-static char _mysql_ConnectionObject_query__doc__[] =
-"Execute a query. store_result() or use_result() will get the\n\
-result set, if any. Non-standard. Use cursor() to create a cursor,\n\
-then cursor.execute().\n\
-" ;
-
-static PyObject *
-_mysql_ConnectionObject_query(
- _mysql_ConnectionObject *self,
- PyObject *args)
-{
- char *query;
- int len, r;
- if (!PyArg_ParseTuple(args, "s#:query", &query, &len)) return NULL;
- check_connection(self);
- Py_BEGIN_ALLOW_THREADS
- r = mysql_real_query(&(self->connection), query, len);
- Py_END_ALLOW_THREADS
- if (r) return _mysql_Exception(self);
- Py_INCREF(Py_None);
- return Py_None;
-}
-
-
-static char _mysql_ConnectionObject_select_db__doc__[] =
-"Causes the database specified by db to become the default\n\
-(current) database on the connection specified by mysql. In subsequent\n\
-queries, this database is the default for table references that do not\n\
-include an explicit database specifier.\n\
-\n\
-Fails unless the connected user can be authenticated as having\n\
-permission to use the database.\n\
-\n\
-Non-standard.\n\
-";
-
-static PyObject *
-_mysql_ConnectionObject_select_db(
- _mysql_ConnectionObject *self,
- PyObject *args)
-{
- char *db;
- int r;
- if (!PyArg_ParseTuple(args, "s:select_db", &db)) return NULL;
- check_connection(self);
- Py_BEGIN_ALLOW_THREADS
- r = mysql_select_db(&(self->connection), db);
- Py_END_ALLOW_THREADS
- if (r) return _mysql_Exception(self);
- Py_INCREF(Py_None);
- return Py_None;
-}
-
-static char _mysql_ConnectionObject_shutdown__doc__[] =
-"Asks the database server to shut down. The connected user must\n\
-have shutdown privileges. Non-standard.\n\
-";
-
-static PyObject *
-_mysql_ConnectionObject_shutdown(
- _mysql_ConnectionObject *self,
- PyObject *args)
-{
- int r;
- if (!PyArg_ParseTuple(args, "")) return NULL;
- check_connection(self);
- Py_BEGIN_ALLOW_THREADS
- r = mysql_shutdown(&(self->connection)
-#if MYSQL_VERSION_ID >= 40103
- , SHUTDOWN_DEFAULT
-#endif
- );
- Py_END_ALLOW_THREADS
- if (r) return _mysql_Exception(self);
- Py_INCREF(Py_None);
- return Py_None;
-}
-
-static char _mysql_ConnectionObject_stat__doc__[] =
-"Returns a character string containing information similar to\n\
-that provided by the mysqladmin status command. This includes\n\
-uptime in seconds and the number of running threads,\n\
-questions, reloads, and open tables. Non-standard.\n\
-";
-
-static PyObject *
-_mysql_ConnectionObject_stat(
- _mysql_ConnectionObject *self,
- PyObject *args)
-{
- const char *s;
- if (!PyArg_ParseTuple(args, "")) return NULL;
- check_connection(self);
- Py_BEGIN_ALLOW_THREADS
- s = mysql_stat(&(self->connection));
- Py_END_ALLOW_THREADS
- if (!s) return _mysql_Exception(self);
-#ifdef IS_PY3K
- return PyUnicode_FromString(s);
-#else
- return PyString_FromString(s);
-#endif
-
-}
-
-static char _mysql_ConnectionObject_store_result__doc__[] =
-"Returns a result object acquired by mysql_store_result\n\
-(results stored in the client). If no results are available,\n\
-None is returned. Non-standard.\n\
-";
-
-static PyObject *
-_mysql_ConnectionObject_store_result(
- _mysql_ConnectionObject *self,
- PyObject *args)
-{
- PyObject *arglist=NULL, *kwarglist=NULL, *result=NULL;
- _mysql_ResultObject *r=NULL;
-
- if (!PyArg_ParseTuple(args, "")) return NULL;
- check_connection(self);
- arglist = Py_BuildValue("(OiO)", self, 0, self->converter);
- if (!arglist) goto error;
- kwarglist = PyDict_New();
- if (!kwarglist) goto error;
- r = MyAlloc(_mysql_ResultObject, _mysql_ResultObject_Type);
- if (!r) goto error;
- if (_mysql_ResultObject_Initialize(r, arglist, kwarglist))
- goto error;
- result = (PyObject *) r;
- if (!(r->result)) {
- Py_DECREF(result);
- Py_INCREF(Py_None);
- result = Py_None;
- }
- error:
- Py_XDECREF(arglist);
- Py_XDECREF(kwarglist);
- return result;
-}
-
-static char _mysql_ConnectionObject_thread_id__doc__[] =
-"Returns the thread ID of the current connection. This value\n\
-can be used as an argument to kill() to kill the thread.\n\
-\n\
-If the connection is lost and you reconnect with ping(), the\n\
-thread ID will change. This means you should not get the\n\
-thread ID and store it for later. You should get it when you\n\
-need it.\n\
-\n\
-Non-standard.";
-
-static PyObject *
-_mysql_ConnectionObject_thread_id(
- _mysql_ConnectionObject *self,
- PyObject *args)
-{
- unsigned long pid;
- if (!PyArg_ParseTuple(args, "")) return NULL;
- check_connection(self);
- Py_BEGIN_ALLOW_THREADS
- pid = mysql_thread_id(&(self->connection));
- Py_END_ALLOW_THREADS
- return PyInt_FromLong((long)pid);
-}
-
-static char _mysql_ConnectionObject_use_result__doc__[] =
-"Returns a result object acquired by mysql_use_result\n\
-(results stored in the server). If no results are available,\n\
-None is returned. Non-standard.\n\
-";
-
-static PyObject *
-_mysql_ConnectionObject_use_result(
- _mysql_ConnectionObject *self,
- PyObject *args)
-{
- PyObject *arglist=NULL, *kwarglist=NULL, *result=NULL;
- _mysql_ResultObject *r=NULL;
-
- if (!PyArg_ParseTuple(args, "")) return NULL;
- check_connection(self);
- arglist = Py_BuildValue("(OiO)", self, 1, self->converter);
- if (!arglist) return NULL;
- kwarglist = PyDict_New();
- if (!kwarglist) goto error;
- r = MyAlloc(_mysql_ResultObject, _mysql_ResultObject_Type);
- if (!r) goto error;
- result = (PyObject *) r;
- if (_mysql_ResultObject_Initialize(r, arglist, kwarglist))
- goto error;
- if (!(r->result)) {
- Py_DECREF(result);
- Py_INCREF(Py_None);
- result = Py_None;
- }
- error:
- Py_DECREF(arglist);
- Py_XDECREF(kwarglist);
- return result;
-}
-
-static void
-_mysql_ConnectionObject_dealloc(
- _mysql_ConnectionObject *self)
-{
- PyObject *o;
-
- PyObject_GC_UnTrack(self);
- if (self->open) {
- o = _mysql_ConnectionObject_close(self, NULL);
- Py_XDECREF(o);
- }
- MyFree(self);
-}
-
-static PyObject *
-_mysql_ConnectionObject_repr(
- _mysql_ConnectionObject *self)
-{
- char buf[300];
- if (self->open)
- sprintf(buf, "<_mysql.connection open to '%.256s' at %lx>",
- self->connection.host,
- (long)self);
- else
- sprintf(buf, "<_mysql.connection closed at %lx>",
- (long)self);
-#ifdef IS_PY3K
- return PyUnicode_FromString(buf);
-#else
- return PyString_FromString(buf);
-#endif
-}
-
-static char _mysql_ResultObject_data_seek__doc__[] =
-"data_seek(n) -- seek to row n of result set";
-static PyObject *
-_mysql_ResultObject_data_seek(
- _mysql_ResultObject *self,
- PyObject *args)
-{
- unsigned int row;
- if (!PyArg_ParseTuple(args, "i:data_seek", &row)) return NULL;
- check_result_connection(self);
- mysql_data_seek(self->result, row);
- Py_INCREF(Py_None);
- return Py_None;
-}
-
-static char _mysql_ResultObject_row_seek__doc__[] =
-"row_seek(n) -- seek by offset n rows of result set";
-static PyObject *
-_mysql_ResultObject_row_seek(
- _mysql_ResultObject *self,
- PyObject *args)
-{
- int offset;
- MYSQL_ROW_OFFSET r;
- if (!PyArg_ParseTuple(args, "i:row_seek", &offset)) return NULL;
- check_result_connection(self);
- if (self->use) {
- PyErr_SetString(_mysql_ProgrammingError,
- "cannot be used with connection.use_result()");
- return NULL;
- }
- r = mysql_row_tell(self->result);
- mysql_row_seek(self->result, r+offset);
- Py_INCREF(Py_None);
- return Py_None;
-}
-
-static char _mysql_ResultObject_row_tell__doc__[] =
-"row_tell() -- return the current row number of the result set.";
-static PyObject *
-_mysql_ResultObject_row_tell(
- _mysql_ResultObject *self,
- PyObject *args)
-{
- MYSQL_ROW_OFFSET r;
- if (!PyArg_ParseTuple(args, "")) return NULL;
- check_result_connection(self);
- if (self->use) {
- PyErr_SetString(_mysql_ProgrammingError,
- "cannot be used with connection.use_result()");
- return NULL;
- }
- r = mysql_row_tell(self->result);
- return PyInt_FromLong(r-self->result->data->data);
-}
-
-static void
-_mysql_ResultObject_dealloc(
- _mysql_ResultObject *self)
-{
- PyObject_GC_UnTrack((PyObject *)self);
- mysql_free_result(self->result);
- _mysql_ResultObject_clear(self);
- MyFree(self);
-}
-
-static PyObject *
-_mysql_ResultObject_repr(
- _mysql_ResultObject *self)
-{
- char buf[300];
- sprintf(buf, "<_mysql.result object at %lx>",
- (long)self);
-#ifdef IS_PY3K
- return PyUnicode_FromString(buf);
-#else
- return PyString_FromString(buf);
-#endif
-}
-
-static PyMethodDef _mysql_ConnectionObject_methods[] = {
- {
- "affected_rows",
- (PyCFunction)_mysql_ConnectionObject_affected_rows,
- METH_VARARGS,
- _mysql_ConnectionObject_affected_rows__doc__
- },
- {
- "autocommit",
- (PyCFunction)_mysql_ConnectionObject_autocommit,
- METH_VARARGS,
- _mysql_ConnectionObject_autocommit__doc__
- },
- {
- "commit",
- (PyCFunction)_mysql_ConnectionObject_commit,
- METH_VARARGS,
- _mysql_ConnectionObject_commit__doc__
- },
- {
- "rollback",
- (PyCFunction)_mysql_ConnectionObject_rollback,
- METH_VARARGS,
- _mysql_ConnectionObject_rollback__doc__
- },
- {
- "next_result",
- (PyCFunction)_mysql_ConnectionObject_next_result,
- METH_VARARGS,
- _mysql_ConnectionObject_next_result__doc__
- },
-#if MYSQL_VERSION_ID >= 40100
- {
- "set_server_option",
- (PyCFunction)_mysql_ConnectionObject_set_server_option,
- METH_VARARGS,
- _mysql_ConnectionObject_set_server_option__doc__
- },
- {
- "sqlstate",
- (PyCFunction)_mysql_ConnectionObject_sqlstate,
- METH_VARARGS,
- _mysql_ConnectionObject_sqlstate__doc__
- },
- {
- "warning_count",
- (PyCFunction)_mysql_ConnectionObject_warning_count,
- METH_VARARGS,
- _mysql_ConnectionObject_warning_count__doc__
- },
-#endif
-#if MYSQL_VERSION_ID >= 32303
- {
- "change_user",
- (PyCFunction)_mysql_ConnectionObject_change_user,
- METH_VARARGS | METH_KEYWORDS,
- _mysql_ConnectionObject_change_user__doc__
- },
-#endif
- {
- "character_set_name",
- (PyCFunction)_mysql_ConnectionObject_character_set_name,
- METH_VARARGS,
- _mysql_ConnectionObject_character_set_name__doc__
- },
-#if MYSQL_VERSION_ID >= 50007
- {
- "set_character_set",
- (PyCFunction)_mysql_ConnectionObject_set_character_set,
- METH_VARARGS,
- _mysql_ConnectionObject_set_character_set__doc__
- },
-#endif
-#if MYSQL_VERSION_ID >= 50010
- {
- "get_character_set_info",
- (PyCFunction)_mysql_ConnectionObject_get_character_set_info,
- METH_VARARGS,
- _mysql_ConnectionObject_get_character_set_info__doc__
- },
-#endif
- {
- "close",
- (PyCFunction)_mysql_ConnectionObject_close,
- METH_VARARGS,
- _mysql_ConnectionObject_close__doc__
- },
- {
- "dump_debug_info",
- (PyCFunction)_mysql_ConnectionObject_dump_debug_info,
- METH_VARARGS,
- _mysql_ConnectionObject_dump_debug_info__doc__
- },
- {
- "escape",
- (PyCFunction)_mysql_escape,
- METH_VARARGS,
- _mysql_escape__doc__
- },
- {
- "escape_string",
- (PyCFunction)_mysql_escape_string,
- METH_VARARGS,
- _mysql_escape_string__doc__
- },
- {
- "error",
- (PyCFunction)_mysql_ConnectionObject_error,
- METH_VARARGS,
- _mysql_ConnectionObject_error__doc__
- },
- {
- "errno",
- (PyCFunction)_mysql_ConnectionObject_errno,
- METH_VARARGS,
- _mysql_ConnectionObject_errno__doc__
- },
- {
- "field_count",
- (PyCFunction)_mysql_ConnectionObject_field_count,
- METH_VARARGS,
- _mysql_ConnectionObject_field_count__doc__
- },
- {
- "get_host_info",
- (PyCFunction)_mysql_ConnectionObject_get_host_info,
- METH_VARARGS,
- _mysql_ConnectionObject_get_host_info__doc__
- },
- {
- "get_proto_info",
- (PyCFunction)_mysql_ConnectionObject_get_proto_info,
- METH_VARARGS,
- _mysql_ConnectionObject_get_proto_info__doc__
- },
- {
- "get_server_info",
- (PyCFunction)_mysql_ConnectionObject_get_server_info,
- METH_VARARGS,
- _mysql_ConnectionObject_get_server_info__doc__
- },
- {
- "info",
- (PyCFunction)_mysql_ConnectionObject_info,
- METH_VARARGS,
- _mysql_ConnectionObject_info__doc__
- },
- {
- "insert_id",
- (PyCFunction)_mysql_ConnectionObject_insert_id,
- METH_VARARGS,
- _mysql_ConnectionObject_insert_id__doc__
- },
- {
- "kill",
- (PyCFunction)_mysql_ConnectionObject_kill,
- METH_VARARGS,
- _mysql_ConnectionObject_kill__doc__
- },
- {
- "ping",
- (PyCFunction)_mysql_ConnectionObject_ping,
- METH_VARARGS,
- _mysql_ConnectionObject_ping__doc__
- },
- {
- "query",
- (PyCFunction)_mysql_ConnectionObject_query,
- METH_VARARGS,
- _mysql_ConnectionObject_query__doc__
- },
- {
- "select_db",
- (PyCFunction)_mysql_ConnectionObject_select_db,
- METH_VARARGS,
- _mysql_ConnectionObject_select_db__doc__
- },
- {
- "shutdown",
- (PyCFunction)_mysql_ConnectionObject_shutdown,
- METH_VARARGS,
- _mysql_ConnectionObject_shutdown__doc__
- },
- {
- "stat",
- (PyCFunction)_mysql_ConnectionObject_stat,
- METH_VARARGS,
- _mysql_ConnectionObject_stat__doc__
- },
- {
- "store_result",
- (PyCFunction)_mysql_ConnectionObject_store_result,
- METH_VARARGS,
- _mysql_ConnectionObject_store_result__doc__
- },
- {
- "string_literal",
- (PyCFunction)_mysql_string_literal,
- METH_VARARGS,
- _mysql_string_literal__doc__},
- {
- "thread_id",
- (PyCFunction)_mysql_ConnectionObject_thread_id,
- METH_VARARGS,
- _mysql_ConnectionObject_thread_id__doc__
- },
- {
- "use_result",
- (PyCFunction)_mysql_ConnectionObject_use_result,
- METH_VARARGS,
- _mysql_ConnectionObject_use_result__doc__
- },
- {NULL, NULL} /* sentinel */
-};
-
-static MyMemberlist(_mysql_ConnectionObject_memberlist)[] = {
- MyMember(
- "open",
- T_INT,
- offsetof(_mysql_ConnectionObject,open),
- READONLY,
- "True if connection is open"
- ),
- MyMember(
- "converter",
- T_OBJECT,
- offsetof(_mysql_ConnectionObject,converter),
- 0,
- "Type conversion mapping"
- ),
- MyMember(
- "server_capabilities",
- T_UINT,
- offsetof(_mysql_ConnectionObject,connection.server_capabilities),
- READONLY,
- "Capabilites of server; consult MySQLdb.constants.CLIENT"
- ),
- MyMember(
- "port",
- T_UINT,
- offsetof(_mysql_ConnectionObject,connection.port),
- READONLY,
- "TCP/IP port of the server connection"
- ),
- MyMember(
- "client_flag",
- T_UINT,
- READONLY,
- offsetof(_mysql_ConnectionObject,connection.client_flag),
- "Client flags; refer to MySQLdb.constants.CLIENT"
- ),
- {NULL} /* Sentinel */
-};
-
-static PyMethodDef _mysql_ResultObject_methods[] = {
- {
- "data_seek",
- (PyCFunction)_mysql_ResultObject_data_seek,
- METH_VARARGS,
- _mysql_ResultObject_data_seek__doc__
- },
- {
- "row_seek",
- (PyCFunction)_mysql_ResultObject_row_seek,
- METH_VARARGS,
- _mysql_ResultObject_row_seek__doc__
- },
- {
- "row_tell",
- (PyCFunction)_mysql_ResultObject_row_tell,
- METH_VARARGS,
- _mysql_ResultObject_row_tell__doc__
- },
- {
- "describe",
- (PyCFunction)_mysql_ResultObject_describe,
- METH_VARARGS,
- _mysql_ResultObject_describe__doc__
- },
- {
- "fetch_row",
- (PyCFunction)_mysql_ResultObject_fetch_row,
- METH_VARARGS | METH_KEYWORDS,
- _mysql_ResultObject_fetch_row__doc__
- },
- {
- "field_flags",
- (PyCFunction)_mysql_ResultObject_field_flags,
- METH_VARARGS,
- _mysql_ResultObject_field_flags__doc__
- },
- {
- "num_fields",
- (PyCFunction)_mysql_ResultObject_num_fields,
- METH_VARARGS,
- _mysql_ResultObject_num_fields__doc__
- },
- {
- "num_rows",
- (PyCFunction)_mysql_ResultObject_num_rows,
- METH_VARARGS,
- _mysql_ResultObject_num_rows__doc__
- },
- {NULL, NULL} /* sentinel */
-};
-
-static MyMemberlist(_mysql_ResultObject_memberlist)[] = {
- MyMember(
- "converter",
- T_OBJECT,
- offsetof(_mysql_ResultObject,converter),
- READONLY,
- "Type conversion mapping"
- ),
- {NULL} /* Sentinel */
-};
-
-static PyObject *
-_mysql_ConnectionObject_getattr(
- _mysql_ConnectionObject *self,
- char *name)
-{
-#ifndef IS_PY3K
- PyObject *res;
-
- res = Py_FindMethod(_mysql_ConnectionObject_methods, (PyObject *)self, name);
- if (res != NULL)
- return res;
- PyErr_Clear();
-#endif
- if (strcmp(name, "closed") == 0)
- return PyInt_FromLong((long)!(self->open));
-#if PY_VERSION_HEX < 0x02020000
- return PyMember_Get((char *)self, _mysql_ConnectionObject_memberlist, name);
-#else
- {
- MyMemberlist(*l);
- for (l = _mysql_ConnectionObject_memberlist; l->name != NULL; l++) {
- if (strcmp(l->name, name) == 0)
- return PyMember_GetOne((char *)self, l);
- }
- PyErr_SetString(PyExc_AttributeError, name);
- return NULL;
- }
-#endif
-}
-
-static PyObject *
-_mysql_ResultObject_getattr(
- _mysql_ResultObject *self,
- char *name)
-{
-#ifndef IS_PY3K
- PyObject *res;
-
- res = Py_FindMethod(_mysql_ResultObject_methods, (PyObject *)self, name);
- if (res != NULL)
- return res;
- PyErr_Clear();
-#endif
-#if PY_VERSION_HEX < 0x02020000
- return PyMember_Get((char *)self, _mysql_ResultObject_memberlist, name);
-#else
- {
- MyMemberlist(*l);
- for (l = _mysql_ResultObject_memberlist; l->name != NULL; l++) {
- if (strcmp(l->name, name) == 0)
- return PyMember_GetOne((char *)self, l);
- }
- PyErr_SetString(PyExc_AttributeError, name);
- return NULL;
- }
-#endif
-}
-
-static int
-_mysql_ConnectionObject_setattr(
- _mysql_ConnectionObject *self,
- char *name,
- PyObject *v)
-{
- if (v == NULL) {
- PyErr_SetString(PyExc_AttributeError,
- "can't delete connection attributes");
- return -1;
- }
-#if PY_VERSION_HEX < 0x02020000
- return PyMember_Set((char *)self, _mysql_ConnectionObject_memberlist, name, v);
-#else
- {
- MyMemberlist(*l);
- for (l = _mysql_ConnectionObject_memberlist; l->name != NULL; l++)
- if (strcmp(l->name, name) == 0)
- return PyMember_SetOne((char *)self, l, v);
- }
- PyErr_SetString(PyExc_AttributeError, name);
- return -1;
-#endif
-}
-
-static int
-_mysql_ResultObject_setattr(
- _mysql_ResultObject *self,
- char *name,
- PyObject *v)
-{
- if (v == NULL) {
- PyErr_SetString(PyExc_AttributeError,
- "can't delete connection attributes");
- return -1;
- }
-#if PY_VERSION_HEX < 0x02020000
- return PyMember_Set((char *)self, _mysql_ResultObject_memberlist, name, v);
-#else
- {
- MyMemberlist(*l);
- for (l = _mysql_ResultObject_memberlist; l->name != NULL; l++)
- if (strcmp(l->name, name) == 0)
- return PyMember_SetOne((char *)self, l, v);
- }
- PyErr_SetString(PyExc_AttributeError, name);
- return -1;
-#endif
-}
-
-PyTypeObject _mysql_ConnectionObject_Type = {
-#ifdef IS_PY3K
- PyVarObject_HEAD_INIT(NULL, 0)
-#else
- PyObject_HEAD_INIT(NULL)
- 0,
-#endif
- "_mysql.connection", /* (char *)tp_name For printing */
- sizeof(_mysql_ConnectionObject),
- 0,
- (destructor)_mysql_ConnectionObject_dealloc, /* tp_dealloc */
- 0, /*tp_print*/
- (getattrfunc)_mysql_ConnectionObject_getattr, /* tp_getattr */
- (setattrfunc)_mysql_ConnectionObject_setattr, /* tp_setattr */
- 0, /*tp_compare*/
- (reprfunc)_mysql_ConnectionObject_repr, /* tp_repr */
-
- /* Method suites for standard classes */
-
- 0, /* (PyNumberMethods *) tp_as_number */
- 0, /* (PySequenceMethods *) tp_as_sequence */
- 0, /* (PyMappingMethods *) tp_as_mapping */
-
- /* More standard operations (here for binary compatibility) */
-
- 0, /* (hashfunc) tp_hash */
- 0, /* (ternaryfunc) tp_call */
- 0, /* (reprfunc) tp_str */
- 0, /* (getattrofunc) tp_getattro */
- 0, /* (setattrofunc) tp_setattro */
-
- /* Functions to access object as input/output buffer */
- 0, /* (PyBufferProcs *) tp_as_buffer */
-
- /* Flags to define presence of optional/expanded features */
-#if PY_VERSION_HEX < 0x02020000
- Py_TPFLAGS_DEFAULT, /* (long) tp_flags */
-#else
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE,
-#endif
- _mysql_connect__doc__, /* (char *) tp_doc Documentation string */
-#if PY_VERSION_HEX >= 0x02000000
- /* Assigned meaning in release 2.0 */
-#if PY_VERSION_HEX >= 0x02020000
- /* call function for all accessible objects */
- (traverseproc) _mysql_ConnectionObject_traverse, /* tp_traverse */
-
- /* delete references to contained objects */
- (inquiry) _mysql_ConnectionObject_clear, /* tp_clear */
-#else
- /* not supporting pre-2.2 GC */
- 0,
- 0,
-#endif
-#if PY_VERSION_HEX >= 0x02010000
- /* Assigned meaning in release 2.1 */
- /* rich comparisons */
- 0, /* (richcmpfunc) tp_richcompare */
-
- /* weak reference enabler */
- 0, /* (long) tp_weaklistoffset */
-#if PY_VERSION_HEX >= 0x02020000
- /* Added in release 2.2 */
- /* Iterators */
- 0, /* (getiterfunc) tp_iter */
- 0, /* (iternextfunc) tp_iternext */
-
- /* Attribute descriptor and subclassing stuff */
- (struct PyMethodDef *)_mysql_ConnectionObject_methods, /* tp_methods */
- (MyMemberlist(*))_mysql_ConnectionObject_memberlist, /* tp_members */
- 0, /* (struct getsetlist *) tp_getset; */
- 0, /* (struct _typeobject *) tp_base; */
- 0, /* (PyObject *) tp_dict */
- 0, /* (descrgetfunc) tp_descr_get */
- 0, /* (descrsetfunc) tp_descr_set */
- 0, /* (long) tp_dictoffset */
- (initproc)_mysql_ConnectionObject_Initialize, /* tp_init */
- NULL, /* tp_alloc */
- NULL, /* tp_new */
- NULL, /* tp_free Low-level free-memory routine */
- 0, /* (PyObject *) tp_bases */
- 0, /* (PyObject *) tp_mro method resolution order */
- 0, /* (PyObject *) tp_defined */
-#endif /* python 2.2 */
-#endif /* python 2.1 */
-#endif /* python 2.0 */
-} ;
-
-PyTypeObject _mysql_ResultObject_Type = {
-#ifdef IS_PY3K
- PyVarObject_HEAD_INIT(NULL, 0)
-#else
- PyObject_HEAD_INIT(NULL)
- 0,
-#endif
- "_mysql.result",
- sizeof(_mysql_ResultObject),
- 0,
- (destructor)_mysql_ResultObject_dealloc, /* tp_dealloc */
- 0, /*tp_print*/
- (getattrfunc)_mysql_ResultObject_getattr, /* tp_getattr */
- (setattrfunc)_mysql_ResultObject_setattr, /* tp_setattr */
- 0, /*tp_compare*/
- (reprfunc)_mysql_ResultObject_repr, /* tp_repr */
-
- /* Method suites for standard classes */
-
- 0, /* (PyNumberMethods *) tp_as_number */
- 0, /* (PySequenceMethods *) tp_as_sequence */
- 0, /* (PyMappingMethods *) tp_as_mapping */
-
- /* More standard operations (here for binary compatibility) */
-
- 0, /* (hashfunc) tp_hash */
- 0, /* (ternaryfunc) tp_call */
- 0, /* (reprfunc) tp_str */
- 0, /* (getattrofunc) tp_getattro */
- 0, /* (setattrofunc) tp_setattro */
-
- /* Functions to access object as input/output buffer */
- 0, /* (PyBufferProcs *) tp_as_buffer */
-
- /* Flags to define presence of optional/expanded features */
-#if PY_VERSION_HEX < 0x02020000
- Py_TPFLAGS_DEFAULT, /* (long) tp_flags */
-#else
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE,
-#endif
-
- _mysql_ResultObject__doc__, /* (char *) tp_doc Documentation string */
-#if PY_VERSION_HEX >= 0x02000000
- /* Assigned meaning in release 2.0 */
-#if PY_VERSION_HEX >= 0x02020000
- /* call function for all accessible objects */
- (traverseproc) _mysql_ResultObject_traverse, /* tp_traverse */
-
- /* delete references to contained objects */
- (inquiry) _mysql_ResultObject_clear, /* tp_clear */
-#else
- /* not supporting pre-2.2 GC */
- 0,
- 0,
-#endif
-#if PY_VERSION_HEX >= 0x02010000
- /* Assigned meaning in release 2.1 */
- /* rich comparisons */
- 0, /* (richcmpfunc) tp_richcompare */
-
- /* weak reference enabler */
- 0, /* (long) tp_weaklistoffset */
-#if PY_VERSION_HEX >= 0x02020000
- /* Added in release 2.2 */
- /* Iterators */
- 0, /* (getiterfunc) tp_iter */
- 0, /* (iternextfunc) tp_iternext */
-
- /* Attribute descriptor and subclassing stuff */
- (struct PyMethodDef *) _mysql_ResultObject_methods, /* tp_methods */
- (MyMemberlist(*)) _mysql_ResultObject_memberlist, /*tp_members */
- 0, /* (struct getsetlist *) tp_getset; */
- 0, /* (struct _typeobject *) tp_base; */
- 0, /* (PyObject *) tp_dict */
- 0, /* (descrgetfunc) tp_descr_get */
- 0, /* (descrsetfunc) tp_descr_set */
- 0, /* (long) tp_dictoffset */
- (initproc)_mysql_ResultObject_Initialize, /* tp_init */
- NULL, /* tp_alloc */
- NULL, /* tp_new */
- NULL, /* tp_free Low-level free-memory routine */
- 0, /* (PyObject *) tp_bases */
- 0, /* (PyObject *) tp_mro method resolution order */
- 0, /* (PyObject *) tp_defined */
-#endif /* python 2.2 */
-#endif /* python 2.1 */
-#endif /* python 2.0 */
-};
-
-static PyMethodDef
-_mysql_methods[] = {
- {
- "connect",
- (PyCFunction)_mysql_connect,
- METH_VARARGS | METH_KEYWORDS,
- _mysql_connect__doc__
- },
- {
- "debug",
- (PyCFunction)_mysql_debug,
- METH_VARARGS,
- _mysql_debug__doc__
- },
- {
- "escape",
- (PyCFunction)_mysql_escape,
- METH_VARARGS,
- _mysql_escape__doc__
- },
- {
- "escape_sequence",
- (PyCFunction)_mysql_escape_sequence,
- METH_VARARGS,
- _mysql_escape_sequence__doc__
- },
- {
- "escape_dict",
- (PyCFunction)_mysql_escape_dict,
- METH_VARARGS,
- _mysql_escape_dict__doc__
- },
- {
- "escape_string",
- (PyCFunction)_mysql_escape_string,
- METH_VARARGS,
- _mysql_escape_string__doc__
- },
- {
- "string_literal",
- (PyCFunction)_mysql_string_literal,
- METH_VARARGS,
- _mysql_string_literal__doc__
- },
- {
- "get_client_info",
- (PyCFunction)_mysql_get_client_info,
- METH_VARARGS,
- _mysql_get_client_info__doc__
- },
-#if MYSQL_VERSION_ID >= 32314
- {
- "thread_safe",
- (PyCFunction)_mysql_thread_safe,
- METH_VARARGS,
- _mysql_thread_safe__doc__
- },
-#endif
- {
- "server_init",
- (PyCFunction)_mysql_server_init,
- METH_VARARGS | METH_KEYWORDS,
- _mysql_server_init__doc__
- },
- {
- "server_end",
- (PyCFunction)_mysql_server_end,
- METH_VARARGS,
- _mysql_server_end__doc__
- },
- {NULL, NULL} /* sentinel */
-};
-
-static PyObject *
-_mysql_NewException(
- PyObject *dict,
- PyObject *edict,
- char *name)
-{
- PyObject *e;
-
- if (!(e = PyDict_GetItemString(edict, name)))
- return NULL;
- if (PyDict_SetItemString(dict, name, e)) return NULL;
- return e;
-}
-
-#define QUOTE(X) _QUOTE(X)
-#define _QUOTE(X) #X
-
-static char _mysql___doc__[] =
-"an adaptation of the MySQL C API (mostly)\n\
-\n\
-You probably are better off using MySQLdb instead of using this\n\
-module directly.\n\
-\n\
-In general, renaming goes from mysql_* to _mysql.*. _mysql.connect()\n\
-returns a connection object (MYSQL). Functions which expect MYSQL * as\n\
-an argument are now methods of the connection object. A number of things\n\
-return result objects (MYSQL_RES). Functions which expect MYSQL_RES * as\n\
-an argument are now methods of the result object. Deprecated functions\n\
-(as of 3.23) are NOT implemented.\n\
-";
-
-#ifdef IS_PY3K
-static struct PyModuleDef _mysqlmodule = {
- PyModuleDef_HEAD_INIT,
- "_mysql", /* name of module */
- _mysql___doc__, /* module documentation, may be NULL */
- -1, /* size of per-interpreter state of the module,
- or -1 if the module keeps state in global variables. */
- _mysql_methods
-};
-
-PyMODINIT_FUNC
-PyInit__mysql(void)
-#else
-DL_EXPORT(void)
-init_mysql(void)
-#endif
-{
- PyObject *dict, *module, *emod, *edict;
-#ifdef IS_PY3K
- module = PyModule_Create(&_mysqlmodule);
- if (!module) return module; /* this really should never happen */
-#else
- module = Py_InitModule4("_mysql", _mysql_methods, _mysql___doc__,
- (PyObject *)NULL, PYTHON_API_VERSION);
- if (!module) return; /* this really should never happen */
-#endif
-#ifdef IS_PY3K
- Py_TYPE(&_mysql_ConnectionObject_Type) = &PyType_Type;
- Py_TYPE(&_mysql_ResultObject_Type) = &PyType_Type;
-#else
- _mysql_ConnectionObject_Type.ob_type = &PyType_Type;
- _mysql_ResultObject_Type.ob_type = &PyType_Type;
-#endif
-#if PY_VERSION_HEX >= 0x02020000
- _mysql_ConnectionObject_Type.tp_alloc = PyType_GenericAlloc;
- _mysql_ConnectionObject_Type.tp_new = PyType_GenericNew;
-#ifndef IS_PY3K
- _mysql_ConnectionObject_Type.tp_free = _PyObject_GC_Del;
-#endif
- _mysql_ResultObject_Type.tp_alloc = PyType_GenericAlloc;
- _mysql_ResultObject_Type.tp_new = PyType_GenericNew;
-#ifndef IS_PY3K
- _mysql_ResultObject_Type.tp_free = _PyObject_GC_Del;
-#endif
-#endif
-
- if (!(dict = PyModule_GetDict(module))) goto error;
- if (PyDict_SetItemString(dict, "version_info",
- PyRun_String(QUOTE(version_info), Py_eval_input,
- dict, dict)))
- goto error;
- if (PyDict_SetItemString(dict, "__version__",
-#ifdef IS_PY3K
- PyUnicode_FromString(QUOTE(__version__))))
-#else
- PyString_FromString(QUOTE(__version__))))
-#endif
- goto error;
- if (PyDict_SetItemString(dict, "connection",
- (PyObject *)&_mysql_ConnectionObject_Type))
- goto error;
- Py_INCREF(&_mysql_ConnectionObject_Type);
- if (PyDict_SetItemString(dict, "result",
- (PyObject *)&_mysql_ResultObject_Type))
- goto error;
- Py_INCREF(&_mysql_ResultObject_Type);
- if (!(emod = PyImport_ImportModule("_mysql_exceptions"))) {
- PyErr_Print();
- goto error;
- }
- if (!(edict = PyModule_GetDict(emod))) goto error;
- if (!(_mysql_MySQLError =
- _mysql_NewException(dict, edict, "MySQLError")))
- goto error;
- if (!(_mysql_Warning =
- _mysql_NewException(dict, edict, "Warning")))
- goto error;
- if (!(_mysql_Error =
- _mysql_NewException(dict, edict, "Error")))
- goto error;
- if (!(_mysql_InterfaceError =
- _mysql_NewException(dict, edict, "InterfaceError")))
- goto error;
- if (!(_mysql_DatabaseError =
- _mysql_NewException(dict, edict, "DatabaseError")))
- goto error;
- if (!(_mysql_DataError =
- _mysql_NewException(dict, edict, "DataError")))
- goto error;
- if (!(_mysql_OperationalError =
- _mysql_NewException(dict, edict, "OperationalError")))
- goto error;
- if (!(_mysql_IntegrityError =
- _mysql_NewException(dict, edict, "IntegrityError")))
- goto error;
- if (!(_mysql_InternalError =
- _mysql_NewException(dict, edict, "InternalError")))
- goto error;
- if (!(_mysql_ProgrammingError =
- _mysql_NewException(dict, edict, "ProgrammingError")))
- goto error;
- if (!(_mysql_NotSupportedError =
- _mysql_NewException(dict, edict, "NotSupportedError")))
- goto error;
- Py_DECREF(emod);
-#ifdef IS_PY3K
- if (!(_mysql_NULL = PyUnicode_FromString("NULL")))
- goto error;
-#else
- if (!(_mysql_NULL = PyString_FromString("NULL")))
- goto error;
-#endif
- if (PyDict_SetItemString(dict, "NULL", _mysql_NULL)) goto error;
- error:
- if (PyErr_Occurred()) {
- PyErr_SetString(PyExc_ImportError,
- "_mysql: init failed");
- module = NULL;
- }
-#ifdef IS_PY3K
- return module;
-#endif
-}
-
-
+/*
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version. Alternatively, you may use the original license
+reproduced below.
+
+Copyright 1999 by Comstar.net, Inc., Atlanta, GA, US.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the name of Comstar.net, Inc.
+or COMSTAR not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior permission.
+
+COMSTAR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+EVENT SHALL COMSTAR BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+PERFORMANCE OF THIS SOFTWARE.
+*/
+
+#include "Python.h"
+#if PY_MAJOR_VERSION >= 3
+#define IS_PY3K
+#define PyInt_FromLong(n) PyLong_FromLong(n)
+#define PyInt_Check(n) PyLong_Check(n)
+#define PyInt_AS_LONG(n) PyLong_AS_LONG(n)
+#endif
+#if PY_VERSION_HEX > 0x02060000
+#include "bytesobject.h"
+#endif
+#include "pymemcompat.h"
+#include "structmember.h"
+#if defined(MS_WINDOWS)
+#include <config-win.h>
+#else
+#include "my_config.h"
+#endif
+#include "mysql.h"
+#include "mysqld_error.h"
+#include "errmsg.h"
+
+#if PY_VERSION_HEX < 0x02020000
+# define MyTuple_Resize(t,n,d) _PyTuple_Resize(t, n, d)
+# define MyMember(a,b,c,d,e) {a,b,c,d}
+# define MyMemberlist(x) struct memberlist x
+# define MyAlloc(s,t) PyObject_New(s,&t)
+# define MyFree(o) PyObject_Del(o)
+#else
+# define MyTuple_Resize(t,n,d) _PyTuple_Resize(t, n)
+# define MyMember(a,b,c,d,e) {a,b,c,d,e}
+# define MyMemberlist(x) struct PyMemberDef x
+# define MyAlloc(s,t) (s *) t.tp_alloc(&t,0)
+#ifdef IS_PY3K
+# define MyFree(o) PyObject_Del(o)
+#else
+# define MyFree(ob) ob->ob_type->tp_free((PyObject *)ob)
+#endif
+#endif
+
+#if PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN)
+typedef int Py_ssize_t;
+#define PY_SSIZE_T_MAX INT_MAX
+#define PY_SSIZE_T_MIN INT_MIN
+#endif
+
+static PyObject *_mysql_MySQLError;
+static PyObject *_mysql_Warning;
+static PyObject *_mysql_Error;
+static PyObject *_mysql_DatabaseError;
+static PyObject *_mysql_InterfaceError;
+static PyObject *_mysql_DataError;
+static PyObject *_mysql_OperationalError;
+static PyObject *_mysql_IntegrityError;
+static PyObject *_mysql_InternalError;
+static PyObject *_mysql_ProgrammingError;
+static PyObject *_mysql_NotSupportedError;
+
+typedef struct {
+ PyObject_HEAD
+ MYSQL connection;
+ int open;
+ PyObject *converter;
+} _mysql_ConnectionObject;
+
+#define check_connection(c) if (!(c->open)) return _mysql_Exception(c)
+#define result_connection(r) ((_mysql_ConnectionObject *)r->conn)
+#define check_result_connection(r) check_connection(result_connection(r))
+
+extern PyTypeObject _mysql_ConnectionObject_Type;
+
+typedef struct {
+ PyObject_HEAD
+ PyObject *conn;
+ MYSQL_RES *result;
+ int nfields;
+ int use;
+ PyObject *converter;
+} _mysql_ResultObject;
+
+extern PyTypeObject _mysql_ResultObject_Type;
+
+static int _mysql_server_init_done = 0;
+#if MYSQL_VERSION_ID >= 40000
+#define check_server_init(x) if (!_mysql_server_init_done) { if (mysql_server_init(0, NULL, NULL)) { _mysql_Exception(NULL); return x; } else { _mysql_server_init_done = 1;} }
+#else
+#define check_server_init(x) if (!_mysql_server_init_done) _mysql_server_init_done = 1
+#endif
+
+#if MYSQL_VERSION_ID >= 50500
+#define HAVE_OPENSSL 1
+#endif
+
+PyObject *
+_mysql_Exception(_mysql_ConnectionObject *c)
+{
+ PyObject *t, *e;
+ int merr;
+
+ if (!(t = PyTuple_New(2))) return NULL;
+ if (!_mysql_server_init_done) {
+ e = _mysql_InternalError;
+ PyTuple_SET_ITEM(t, 0, PyInt_FromLong(-1L));
+#ifdef IS_PY3K
+ PyTuple_SET_ITEM(t, 1, PyUnicode_FromString("server not initialized"));
+#else
+ PyTuple_SET_ITEM(t, 1, PyString_FromString("server not initialized"));
+#endif
+ PyErr_SetObject(e, t);
+ Py_DECREF(t);
+ return NULL;
+ }
+ merr = mysql_errno(&(c->connection));
+ if (!merr)
+ e = _mysql_InterfaceError;
+ else if (merr > CR_MAX_ERROR) {
+ PyTuple_SET_ITEM(t, 0, PyInt_FromLong(-1L));
+#ifdef IS_PY3K
+ PyTuple_SET_ITEM(t, 1, PyUnicode_FromString("error totally whack"));
+#else
+ PyTuple_SET_ITEM(t, 1, PyString_FromString("error totally whack"));
+#endif
+ PyErr_SetObject(_mysql_InterfaceError, t);
+ Py_DECREF(t);
+ return NULL;
+ }
+ else switch (merr) {
+ case CR_COMMANDS_OUT_OF_SYNC:
+ case ER_DB_CREATE_EXISTS:
+ case ER_SYNTAX_ERROR:
+ case ER_PARSE_ERROR:
+ case ER_NO_SUCH_TABLE:
+ case ER_WRONG_DB_NAME:
+ case ER_WRONG_TABLE_NAME:
+ case ER_FIELD_SPECIFIED_TWICE:
+ case ER_INVALID_GROUP_FUNC_USE:
+ case ER_UNSUPPORTED_EXTENSION:
+ case ER_TABLE_MUST_HAVE_COLUMNS:
+#ifdef ER_CANT_DO_THIS_DURING_AN_TRANSACTION
+ case ER_CANT_DO_THIS_DURING_AN_TRANSACTION:
+#endif
+ e = _mysql_ProgrammingError;
+ break;
+#ifdef WARN_DATA_TRUNCATED
+ case WARN_DATA_TRUNCATED:
+#ifdef WARN_NULL_TO_NOTNULL
+ case WARN_NULL_TO_NOTNULL:
+#endif
+#ifdef ER_WARN_DATA_OUT_OF_RANGE
+ case ER_WARN_DATA_OUT_OF_RANGE:
+#endif
+#ifdef ER_NO_DEFAULT
+ case ER_NO_DEFAULT:
+#endif
+#ifdef ER_PRIMARY_CANT_HAVE_NULL
+ case ER_PRIMARY_CANT_HAVE_NULL:
+#endif
+#ifdef ER_DATA_TOO_LONG
+ case ER_DATA_TOO_LONG:
+#endif
+#ifdef ER_DATETIME_FUNCTION_OVERFLOW
+ case ER_DATETIME_FUNCTION_OVERFLOW:
+#endif
+ e = _mysql_DataError;
+ break;
+#endif
+ case ER_DUP_ENTRY:
+#ifdef ER_DUP_UNIQUE
+ case ER_DUP_UNIQUE:
+#endif
+#ifdef ER_NO_REFERENCED_ROW
+ case ER_NO_REFERENCED_ROW:
+#endif
+#ifdef ER_NO_REFERENCED_ROW_2
+ case ER_NO_REFERENCED_ROW_2:
+#endif
+#ifdef ER_ROW_IS_REFERENCED
+ case ER_ROW_IS_REFERENCED:
+#endif
+#ifdef ER_ROW_IS_REFERENCED_2
+ case ER_ROW_IS_REFERENCED_2:
+#endif
+#ifdef ER_CANNOT_ADD_FOREIGN
+ case ER_CANNOT_ADD_FOREIGN:
+#endif
+ e = _mysql_IntegrityError;
+ break;
+#ifdef ER_WARNING_NOT_COMPLETE_ROLLBACK
+ case ER_WARNING_NOT_COMPLETE_ROLLBACK:
+#endif
+#ifdef ER_NOT_SUPPORTED_YET
+ case ER_NOT_SUPPORTED_YET:
+#endif
+#ifdef ER_FEATURE_DISABLED
+ case ER_FEATURE_DISABLED:
+#endif
+#ifdef ER_UNKNOWN_STORAGE_ENGINE
+ case ER_UNKNOWN_STORAGE_ENGINE:
+#endif
+ e = _mysql_NotSupportedError;
+ break;
+ default:
+ if (merr < 1000)
+ e = _mysql_InternalError;
+ else
+ e = _mysql_OperationalError;
+ break;
+ }
+ PyTuple_SET_ITEM(t, 0, PyInt_FromLong((long)merr));
+#ifdef IS_PY3K
+ PyTuple_SET_ITEM(t, 1, PyUnicode_FromString(mysql_error(&(c->connection))));
+#else
+ PyTuple_SET_ITEM(t, 1, PyString_FromString(mysql_error(&(c->connection))));
+#endif
+ PyErr_SetObject(e, t);
+ Py_DECREF(t);
+ return NULL;
+}
+
+static char _mysql_server_init__doc__[] =
+"Initialize embedded server. If this client is not linked against\n\
+the embedded server library, this function does nothing.\n\
+\n\
+args -- sequence of command-line arguments\n\
+groups -- sequence of groups to use in defaults files\n\
+";
+
+static PyObject *_mysql_server_init(
+ PyObject *self,
+ PyObject *args,
+ PyObject *kwargs) {
+ static char *kwlist[] = {"args", "groups", NULL};
+ char **cmd_args_c=NULL, **groups_c=NULL, *s;
+ int cmd_argc=0, i, groupc;
+ PyObject *cmd_args=NULL, *groups=NULL, *ret=NULL, *item;
+
+ if (_mysql_server_init_done) {
+ PyErr_SetString(_mysql_ProgrammingError,
+ "already initialized");
+ return NULL;
+ }
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OO", kwlist,
+ &cmd_args, &groups))
+ return NULL;
+
+#if MYSQL_VERSION_ID >= 40000
+ if (cmd_args) {
+ if (!PySequence_Check(cmd_args)) {
+ PyErr_SetString(PyExc_TypeError,
+ "args must be a sequence");
+ goto finish;
+ }
+ cmd_argc = PySequence_Size(cmd_args);
+ if (cmd_argc == -1) {
+ PyErr_SetString(PyExc_TypeError,
+ "args could not be sized");
+ goto finish;
+ }
+ cmd_args_c = (char **) PyMem_Malloc(cmd_argc*sizeof(char *));
+ for (i=0; i< cmd_argc; i++) {
+ item = PySequence_GetItem(cmd_args, i);
+#ifdef IS_PY3K
+ s = PyUnicode_AS_DATA(item);
+#else
+ s = PyString_AsString(item);
+#endif
+
+ Py_DECREF(item);
+ if (!s) {
+ PyErr_SetString(PyExc_TypeError,
+ "args must contain strings");
+ goto finish;
+ }
+ cmd_args_c[i] = s;
+ }
+ }
+ if (groups) {
+ if (!PySequence_Check(groups)) {
+ PyErr_SetString(PyExc_TypeError,
+ "groups must be a sequence");
+ goto finish;
+ }
+ groupc = PySequence_Size(groups);
+ if (groupc == -1) {
+ PyErr_SetString(PyExc_TypeError,
+ "groups could not be sized");
+ goto finish;
+ }
+ groups_c = (char **) PyMem_Malloc((1+groupc)*sizeof(char *));
+ for (i=0; i< groupc; i++) {
+ item = PySequence_GetItem(groups, i);
+#ifdef IS_PY3K
+ s = PyUnicode_AS_DATA(item);
+#else
+ s = PyString_AsString(item);
+#endif
+ Py_DECREF(item);
+ if (!s) {
+ PyErr_SetString(PyExc_TypeError,
+ "groups must contain strings");
+ goto finish;
+ }
+ groups_c[i] = s;
+ }
+ groups_c[groupc] = (char *)NULL;
+ }
+ /* even though this may block, don't give up the interpreter lock
+ so that the server can't be initialized multiple times. */
+ if (mysql_server_init(cmd_argc, cmd_args_c, groups_c)) {
+ _mysql_Exception(NULL);
+ goto finish;
+ }
+#endif
+ ret = Py_None;
+ Py_INCREF(Py_None);
+ _mysql_server_init_done = 1;
+ finish:
+ PyMem_Free(groups_c);
+ PyMem_Free(cmd_args_c);
+ return ret;
+}
+
+static char _mysql_server_end__doc__[] =
+"Shut down embedded server. If not using an embedded server, this\n\
+does nothing.";
+
+static PyObject *_mysql_server_end(
+ PyObject *self,
+ PyObject *args) {
+ if (_mysql_server_init_done) {
+#if MYSQL_VERSION_ID >= 40000
+ mysql_server_end();
+#endif
+ _mysql_server_init_done = 0;
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+ return _mysql_Exception(NULL);
+}
+
+#if MYSQL_VERSION_ID >= 32314
+static char _mysql_thread_safe__doc__[] =
+"Indicates whether the client is compiled as thread-safe.";
+
+static PyObject *_mysql_thread_safe(
+ PyObject *self,
+ PyObject *args) {
+ PyObject *flag;
+ if (!PyArg_ParseTuple(args, "")) return NULL;
+ check_server_init(NULL);
+ if (!(flag=PyInt_FromLong((long)mysql_thread_safe()))) return NULL;
+ return flag;
+}
+#endif
+
+static char _mysql_ResultObject__doc__[] =
+"result(connection, use=0, converter={}) -- Result set from a query.\n\
+\n\
+Creating instances of this class directly is an excellent way to\n\
+shoot yourself in the foot. If using _mysql.connection directly,\n\
+use connection.store_result() or connection.use_result() instead.\n\
+If using MySQLdb.Connection, this is done by the cursor class.\n\
+Just forget you ever saw this. Forget... FOR-GET...";
+
+static int
+_mysql_ResultObject_Initialize(
+ _mysql_ResultObject *self,
+ PyObject *args,
+ PyObject *kwargs)
+{
+ static char *kwlist[] = {"connection", "use", "converter", NULL};
+ MYSQL_RES *result;
+ _mysql_ConnectionObject *conn=NULL;
+ int use=0;
+ PyObject *conv=NULL;
+ int n, i;
+ MYSQL_FIELD *fields;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|iO", kwlist,
+ &conn, &use, &conv))
+ return -1;
+ if (!conv) conv = PyDict_New();
+ if (!conv) return -1;
+ self->conn = (PyObject *) conn;
+ Py_INCREF(conn);
+ self->use = use;
+ Py_BEGIN_ALLOW_THREADS ;
+ if (use)
+ result = mysql_use_result(&(conn->connection));
+ else
+ result = mysql_store_result(&(conn->connection));
+ self->result = result;
+ Py_END_ALLOW_THREADS ;
+ if (!result) {
+ if (mysql_field_count(&(conn->connection)) > 0) {
+ _mysql_Exception(conn);
+ return -1;
+ }
+ self->converter = PyTuple_New(0);
+ return 0;
+ }
+ n = mysql_num_fields(result);
+ self->nfields = n;
+ if (!(self->converter = PyTuple_New(n))) return -1;
+ fields = mysql_fetch_fields(result);
+ for (i=0; i<n; i++) {
+ PyObject *tmp, *fun;
+ tmp = PyInt_FromLong((long) fields[i].type);
+ if (!tmp) return -1;
+ fun = PyObject_GetItem(conv, tmp);
+ Py_DECREF(tmp);
+ if (!fun) {
+ PyErr_Clear();
+ fun = Py_None;
+ Py_INCREF(Py_None);
+ }
+ if (PySequence_Check(fun)) {
+ int j, n2=PySequence_Size(fun);
+ PyObject *fun2=NULL;
+ for (j=0; j<n2; j++) {
+ PyObject *t = PySequence_GetItem(fun, j);
+ if (!t) continue;
+ if (!PyTuple_Check(t)) goto cleanup;
+ if (PyTuple_GET_SIZE(t) == 2) {
+ long mask;
+ PyObject *pmask=NULL;
+ pmask = PyTuple_GET_ITEM(t, 0);
+ fun2 = PyTuple_GET_ITEM(t, 1);
+ if (PyInt_Check(pmask)) {
+ mask = PyInt_AS_LONG(pmask);
+ if (mask & fields[i].flags) {
+ Py_DECREF(t);
+ break;
+ }
+ else {
+ goto cleanup;
+ }
+ } else {
+ Py_DECREF(t);
+ break;
+ }
+ }
+ cleanup:
+ Py_DECREF(t);
+ }
+ if (!fun2) fun2 = Py_None;
+ Py_INCREF(fun2);
+ Py_DECREF(fun);
+ fun = fun2;
+ }
+ PyTuple_SET_ITEM(self->converter, i, fun);
+ }
+ return 0;
+}
+
+#if PY_VERSION_HEX >= 0x02020000
+static int _mysql_ResultObject_traverse(
+ _mysql_ResultObject *self,
+ visitproc visit,
+ void *arg)
+{
+ int r;
+ if (self->converter) {
+ if (!(r = visit(self->converter, arg))) return r;
+ }
+ if (self->conn)
+ return visit(self->conn, arg);
+ return 0;
+}
+#endif
+
+static int _mysql_ResultObject_clear(
+ _mysql_ResultObject *self)
+{
+ Py_XDECREF(self->converter);
+ self->converter = NULL;
+ Py_XDECREF(self->conn);
+ self->conn = NULL;
+ return 0;
+}
+
+static int
+_mysql_ConnectionObject_Initialize(
+ _mysql_ConnectionObject *self,
+ PyObject *args,
+ PyObject *kwargs)
+{
+ MYSQL *conn = NULL;
+ PyObject *conv = NULL;
+ PyObject *ssl = NULL;
+#if HAVE_OPENSSL
+ char *key = NULL, *cert = NULL, *ca = NULL,
+ *capath = NULL, *cipher = NULL;
+#endif
+ char *host = NULL, *user = NULL, *passwd = NULL,
+ *db = NULL, *unix_socket = NULL;
+ unsigned int port = 0;
+ unsigned int client_flag = 0;
+ static char *kwlist[] = { "host", "user", "passwd", "db", "port",
+ "unix_socket", "conv",
+ "connect_timeout", "compress",
+ "named_pipe", "init_command",
+ "read_default_file", "read_default_group",
+ "client_flag", "ssl",
+ "local_infile",
+ NULL } ;
+ int connect_timeout = 0;
+ int compress = -1, named_pipe = -1, local_infile = -1;
+ char *init_command=NULL,
+ *read_default_file=NULL,
+ *read_default_group=NULL;
+
+ self->converter = NULL;
+ self->open = 0;
+ check_server_init(-1);
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|ssssisOiiisssiOi:connect",
+ kwlist,
+ &host, &user, &passwd, &db,
+ &port, &unix_socket, &conv,
+ &connect_timeout,
+ &compress, &named_pipe,
+ &init_command, &read_default_file,
+ &read_default_group,
+ &client_flag, &ssl,
+ &local_infile /* DO NOT PATCH FOR RECONNECT, IDIOTS
+ IF YOU DO THIS, I WILL NOT SUPPORT YOUR PACKAGES. */
+ ))
+ return -1;
+
+#ifdef IS_PY3K
+#define _stringsuck(d,t,s) {t=PyMapping_GetItemString(s,#d);\
+ if(t){d=PyUnicode_AS_DATA(t);Py_DECREF(t);}\
+ PyErr_Clear();}
+#else
+#define _stringsuck(d,t,s) {t=PyMapping_GetItemString(s,#d);\
+ if(t){d=PyString_AsString(t);Py_DECREF(t);}\
+ PyErr_Clear();}
+#endif
+
+ if (ssl) {
+#if HAVE_OPENSSL
+ PyObject *value = NULL;
+ _stringsuck(ca, value, ssl);
+ _stringsuck(capath, value, ssl);
+ _stringsuck(cert, value, ssl);
+ _stringsuck(key, value, ssl);
+ _stringsuck(cipher, value, ssl);
+#else
+ PyErr_SetString(_mysql_NotSupportedError,
+ "client library does not have SSL support");
+ return -1;
+#endif
+ }
+
+ Py_BEGIN_ALLOW_THREADS ;
+ conn = mysql_init(&(self->connection));
+ if (connect_timeout) {
+ unsigned int timeout = connect_timeout;
+ mysql_options(&(self->connection), MYSQL_OPT_CONNECT_TIMEOUT,
+ (char *)&timeout);
+ }
+ if (compress != -1) {
+ mysql_options(&(self->connection), MYSQL_OPT_COMPRESS, 0);
+ client_flag |= CLIENT_COMPRESS;
+ }
+ if (named_pipe != -1)
+ mysql_options(&(self->connection), MYSQL_OPT_NAMED_PIPE, 0);
+ if (init_command != NULL)
+ mysql_options(&(self->connection), MYSQL_INIT_COMMAND, init_command);
+ if (read_default_file != NULL)
+ mysql_options(&(self->connection), MYSQL_READ_DEFAULT_FILE, read_default_file);
+ if (read_default_group != NULL)
+ mysql_options(&(self->connection), MYSQL_READ_DEFAULT_GROUP, read_default_group);
+
+ if (local_infile != -1)
+ mysql_options(&(self->connection), MYSQL_OPT_LOCAL_INFILE, (char *) &local_infile);
+
+#if HAVE_OPENSSL
+ if (ssl)
+ mysql_ssl_set(&(self->connection),
+ key, cert, ca, capath, cipher);
+#endif
+
+ conn = mysql_real_connect(&(self->connection), host, user, passwd, db,
+ port, unix_socket, client_flag);
+
+ Py_END_ALLOW_THREADS ;
+
+ if (!conn) {
+ _mysql_Exception(self);
+ return -1;
+ }
+
+ /* Internal references to python-land objects */
+ if (!conv)
+ conv = PyDict_New();
+ else
+ Py_INCREF(conv);
+
+ if (!conv)
+ return -1;
+ self->converter = conv;
+
+ /*
+ PyType_GenericAlloc() automatically sets up GC allocation and
+ tracking for GC objects, at least in 2.2.1, so it does not need to
+ be done here. tp_dealloc still needs to call PyObject_GC_UnTrack(),
+ however.
+ */
+ self->open = 1;
+ return 0;
+}
+
+static char _mysql_connect__doc__[] =
+"Returns a MYSQL connection object. Exclusive use of\n\
+keyword parameters strongly recommended. Consult the\n\
+MySQL C API documentation for more details.\n\
+\n\
+host\n\
+ string, host to connect\n\
+\n\
+user\n\
+ string, user to connect as\n\
+\n\
+passwd\n\
+ string, password to use\n\
+\n\
+db\n\
+ string, database to use\n\
+\n\
+port\n\
+ integer, TCP/IP port to connect to\n\
+\n\
+unix_socket\n\
+ string, location of unix_socket (UNIX-ish only)\n\
+\n\
+conv\n\
+ mapping, maps MySQL FIELD_TYPE.* to Python functions which\n\
+ convert a string to the appropriate Python type\n\
+\n\
+connect_timeout\n\
+ number of seconds to wait before the connection\n\
+ attempt fails.\n\
+\n\
+compress\n\
+ if set, gzip compression is enabled\n\
+\n\
+named_pipe\n\
+ if set, connect to server via named pipe (Windows only)\n\
+\n\
+init_command\n\
+ command which is run once the connection is created\n\
+\n\
+read_default_file\n\
+ see the MySQL documentation for mysql_options()\n\
+\n\
+read_default_group\n\
+ see the MySQL documentation for mysql_options()\n\
+\n\
+client_flag\n\
+ client flags from MySQLdb.constants.CLIENT\n\
+\n\
+load_infile\n\
+ int, non-zero enables LOAD LOCAL INFILE, zero disables\n\
+\n\
+";
+
+static PyObject *
+_mysql_connect(
+ PyObject *self,
+ PyObject *args,
+ PyObject *kwargs)
+{
+ _mysql_ConnectionObject *c=NULL;
+
+ c = MyAlloc(_mysql_ConnectionObject, _mysql_ConnectionObject_Type);
+ if (c == NULL) return NULL;
+ if (_mysql_ConnectionObject_Initialize(c, args, kwargs)) {
+ Py_DECREF(c);
+ c = NULL;
+ }
+ return (PyObject *) c;
+}
+
+#if PY_VERSION_HEX >= 0x02020000
+static int _mysql_ConnectionObject_traverse(
+ _mysql_ConnectionObject *self,
+ visitproc visit,
+ void *arg)
+{
+ if (self->converter)
+ return visit(self->converter, arg);
+ return 0;
+}
+#endif
+
+static int _mysql_ConnectionObject_clear(
+ _mysql_ConnectionObject *self)
+{
+ Py_XDECREF(self->converter);
+ self->converter = NULL;
+ return 0;
+}
+
+static char _mysql_ConnectionObject_close__doc__[] =
+"Close the connection. No further activity possible.";
+
+static PyObject *
+_mysql_ConnectionObject_close(
+ _mysql_ConnectionObject *self,
+ PyObject *args)
+{
+ if (args) {
+ if (!PyArg_ParseTuple(args, "")) return NULL;
+ }
+ if (self->open) {
+ Py_BEGIN_ALLOW_THREADS
+ mysql_close(&(self->connection));
+ Py_END_ALLOW_THREADS
+ self->open = 0;
+ } else {
+ PyErr_SetString(_mysql_ProgrammingError,
+ "closing a closed connection");
+ return NULL;
+ }
+ _mysql_ConnectionObject_clear(self);
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static char _mysql_ConnectionObject_affected_rows__doc__ [] =
+"Return number of rows affected by the last query.\n\
+Non-standard. Use Cursor.rowcount.\n\
+";
+
+static PyObject *
+_mysql_ConnectionObject_affected_rows(
+ _mysql_ConnectionObject *self,
+ PyObject *args)
+{
+ if (!PyArg_ParseTuple(args, "")) return NULL;
+ check_connection(self);
+ return PyLong_FromUnsignedLongLong(mysql_affected_rows(&(self->connection)));
+}
+
+static char _mysql_debug__doc__[] =
+"Does a DBUG_PUSH with the given string.\n\
+mysql_debug() uses the Fred Fish debug library.\n\
+To use this function, you must compile the client library to\n\
+support debugging.\n\
+";
+static PyObject *
+_mysql_debug(
+ PyObject *self,
+ PyObject *args)
+{
+ char *debug;
+ if (!PyArg_ParseTuple(args, "s", &debug)) return NULL;
+ mysql_debug(debug);
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static char _mysql_ConnectionObject_dump_debug_info__doc__[] =
+"Instructs the server to write some debug information to the\n\
+log. The connected user must have the process privilege for\n\
+this to work. Non-standard.\n\
+";
+
+static PyObject *
+_mysql_ConnectionObject_dump_debug_info(
+ _mysql_ConnectionObject *self,
+ PyObject *args)
+{
+ int err;
+ if (!PyArg_ParseTuple(args, "")) return NULL;
+ check_connection(self);
+ Py_BEGIN_ALLOW_THREADS
+ err = mysql_dump_debug_info(&(self->connection));
+ Py_END_ALLOW_THREADS
+ if (err) return _mysql_Exception(self);
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static char _mysql_ConnectionObject_autocommit__doc__[] =
+"Set the autocommit mode. True values enable; False value disable.\n\
+";
+static PyObject *
+_mysql_ConnectionObject_autocommit(
+ _mysql_ConnectionObject *self,
+ PyObject *args)
+{
+ int flag, err;
+ if (!PyArg_ParseTuple(args, "i", &flag)) return NULL;
+ Py_BEGIN_ALLOW_THREADS
+#if MYSQL_VERSION_ID >= 40100
+ err = mysql_autocommit(&(self->connection), flag);
+#else
+ {
+ char query[256];
+ snprintf(query, 256, "SET AUTOCOMMIT=%d", flag);
+ err = mysql_query(&(self->connection), query);
+ }
+#endif
+ Py_END_ALLOW_THREADS
+ if (err) return _mysql_Exception(self);
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static char _mysql_ConnectionObject_commit__doc__[] =
+"Commits the current transaction\n\
+";
+static PyObject *
+_mysql_ConnectionObject_commit(
+ _mysql_ConnectionObject *self,
+ PyObject *args)
+{
+ int err;
+ if (!PyArg_ParseTuple(args, "")) return NULL;
+ Py_BEGIN_ALLOW_THREADS
+#if MYSQL_VERSION_ID >= 40100
+ err = mysql_commit(&(self->connection));
+#else
+ err = mysql_query(&(self->connection), "COMMIT");
+#endif
+ Py_END_ALLOW_THREADS
+ if (err) return _mysql_Exception(self);
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static char _mysql_ConnectionObject_rollback__doc__[] =
+"Rolls backs the current transaction\n\
+";
+static PyObject *
+_mysql_ConnectionObject_rollback(
+ _mysql_ConnectionObject *self,
+ PyObject *args)
+{
+ int err;
+ if (!PyArg_ParseTuple(args, "")) return NULL;
+ Py_BEGIN_ALLOW_THREADS
+#if MYSQL_VERSION_ID >= 40100
+ err = mysql_rollback(&(self->connection));
+#else
+ err = mysql_query(&(self->connection), "ROLLBACK");
+#endif
+ Py_END_ALLOW_THREADS
+ if (err) return _mysql_Exception(self);
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static char _mysql_ConnectionObject_next_result__doc__[] =
+"If more query results exist, next_result() reads the next query\n\
+results and returns the status back to application.\n\
+\n\
+After calling next_result() the state of the connection is as if\n\
+you had called query() for the next query. This means that you can\n\
+now call store_result(), warning_count(), affected_rows()\n\
+, and so forth. \n\
+\n\
+Returns 0 if there are more results; -1 if there are no more results\n\
+\n\
+Non-standard.\n\
+";
+static PyObject *
+_mysql_ConnectionObject_next_result(
+ _mysql_ConnectionObject *self,
+ PyObject *args)
+{
+ int err;
+ if (!PyArg_ParseTuple(args, "")) return NULL;
+ Py_BEGIN_ALLOW_THREADS
+#if MYSQL_VERSION_ID >= 40100
+ err = mysql_next_result(&(self->connection));
+#else
+ err = -1;
+#endif
+ Py_END_ALLOW_THREADS
+ if (err > 0) return _mysql_Exception(self);
+ return PyInt_FromLong(err);
+}
+
+#if MYSQL_VERSION_ID >= 40100
+
+static char _mysql_ConnectionObject_set_server_option__doc__[] =
+"set_server_option(option) -- Enables or disables an option\n\
+for the connection.\n\
+\n\
+Non-standard.\n\
+";
+static PyObject *
+_mysql_ConnectionObject_set_server_option(
+ _mysql_ConnectionObject *self,
+ PyObject *args)
+{
+ int err, flags=0;
+ if (!PyArg_ParseTuple(args, "i", &flags))
+ return NULL;
+ Py_BEGIN_ALLOW_THREADS
+ err = mysql_set_server_option(&(self->connection), flags);
+ Py_END_ALLOW_THREADS
+ if (err) return _mysql_Exception(self);
+ return PyInt_FromLong(err);
+}
+
+static char _mysql_ConnectionObject_sqlstate__doc__[] =
+"Returns a string containing the SQLSTATE error code\n\
+for the last error. The error code consists of five characters.\n\
+'00000' means \"no error.\" The values are specified by ANSI SQL\n\
+and ODBC. For a list of possible values, see section 23\n\
+Error Handling in MySQL in the MySQL Manual.\n\
+\n\
+Note that not all MySQL errors are yet mapped to SQLSTATE's.\n\
+The value 'HY000' (general error) is used for unmapped errors.\n\
+\n\
+Non-standard.\n\
+";
+static PyObject *
+_mysql_ConnectionObject_sqlstate(
+ _mysql_ConnectionObject *self,
+ PyObject *args)
+{
+ if (!PyArg_ParseTuple(args, "")) return NULL;
+#ifdef IS_PY3K
+ return PyUnicode_FromString(mysql_sqlstate(&(self->connection)));
+#else
+ return PyString_FromString(mysql_sqlstate(&(self->connection)));
+#endif
+}
+
+static char _mysql_ConnectionObject_warning_count__doc__[] =
+"Returns the number of warnings generated during execution\n\
+of the previous SQL statement.\n\
+\n\
+Non-standard.\n\
+";
+static PyObject *
+_mysql_ConnectionObject_warning_count(
+ _mysql_ConnectionObject *self,
+ PyObject *args)
+{
+ if (!PyArg_ParseTuple(args, "")) return NULL;
+ return PyInt_FromLong(mysql_warning_count(&(self->connection)));
+}
+
+#endif
+
+static char _mysql_ConnectionObject_errno__doc__[] =
+"Returns the error code for the most recently invoked API function\n\
+that can succeed or fail. A return value of zero means that no error\n\
+occurred.\n\
+";
+
+static PyObject *
+_mysql_ConnectionObject_errno(
+ _mysql_ConnectionObject *self,
+ PyObject *args)
+{
+ if (!PyArg_ParseTuple(args, "")) return NULL;
+ check_connection(self);
+ return PyInt_FromLong((long)mysql_errno(&(self->connection)));
+}
+
+static char _mysql_ConnectionObject_error__doc__[] =
+"Returns the error message for the most recently invoked API function\n\
+that can succeed or fail. An empty string ("") is returned if no error\n\
+occurred.\n\
+";
+
+static PyObject *
+_mysql_ConnectionObject_error(
+ _mysql_ConnectionObject *self,
+ PyObject *args)
+{
+ if (!PyArg_ParseTuple(args, "")) return NULL;
+ check_connection(self);
+#ifdef IS_PY3K
+ return PyUnicode_FromString(mysql_error(&(self->connection)));
+#else
+ return PyString_FromString(mysql_error(&(self->connection)));
+#endif
+}
+
+static char _mysql_escape_string__doc__[] =
+"escape_string(s) -- quote any SQL-interpreted characters in string s.\n\
+\n\
+Use connection.escape_string(s), if you use it at all.\n\
+_mysql.escape_string(s) cannot handle character sets. You are\n\
+probably better off using connection.escape(o) instead, since\n\
+it will escape entire sequences as well as strings.";
+
+static PyObject *
+_mysql_escape_string(
+ _mysql_ConnectionObject *self,
+ PyObject *args)
+{
+ PyObject *str;
+ char *in, *out;
+ int len, size;
+ if (!PyArg_ParseTuple(args, "s#:escape_string", &in, &size)) return NULL;
+#ifdef IS_PY3K
+ str = PyUnicode_FromStringAndSize((char *) NULL, size*2+1);
+#else
+ str = PyString_FromStringAndSize((char *) NULL, size*2+1);
+#endif
+ if (!str) return PyErr_NoMemory();
+#ifdef IS_PY3K
+ out = PyUnicode_AS_DATA(str);
+#else
+ out = PyString_AS_STRING(str);
+#endif
+#if MYSQL_VERSION_ID < 32321
+ len = mysql_escape_string(out, in, size);
+#else
+ check_server_init(NULL);
+ if (self && self->open)
+ len = mysql_real_escape_string(&(self->connection), out, in, size);
+ else
+ len = mysql_escape_string(out, in, size);
+#endif
+#ifdef IS_PY3K
+ if (PyUnicode_Resize(&str, len) < 0) return NULL;
+#else
+ if (_PyString_Resize(&str, len) < 0) return NULL;
+#endif
+ return (str);
+}
+
+static char _mysql_string_literal__doc__[] =
+"string_literal(obj) -- converts object obj into a SQL string literal.\n\
+This means, any special SQL characters are escaped, and it is enclosed\n\
+within single quotes. In other words, it performs:\n\
+\n\
+\"'%s'\" % escape_string(str(obj))\n\
+\n\
+Use connection.string_literal(obj), if you use it at all.\n\
+_mysql.string_literal(obj) cannot handle character sets.";
+
+static PyObject *
+_mysql_string_literal(
+ _mysql_ConnectionObject *self,
+ PyObject *args)
+{
+ PyObject *str, *s, *o, *d;
+ char *in, *out;
+ int len, size;
+ if (!PyArg_ParseTuple(args, "O|O:string_literal", &o, &d)) return NULL;
+ s = PyObject_Str(o);
+ if (!s) return NULL;
+#ifdef IS_PY3K
+ in = PyUnicode_AS_DATA(s);
+ size = PyUnicode_GetSize(s);
+ str = PyUnicode_FromStringAndSize((char *) NULL, size*2+3);
+ if (!str) return PyErr_NoMemory();
+ out = PyUnicode_AS_DATA(str);
+#else
+ in = PyString_AsString(s);
+ size = PyString_GET_SIZE(s);
+ str = PyString_FromStringAndSize((char *) NULL, size*2+3);
+ if (!str) return PyErr_NoMemory();
+ out = PyString_AS_STRING(str);
+#endif
+#if MYSQL_VERSION_ID < 32321
+ len = mysql_escape_string(out+1, in, size);
+#else
+ check_server_init(NULL);
+ if (self && self->open)
+ len = mysql_real_escape_string(&(self->connection), out+1, in, size);
+ else
+ len = mysql_escape_string(out+1, in, size);
+#endif
+ *out = *(out+len+1) = '\'';
+#ifdef IS_PY3K
+ if (PyUnicode_Resize(&str, len+2) < 0) return NULL;
+#else
+ if (_PyString_Resize(&str, len+2) < 0) return NULL;
+#endif
+ Py_DECREF(s);
+ return (str);
+}
+
+static PyObject *_mysql_NULL;
+
+static PyObject *
+_escape_item(
+ PyObject *item,
+ PyObject *d)
+{
+ PyObject *quoted=NULL, *itemtype, *itemconv;
+ if (!(itemtype = PyObject_Type(item)))
+ goto error;
+ itemconv = PyObject_GetItem(d, itemtype);
+ Py_DECREF(itemtype);
+ if (!itemconv) {
+ PyErr_Clear();
+ itemconv = PyObject_GetItem(d,
+#ifdef IS_PY3K
+ (PyObject *) &PyUnicode_Type);
+#else
+ (PyObject *) &PyString_Type);
+#endif
+ }
+ if (!itemconv) {
+ PyErr_SetString(PyExc_TypeError,
+ "no default type converter defined");
+ goto error;
+ }
+ quoted = PyObject_CallFunction(itemconv, "OO", item, d);
+ Py_DECREF(itemconv);
+error:
+ return quoted;
+}
+
+static char _mysql_escape__doc__[] =
+"escape(obj, dict) -- escape any special characters in object obj\n\
+using mapping dict to provide quoting functions for each type.\n\
+Returns a SQL literal string.";
+static PyObject *
+_mysql_escape(
+ PyObject *self,
+ PyObject *args)
+{
+ PyObject *o=NULL, *d=NULL;
+ if (!PyArg_ParseTuple(args, "O|O:escape", &o, &d))
+ return NULL;
+ if (d) {
+ if (!PyMapping_Check(d)) {
+ PyErr_SetString(PyExc_TypeError,
+ "argument 2 must be a mapping");
+ return NULL;
+ }
+ return _escape_item(o, d);
+ } else {
+ if (!self) {
+ PyErr_SetString(PyExc_TypeError,
+ "argument 2 must be a mapping");
+ return NULL;
+ }
+ return _escape_item(o,
+ ((_mysql_ConnectionObject *) self)->converter);
+ }
+}
+
+static char _mysql_escape_sequence__doc__[] =
+"escape_sequence(seq, dict) -- escape any special characters in sequence\n\
+seq using mapping dict to provide quoting functions for each type.\n\
+Returns a tuple of escaped items.";
+static PyObject *
+_mysql_escape_sequence(
+ PyObject *self,
+ PyObject *args)
+{
+ PyObject *o=NULL, *d=NULL, *r=NULL, *item, *quoted;
+ int i, n;
+ if (!PyArg_ParseTuple(args, "OO:escape_sequence", &o, &d))
+ goto error;
+ if (!PyMapping_Check(d)) {
+ PyErr_SetString(PyExc_TypeError,
+ "argument 2 must be a mapping");
+ return NULL;
+ }
+ if ((n = PyObject_Length(o)) == -1) goto error;
+ if (!(r = PyTuple_New(n))) goto error;
+ for (i=0; i<n; i++) {
+ item = PySequence_GetItem(o, i);
+ if (!item) goto error;
+ quoted = _escape_item(item, d);
+ Py_DECREF(item);
+ if (!quoted) goto error;
+ PyTuple_SET_ITEM(r, i, quoted);
+ }
+ return r;
+ error:
+ Py_XDECREF(r);
+ return NULL;
+}
+
+static char _mysql_escape_dict__doc__[] =
+"escape_sequence(d, dict) -- escape any special characters in\n\
+dictionary d using mapping dict to provide quoting functions for each type.\n\
+Returns a dictionary of escaped items.";
+static PyObject *
+_mysql_escape_dict(
+ PyObject *self,
+ PyObject *args)
+{
+ PyObject *o=NULL, *d=NULL, *r=NULL, *item, *quoted, *pkey;
+ Py_ssize_t ppos = 0;
+ if (!PyArg_ParseTuple(args, "O!O:escape_dict", &PyDict_Type, &o, &d))
+ goto error;
+ if (!PyMapping_Check(d)) {
+ PyErr_SetString(PyExc_TypeError,
+ "argument 2 must be a mapping");
+ return NULL;
+ }
+ if (!(r = PyDict_New())) goto error;
+ while (PyDict_Next(o, &ppos, &pkey, &item)) {
+ quoted = _escape_item(item, d);
+ if (!quoted) goto error;
+ if (PyDict_SetItem(r, pkey, quoted)==-1) goto error;
+ Py_DECREF(quoted);
+ }
+ return r;
+ error:
+ Py_XDECREF(r);
+ return NULL;
+}
+
+static char _mysql_ResultObject_describe__doc__[] =
+"Returns the sequence of 7-tuples required by the DB-API for\n\
+the Cursor.description attribute.\n\
+";
+
+static PyObject *
+_mysql_ResultObject_describe(
+ _mysql_ResultObject *self,
+ PyObject *args)
+{
+ PyObject *d;
+ MYSQL_FIELD *fields;
+ unsigned int i, n;
+ if (!PyArg_ParseTuple(args, "")) return NULL;
+ check_result_connection(self);
+ n = mysql_num_fields(self->result);
+ fields = mysql_fetch_fields(self->result);
+ if (!(d = PyTuple_New(n))) return NULL;
+ for (i=0; i<n; i++) {
+ PyObject *t;
+ t = Py_BuildValue("(siiiiii)",
+ fields[i].name,
+ (long) fields[i].type,
+ (long) fields[i].max_length,
+ (long) fields[i].length,
+ (long) fields[i].length,
+ (long) fields[i].decimals,
+ (long) !(IS_NOT_NULL(fields[i].flags)));
+ if (!t) goto error;
+ PyTuple_SET_ITEM(d, i, t);
+ }
+ return d;
+ error:
+ Py_XDECREF(d);
+ return NULL;
+}
+
+static char _mysql_ResultObject_field_flags__doc__[] =
+"Returns a tuple of field flags, one for each column in the result.\n\
+" ;
+
+static PyObject *
+_mysql_ResultObject_field_flags(
+ _mysql_ResultObject *self,
+ PyObject *args)
+{
+ PyObject *d;
+ MYSQL_FIELD *fields;
+ unsigned int i, n;
+ if (!PyArg_ParseTuple(args, "")) return NULL;
+ check_result_connection(self);
+ n = mysql_num_fields(self->result);
+ fields = mysql_fetch_fields(self->result);
+ if (!(d = PyTuple_New(n))) return NULL;
+ for (i=0; i<n; i++) {
+ PyObject *f;
+ if (!(f = PyInt_FromLong((long)fields[i].flags))) goto error;
+ PyTuple_SET_ITEM(d, i, f);
+ }
+ return d;
+ error:
+ Py_XDECREF(d);
+ return NULL;
+}
+
+static PyObject *
+_mysql_field_to_python(
+ PyObject *converter,
+ char *rowitem,
+ unsigned long length)
+{
+ PyObject *v;
+ if (rowitem) {
+ if (converter != Py_None)
+ v = PyObject_CallFunction(converter,
+ "s#",
+ rowitem,
+ (int)length);
+ else
+#ifdef IS_PY3K
+ v = PyUnicode_FromStringAndSize(rowitem,
+ (int)length);
+#else
+ v = PyString_FromStringAndSize(rowitem,
+ (int)length);
+#endif
+ if (!v)
+ return NULL;
+ } else {
+ Py_INCREF(Py_None);
+ v = Py_None;
+ }
+ return v;
+}
+
+static PyObject *
+_mysql_row_to_tuple(
+ _mysql_ResultObject *self,
+ MYSQL_ROW row)
+{
+ unsigned int n, i;
+ unsigned long *length;
+ PyObject *r, *c;
+
+ n = mysql_num_fields(self->result);
+ if (!(r = PyTuple_New(n))) return NULL;
+ length = mysql_fetch_lengths(self->result);
+ for (i=0; i<n; i++) {
+ PyObject *v;
+ c = PyTuple_GET_ITEM(self->converter, i);
+ v = _mysql_field_to_python(c, row[i], length[i]);
+ if (!v) goto error;
+ PyTuple_SET_ITEM(r, i, v);
+ }
+ return r;
+ error:
+ Py_XDECREF(r);
+ return NULL;
+}
+
+static PyObject *
+_mysql_row_to_dict(
+ _mysql_ResultObject *self,
+ MYSQL_ROW row)
+{
+ unsigned int n, i;
+ unsigned long *length;
+ PyObject *r, *c;
+ MYSQL_FIELD *fields;
+
+ n = mysql_num_fields(self->result);
+ if (!(r = PyDict_New())) return NULL;
+ length = mysql_fetch_lengths(self->result);
+ fields = mysql_fetch_fields(self->result);
+ for (i=0; i<n; i++) {
+ PyObject *v;
+ c = PyTuple_GET_ITEM(self->converter, i);
+ v = _mysql_field_to_python(c, row[i], length[i]);
+ if (!v) goto error;
+ if (!PyMapping_HasKeyString(r, fields[i].name)) {
+ PyMapping_SetItemString(r, fields[i].name, v);
+ } else {
+ int len;
+ char buf[256];
+ strncpy(buf, fields[i].table, 256);
+ len = strlen(buf);
+ strncat(buf, ".", 256-len);
+ len = strlen(buf);
+ strncat(buf, fields[i].name, 256-len);
+ PyMapping_SetItemString(r, buf, v);
+ }
+ Py_DECREF(v);
+ }
+ return r;
+ error:
+ Py_XDECREF(r);
+ return NULL;
+}
+
+static PyObject *
+_mysql_row_to_dict_old(
+ _mysql_ResultObject *self,
+ MYSQL_ROW row)
+{
+ unsigned int n, i;
+ unsigned long *length;
+ PyObject *r, *c;
+ MYSQL_FIELD *fields;
+
+ n = mysql_num_fields(self->result);
+ if (!(r = PyDict_New())) return NULL;
+ length = mysql_fetch_lengths(self->result);
+ fields = mysql_fetch_fields(self->result);
+ for (i=0; i<n; i++) {
+ PyObject *v;
+ c = PyTuple_GET_ITEM(self->converter, i);
+ v = _mysql_field_to_python(c, row[i], length[i]);
+ if (!v) goto error;
+ {
+ int len=0;
+ char buf[256]="";
+ if (strlen(fields[i].table)) {
+ strncpy(buf, fields[i].table, 256);
+ len = strlen(buf);
+ strncat(buf, ".", 256-len);
+ len = strlen(buf);
+ }
+ strncat(buf, fields[i].name, 256-len);
+ PyMapping_SetItemString(r, buf, v);
+ }
+ Py_DECREF(v);
+ }
+ return r;
+ error:
+ Py_XDECREF(r);
+ return NULL;
+}
+
+typedef PyObject *_PYFUNC(_mysql_ResultObject *, MYSQL_ROW);
+
+int
+_mysql__fetch_row(
+ _mysql_ResultObject *self,
+ PyObject **r,
+ int skiprows,
+ int maxrows,
+ _PYFUNC *convert_row)
+{
+ unsigned int i;
+ MYSQL_ROW row;
+
+ for (i = skiprows; i<(skiprows+maxrows); i++) {
+ PyObject *v;
+ if (!self->use)
+ row = mysql_fetch_row(self->result);
+ else {
+ Py_BEGIN_ALLOW_THREADS;
+ row = mysql_fetch_row(self->result);
+ Py_END_ALLOW_THREADS;
+ }
+ if (!row && mysql_errno(&(((_mysql_ConnectionObject *)(self->conn))->connection))) {
+ _mysql_Exception((_mysql_ConnectionObject *)self->conn);
+ goto error;
+ }
+ if (!row) {
+ if (MyTuple_Resize(r, i, 0) == -1) goto error;
+ break;
+ }
+ v = convert_row(self, row);
+ if (!v) goto error;
+ PyTuple_SET_ITEM(*r, i, v);
+ }
+ return i-skiprows;
+ error:
+ return -1;
+}
+
+static char _mysql_ResultObject_fetch_row__doc__[] =
+"fetch_row([maxrows, how]) -- Fetches up to maxrows as a tuple.\n\
+The rows are formatted according to how:\n\
+\n\
+ 0 -- tuples (default)\n\
+ 1 -- dictionaries, key=column or table.column if duplicated\n\
+ 2 -- dictionaries, key=table.column\n\
+";
+
+static PyObject *
+_mysql_ResultObject_fetch_row(
+ _mysql_ResultObject *self,
+ PyObject *args,
+ PyObject *kwargs)
+{
+ typedef PyObject *_PYFUNC(_mysql_ResultObject *, MYSQL_ROW);
+ static char *kwlist[] = { "maxrows", "how", NULL };
+ static _PYFUNC *row_converters[] =
+ {
+ _mysql_row_to_tuple,
+ _mysql_row_to_dict,
+ _mysql_row_to_dict_old
+ };
+ _PYFUNC *convert_row;
+ unsigned int maxrows=1, how=0, skiprows=0, rowsadded;
+ PyObject *r=NULL;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|ii:fetch_row", kwlist,
+ &maxrows, &how))
+ return NULL;
+ check_result_connection(self);
+ if (how < 0 || how >= sizeof(row_converters)) {
+ PyErr_SetString(PyExc_ValueError, "how out of range");
+ return NULL;
+ }
+ convert_row = row_converters[how];
+ if (maxrows) {
+ if (!(r = PyTuple_New(maxrows))) goto error;
+ rowsadded = _mysql__fetch_row(self, &r, skiprows, maxrows,
+ convert_row);
+ if (rowsadded == -1) goto error;
+ } else {
+ if (self->use) {
+ maxrows = 1000;
+ if (!(r = PyTuple_New(maxrows))) goto error;
+ while (1) {
+ rowsadded = _mysql__fetch_row(self, &r, skiprows,
+ maxrows, convert_row);
+ if (rowsadded == -1) goto error;
+ skiprows += rowsadded;
+ if (rowsadded < maxrows) break;
+ if (MyTuple_Resize(&r, skiprows+maxrows, 0) == -1)
+ goto error;
+ }
+ } else {
+ /* XXX if overflow, maxrows<0? */
+ maxrows = (int) mysql_num_rows(self->result);
+ if (!(r = PyTuple_New(maxrows))) goto error;
+ rowsadded = _mysql__fetch_row(self, &r, 0,
+ maxrows, convert_row);
+ if (rowsadded == -1) goto error;
+ }
+ }
+ return r;
+ error:
+ Py_XDECREF(r);
+ return NULL;
+}
+
+#if MYSQL_VERSION_ID >= 32303
+
+static char _mysql_ConnectionObject_change_user__doc__[] =
+"Changes the user and causes the database specified by db to\n\
+become the default (current) database on the connection\n\
+specified by mysql. In subsequent queries, this database is\n\
+the default for table references that do not include an\n\
+explicit database specifier.\n\
+\n\
+This function was introduced in MySQL Version 3.23.3.\n\
+\n\
+Fails unless the connected user can be authenticated or if he\n\
+doesn't have permission to use the database. In this case the\n\
+user and database are not changed.\n\
+\n\
+The db parameter may be set to None if you don't want to have\n\
+a default database.\n\
+";
+
+static PyObject *
+_mysql_ConnectionObject_change_user(
+ _mysql_ConnectionObject *self,
+ PyObject *args,
+ PyObject *kwargs)
+{
+ char *user, *pwd=NULL, *db=NULL;
+ int r;
+ static char *kwlist[] = { "user", "passwd", "db", NULL } ;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|ss:change_user",
+ kwlist, &user, &pwd, &db))
+ return NULL;
+ check_connection(self);
+ Py_BEGIN_ALLOW_THREADS
+ r = mysql_change_user(&(self->connection), user, pwd, db);
+ Py_END_ALLOW_THREADS
+ if (r) return _mysql_Exception(self);
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+#endif
+
+static char _mysql_ConnectionObject_character_set_name__doc__[] =
+"Returns the default character set for the current connection.\n\
+Non-standard.\n\
+";
+
+static PyObject *
+_mysql_ConnectionObject_character_set_name(
+ _mysql_ConnectionObject *self,
+ PyObject *args)
+{
+ const char *s;
+ if (!PyArg_ParseTuple(args, "")) return NULL;
+ check_connection(self);
+#if MYSQL_VERSION_ID >= 32321
+ s = mysql_character_set_name(&(self->connection));
+#else
+ s = "latin1";
+#endif
+#ifdef IS_PY3K
+ return PyUnicode_FromString(s);
+#else
+ return PyString_FromString(s);
+#endif
+}
+
+#if MYSQL_VERSION_ID >= 50007
+static char _mysql_ConnectionObject_set_character_set__doc__[] =
+"Sets the default character set for the current connection.\n\
+Non-standard.\n\
+";
+
+static PyObject *
+_mysql_ConnectionObject_set_character_set(
+ _mysql_ConnectionObject *self,
+ PyObject *args)
+{
+ const char *s;
+ int err;
+ if (!PyArg_ParseTuple(args, "s", &s)) return NULL;
+ check_connection(self);
+ Py_BEGIN_ALLOW_THREADS
+ err = mysql_set_character_set(&(self->connection), s);
+ Py_END_ALLOW_THREADS
+ if (err) return _mysql_Exception(self);
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+#endif
+
+#if MYSQL_VERSION_ID >= 50010
+static char _mysql_ConnectionObject_get_character_set_info__doc__[] =
+"Returns a dict with information about the current character set:\n\
+\n\
+collation\n\
+ collation name\n\
+name\n\
+ character set name\n\
+comment\n\
+ comment or descriptive name\n\
+dir\n\
+ character set directory\n\
+mbminlen\n\
+ min. length for multibyte string\n\
+mbmaxlen\n\
+ max. length for multibyte string\n\
+\n\
+Not all keys may be present, particularly dir.\n\
+\n\
+Non-standard.\n\
+";
+
+static PyObject *
+_mysql_ConnectionObject_get_character_set_info(
+ _mysql_ConnectionObject *self,
+ PyObject *args)
+{
+ PyObject *result;
+ MY_CHARSET_INFO cs;
+
+ if (!PyArg_ParseTuple(args, "")) return NULL;
+ check_connection(self);
+ mysql_get_character_set_info(&(self->connection), &cs);
+ if (!(result = PyDict_New())) return NULL;
+#ifdef IS_PY3K
+ if (cs.csname)
+ PyDict_SetItemString(result, "name", PyUnicode_FromString(cs.csname));
+ if (cs.name)
+ PyDict_SetItemString(result, "collation", PyUnicode_FromString(cs.name));
+ if (cs.comment)
+ PyDict_SetItemString(result, "comment", PyUnicode_FromString(cs.comment));
+ if (cs.dir)
+ PyDict_SetItemString(result, "dir", PyUnicode_FromString(cs.dir));
+ PyDict_SetItemString(result, "mbminlen", PyInt_FromLong(cs.mbminlen));
+ PyDict_SetItemString(result, "mbmaxlen", PyInt_FromLong(cs.mbmaxlen));
+#else
+ if (cs.csname)
+ PyDict_SetItemString(result, "name", PyString_FromString(cs.csname));
+ if (cs.name)
+ PyDict_SetItemString(result, "collation", PyString_FromString(cs.name));
+ if (cs.comment)
+ PyDict_SetItemString(result, "comment", PyString_FromString(cs.comment));
+ if (cs.dir)
+ PyDict_SetItemString(result, "dir", PyString_FromString(cs.dir));
+ PyDict_SetItemString(result, "mbminlen", PyInt_FromLong(cs.mbminlen));
+ PyDict_SetItemString(result, "mbmaxlen", PyInt_FromLong(cs.mbmaxlen));
+#endif
+ return result;
+}
+#endif
+
+static char _mysql_get_client_info__doc__[] =
+"get_client_info() -- Returns a string that represents\n\
+the client library version.";
+static PyObject *
+_mysql_get_client_info(
+ PyObject *self,
+ PyObject *args)
+{
+ if (!PyArg_ParseTuple(args, "")) return NULL;
+ check_server_init(NULL);
+#ifdef IS_PY3K
+ return PyUnicode_FromString(mysql_get_client_info());
+#else
+ return PyString_FromString(mysql_get_client_info());
+#endif
+}
+
+static char _mysql_ConnectionObject_get_host_info__doc__[] =
+"Returns a string that represents the MySQL client library\n\
+version. Non-standard.\n\
+";
+
+static PyObject *
+_mysql_ConnectionObject_get_host_info(
+ _mysql_ConnectionObject *self,
+ PyObject *args)
+{
+ if (!PyArg_ParseTuple(args, "")) return NULL;
+ check_connection(self);
+#ifdef IS_PY3K
+ return PyUnicode_FromString(mysql_get_host_info(&(self->connection)));
+#else
+ return PyString_FromString(mysql_get_host_info(&(self->connection)));
+#endif
+}
+
+static char _mysql_ConnectionObject_get_proto_info__doc__[] =
+"Returns an unsigned integer representing the protocol version\n\
+used by the current connection. Non-standard.\n\
+";
+
+static PyObject *
+_mysql_ConnectionObject_get_proto_info(
+ _mysql_ConnectionObject *self,
+ PyObject *args)
+{
+ if (!PyArg_ParseTuple(args, "")) return NULL;
+ check_connection(self);
+ return PyInt_FromLong((long)mysql_get_proto_info(&(self->connection)));
+}
+
+static char _mysql_ConnectionObject_get_server_info__doc__[] =
+"Returns a string that represents the server version number.\n\
+Non-standard.\n\
+";
+
+static PyObject *
+_mysql_ConnectionObject_get_server_info(
+ _mysql_ConnectionObject *self,
+ PyObject *args)
+{
+ if (!PyArg_ParseTuple(args, "")) return NULL;
+ check_connection(self);
+#ifdef IS_PY3K
+ return PyUnicode_FromString(mysql_get_server_info(&(self->connection)));
+#else
+ return PyString_FromString(mysql_get_server_info(&(self->connection)));
+#endif
+}
+
+static char _mysql_ConnectionObject_info__doc__[] =
+"Retrieves a string providing information about the most\n\
+recently executed query. Non-standard. Use messages or\n\
+Cursor.messages.\n\
+";
+
+static PyObject *
+_mysql_ConnectionObject_info(
+ _mysql_ConnectionObject *self,
+ PyObject *args)
+{
+ const char *s;
+ if (!PyArg_ParseTuple(args, "")) return NULL;
+ check_connection(self);
+ s = mysql_info(&(self->connection));
+#ifdef IS_PY3K
+ if (s) return PyUnicode_FromString(s);
+#else
+ if (s) return PyString_FromString(s);
+#endif
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static char _mysql_ConnectionObject_insert_id__doc__[] =
+"Returns the ID generated for an AUTO_INCREMENT column by the previous\n\
+query. Use this function after you have performed an INSERT query into a\n\
+table that contains an AUTO_INCREMENT field.\n\
+\n\
+Note that this returns 0 if the previous query does not\n\
+generate an AUTO_INCREMENT value. If you need to save the value for\n\
+later, be sure to call this immediately after the query\n\
+that generates the value.\n\
+\n\
+The ID is updated after INSERT and UPDATE statements that generate\n\
+an AUTO_INCREMENT value or that set a column value to\n\
+LAST_INSERT_ID(expr). See section 6.3.5.2 Miscellaneous Functions\n\
+in the MySQL documentation.\n\
+\n\
+Also note that the value of the SQL LAST_INSERT_ID() function always\n\
+contains the most recently generated AUTO_INCREMENT value, and is not\n\
+reset between queries because the value of that function is maintained\n\
+in the server.\n\
+" ;
+
+static PyObject *
+_mysql_ConnectionObject_insert_id(
+ _mysql_ConnectionObject *self,
+ PyObject *args)
+{
+ my_ulonglong r;
+ if (!PyArg_ParseTuple(args, "")) return NULL;
+ check_connection(self);
+ Py_BEGIN_ALLOW_THREADS
+ r = mysql_insert_id(&(self->connection));
+ Py_END_ALLOW_THREADS
+ return PyLong_FromUnsignedLongLong(r);
+}
+
+static char _mysql_ConnectionObject_kill__doc__[] =
+"Asks the server to kill the thread specified by pid.\n\
+Non-standard.";
+
+static PyObject *
+_mysql_ConnectionObject_kill(
+ _mysql_ConnectionObject *self,
+ PyObject *args)
+{
+ unsigned long pid;
+ int r;
+ if (!PyArg_ParseTuple(args, "k:kill", &pid)) return NULL;
+ check_connection(self);
+ Py_BEGIN_ALLOW_THREADS
+ r = mysql_kill(&(self->connection), pid);
+ Py_END_ALLOW_THREADS
+ if (r) return _mysql_Exception(self);
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static char _mysql_ConnectionObject_field_count__doc__[] =
+"Returns the number of columns for the most recent query on the\n\
+connection. Non-standard. Will probably give you bogus results\n\
+on most cursor classes. Use Cursor.rowcount.\n\
+";
+
+static PyObject *
+_mysql_ConnectionObject_field_count(
+ _mysql_ConnectionObject *self,
+ PyObject *args)
+{
+ if (!PyArg_ParseTuple(args, "")) return NULL;
+ check_connection(self);
+#if MYSQL_VERSION_ID < 32224
+ return PyInt_FromLong((long)mysql_num_fields(&(self->connection)));
+#else
+ return PyInt_FromLong((long)mysql_field_count(&(self->connection)));
+#endif
+}
+
+static char _mysql_ResultObject_num_fields__doc__[] =
+"Returns the number of fields (column) in the result." ;
+
+static PyObject *
+_mysql_ResultObject_num_fields(
+ _mysql_ResultObject *self,
+ PyObject *args)
+{
+ if (!PyArg_ParseTuple(args, "")) return NULL;
+ check_result_connection(self);
+ return PyInt_FromLong((long)mysql_num_fields(self->result));
+}
+
+static char _mysql_ResultObject_num_rows__doc__[] =
+"Returns the number of rows in the result set. Note that if\n\
+use=1, this will not return a valid value until the entire result\n\
+set has been read.\n\
+";
+
+static PyObject *
+_mysql_ResultObject_num_rows(
+ _mysql_ResultObject *self,
+ PyObject *args)
+{
+ if (!PyArg_ParseTuple(args, "")) return NULL;
+ check_result_connection(self);
+ return PyLong_FromUnsignedLongLong(mysql_num_rows(self->result));
+}
+
+static char _mysql_ConnectionObject_ping__doc__[] =
+"Checks whether or not the connection to the server is\n\
+working. If it has gone down, an automatic reconnection is\n\
+attempted.\n\
+\n\
+This function can be used by clients that remain idle for a\n\
+long while, to check whether or not the server has closed the\n\
+connection and reconnect if necessary.\n\
+\n\
+New in 1.2.2: Accepts an optional reconnect parameter. If True,\n\
+then the client will attempt reconnection. Note that this setting\n\
+is persistent. By default, this is on in MySQL<5.0.3, and off\n\
+thereafter.\n\
+\n\
+Non-standard. You should assume that ping() performs an\n\
+implicit rollback; use only when starting a new transaction.\n\
+You have been warned.\n\
+";
+
+static PyObject *
+_mysql_ConnectionObject_ping(
+ _mysql_ConnectionObject *self,
+ PyObject *args)
+{
+ int r, reconnect = -1;
+ if (!PyArg_ParseTuple(args, "|I", &reconnect)) return NULL;
+ check_connection(self);
+ if ( reconnect != -1 ) self->connection.reconnect = reconnect;
+ Py_BEGIN_ALLOW_THREADS
+ r = mysql_ping(&(self->connection));
+ Py_END_ALLOW_THREADS
+ if (r) return _mysql_Exception(self);
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static char _mysql_ConnectionObject_query__doc__[] =
+"Execute a query. store_result() or use_result() will get the\n\
+result set, if any. Non-standard. Use cursor() to create a cursor,\n\
+then cursor.execute().\n\
+" ;
+
+static PyObject *
+_mysql_ConnectionObject_query(
+ _mysql_ConnectionObject *self,
+ PyObject *args)
+{
+ char *query;
+ int len, r;
+ if (!PyArg_ParseTuple(args, "s#:query", &query, &len)) return NULL;
+ check_connection(self);
+ Py_BEGIN_ALLOW_THREADS
+ r = mysql_real_query(&(self->connection), query, len);
+ Py_END_ALLOW_THREADS
+ if (r) return _mysql_Exception(self);
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+
+static char _mysql_ConnectionObject_select_db__doc__[] =
+"Causes the database specified by db to become the default\n\
+(current) database on the connection specified by mysql. In subsequent\n\
+queries, this database is the default for table references that do not\n\
+include an explicit database specifier.\n\
+\n\
+Fails unless the connected user can be authenticated as having\n\
+permission to use the database.\n\
+\n\
+Non-standard.\n\
+";
+
+static PyObject *
+_mysql_ConnectionObject_select_db(
+ _mysql_ConnectionObject *self,
+ PyObject *args)
+{
+ char *db;
+ int r;
+ if (!PyArg_ParseTuple(args, "s:select_db", &db)) return NULL;
+ check_connection(self);
+ Py_BEGIN_ALLOW_THREADS
+ r = mysql_select_db(&(self->connection), db);
+ Py_END_ALLOW_THREADS
+ if (r) return _mysql_Exception(self);
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static char _mysql_ConnectionObject_shutdown__doc__[] =
+"Asks the database server to shut down. The connected user must\n\
+have shutdown privileges. Non-standard.\n\
+";
+
+static PyObject *
+_mysql_ConnectionObject_shutdown(
+ _mysql_ConnectionObject *self,
+ PyObject *args)
+{
+ int r;
+ if (!PyArg_ParseTuple(args, "")) return NULL;
+ check_connection(self);
+ Py_BEGIN_ALLOW_THREADS
+ r = mysql_shutdown(&(self->connection)
+#if MYSQL_VERSION_ID >= 40103
+ , SHUTDOWN_DEFAULT
+#endif
+ );
+ Py_END_ALLOW_THREADS
+ if (r) return _mysql_Exception(self);
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static char _mysql_ConnectionObject_stat__doc__[] =
+"Returns a character string containing information similar to\n\
+that provided by the mysqladmin status command. This includes\n\
+uptime in seconds and the number of running threads,\n\
+questions, reloads, and open tables. Non-standard.\n\
+";
+
+static PyObject *
+_mysql_ConnectionObject_stat(
+ _mysql_ConnectionObject *self,
+ PyObject *args)
+{
+ const char *s;
+ if (!PyArg_ParseTuple(args, "")) return NULL;
+ check_connection(self);
+ Py_BEGIN_ALLOW_THREADS
+ s = mysql_stat(&(self->connection));
+ Py_END_ALLOW_THREADS
+ if (!s) return _mysql_Exception(self);
+#ifdef IS_PY3K
+ return PyUnicode_FromString(s);
+#else
+ return PyString_FromString(s);
+#endif
+
+}
+
+static char _mysql_ConnectionObject_store_result__doc__[] =
+"Returns a result object acquired by mysql_store_result\n\
+(results stored in the client). If no results are available,\n\
+None is returned. Non-standard.\n\
+";
+
+static PyObject *
+_mysql_ConnectionObject_store_result(
+ _mysql_ConnectionObject *self,
+ PyObject *args)
+{
+ PyObject *arglist=NULL, *kwarglist=NULL, *result=NULL;
+ _mysql_ResultObject *r=NULL;
+
+ if (!PyArg_ParseTuple(args, "")) return NULL;
+ check_connection(self);
+ arglist = Py_BuildValue("(OiO)", self, 0, self->converter);
+ if (!arglist) goto error;
+ kwarglist = PyDict_New();
+ if (!kwarglist) goto error;
+ r = MyAlloc(_mysql_ResultObject, _mysql_ResultObject_Type);
+ if (!r) goto error;
+ if (_mysql_ResultObject_Initialize(r, arglist, kwarglist))
+ goto error;
+ result = (PyObject *) r;
+ if (!(r->result)) {
+ Py_DECREF(result);
+ Py_INCREF(Py_None);
+ result = Py_None;
+ }
+ error:
+ Py_XDECREF(arglist);
+ Py_XDECREF(kwarglist);
+ return result;
+}
+
+static char _mysql_ConnectionObject_thread_id__doc__[] =
+"Returns the thread ID of the current connection. This value\n\
+can be used as an argument to kill() to kill the thread.\n\
+\n\
+If the connection is lost and you reconnect with ping(), the\n\
+thread ID will change. This means you should not get the\n\
+thread ID and store it for later. You should get it when you\n\
+need it.\n\
+\n\
+Non-standard.";
+
+static PyObject *
+_mysql_ConnectionObject_thread_id(
+ _mysql_ConnectionObject *self,
+ PyObject *args)
+{
+ unsigned long pid;
+ if (!PyArg_ParseTuple(args, "")) return NULL;
+ check_connection(self);
+ Py_BEGIN_ALLOW_THREADS
+ pid = mysql_thread_id(&(self->connection));
+ Py_END_ALLOW_THREADS
+ return PyInt_FromLong((long)pid);
+}
+
+static char _mysql_ConnectionObject_use_result__doc__[] =
+"Returns a result object acquired by mysql_use_result\n\
+(results stored in the server). If no results are available,\n\
+None is returned. Non-standard.\n\
+";
+
+static PyObject *
+_mysql_ConnectionObject_use_result(
+ _mysql_ConnectionObject *self,
+ PyObject *args)
+{
+ PyObject *arglist=NULL, *kwarglist=NULL, *result=NULL;
+ _mysql_ResultObject *r=NULL;
+
+ if (!PyArg_ParseTuple(args, "")) return NULL;
+ check_connection(self);
+ arglist = Py_BuildValue("(OiO)", self, 1, self->converter);
+ if (!arglist) return NULL;
+ kwarglist = PyDict_New();
+ if (!kwarglist) goto error;
+ r = MyAlloc(_mysql_ResultObject, _mysql_ResultObject_Type);
+ if (!r) goto error;
+ result = (PyObject *) r;
+ if (_mysql_ResultObject_Initialize(r, arglist, kwarglist))
+ goto error;
+ if (!(r->result)) {
+ Py_DECREF(result);
+ Py_INCREF(Py_None);
+ result = Py_None;
+ }
+ error:
+ Py_DECREF(arglist);
+ Py_XDECREF(kwarglist);
+ return result;
+}
+
+static void
+_mysql_ConnectionObject_dealloc(
+ _mysql_ConnectionObject *self)
+{
+ PyObject *o;
+
+ PyObject_GC_UnTrack(self);
+ if (self->open) {
+ o = _mysql_ConnectionObject_close(self, NULL);
+ Py_XDECREF(o);
+ }
+ MyFree(self);
+}
+
+static PyObject *
+_mysql_ConnectionObject_repr(
+ _mysql_ConnectionObject *self)
+{
+ char buf[300];
+ if (self->open)
+ sprintf(buf, "<_mysql.connection open to '%.256s' at %lx>",
+ self->connection.host,
+ (long)self);
+ else
+ sprintf(buf, "<_mysql.connection closed at %lx>",
+ (long)self);
+#ifdef IS_PY3K
+ return PyUnicode_FromString(buf);
+#else
+ return PyString_FromString(buf);
+#endif
+}
+
+static char _mysql_ResultObject_data_seek__doc__[] =
+"data_seek(n) -- seek to row n of result set";
+static PyObject *
+_mysql_ResultObject_data_seek(
+ _mysql_ResultObject *self,
+ PyObject *args)
+{
+ unsigned int row;
+ if (!PyArg_ParseTuple(args, "i:data_seek", &row)) return NULL;
+ check_result_connection(self);
+ mysql_data_seek(self->result, row);
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static char _mysql_ResultObject_row_seek__doc__[] =
+"row_seek(n) -- seek by offset n rows of result set";
+static PyObject *
+_mysql_ResultObject_row_seek(
+ _mysql_ResultObject *self,
+ PyObject *args)
+{
+ int offset;
+ MYSQL_ROW_OFFSET r;
+ if (!PyArg_ParseTuple(args, "i:row_seek", &offset)) return NULL;
+ check_result_connection(self);
+ if (self->use) {
+ PyErr_SetString(_mysql_ProgrammingError,
+ "cannot be used with connection.use_result()");
+ return NULL;
+ }
+ r = mysql_row_tell(self->result);
+ mysql_row_seek(self->result, r+offset);
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static char _mysql_ResultObject_row_tell__doc__[] =
+"row_tell() -- return the current row number of the result set.";
+static PyObject *
+_mysql_ResultObject_row_tell(
+ _mysql_ResultObject *self,
+ PyObject *args)
+{
+ MYSQL_ROW_OFFSET r;
+ if (!PyArg_ParseTuple(args, "")) return NULL;
+ check_result_connection(self);
+ if (self->use) {
+ PyErr_SetString(_mysql_ProgrammingError,
+ "cannot be used with connection.use_result()");
+ return NULL;
+ }
+ r = mysql_row_tell(self->result);
+ return PyInt_FromLong(r-self->result->data->data);
+}
+
+static void
+_mysql_ResultObject_dealloc(
+ _mysql_ResultObject *self)
+{
+ PyObject_GC_UnTrack((PyObject *)self);
+ mysql_free_result(self->result);
+ _mysql_ResultObject_clear(self);
+ MyFree(self);
+}
+
+static PyObject *
+_mysql_ResultObject_repr(
+ _mysql_ResultObject *self)
+{
+ char buf[300];
+ sprintf(buf, "<_mysql.result object at %lx>",
+ (long)self);
+#ifdef IS_PY3K
+ return PyUnicode_FromString(buf);
+#else
+ return PyString_FromString(buf);
+#endif
+}
+
+static PyMethodDef _mysql_ConnectionObject_methods[] = {
+ {
+ "affected_rows",
+ (PyCFunction)_mysql_ConnectionObject_affected_rows,
+ METH_VARARGS,
+ _mysql_ConnectionObject_affected_rows__doc__
+ },
+ {
+ "autocommit",
+ (PyCFunction)_mysql_ConnectionObject_autocommit,
+ METH_VARARGS,
+ _mysql_ConnectionObject_autocommit__doc__
+ },
+ {
+ "commit",
+ (PyCFunction)_mysql_ConnectionObject_commit,
+ METH_VARARGS,
+ _mysql_ConnectionObject_commit__doc__
+ },
+ {
+ "rollback",
+ (PyCFunction)_mysql_ConnectionObject_rollback,
+ METH_VARARGS,
+ _mysql_ConnectionObject_rollback__doc__
+ },
+ {
+ "next_result",
+ (PyCFunction)_mysql_ConnectionObject_next_result,
+ METH_VARARGS,
+ _mysql_ConnectionObject_next_result__doc__
+ },
+#if MYSQL_VERSION_ID >= 40100
+ {
+ "set_server_option",
+ (PyCFunction)_mysql_ConnectionObject_set_server_option,
+ METH_VARARGS,
+ _mysql_ConnectionObject_set_server_option__doc__
+ },
+ {
+ "sqlstate",
+ (PyCFunction)_mysql_ConnectionObject_sqlstate,
+ METH_VARARGS,
+ _mysql_ConnectionObject_sqlstate__doc__
+ },
+ {
+ "warning_count",
+ (PyCFunction)_mysql_ConnectionObject_warning_count,
+ METH_VARARGS,
+ _mysql_ConnectionObject_warning_count__doc__
+ },
+#endif
+#if MYSQL_VERSION_ID >= 32303
+ {
+ "change_user",
+ (PyCFunction)_mysql_ConnectionObject_change_user,
+ METH_VARARGS | METH_KEYWORDS,
+ _mysql_ConnectionObject_change_user__doc__
+ },
+#endif
+ {
+ "character_set_name",
+ (PyCFunction)_mysql_ConnectionObject_character_set_name,
+ METH_VARARGS,
+ _mysql_ConnectionObject_character_set_name__doc__
+ },
+#if MYSQL_VERSION_ID >= 50007
+ {
+ "set_character_set",
+ (PyCFunction)_mysql_ConnectionObject_set_character_set,
+ METH_VARARGS,
+ _mysql_ConnectionObject_set_character_set__doc__
+ },
+#endif
+#if MYSQL_VERSION_ID >= 50010
+ {
+ "get_character_set_info",
+ (PyCFunction)_mysql_ConnectionObject_get_character_set_info,
+ METH_VARARGS,
+ _mysql_ConnectionObject_get_character_set_info__doc__
+ },
+#endif
+ {
+ "close",
+ (PyCFunction)_mysql_ConnectionObject_close,
+ METH_VARARGS,
+ _mysql_ConnectionObject_close__doc__
+ },
+ {
+ "dump_debug_info",
+ (PyCFunction)_mysql_ConnectionObject_dump_debug_info,
+ METH_VARARGS,
+ _mysql_ConnectionObject_dump_debug_info__doc__
+ },
+ {
+ "escape",
+ (PyCFunction)_mysql_escape,
+ METH_VARARGS,
+ _mysql_escape__doc__
+ },
+ {
+ "escape_string",
+ (PyCFunction)_mysql_escape_string,
+ METH_VARARGS,
+ _mysql_escape_string__doc__
+ },
+ {
+ "error",
+ (PyCFunction)_mysql_ConnectionObject_error,
+ METH_VARARGS,
+ _mysql_ConnectionObject_error__doc__
+ },
+ {
+ "errno",
+ (PyCFunction)_mysql_ConnectionObject_errno,
+ METH_VARARGS,
+ _mysql_ConnectionObject_errno__doc__
+ },
+ {
+ "field_count",
+ (PyCFunction)_mysql_ConnectionObject_field_count,
+ METH_VARARGS,
+ _mysql_ConnectionObject_field_count__doc__
+ },
+ {
+ "get_host_info",
+ (PyCFunction)_mysql_ConnectionObject_get_host_info,
+ METH_VARARGS,
+ _mysql_ConnectionObject_get_host_info__doc__
+ },
+ {
+ "get_proto_info",
+ (PyCFunction)_mysql_ConnectionObject_get_proto_info,
+ METH_VARARGS,
+ _mysql_ConnectionObject_get_proto_info__doc__
+ },
+ {
+ "get_server_info",
+ (PyCFunction)_mysql_ConnectionObject_get_server_info,
+ METH_VARARGS,
+ _mysql_ConnectionObject_get_server_info__doc__
+ },
+ {
+ "info",
+ (PyCFunction)_mysql_ConnectionObject_info,
+ METH_VARARGS,
+ _mysql_ConnectionObject_info__doc__
+ },
+ {
+ "insert_id",
+ (PyCFunction)_mysql_ConnectionObject_insert_id,
+ METH_VARARGS,
+ _mysql_ConnectionObject_insert_id__doc__
+ },
+ {
+ "kill",
+ (PyCFunction)_mysql_ConnectionObject_kill,
+ METH_VARARGS,
+ _mysql_ConnectionObject_kill__doc__
+ },
+ {
+ "ping",
+ (PyCFunction)_mysql_ConnectionObject_ping,
+ METH_VARARGS,
+ _mysql_ConnectionObject_ping__doc__
+ },
+ {
+ "query",
+ (PyCFunction)_mysql_ConnectionObject_query,
+ METH_VARARGS,
+ _mysql_ConnectionObject_query__doc__
+ },
+ {
+ "select_db",
+ (PyCFunction)_mysql_ConnectionObject_select_db,
+ METH_VARARGS,
+ _mysql_ConnectionObject_select_db__doc__
+ },
+ {
+ "shutdown",
+ (PyCFunction)_mysql_ConnectionObject_shutdown,
+ METH_VARARGS,
+ _mysql_ConnectionObject_shutdown__doc__
+ },
+ {
+ "stat",
+ (PyCFunction)_mysql_ConnectionObject_stat,
+ METH_VARARGS,
+ _mysql_ConnectionObject_stat__doc__
+ },
+ {
+ "store_result",
+ (PyCFunction)_mysql_ConnectionObject_store_result,
+ METH_VARARGS,
+ _mysql_ConnectionObject_store_result__doc__
+ },
+ {
+ "string_literal",
+ (PyCFunction)_mysql_string_literal,
+ METH_VARARGS,
+ _mysql_string_literal__doc__},
+ {
+ "thread_id",
+ (PyCFunction)_mysql_ConnectionObject_thread_id,
+ METH_VARARGS,
+ _mysql_ConnectionObject_thread_id__doc__
+ },
+ {
+ "use_result",
+ (PyCFunction)_mysql_ConnectionObject_use_result,
+ METH_VARARGS,
+ _mysql_ConnectionObject_use_result__doc__
+ },
+ {NULL, NULL} /* sentinel */
+};
+
+static MyMemberlist(_mysql_ConnectionObject_memberlist)[] = {
+ MyMember(
+ "open",
+ T_INT,
+ offsetof(_mysql_ConnectionObject,open),
+ READONLY,
+ "True if connection is open"
+ ),
+ MyMember(
+ "converter",
+ T_OBJECT,
+ offsetof(_mysql_ConnectionObject,converter),
+ 0,
+ "Type conversion mapping"
+ ),
+ MyMember(
+ "server_capabilities",
+ T_UINT,
+ offsetof(_mysql_ConnectionObject,connection.server_capabilities),
+ READONLY,
+ "Capabilites of server; consult MySQLdb.constants.CLIENT"
+ ),
+ MyMember(
+ "port",
+ T_UINT,
+ offsetof(_mysql_ConnectionObject,connection.port),
+ READONLY,
+ "TCP/IP port of the server connection"
+ ),
+ MyMember(
+ "client_flag",
+ T_UINT,
+ READONLY,
+ offsetof(_mysql_ConnectionObject,connection.client_flag),
+ "Client flags; refer to MySQLdb.constants.CLIENT"
+ ),
+ {NULL} /* Sentinel */
+};
+
+static PyMethodDef _mysql_ResultObject_methods[] = {
+ {
+ "data_seek",
+ (PyCFunction)_mysql_ResultObject_data_seek,
+ METH_VARARGS,
+ _mysql_ResultObject_data_seek__doc__
+ },
+ {
+ "row_seek",
+ (PyCFunction)_mysql_ResultObject_row_seek,
+ METH_VARARGS,
+ _mysql_ResultObject_row_seek__doc__
+ },
+ {
+ "row_tell",
+ (PyCFunction)_mysql_ResultObject_row_tell,
+ METH_VARARGS,
+ _mysql_ResultObject_row_tell__doc__
+ },
+ {
+ "describe",
+ (PyCFunction)_mysql_ResultObject_describe,
+ METH_VARARGS,
+ _mysql_ResultObject_describe__doc__
+ },
+ {
+ "fetch_row",
+ (PyCFunction)_mysql_ResultObject_fetch_row,
+ METH_VARARGS | METH_KEYWORDS,
+ _mysql_ResultObject_fetch_row__doc__
+ },
+ {
+ "field_flags",
+ (PyCFunction)_mysql_ResultObject_field_flags,
+ METH_VARARGS,
+ _mysql_ResultObject_field_flags__doc__
+ },
+ {
+ "num_fields",
+ (PyCFunction)_mysql_ResultObject_num_fields,
+ METH_VARARGS,
+ _mysql_ResultObject_num_fields__doc__
+ },
+ {
+ "num_rows",
+ (PyCFunction)_mysql_ResultObject_num_rows,
+ METH_VARARGS,
+ _mysql_ResultObject_num_rows__doc__
+ },
+ {NULL, NULL} /* sentinel */
+};
+
+static MyMemberlist(_mysql_ResultObject_memberlist)[] = {
+ MyMember(
+ "converter",
+ T_OBJECT,
+ offsetof(_mysql_ResultObject,converter),
+ READONLY,
+ "Type conversion mapping"
+ ),
+ {NULL} /* Sentinel */
+};
+
+static PyObject *
+_mysql_ConnectionObject_getattr(
+ _mysql_ConnectionObject *self,
+ char *name)
+{
+#ifndef IS_PY3K
+ PyObject *res;
+
+ res = Py_FindMethod(_mysql_ConnectionObject_methods, (PyObject *)self, name);
+ if (res != NULL)
+ return res;
+ PyErr_Clear();
+#endif
+ if (strcmp(name, "closed") == 0)
+ return PyInt_FromLong((long)!(self->open));
+#if PY_VERSION_HEX < 0x02020000
+ return PyMember_Get((char *)self, _mysql_ConnectionObject_memberlist, name);
+#else
+ {
+ MyMemberlist(*l);
+ for (l = _mysql_ConnectionObject_memberlist; l->name != NULL; l++) {
+ if (strcmp(l->name, name) == 0)
+ return PyMember_GetOne((char *)self, l);
+ }
+ PyErr_SetString(PyExc_AttributeError, name);
+ return NULL;
+ }
+#endif
+}
+
+static PyObject *
+_mysql_ResultObject_getattr(
+ _mysql_ResultObject *self,
+ char *name)
+{
+#ifndef IS_PY3K
+ PyObject *res;
+
+ res = Py_FindMethod(_mysql_ResultObject_methods, (PyObject *)self, name);
+ if (res != NULL)
+ return res;
+ PyErr_Clear();
+#endif
+#if PY_VERSION_HEX < 0x02020000
+ return PyMember_Get((char *)self, _mysql_ResultObject_memberlist, name);
+#else
+ {
+ MyMemberlist(*l);
+ for (l = _mysql_ResultObject_memberlist; l->name != NULL; l++) {
+ if (strcmp(l->name, name) == 0)
+ return PyMember_GetOne((char *)self, l);
+ }
+ PyErr_SetString(PyExc_AttributeError, name);
+ return NULL;
+ }
+#endif
+}
+
+static int
+_mysql_ConnectionObject_setattr(
+ _mysql_ConnectionObject *self,
+ char *name,
+ PyObject *v)
+{
+ if (v == NULL) {
+ PyErr_SetString(PyExc_AttributeError,
+ "can't delete connection attributes");
+ return -1;
+ }
+#if PY_VERSION_HEX < 0x02020000
+ return PyMember_Set((char *)self, _mysql_ConnectionObject_memberlist, name, v);
+#else
+ {
+ MyMemberlist(*l);
+ for (l = _mysql_ConnectionObject_memberlist; l->name != NULL; l++)
+ if (strcmp(l->name, name) == 0)
+ return PyMember_SetOne((char *)self, l, v);
+ }
+ PyErr_SetString(PyExc_AttributeError, name);
+ return -1;
+#endif
+}
+
+static int
+_mysql_ResultObject_setattr(
+ _mysql_ResultObject *self,
+ char *name,
+ PyObject *v)
+{
+ if (v == NULL) {
+ PyErr_SetString(PyExc_AttributeError,
+ "can't delete connection attributes");
+ return -1;
+ }
+#if PY_VERSION_HEX < 0x02020000
+ return PyMember_Set((char *)self, _mysql_ResultObject_memberlist, name, v);
+#else
+ {
+ MyMemberlist(*l);
+ for (l = _mysql_ResultObject_memberlist; l->name != NULL; l++)
+ if (strcmp(l->name, name) == 0)
+ return PyMember_SetOne((char *)self, l, v);
+ }
+ PyErr_SetString(PyExc_AttributeError, name);
+ return -1;
+#endif
+}
+
+PyTypeObject _mysql_ConnectionObject_Type = {
+#ifdef IS_PY3K
+ PyVarObject_HEAD_INIT(NULL, 0)
+#else
+ PyObject_HEAD_INIT(NULL)
+ 0,
+#endif
+ "_mysql.connection", /* (char *)tp_name For printing */
+ sizeof(_mysql_ConnectionObject),
+ 0,
+ (destructor)_mysql_ConnectionObject_dealloc, /* tp_dealloc */
+ 0, /*tp_print*/
+ (getattrfunc)_mysql_ConnectionObject_getattr, /* tp_getattr */
+ (setattrfunc)_mysql_ConnectionObject_setattr, /* tp_setattr */
+ 0, /*tp_compare*/
+ (reprfunc)_mysql_ConnectionObject_repr, /* tp_repr */
+
+ /* Method suites for standard classes */
+
+ 0, /* (PyNumberMethods *) tp_as_number */
+ 0, /* (PySequenceMethods *) tp_as_sequence */
+ 0, /* (PyMappingMethods *) tp_as_mapping */
+
+ /* More standard operations (here for binary compatibility) */
+
+ 0, /* (hashfunc) tp_hash */
+ 0, /* (ternaryfunc) tp_call */
+ 0, /* (reprfunc) tp_str */
+ 0, /* (getattrofunc) tp_getattro */
+ 0, /* (setattrofunc) tp_setattro */
+
+ /* Functions to access object as input/output buffer */
+ 0, /* (PyBufferProcs *) tp_as_buffer */
+
+ /* Flags to define presence of optional/expanded features */
+#if PY_VERSION_HEX < 0x02020000
+ Py_TPFLAGS_DEFAULT, /* (long) tp_flags */
+#else
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE,
+#endif
+ _mysql_connect__doc__, /* (char *) tp_doc Documentation string */
+#if PY_VERSION_HEX >= 0x02000000
+ /* Assigned meaning in release 2.0 */
+#if PY_VERSION_HEX >= 0x02020000
+ /* call function for all accessible objects */
+ (traverseproc) _mysql_ConnectionObject_traverse, /* tp_traverse */
+
+ /* delete references to contained objects */
+ (inquiry) _mysql_ConnectionObject_clear, /* tp_clear */
+#else
+ /* not supporting pre-2.2 GC */
+ 0,
+ 0,
+#endif
+#if PY_VERSION_HEX >= 0x02010000
+ /* Assigned meaning in release 2.1 */
+ /* rich comparisons */
+ 0, /* (richcmpfunc) tp_richcompare */
+
+ /* weak reference enabler */
+ 0, /* (long) tp_weaklistoffset */
+#if PY_VERSION_HEX >= 0x02020000
+ /* Added in release 2.2 */
+ /* Iterators */
+ 0, /* (getiterfunc) tp_iter */
+ 0, /* (iternextfunc) tp_iternext */
+
+ /* Attribute descriptor and subclassing stuff */
+ (struct PyMethodDef *)_mysql_ConnectionObject_methods, /* tp_methods */
+ (MyMemberlist(*))_mysql_ConnectionObject_memberlist, /* tp_members */
+ 0, /* (struct getsetlist *) tp_getset; */
+ 0, /* (struct _typeobject *) tp_base; */
+ 0, /* (PyObject *) tp_dict */
+ 0, /* (descrgetfunc) tp_descr_get */
+ 0, /* (descrsetfunc) tp_descr_set */
+ 0, /* (long) tp_dictoffset */
+ (initproc)_mysql_ConnectionObject_Initialize, /* tp_init */
+ NULL, /* tp_alloc */
+ NULL, /* tp_new */
+ NULL, /* tp_free Low-level free-memory routine */
+ 0, /* (PyObject *) tp_bases */
+ 0, /* (PyObject *) tp_mro method resolution order */
+ 0, /* (PyObject *) tp_defined */
+#endif /* python 2.2 */
+#endif /* python 2.1 */
+#endif /* python 2.0 */
+} ;
+
+PyTypeObject _mysql_ResultObject_Type = {
+#ifdef IS_PY3K
+ PyVarObject_HEAD_INIT(NULL, 0)
+#else
+ PyObject_HEAD_INIT(NULL)
+ 0,
+#endif
+ "_mysql.result",
+ sizeof(_mysql_ResultObject),
+ 0,
+ (destructor)_mysql_ResultObject_dealloc, /* tp_dealloc */
+ 0, /*tp_print*/
+ (getattrfunc)_mysql_ResultObject_getattr, /* tp_getattr */
+ (setattrfunc)_mysql_ResultObject_setattr, /* tp_setattr */
+ 0, /*tp_compare*/
+ (reprfunc)_mysql_ResultObject_repr, /* tp_repr */
+
+ /* Method suites for standard classes */
+
+ 0, /* (PyNumberMethods *) tp_as_number */
+ 0, /* (PySequenceMethods *) tp_as_sequence */
+ 0, /* (PyMappingMethods *) tp_as_mapping */
+
+ /* More standard operations (here for binary compatibility) */
+
+ 0, /* (hashfunc) tp_hash */
+ 0, /* (ternaryfunc) tp_call */
+ 0, /* (reprfunc) tp_str */
+ 0, /* (getattrofunc) tp_getattro */
+ 0, /* (setattrofunc) tp_setattro */
+
+ /* Functions to access object as input/output buffer */
+ 0, /* (PyBufferProcs *) tp_as_buffer */
+
+ /* Flags to define presence of optional/expanded features */
+#if PY_VERSION_HEX < 0x02020000
+ Py_TPFLAGS_DEFAULT, /* (long) tp_flags */
+#else
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE,
+#endif
+
+ _mysql_ResultObject__doc__, /* (char *) tp_doc Documentation string */
+#if PY_VERSION_HEX >= 0x02000000
+ /* Assigned meaning in release 2.0 */
+#if PY_VERSION_HEX >= 0x02020000
+ /* call function for all accessible objects */
+ (traverseproc) _mysql_ResultObject_traverse, /* tp_traverse */
+
+ /* delete references to contained objects */
+ (inquiry) _mysql_ResultObject_clear, /* tp_clear */
+#else
+ /* not supporting pre-2.2 GC */
+ 0,
+ 0,
+#endif
+#if PY_VERSION_HEX >= 0x02010000
+ /* Assigned meaning in release 2.1 */
+ /* rich comparisons */
+ 0, /* (richcmpfunc) tp_richcompare */
+
+ /* weak reference enabler */
+ 0, /* (long) tp_weaklistoffset */
+#if PY_VERSION_HEX >= 0x02020000
+ /* Added in release 2.2 */
+ /* Iterators */
+ 0, /* (getiterfunc) tp_iter */
+ 0, /* (iternextfunc) tp_iternext */
+
+ /* Attribute descriptor and subclassing stuff */
+ (struct PyMethodDef *) _mysql_ResultObject_methods, /* tp_methods */
+ (MyMemberlist(*)) _mysql_ResultObject_memberlist, /*tp_members */
+ 0, /* (struct getsetlist *) tp_getset; */
+ 0, /* (struct _typeobject *) tp_base; */
+ 0, /* (PyObject *) tp_dict */
+ 0, /* (descrgetfunc) tp_descr_get */
+ 0, /* (descrsetfunc) tp_descr_set */
+ 0, /* (long) tp_dictoffset */
+ (initproc)_mysql_ResultObject_Initialize, /* tp_init */
+ NULL, /* tp_alloc */
+ NULL, /* tp_new */
+ NULL, /* tp_free Low-level free-memory routine */
+ 0, /* (PyObject *) tp_bases */
+ 0, /* (PyObject *) tp_mro method resolution order */
+ 0, /* (PyObject *) tp_defined */
+#endif /* python 2.2 */
+#endif /* python 2.1 */
+#endif /* python 2.0 */
+};
+
+static PyMethodDef
+_mysql_methods[] = {
+ {
+ "connect",
+ (PyCFunction)_mysql_connect,
+ METH_VARARGS | METH_KEYWORDS,
+ _mysql_connect__doc__
+ },
+ {
+ "debug",
+ (PyCFunction)_mysql_debug,
+ METH_VARARGS,
+ _mysql_debug__doc__
+ },
+ {
+ "escape",
+ (PyCFunction)_mysql_escape,
+ METH_VARARGS,
+ _mysql_escape__doc__
+ },
+ {
+ "escape_sequence",
+ (PyCFunction)_mysql_escape_sequence,
+ METH_VARARGS,
+ _mysql_escape_sequence__doc__
+ },
+ {
+ "escape_dict",
+ (PyCFunction)_mysql_escape_dict,
+ METH_VARARGS,
+ _mysql_escape_dict__doc__
+ },
+ {
+ "escape_string",
+ (PyCFunction)_mysql_escape_string,
+ METH_VARARGS,
+ _mysql_escape_string__doc__
+ },
+ {
+ "string_literal",
+ (PyCFunction)_mysql_string_literal,
+ METH_VARARGS,
+ _mysql_string_literal__doc__
+ },
+ {
+ "get_client_info",
+ (PyCFunction)_mysql_get_client_info,
+ METH_VARARGS,
+ _mysql_get_client_info__doc__
+ },
+#if MYSQL_VERSION_ID >= 32314
+ {
+ "thread_safe",
+ (PyCFunction)_mysql_thread_safe,
+ METH_VARARGS,
+ _mysql_thread_safe__doc__
+ },
+#endif
+ {
+ "server_init",
+ (PyCFunction)_mysql_server_init,
+ METH_VARARGS | METH_KEYWORDS,
+ _mysql_server_init__doc__
+ },
+ {
+ "server_end",
+ (PyCFunction)_mysql_server_end,
+ METH_VARARGS,
+ _mysql_server_end__doc__
+ },
+ {NULL, NULL} /* sentinel */
+};
+
+static PyObject *
+_mysql_NewException(
+ PyObject *dict,
+ PyObject *edict,
+ char *name)
+{
+ PyObject *e;
+
+ if (!(e = PyDict_GetItemString(edict, name)))
+ return NULL;
+ if (PyDict_SetItemString(dict, name, e)) return NULL;
+ return e;
+}
+
+#define QUOTE(X) _QUOTE(X)
+#define _QUOTE(X) #X
+
+static char _mysql___doc__[] =
+"an adaptation of the MySQL C API (mostly)\n\
+\n\
+You probably are better off using MySQLdb instead of using this\n\
+module directly.\n\
+\n\
+In general, renaming goes from mysql_* to _mysql.*. _mysql.connect()\n\
+returns a connection object (MYSQL). Functions which expect MYSQL * as\n\
+an argument are now methods of the connection object. A number of things\n\
+return result objects (MYSQL_RES). Functions which expect MYSQL_RES * as\n\
+an argument are now methods of the result object. Deprecated functions\n\
+(as of 3.23) are NOT implemented.\n\
+";
+
+#ifdef IS_PY3K
+static struct PyModuleDef _mysqlmodule = {
+ PyModuleDef_HEAD_INIT,
+ "_mysql", /* name of module */
+ _mysql___doc__, /* module documentation, may be NULL */
+ -1, /* size of per-interpreter state of the module,
+ or -1 if the module keeps state in global variables. */
+ _mysql_methods
+};
+
+PyMODINIT_FUNC
+PyInit__mysql(void)
+#else
+DL_EXPORT(void)
+init_mysql(void)
+#endif
+{
+ PyObject *dict, *module, *emod, *edict;
+#ifdef IS_PY3K
+ module = PyModule_Create(&_mysqlmodule);
+ if (!module) return module; /* this really should never happen */
+#else
+ module = Py_InitModule4("_mysql", _mysql_methods, _mysql___doc__,
+ (PyObject *)NULL, PYTHON_API_VERSION);
+ if (!module) return; /* this really should never happen */
+#endif
+#ifdef IS_PY3K
+ Py_TYPE(&_mysql_ConnectionObject_Type) = &PyType_Type;
+ Py_TYPE(&_mysql_ResultObject_Type) = &PyType_Type;
+#else
+ _mysql_ConnectionObject_Type.ob_type = &PyType_Type;
+ _mysql_ResultObject_Type.ob_type = &PyType_Type;
+#endif
+#if PY_VERSION_HEX >= 0x02020000
+ _mysql_ConnectionObject_Type.tp_alloc = PyType_GenericAlloc;
+ _mysql_ConnectionObject_Type.tp_new = PyType_GenericNew;
+#ifndef IS_PY3K
+ _mysql_ConnectionObject_Type.tp_free = _PyObject_GC_Del;
+#endif
+ _mysql_ResultObject_Type.tp_alloc = PyType_GenericAlloc;
+ _mysql_ResultObject_Type.tp_new = PyType_GenericNew;
+#ifndef IS_PY3K
+ _mysql_ResultObject_Type.tp_free = _PyObject_GC_Del;
+#endif
+#endif
+
+ if (!(dict = PyModule_GetDict(module))) goto error;
+ if (PyDict_SetItemString(dict, "version_info",
+ PyRun_String(QUOTE(version_info), Py_eval_input,
+ dict, dict)))
+ goto error;
+ if (PyDict_SetItemString(dict, "__version__",
+#ifdef IS_PY3K
+ PyUnicode_FromString(QUOTE(__version__))))
+#else
+ PyString_FromString(QUOTE(__version__))))
+#endif
+ goto error;
+ if (PyDict_SetItemString(dict, "connection",
+ (PyObject *)&_mysql_ConnectionObject_Type))
+ goto error;
+ Py_INCREF(&_mysql_ConnectionObject_Type);
+ if (PyDict_SetItemString(dict, "result",
+ (PyObject *)&_mysql_ResultObject_Type))
+ goto error;
+ Py_INCREF(&_mysql_ResultObject_Type);
+ if (!(emod = PyImport_ImportModule("_mysql_exceptions"))) {
+ PyErr_Print();
+ goto error;
+ }
+ if (!(edict = PyModule_GetDict(emod))) goto error;
+ if (!(_mysql_MySQLError =
+ _mysql_NewException(dict, edict, "MySQLError")))
+ goto error;
+ if (!(_mysql_Warning =
+ _mysql_NewException(dict, edict, "Warning")))
+ goto error;
+ if (!(_mysql_Error =
+ _mysql_NewException(dict, edict, "Error")))
+ goto error;
+ if (!(_mysql_InterfaceError =
+ _mysql_NewException(dict, edict, "InterfaceError")))
+ goto error;
+ if (!(_mysql_DatabaseError =
+ _mysql_NewException(dict, edict, "DatabaseError")))
+ goto error;
+ if (!(_mysql_DataError =
+ _mysql_NewException(dict, edict, "DataError")))
+ goto error;
+ if (!(_mysql_OperationalError =
+ _mysql_NewException(dict, edict, "OperationalError")))
+ goto error;
+ if (!(_mysql_IntegrityError =
+ _mysql_NewException(dict, edict, "IntegrityError")))
+ goto error;
+ if (!(_mysql_InternalError =
+ _mysql_NewException(dict, edict, "InternalError")))
+ goto error;
+ if (!(_mysql_ProgrammingError =
+ _mysql_NewException(dict, edict, "ProgrammingError")))
+ goto error;
+ if (!(_mysql_NotSupportedError =
+ _mysql_NewException(dict, edict, "NotSupportedError")))
+ goto error;
+ Py_DECREF(emod);
+#ifdef IS_PY3K
+ if (!(_mysql_NULL = PyUnicode_FromString("NULL")))
+ goto error;
+#else
+ if (!(_mysql_NULL = PyString_FromString("NULL")))
+ goto error;
+#endif
+ if (PyDict_SetItemString(dict, "NULL", _mysql_NULL)) goto error;
+ error:
+ if (PyErr_Occurred()) {
+ PyErr_SetString(PyExc_ImportError,
+ "_mysql: init failed");
+ module = NULL;
+ }
+#ifdef IS_PY3K
+ return module;
+#endif
+}
+
+
diff --git a/MySQLdb/_mysql_exceptions.py b/MySQLdb/_mysql_exceptions.py
index 3241e74..99f556a 100644
--- a/MySQLdb/_mysql_exceptions.py
+++ b/MySQLdb/_mysql_exceptions.py
@@ -1,87 +1,87 @@
-"""_mysql_exceptions: Exception classes for _mysql and MySQLdb.
-
-These classes are dictated by the DB API v2.0:
-
- http://www.python.org/topics/database/DatabaseAPI-2.0.html
-"""
-
-try:
- from exceptions import Exception, StandardError, Warning
-except ImportError:
- # Python 3
- StandardError = Exception
-
-
-class MySQLError(StandardError):
-
- """Exception related to operation with MySQL."""
-
-
-class Warning(Warning, MySQLError):
-
- """Exception raised for important warnings like data truncations
- while inserting, etc."""
-
-class Error(MySQLError):
-
- """Exception that is the base class of all other error exceptions
- (not Warning)."""
-
-
-class InterfaceError(Error):
-
- """Exception raised for errors that are related to the database
- interface rather than the database itself."""
-
-
-class DatabaseError(Error):
-
- """Exception raised for errors that are related to the
- database."""
-
-
-class DataError(DatabaseError):
-
- """Exception raised for errors that are due to problems with the
- processed data like division by zero, numeric value out of range,
- etc."""
-
-
-class OperationalError(DatabaseError):
-
- """Exception raised for errors that are related to the database's
- operation and not necessarily under the control of the programmer,
- e.g. an unexpected disconnect occurs, the data source name is not
- found, a transaction could not be processed, a memory allocation
- error occurred during processing, etc."""
-
-
-class IntegrityError(DatabaseError):
-
- """Exception raised when the relational integrity of the database
- is affected, e.g. a foreign key check fails, duplicate key,
- etc."""
-
-
-class InternalError(DatabaseError):
-
- """Exception raised when the database encounters an internal
- error, e.g. the cursor is not valid anymore, the transaction is
- out of sync, etc."""
-
-
-class ProgrammingError(DatabaseError):
-
- """Exception raised for programming errors, e.g. table not found
- or already exists, syntax error in the SQL statement, wrong number
- of parameters specified, etc."""
-
-
-class NotSupportedError(DatabaseError):
-
- """Exception raised in case a method or database API was used
- which is not supported by the database, e.g. requesting a
- .rollback() on a connection that does not support transaction or
- has transactions turned off."""
-
-
+"""_mysql_exceptions: Exception classes for _mysql and MySQLdb.
+
+These classes are dictated by the DB API v2.0:
+
+ http://www.python.org/topics/database/DatabaseAPI-2.0.html
+"""
+
+try:
+ from exceptions import Exception, StandardError, Warning
+except ImportError:
+ # Python 3
+ StandardError = Exception
+
+
+class MySQLError(StandardError):
+
+ """Exception related to operation with MySQL."""
+
+
+class Warning(Warning, MySQLError):
+
+ """Exception raised for important warnings like data truncations
+ while inserting, etc."""
+
+class Error(MySQLError):
+
+ """Exception that is the base class of all other error exceptions
+ (not Warning)."""
+
+
+class InterfaceError(Error):
+
+ """Exception raised for errors that are related to the database
+ interface rather than the database itself."""
+
+
+class DatabaseError(Error):
+
+ """Exception raised for errors that are related to the
+ database."""
+
+
+class DataError(DatabaseError):
+
+ """Exception raised for errors that are due to problems with the
+ processed data like division by zero, numeric value out of range,
+ etc."""
+
+
+class OperationalError(DatabaseError):
+
+ """Exception raised for errors that are related to the database's
+ operation and not necessarily under the control of the programmer,
+ e.g. an unexpected disconnect occurs, the data source name is not
+ found, a transaction could not be processed, a memory allocation
+ error occurred during processing, etc."""
+
+
+class IntegrityError(DatabaseError):
+
+ """Exception raised when the relational integrity of the database
+ is affected, e.g. a foreign key check fails, duplicate key,
+ etc."""
+
+
+class InternalError(DatabaseError):
+
+ """Exception raised when the database encounters an internal
+ error, e.g. the cursor is not valid anymore, the transaction is
+ out of sync, etc."""
+
+
+class ProgrammingError(DatabaseError):
+
+ """Exception raised for programming errors, e.g. table not found
+ or already exists, syntax error in the SQL statement, wrong number
+ of parameters specified, etc."""
+
+
+class NotSupportedError(DatabaseError):
+
+ """Exception raised in case a method or database API was used
+ which is not supported by the database, e.g. requesting a
+ .rollback() on a connection that does not support transaction or
+ has transactions turned off."""
+
+
diff --git a/MySQLdb/distribute_setup.py b/MySQLdb/distribute_setup.py
index 8f5b063..3c8c34e 100644
--- a/MySQLdb/distribute_setup.py
+++ b/MySQLdb/distribute_setup.py
@@ -1,515 +1,515 @@
-#!python
-"""Bootstrap distribute installation
-
-If you want to use setuptools in your package's setup.py, just include this
-file in the same directory with it, and add this to the top of your setup.py::
-
- from distribute_setup import use_setuptools
- use_setuptools()
-
-If you want to require a specific version of setuptools, set a download
-mirror, or use an alternate download directory, you can do so by supplying
-the appropriate options to ``use_setuptools()``.
-
-This file can also be run as a script to install or upgrade setuptools.
-"""
-import os
-import sys
-import time
-import fnmatch
-import tempfile
-import tarfile
-from distutils import log
-
-try:
- from site import USER_SITE
-except ImportError:
- USER_SITE = None
-
-try:
- import subprocess
-
- def _python_cmd(*args):
- args = (sys.executable,) + args
- return subprocess.call(args) == 0
-
-except ImportError:
- # will be used for python 2.3
- def _python_cmd(*args):
- args = (sys.executable,) + args
- # quoting arguments if windows
- if sys.platform == 'win32':
- def quote(arg):
- if ' ' in arg:
- return '"%s"' % arg
- return arg
- args = [quote(arg) for arg in args]
- return os.spawnl(os.P_WAIT, sys.executable, *args) == 0
-
-DEFAULT_VERSION = "0.6.28"
-DEFAULT_URL = "http://pypi.python.org/packages/source/d/distribute/"
-SETUPTOOLS_FAKED_VERSION = "0.6c11"
-
-SETUPTOOLS_PKG_INFO = """\
-Metadata-Version: 1.0
-Name: setuptools
-Version: %s
-Summary: xxxx
-Home-page: xxx
-Author: xxx
-Author-email: xxx
-License: xxx
-Description: xxx
-""" % SETUPTOOLS_FAKED_VERSION
-
-
-def _install(tarball, install_args=()):
- # extracting the tarball
- tmpdir = tempfile.mkdtemp()
- log.warn('Extracting in %s', tmpdir)
- old_wd = os.getcwd()
- try:
- os.chdir(tmpdir)
- tar = tarfile.open(tarball)
- _extractall(tar)
- tar.close()
-
- # going in the directory
- subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0])
- os.chdir(subdir)
- log.warn('Now working in %s', subdir)
-
- # installing
- log.warn('Installing Distribute')
- if not _python_cmd('setup.py', 'install', *install_args):
- log.warn('Something went wrong during the installation.')
- log.warn('See the error message above.')
- finally:
- os.chdir(old_wd)
-
-
-def _build_egg(egg, tarball, to_dir):
- # extracting the tarball
- tmpdir = tempfile.mkdtemp()
- log.warn('Extracting in %s', tmpdir)
- old_wd = os.getcwd()
- try:
- os.chdir(tmpdir)
- tar = tarfile.open(tarball)
- _extractall(tar)
- tar.close()
-
- # going in the directory
- subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0])
- os.chdir(subdir)
- log.warn('Now working in %s', subdir)
-
- # building an egg
- log.warn('Building a Distribute egg in %s', to_dir)
- _python_cmd('setup.py', '-q', 'bdist_egg', '--dist-dir', to_dir)
-
- finally:
- os.chdir(old_wd)
- # returning the result
- log.warn(egg)
- if not os.path.exists(egg):
- raise IOError('Could not build the egg.')
-
-
-def _do_download(version, download_base, to_dir, download_delay):
- egg = os.path.join(to_dir, 'distribute-%s-py%d.%d.egg'
- % (version, sys.version_info[0], sys.version_info[1]))
- if not os.path.exists(egg):
- tarball = download_setuptools(version, download_base,
- to_dir, download_delay)
- _build_egg(egg, tarball, to_dir)
- sys.path.insert(0, egg)
- import setuptools
- setuptools.bootstrap_install_from = egg
-
-
-def use_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL,
- to_dir=os.curdir, download_delay=15, no_fake=True):
- # making sure we use the absolute path
- to_dir = os.path.abspath(to_dir)
- was_imported = 'pkg_resources' in sys.modules or \
- 'setuptools' in sys.modules
- try:
- try:
- import pkg_resources
- if not hasattr(pkg_resources, '_distribute'):
- if not no_fake:
- _fake_setuptools()
- raise ImportError
- except ImportError:
- return _do_download(version, download_base, to_dir, download_delay)
- try:
- pkg_resources.require("distribute>=" + version)
- return
- except pkg_resources.VersionConflict:
- e = sys.exc_info()[1]
- if was_imported:
- sys.stderr.write(
- "The required version of distribute (>=%s) is not available,\n"
- "and can't be installed while this script is running. Please\n"
- "install a more recent version first, using\n"
- "'easy_install -U distribute'."
- "\n\n(Currently using %r)\n" % (version, e.args[0]))
- sys.exit(2)
- else:
- del pkg_resources, sys.modules['pkg_resources'] # reload ok
- return _do_download(version, download_base, to_dir,
- download_delay)
- except pkg_resources.DistributionNotFound:
- return _do_download(version, download_base, to_dir,
- download_delay)
- finally:
- if not no_fake:
- _create_fake_setuptools_pkg_info(to_dir)
-
-
-def download_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL,
- to_dir=os.curdir, delay=15):
- """Download distribute from a specified location and return its filename
-
- `version` should be a valid distribute version number that is available
- as an egg for download under the `download_base` URL (which should end
- with a '/'). `to_dir` is the directory where the egg will be downloaded.
- `delay` is the number of seconds to pause before an actual download
- attempt.
- """
- # making sure we use the absolute path
- to_dir = os.path.abspath(to_dir)
- try:
- from urllib.request import urlopen
- except ImportError:
- from urllib2 import urlopen
- tgz_name = "distribute-%s.tar.gz" % version
- url = download_base + tgz_name
- saveto = os.path.join(to_dir, tgz_name)
- src = dst = None
- if not os.path.exists(saveto): # Avoid repeated downloads
- try:
- log.warn("Downloading %s", url)
- src = urlopen(url)
- # Read/write all in one block, so we don't create a corrupt file
- # if the download is interrupted.
- data = src.read()
- dst = open(saveto, "wb")
- dst.write(data)
- finally:
- if src:
- src.close()
- if dst:
- dst.close()
- return os.path.realpath(saveto)
-
-
-def _no_sandbox(function):
- def __no_sandbox(*args, **kw):
- try:
- from setuptools.sandbox import DirectorySandbox
- if not hasattr(DirectorySandbox, '_old'):
- def violation(*args):
- pass
- DirectorySandbox._old = DirectorySandbox._violation
- DirectorySandbox._violation = violation
- patched = True
- else:
- patched = False
- except ImportError:
- patched = False
-
- try:
- return function(*args, **kw)
- finally:
- if patched:
- DirectorySandbox._violation = DirectorySandbox._old
- del DirectorySandbox._old
-
- return __no_sandbox
-
-
-def _patch_file(path, content):
- """Will backup the file then patch it"""
- existing_content = open(path).read()
- if existing_content == content:
- # already patched
- log.warn('Already patched.')
- return False
- log.warn('Patching...')
- _rename_path(path)
- f = open(path, 'w')
- try:
- f.write(content)
- finally:
- f.close()
- return True
-
-_patch_file = _no_sandbox(_patch_file)
-
-
-def _same_content(path, content):
- return open(path).read() == content
-
-
-def _rename_path(path):
- new_name = path + '.OLD.%s' % time.time()
- log.warn('Renaming %s into %s', path, new_name)
- os.rename(path, new_name)
- return new_name
-
-
-def _remove_flat_installation(placeholder):
- if not os.path.isdir(placeholder):
- log.warn('Unkown installation at %s', placeholder)
- return False
- found = False
- for file in os.listdir(placeholder):
- if fnmatch.fnmatch(file, 'setuptools*.egg-info'):
- found = True
- break
- if not found:
- log.warn('Could not locate setuptools*.egg-info')
- return
-
- log.warn('Removing elements out of the way...')
- pkg_info = os.path.join(placeholder, file)
- if os.path.isdir(pkg_info):
- patched = _patch_egg_dir(pkg_info)
- else:
- patched = _patch_file(pkg_info, SETUPTOOLS_PKG_INFO)
-
- if not patched:
- log.warn('%s already patched.', pkg_info)
- return False
- # now let's move the files out of the way
- for element in ('setuptools', 'pkg_resources.py', 'site.py'):
- element = os.path.join(placeholder, element)
- if os.path.exists(element):
- _rename_path(element)
- else:
- log.warn('Could not find the %s element of the '
- 'Setuptools distribution', element)
- return True
-
-_remove_flat_installation = _no_sandbox(_remove_flat_installation)
-
-
-def _after_install(dist):
- log.warn('After install bootstrap.')
- placeholder = dist.get_command_obj('install').install_purelib
- _create_fake_setuptools_pkg_info(placeholder)
-
-
-def _create_fake_setuptools_pkg_info(placeholder):
- if not placeholder or not os.path.exists(placeholder):
- log.warn('Could not find the install location')
- return
- pyver = '%s.%s' % (sys.version_info[0], sys.version_info[1])
- setuptools_file = 'setuptools-%s-py%s.egg-info' % \
- (SETUPTOOLS_FAKED_VERSION, pyver)
- pkg_info = os.path.join(placeholder, setuptools_file)
- if os.path.exists(pkg_info):
- log.warn('%s already exists', pkg_info)
- return
-
- if not os.access(pkg_info, os.W_OK):
- log.warn("Don't have permissions to write %s, skipping", pkg_info)
-
- log.warn('Creating %s', pkg_info)
- f = open(pkg_info, 'w')
- try:
- f.write(SETUPTOOLS_PKG_INFO)
- finally:
- f.close()
-
- pth_file = os.path.join(placeholder, 'setuptools.pth')
- log.warn('Creating %s', pth_file)
- f = open(pth_file, 'w')
- try:
- f.write(os.path.join(os.curdir, setuptools_file))
- finally:
- f.close()
-
-_create_fake_setuptools_pkg_info = _no_sandbox(
- _create_fake_setuptools_pkg_info
-)
-
-
-def _patch_egg_dir(path):
- # let's check if it's already patched
- pkg_info = os.path.join(path, 'EGG-INFO', 'PKG-INFO')
- if os.path.exists(pkg_info):
- if _same_content(pkg_info, SETUPTOOLS_PKG_INFO):
- log.warn('%s already patched.', pkg_info)
- return False
- _rename_path(path)
- os.mkdir(path)
- os.mkdir(os.path.join(path, 'EGG-INFO'))
- pkg_info = os.path.join(path, 'EGG-INFO', 'PKG-INFO')
- f = open(pkg_info, 'w')
- try:
- f.write(SETUPTOOLS_PKG_INFO)
- finally:
- f.close()
- return True
-
-_patch_egg_dir = _no_sandbox(_patch_egg_dir)
-
-
-def _before_install():
- log.warn('Before install bootstrap.')
- _fake_setuptools()
-
-
-def _under_prefix(location):
- if 'install' not in sys.argv:
- return True
- args = sys.argv[sys.argv.index('install') + 1:]
- for index, arg in enumerate(args):
- for option in ('--root', '--prefix'):
- if arg.startswith('%s=' % option):
- top_dir = arg.split('root=')[-1]
- return location.startswith(top_dir)
- elif arg == option:
- if len(args) > index:
- top_dir = args[index + 1]
- return location.startswith(top_dir)
- if arg == '--user' and USER_SITE is not None:
- return location.startswith(USER_SITE)
- return True
-
-
-def _fake_setuptools():
- log.warn('Scanning installed packages')
- try:
- import pkg_resources
- except ImportError:
- # we're cool
- log.warn('Setuptools or Distribute does not seem to be installed.')
- return
- ws = pkg_resources.working_set
- try:
- setuptools_dist = ws.find(
- pkg_resources.Requirement.parse('setuptools', replacement=False)
- )
- except TypeError:
- # old distribute API
- setuptools_dist = ws.find(
- pkg_resources.Requirement.parse('setuptools')
- )
-
- if setuptools_dist is None:
- log.warn('No setuptools distribution found')
- return
- # detecting if it was already faked
- setuptools_location = setuptools_dist.location
- log.warn('Setuptools installation detected at %s', setuptools_location)
-
- # if --root or --preix was provided, and if
- # setuptools is not located in them, we don't patch it
- if not _under_prefix(setuptools_location):
- log.warn('Not patching, --root or --prefix is installing Distribute'
- ' in another location')
- return
-
- # let's see if its an egg
- if not setuptools_location.endswith('.egg'):
- log.warn('Non-egg installation')
- res = _remove_flat_installation(setuptools_location)
- if not res:
- return
- else:
- log.warn('Egg installation')
- pkg_info = os.path.join(setuptools_location, 'EGG-INFO', 'PKG-INFO')
- if (os.path.exists(pkg_info) and
- _same_content(pkg_info, SETUPTOOLS_PKG_INFO)):
- log.warn('Already patched.')
- return
- log.warn('Patching...')
- # let's create a fake egg replacing setuptools one
- res = _patch_egg_dir(setuptools_location)
- if not res:
- return
- log.warn('Patched done.')
- _relaunch()
-
-
-def _relaunch():
- log.warn('Relaunching...')
- # we have to relaunch the process
- # pip marker to avoid a relaunch bug
- _cmd = ['-c', 'install', '--single-version-externally-managed']
- if sys.argv[:3] == _cmd:
- sys.argv[0] = 'setup.py'
- args = [sys.executable] + sys.argv
- sys.exit(subprocess.call(args))
-
-
-def _extractall(self, path=".", members=None):
- """Extract all members from the archive to the current working
- directory and set owner, modification time and permissions on
- directories afterwards. `path' specifies a different directory
- to extract to. `members' is optional and must be a subset of the
- list returned by getmembers().
- """
- import copy
- import operator
- from tarfile import ExtractError
- directories = []
-
- if members is None:
- members = self
-
- for tarinfo in members:
- if tarinfo.isdir():
- # Extract directories with a safe mode.
- directories.append(tarinfo)
- tarinfo = copy.copy(tarinfo)
- tarinfo.mode = 448 # decimal for oct 0700
- self.extract(tarinfo, path)
-
- # Reverse sort directories.
- if sys.version_info < (2, 4):
- def sorter(dir1, dir2):
- return cmp(dir1.name, dir2.name)
- directories.sort(sorter)
- directories.reverse()
- else:
- directories.sort(key=operator.attrgetter('name'), reverse=True)
-
- # Set correct owner, mtime and filemode on directories.
- for tarinfo in directories:
- dirpath = os.path.join(path, tarinfo.name)
- try:
- self.chown(tarinfo, dirpath)
- self.utime(tarinfo, dirpath)
- self.chmod(tarinfo, dirpath)
- except ExtractError:
- e = sys.exc_info()[1]
- if self.errorlevel > 1:
- raise
- else:
- self._dbg(1, "tarfile: %s" % e)
-
-
-def _build_install_args(argv):
- install_args = []
- user_install = '--user' in argv
- if user_install and sys.version_info < (2, 6):
- log.warn("--user requires Python 2.6 or later")
- raise SystemExit(1)
- if user_install:
- install_args.append('--user')
- return install_args
-
-
-def main(argv, version=DEFAULT_VERSION):
- """Install or upgrade setuptools and EasyInstall"""
- tarball = download_setuptools()
- _install(tarball, _build_install_args(argv))
-
-
-if __name__ == '__main__':
- main(sys.argv[1:])
+#!python
+"""Bootstrap distribute installation
+
+If you want to use setuptools in your package's setup.py, just include this
+file in the same directory with it, and add this to the top of your setup.py::
+
+ from distribute_setup import use_setuptools
+ use_setuptools()
+
+If you want to require a specific version of setuptools, set a download
+mirror, or use an alternate download directory, you can do so by supplying
+the appropriate options to ``use_setuptools()``.
+
+This file can also be run as a script to install or upgrade setuptools.
+"""
+import os
+import sys
+import time
+import fnmatch
+import tempfile
+import tarfile
+from distutils import log
+
+try:
+ from site import USER_SITE
+except ImportError:
+ USER_SITE = None
+
+try:
+ import subprocess
+
+ def _python_cmd(*args):
+ args = (sys.executable,) + args
+ return subprocess.call(args) == 0
+
+except ImportError:
+ # will be used for python 2.3
+ def _python_cmd(*args):
+ args = (sys.executable,) + args
+ # quoting arguments if windows
+ if sys.platform == 'win32':
+ def quote(arg):
+ if ' ' in arg:
+ return '"%s"' % arg
+ return arg
+ args = [quote(arg) for arg in args]
+ return os.spawnl(os.P_WAIT, sys.executable, *args) == 0
+
+DEFAULT_VERSION = "0.6.28"
+DEFAULT_URL = "http://pypi.python.org/packages/source/d/distribute/"
+SETUPTOOLS_FAKED_VERSION = "0.6c11"
+
+SETUPTOOLS_PKG_INFO = """\
+Metadata-Version: 1.0
+Name: setuptools
+Version: %s
+Summary: xxxx
+Home-page: xxx
+Author: xxx
+Author-email: xxx
+License: xxx
+Description: xxx
+""" % SETUPTOOLS_FAKED_VERSION
+
+
+def _install(tarball, install_args=()):
+ # extracting the tarball
+ tmpdir = tempfile.mkdtemp()
+ log.warn('Extracting in %s', tmpdir)
+ old_wd = os.getcwd()
+ try:
+ os.chdir(tmpdir)
+ tar = tarfile.open(tarball)
+ _extractall(tar)
+ tar.close()
+
+ # going in the directory
+ subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0])
+ os.chdir(subdir)
+ log.warn('Now working in %s', subdir)
+
+ # installing
+ log.warn('Installing Distribute')
+ if not _python_cmd('setup.py', 'install', *install_args):
+ log.warn('Something went wrong during the installation.')
+ log.warn('See the error message above.')
+ finally:
+ os.chdir(old_wd)
+
+
+def _build_egg(egg, tarball, to_dir):
+ # extracting the tarball
+ tmpdir = tempfile.mkdtemp()
+ log.warn('Extracting in %s', tmpdir)
+ old_wd = os.getcwd()
+ try:
+ os.chdir(tmpdir)
+ tar = tarfile.open(tarball)
+ _extractall(tar)
+ tar.close()
+
+ # going in the directory
+ subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0])
+ os.chdir(subdir)
+ log.warn('Now working in %s', subdir)
+
+ # building an egg
+ log.warn('Building a Distribute egg in %s', to_dir)
+ _python_cmd('setup.py', '-q', 'bdist_egg', '--dist-dir', to_dir)
+
+ finally:
+ os.chdir(old_wd)
+ # returning the result
+ log.warn(egg)
+ if not os.path.exists(egg):
+ raise IOError('Could not build the egg.')
+
+
+def _do_download(version, download_base, to_dir, download_delay):
+ egg = os.path.join(to_dir, 'distribute-%s-py%d.%d.egg'
+ % (version, sys.version_info[0], sys.version_info[1]))
+ if not os.path.exists(egg):
+ tarball = download_setuptools(version, download_base,
+ to_dir, download_delay)
+ _build_egg(egg, tarball, to_dir)
+ sys.path.insert(0, egg)
+ import setuptools
+ setuptools.bootstrap_install_from = egg
+
+
+def use_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL,
+ to_dir=os.curdir, download_delay=15, no_fake=True):
+ # making sure we use the absolute path
+ to_dir = os.path.abspath(to_dir)
+ was_imported = 'pkg_resources' in sys.modules or \
+ 'setuptools' in sys.modules
+ try:
+ try:
+ import pkg_resources
+ if not hasattr(pkg_resources, '_distribute'):
+ if not no_fake:
+ _fake_setuptools()
+ raise ImportError
+ except ImportError:
+ return _do_download(version, download_base, to_dir, download_delay)
+ try:
+ pkg_resources.require("distribute>=" + version)
+ return
+ except pkg_resources.VersionConflict:
+ e = sys.exc_info()[1]
+ if was_imported:
+ sys.stderr.write(
+ "The required version of distribute (>=%s) is not available,\n"
+ "and can't be installed while this script is running. Please\n"
+ "install a more recent version first, using\n"
+ "'easy_install -U distribute'."
+ "\n\n(Currently using %r)\n" % (version, e.args[0]))
+ sys.exit(2)
+ else:
+ del pkg_resources, sys.modules['pkg_resources'] # reload ok
+ return _do_download(version, download_base, to_dir,
+ download_delay)
+ except pkg_resources.DistributionNotFound:
+ return _do_download(version, download_base, to_dir,
+ download_delay)
+ finally:
+ if not no_fake:
+ _create_fake_setuptools_pkg_info(to_dir)
+
+
+def download_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL,
+ to_dir=os.curdir, delay=15):
+ """Download distribute from a specified location and return its filename
+
+ `version` should be a valid distribute version number that is available
+ as an egg for download under the `download_base` URL (which should end
+ with a '/'). `to_dir` is the directory where the egg will be downloaded.
+ `delay` is the number of seconds to pause before an actual download
+ attempt.
+ """
+ # making sure we use the absolute path
+ to_dir = os.path.abspath(to_dir)
+ try:
+ from urllib.request import urlopen
+ except ImportError:
+ from urllib2 import urlopen
+ tgz_name = "distribute-%s.tar.gz" % version
+ url = download_base + tgz_name
+ saveto = os.path.join(to_dir, tgz_name)
+ src = dst = None
+ if not os.path.exists(saveto): # Avoid repeated downloads
+ try:
+ log.warn("Downloading %s", url)
+ src = urlopen(url)
+ # Read/write all in one block, so we don't create a corrupt file
+ # if the download is interrupted.
+ data = src.read()
+ dst = open(saveto, "wb")
+ dst.write(data)
+ finally:
+ if src:
+ src.close()
+ if dst:
+ dst.close()
+ return os.path.realpath(saveto)
+
+
+def _no_sandbox(function):
+ def __no_sandbox(*args, **kw):
+ try:
+ from setuptools.sandbox import DirectorySandbox
+ if not hasattr(DirectorySandbox, '_old'):
+ def violation(*args):
+ pass
+ DirectorySandbox._old = DirectorySandbox._violation
+ DirectorySandbox._violation = violation
+ patched = True
+ else:
+ patched = False
+ except ImportError:
+ patched = False
+
+ try:
+ return function(*args, **kw)
+ finally:
+ if patched:
+ DirectorySandbox._violation = DirectorySandbox._old
+ del DirectorySandbox._old
+
+ return __no_sandbox
+
+
+def _patch_file(path, content):
+ """Will backup the file then patch it"""
+ existing_content = open(path).read()
+ if existing_content == content:
+ # already patched
+ log.warn('Already patched.')
+ return False
+ log.warn('Patching...')
+ _rename_path(path)
+ f = open(path, 'w')
+ try:
+ f.write(content)
+ finally:
+ f.close()
+ return True
+
+_patch_file = _no_sandbox(_patch_file)
+
+
+def _same_content(path, content):
+ return open(path).read() == content
+
+
+def _rename_path(path):
+ new_name = path + '.OLD.%s' % time.time()
+ log.warn('Renaming %s into %s', path, new_name)
+ os.rename(path, new_name)
+ return new_name
+
+
+def _remove_flat_installation(placeholder):
+ if not os.path.isdir(placeholder):
+ log.warn('Unkown installation at %s', placeholder)
+ return False
+ found = False
+ for file in os.listdir(placeholder):
+ if fnmatch.fnmatch(file, 'setuptools*.egg-info'):
+ found = True
+ break
+ if not found:
+ log.warn('Could not locate setuptools*.egg-info')
+ return
+
+ log.warn('Removing elements out of the way...')
+ pkg_info = os.path.join(placeholder, file)
+ if os.path.isdir(pkg_info):
+ patched = _patch_egg_dir(pkg_info)
+ else:
+ patched = _patch_file(pkg_info, SETUPTOOLS_PKG_INFO)
+
+ if not patched:
+ log.warn('%s already patched.', pkg_info)
+ return False
+ # now let's move the files out of the way
+ for element in ('setuptools', 'pkg_resources.py', 'site.py'):
+ element = os.path.join(placeholder, element)
+ if os.path.exists(element):
+ _rename_path(element)
+ else:
+ log.warn('Could not find the %s element of the '
+ 'Setuptools distribution', element)
+ return True
+
+_remove_flat_installation = _no_sandbox(_remove_flat_installation)
+
+
+def _after_install(dist):
+ log.warn('After install bootstrap.')
+ placeholder = dist.get_command_obj('install').install_purelib
+ _create_fake_setuptools_pkg_info(placeholder)
+
+
+def _create_fake_setuptools_pkg_info(placeholder):
+ if not placeholder or not os.path.exists(placeholder):
+ log.warn('Could not find the install location')
+ return
+ pyver = '%s.%s' % (sys.version_info[0], sys.version_info[1])
+ setuptools_file = 'setuptools-%s-py%s.egg-info' % \
+ (SETUPTOOLS_FAKED_VERSION, pyver)
+ pkg_info = os.path.join(placeholder, setuptools_file)
+ if os.path.exists(pkg_info):
+ log.warn('%s already exists', pkg_info)
+ return
+
+ if not os.access(pkg_info, os.W_OK):
+ log.warn("Don't have permissions to write %s, skipping", pkg_info)
+
+ log.warn('Creating %s', pkg_info)
+ f = open(pkg_info, 'w')
+ try:
+ f.write(SETUPTOOLS_PKG_INFO)
+ finally:
+ f.close()
+
+ pth_file = os.path.join(placeholder, 'setuptools.pth')
+ log.warn('Creating %s', pth_file)
+ f = open(pth_file, 'w')
+ try:
+ f.write(os.path.join(os.curdir, setuptools_file))
+ finally:
+ f.close()
+
+_create_fake_setuptools_pkg_info = _no_sandbox(
+ _create_fake_setuptools_pkg_info
+)
+
+
+def _patch_egg_dir(path):
+ # let's check if it's already patched
+ pkg_info = os.path.join(path, 'EGG-INFO', 'PKG-INFO')
+ if os.path.exists(pkg_info):
+ if _same_content(pkg_info, SETUPTOOLS_PKG_INFO):
+ log.warn('%s already patched.', pkg_info)
+ return False
+ _rename_path(path)
+ os.mkdir(path)
+ os.mkdir(os.path.join(path, 'EGG-INFO'))
+ pkg_info = os.path.join(path, 'EGG-INFO', 'PKG-INFO')
+ f = open(pkg_info, 'w')
+ try:
+ f.write(SETUPTOOLS_PKG_INFO)
+ finally:
+ f.close()
+ return True
+
+_patch_egg_dir = _no_sandbox(_patch_egg_dir)
+
+
+def _before_install():
+ log.warn('Before install bootstrap.')
+ _fake_setuptools()
+
+
+def _under_prefix(location):
+ if 'install' not in sys.argv:
+ return True
+ args = sys.argv[sys.argv.index('install') + 1:]
+ for index, arg in enumerate(args):
+ for option in ('--root', '--prefix'):
+ if arg.startswith('%s=' % option):
+ top_dir = arg.split('root=')[-1]
+ return location.startswith(top_dir)
+ elif arg == option:
+ if len(args) > index:
+ top_dir = args[index + 1]
+ return location.startswith(top_dir)
+ if arg == '--user' and USER_SITE is not None:
+ return location.startswith(USER_SITE)
+ return True
+
+
+def _fake_setuptools():
+ log.warn('Scanning installed packages')
+ try:
+ import pkg_resources
+ except ImportError:
+ # we're cool
+ log.warn('Setuptools or Distribute does not seem to be installed.')
+ return
+ ws = pkg_resources.working_set
+ try:
+ setuptools_dist = ws.find(
+ pkg_resources.Requirement.parse('setuptools', replacement=False)
+ )
+ except TypeError:
+ # old distribute API
+ setuptools_dist = ws.find(
+ pkg_resources.Requirement.parse('setuptools')
+ )
+
+ if setuptools_dist is None:
+ log.warn('No setuptools distribution found')
+ return
+ # detecting if it was already faked
+ setuptools_location = setuptools_dist.location
+ log.warn('Setuptools installation detected at %s', setuptools_location)
+
+ # if --root or --preix was provided, and if
+ # setuptools is not located in them, we don't patch it
+ if not _under_prefix(setuptools_location):
+ log.warn('Not patching, --root or --prefix is installing Distribute'
+ ' in another location')
+ return
+
+ # let's see if its an egg
+ if not setuptools_location.endswith('.egg'):
+ log.warn('Non-egg installation')
+ res = _remove_flat_installation(setuptools_location)
+ if not res:
+ return
+ else:
+ log.warn('Egg installation')
+ pkg_info = os.path.join(setuptools_location, 'EGG-INFO', 'PKG-INFO')
+ if (os.path.exists(pkg_info) and
+ _same_content(pkg_info, SETUPTOOLS_PKG_INFO)):
+ log.warn('Already patched.')
+ return
+ log.warn('Patching...')
+ # let's create a fake egg replacing setuptools one
+ res = _patch_egg_dir(setuptools_location)
+ if not res:
+ return
+ log.warn('Patched done.')
+ _relaunch()
+
+
+def _relaunch():
+ log.warn('Relaunching...')
+ # we have to relaunch the process
+ # pip marker to avoid a relaunch bug
+ _cmd = ['-c', 'install', '--single-version-externally-managed']
+ if sys.argv[:3] == _cmd:
+ sys.argv[0] = 'setup.py'
+ args = [sys.executable] + sys.argv
+ sys.exit(subprocess.call(args))
+
+
+def _extractall(self, path=".", members=None):
+ """Extract all members from the archive to the current working
+ directory and set owner, modification time and permissions on
+ directories afterwards. `path' specifies a different directory
+ to extract to. `members' is optional and must be a subset of the
+ list returned by getmembers().
+ """
+ import copy
+ import operator
+ from tarfile import ExtractError
+ directories = []
+
+ if members is None:
+ members = self
+
+ for tarinfo in members:
+ if tarinfo.isdir():
+ # Extract directories with a safe mode.
+ directories.append(tarinfo)
+ tarinfo = copy.copy(tarinfo)
+ tarinfo.mode = 448 # decimal for oct 0700
+ self.extract(tarinfo, path)
+
+ # Reverse sort directories.
+ if sys.version_info < (2, 4):
+ def sorter(dir1, dir2):
+ return cmp(dir1.name, dir2.name)
+ directories.sort(sorter)
+ directories.reverse()
+ else:
+ directories.sort(key=operator.attrgetter('name'), reverse=True)
+
+ # Set correct owner, mtime and filemode on directories.
+ for tarinfo in directories:
+ dirpath = os.path.join(path, tarinfo.name)
+ try:
+ self.chown(tarinfo, dirpath)
+ self.utime(tarinfo, dirpath)
+ self.chmod(tarinfo, dirpath)
+ except ExtractError:
+ e = sys.exc_info()[1]
+ if self.errorlevel > 1:
+ raise
+ else:
+ self._dbg(1, "tarfile: %s" % e)
+
+
+def _build_install_args(argv):
+ install_args = []
+ user_install = '--user' in argv
+ if user_install and sys.version_info < (2, 6):
+ log.warn("--user requires Python 2.6 or later")
+ raise SystemExit(1)
+ if user_install:
+ install_args.append('--user')
+ return install_args
+
+
+def main(argv, version=DEFAULT_VERSION):
+ """Install or upgrade setuptools and EasyInstall"""
+ tarball = download_setuptools()
+ _install(tarball, _build_install_args(argv))
+
+
+if __name__ == '__main__':
+ main(sys.argv[1:])
diff --git a/MySQLdb/doc/.cvsignore b/MySQLdb/doc/.cvsignore
deleted file mode 100644
index 5367f6a..0000000
--- a/MySQLdb/doc/.cvsignore
+++ /dev/null
@@ -1,2 +0,0 @@
-*.tex
-*.html
diff --git a/MySQLdb/doc/FAQ.txt b/MySQLdb/doc/FAQ.txt
index b6a4ce9..851c3e2 100644
--- a/MySQLdb/doc/FAQ.txt
+++ b/MySQLdb/doc/FAQ.txt
@@ -1,143 +1,143 @@
-====================================
- MySQLdb Frequently Asked Questions
-====================================
-
-.. contents::
-..
-
-
-Build Errors
-------------
-
- ld: fatal: library -lmysqlclient_r: not found
-
-mysqlclient_r is the thread-safe library. It's not available on
-all platforms, or all installations, apparently. You'll need to
-reconfigure site.cfg (in MySQLdb-1.2.1 and newer) to have
-threadsafe = False.
-
- mysql.h: No such file or directory
-
-This almost always mean you don't have development packages
-installed. On some systems, C headers for various things (like MySQL)
-are distributed as a seperate package. You'll need to figure out
-what that is and install it, but often the name ends with -devel.
-
-Another possibility: Some older versions of mysql_config behave oddly
-and may throw quotes around some of the path names, which confused
-MySQLdb-1.2.0. 1.2.1 works around these problems. If you see things
-like -I'/usr/local/include/mysql' in your compile command, that's
-probably the issue, but it shouldn't happen any more.
-
-
-ImportError
------------
-
- ImportError: No module named _mysql
-
-If you see this, it's likely you did some wrong when installing
-MySQLdb; re-read (or read) README. _mysql is the low-level C module
-that interfaces with the MySQL client library.
-
-Various versions of MySQLdb in the past have had build issues on
-"weird" platforms; "weird" in this case means "not Linux", though
-generally there aren't problems on Unix/POSIX platforms, including
-BSDs and Mac OS X. Windows has been more problematic, in part because
-there is no `mysql_config` available in the Windows installation of
-MySQL. 1.2.1 solves most, if not all, of these problems, but you will
-still have to edit a configuration file so that the setup knows where
-to find MySQL and what libraries to include.
-
-
- ImportError: libmysqlclient_r.so.14: cannot open shared object file: No such file or directory
-
-The number after .so may vary, but this means you have a version of
-MySQLdb compiled against one version of MySQL, and are now trying to
-run it against a different version. The shared library version tends
-to change between major releases.
-
-Solution: Rebuilt MySQLdb, or get the matching version of MySQL.
-
-Another thing that can cause this: The MySQL libraries may not be on
-your system path.
-
-Solutions:
-
-* set the LD_LIBRARY_PATH environment variable so that it includes
- the path to the MySQL libraries.
-
-* set static=True in site.cfg for static linking
-
-* reconfigure your system so that the MySQL libraries are on the
- default loader path. In Linux, you edit /etc/ld.so.conf and run
- ldconfig. For Solaris, see `Linker and Libraries Guide
- <http://docs.sun.com/app/docs/doc/817-3677/6mj8mbtbe?a=view>`_.
-
-
- ImportError: ld.so.1: python: fatal: libmtmalloc.so.1: DF_1_NOOPEN tagged object may not be dlopen()'ed
-
-This is a weird one from Solaris. What does it mean? I have no idea.
-However, things like this can happen if there is some sort of a compiler
-or environment mismatch between Python and MySQL. For example, on some
-commercial systems, you might have some code compiled with their own
-compiler, and other things compiled with GCC. They don't always mesh
-together. One way to encounter this is by getting binary packages from
-different vendors.
-
-Solution: Rebuild Python or MySQL (or maybe both) from source.
-
- ImportError: dlopen(./_mysql.so, 2): Symbol not found: _sprintf$LDBLStub
- Referenced from: ./_mysql.so
- Expected in: dynamic lookup
-
-This is one from Mac OS X. It seems to have been a compiler mismatch,
-but this time between two different versions of GCC. It seems nearly
-every major release of GCC changes the ABI in some why, so linking
-code compiled with GCC-3.3 and GCC-4.0, for example, can be
-problematic.
-
-
-My data disappeared! (or won't go away!)
-----------------------------------------
-
-Starting with 1.2.0, MySQLdb disables autocommit by default, as
-required by the DB-API standard (`PEP-249`_). If you are using InnoDB
-tables or some other type of transactional table type, you'll need
-to do connection.commit() before closing the connection, or else
-none of your changes will be written to the database.
-
-Conversely, you can also use connection.rollback() to throw away
-any changes you've made since the last commit.
-
-Important note: Some SQL statements -- specifically DDL statements
-like CREATE TABLE -- are non-transactional, so they can't be
-rolled back, and they cause pending transactions to commit.
-
-
-Other Errors
-------------
-
- OperationalError: (1251, 'Client does not support authentication protocol requested by server; consider upgrading MySQL client')
-
-This means your server and client libraries are not the same version.
-More specifically, it probably means you have a 4.1 or newer server
-and 4.0 or older client. You can either upgrade the client side, or
-try some of the workarounds in `Password Hashing as of MySQL 4.1
-<http://dev.mysql.com/doc/refman/5.0/en/password-hashing.html>`_.
-
-
-Other Resources
----------------
-
-* Help forum. Please search before posting.
-
-* `Google <http://www.google.com/>`_
-
-* READ README!
-
-* Read the User's Guide
-
-* Read `PEP-249`_
-
-.. _`PEP-249`: http://www.python.org/peps/pep-0249.html
-
+====================================
+ MySQLdb Frequently Asked Questions
+====================================
+
+.. contents::
+..
+
+
+Build Errors
+------------
+
+ ld: fatal: library -lmysqlclient_r: not found
+
+mysqlclient_r is the thread-safe library. It's not available on
+all platforms, or all installations, apparently. You'll need to
+reconfigure site.cfg (in MySQLdb-1.2.1 and newer) to have
+threadsafe = False.
+
+ mysql.h: No such file or directory
+
+This almost always mean you don't have development packages
+installed. On some systems, C headers for various things (like MySQL)
+are distributed as a seperate package. You'll need to figure out
+what that is and install it, but often the name ends with -devel.
+
+Another possibility: Some older versions of mysql_config behave oddly
+and may throw quotes around some of the path names, which confused
+MySQLdb-1.2.0. 1.2.1 works around these problems. If you see things
+like -I'/usr/local/include/mysql' in your compile command, that's
+probably the issue, but it shouldn't happen any more.
+
+
+ImportError
+-----------
+
+ ImportError: No module named _mysql
+
+If you see this, it's likely you did some wrong when installing
+MySQLdb; re-read (or read) README. _mysql is the low-level C module
+that interfaces with the MySQL client library.
+
+Various versions of MySQLdb in the past have had build issues on
+"weird" platforms; "weird" in this case means "not Linux", though
+generally there aren't problems on Unix/POSIX platforms, including
+BSDs and Mac OS X. Windows has been more problematic, in part because
+there is no `mysql_config` available in the Windows installation of
+MySQL. 1.2.1 solves most, if not all, of these problems, but you will
+still have to edit a configuration file so that the setup knows where
+to find MySQL and what libraries to include.
+
+
+ ImportError: libmysqlclient_r.so.14: cannot open shared object file: No such file or directory
+
+The number after .so may vary, but this means you have a version of
+MySQLdb compiled against one version of MySQL, and are now trying to
+run it against a different version. The shared library version tends
+to change between major releases.
+
+Solution: Rebuilt MySQLdb, or get the matching version of MySQL.
+
+Another thing that can cause this: The MySQL libraries may not be on
+your system path.
+
+Solutions:
+
+* set the LD_LIBRARY_PATH environment variable so that it includes
+ the path to the MySQL libraries.
+
+* set static=True in site.cfg for static linking
+
+* reconfigure your system so that the MySQL libraries are on the
+ default loader path. In Linux, you edit /etc/ld.so.conf and run
+ ldconfig. For Solaris, see `Linker and Libraries Guide
+ <http://docs.sun.com/app/docs/doc/817-3677/6mj8mbtbe?a=view>`_.
+
+
+ ImportError: ld.so.1: python: fatal: libmtmalloc.so.1: DF_1_NOOPEN tagged object may not be dlopen()'ed
+
+This is a weird one from Solaris. What does it mean? I have no idea.
+However, things like this can happen if there is some sort of a compiler
+or environment mismatch between Python and MySQL. For example, on some
+commercial systems, you might have some code compiled with their own
+compiler, and other things compiled with GCC. They don't always mesh
+together. One way to encounter this is by getting binary packages from
+different vendors.
+
+Solution: Rebuild Python or MySQL (or maybe both) from source.
+
+ ImportError: dlopen(./_mysql.so, 2): Symbol not found: _sprintf$LDBLStub
+ Referenced from: ./_mysql.so
+ Expected in: dynamic lookup
+
+This is one from Mac OS X. It seems to have been a compiler mismatch,
+but this time between two different versions of GCC. It seems nearly
+every major release of GCC changes the ABI in some why, so linking
+code compiled with GCC-3.3 and GCC-4.0, for example, can be
+problematic.
+
+
+My data disappeared! (or won't go away!)
+----------------------------------------
+
+Starting with 1.2.0, MySQLdb disables autocommit by default, as
+required by the DB-API standard (`PEP-249`_). If you are using InnoDB
+tables or some other type of transactional table type, you'll need
+to do connection.commit() before closing the connection, or else
+none of your changes will be written to the database.
+
+Conversely, you can also use connection.rollback() to throw away
+any changes you've made since the last commit.
+
+Important note: Some SQL statements -- specifically DDL statements
+like CREATE TABLE -- are non-transactional, so they can't be
+rolled back, and they cause pending transactions to commit.
+
+
+Other Errors
+------------
+
+ OperationalError: (1251, 'Client does not support authentication protocol requested by server; consider upgrading MySQL client')
+
+This means your server and client libraries are not the same version.
+More specifically, it probably means you have a 4.1 or newer server
+and 4.0 or older client. You can either upgrade the client side, or
+try some of the workarounds in `Password Hashing as of MySQL 4.1
+<http://dev.mysql.com/doc/refman/5.0/en/password-hashing.html>`_.
+
+
+Other Resources
+---------------
+
+* Help forum. Please search before posting.
+
+* `Google <http://www.google.com/>`_
+
+* READ README!
+
+* Read the User's Guide
+
+* Read `PEP-249`_
+
+.. _`PEP-249`: http://www.python.org/peps/pep-0249.html
+
diff --git a/MySQLdb/doc/MySQLdb.txt b/MySQLdb/doc/MySQLdb.txt
index fbc86e5..572bcb8 100644
--- a/MySQLdb/doc/MySQLdb.txt
+++ b/MySQLdb/doc/MySQLdb.txt
@@ -1,718 +1,718 @@
-====================
-MySQLdb User's Guide
-====================
-
-.. contents::
-..
-
-Introduction
-------------
-
-MySQLdb is an thread-compatible interface to the popular MySQL
-database server that provides the Python database API.
-
-Installation
-------------
-
-The ``README`` file has complete installation instructions.
-
-
-_mysql
-------
-
-If you want to write applications which are portable across databases,
-use MySQLdb_, and avoid using this module directly. ``_mysql``
-provides an interface which mostly implements the MySQL C API. For
-more information, see the `MySQL documentation`_. The documentation
-for this module is intentionally weak because you probably should use
-the higher-level MySQLdb module. If you really need it, use the
-standard MySQL docs and transliterate as necessary.
-
-.. _`MySQL documentation`: http://dev.mysql.com/doc/
-
-
-MySQL C API translation
-.......................
-
-The MySQL C API has been wrapped in an object-oriented way. The only
-MySQL data structures which are implemented are the ``MYSQL``
-(database connection handle) and ``MYSQL_RES`` (result handle)
-types. In general, any function which takes ``MYSQL *mysql`` as an
-argument is now a method of the connection object, and any function
-which takes ``MYSQL_RES *result`` as an argument is a method of the
-result object. Functions requiring none of the MySQL data structures
-are implemented as functions in the module. Functions requiring one of
-the other MySQL data structures are generally not implemented.
-Deprecated functions are not implemented. In all cases, the ``mysql_``
-prefix is dropped from the name. Most of the ``conn`` methods listed
-are also available as MySQLdb Connection object methods. Their use is
-non-portable.
-
-MySQL C API function mapping
-............................
-
-=================================== ==================================
- C API ``_mysql``
-=================================== ==================================
- ``mysql_affected_rows()`` ``conn.affected_rows()``
- ``mysql_autocommit()`` ``conn.autocommit()``
- ``mysql_character_set_name()`` ``conn.character_set_name()``
- ``mysql_close()`` ``conn.close()``
- ``mysql_commit()`` ``conn.commit()``
- ``mysql_connect()`` ``_mysql.connect()``
- ``mysql_data_seek()`` ``result.data_seek()``
- ``mysql_debug()`` ``_mysql.debug()``
- ``mysql_dump_debug_info`` ``conn.dump_debug_info()``
- ``mysql_escape_string()`` ``_mysql.escape_string()``
- ``mysql_fetch_row()`` ``result.fetch_row()``
- ``mysql_get_character_set_info()`` ``conn.get_character_set_info()``
- ``mysql_get_client_info()`` ``_mysql.get_client_info()``
- ``mysql_get_host_info()`` ``conn.get_host_info()``
- ``mysql_get_proto_info()`` ``conn.get_proto_info()``
- ``mysql_get_server_info()`` ``conn.get_server_info()``
- ``mysql_info()`` ``conn.info()``
- ``mysql_insert_id()`` ``conn.insert_id()``
- ``mysql_num_fields()`` ``result.num_fields()``
- ``mysql_num_rows()`` ``result.num_rows()``
- ``mysql_options()`` various options to ``_mysql.connect()``
- ``mysql_ping()`` ``conn.ping()``
- ``mysql_query()`` ``conn.query()``
- ``mysql_real_connect()`` ``_mysql.connect()``
- ``mysql_real_query()`` ``conn.query()``
- ``mysql_real_escape_string()`` ``conn.escape_string()``
- ``mysql_rollback()`` ``conn.rollback()``
- ``mysql_row_seek()`` ``result.row_seek()``
- ``mysql_row_tell()`` ``result.row_tell()``
- ``mysql_select_db()`` ``conn.select_db()``
- ``mysql_set_character_set()`` ``conn.set_character_set()``
- ``mysql_ssl_set()`` ``ssl`` option to ``_mysql.connect()``
- ``mysql_stat()`` ``conn.stat()``
- ``mysql_store_result()`` ``conn.store_result()``
- ``mysql_thread_id()`` ``conn.thread_id()``
- ``mysql_thread_safe_client()`` ``conn.thread_safe_client()``
- ``mysql_use_result()`` ``conn.use_result()``
- ``mysql_warning_count()`` ``conn.warning_count()``
- ``CLIENT_*`` ``MySQLdb.constants.CLIENT.*``
- ``CR_*`` ``MySQLdb.constants.CR.*``
- ``ER_*`` ``MySQLdb.constants.ER.*``
- ``FIELD_TYPE_*`` ``MySQLdb.constants.FIELD_TYPE.*``
- ``FLAG_*`` ``MySQLdb.constants.FLAG.*``
-=================================== ==================================
-
-
-Some _mysql examples
-....................
-
-Okay, so you want to use ``_mysql`` anyway. Here are some examples.
-
-The simplest possible database connection is::
-
- import _mysql
- db=_mysql.connect()
-
-This creates a connection to the MySQL server running on the local
-machine using the standard UNIX socket (or named pipe on Windows),
-your login name (from the USER environment variable), no password, and
-does not ``USE`` a database. Chances are you need to supply more
-information.::
-
- db=_mysql.connect("localhost","joebob","moonpie","thangs")
-
-This creates a connection to the MySQL server running on the local
-machine via a UNIX socket (or named pipe), the user name "joebob", the
-password "moonpie", and selects the initial database "thangs".
-
-We haven't even begun to touch upon all the parameters ``connect()``
-can take. For this reason, I prefer to use keyword parameters::
-
- db=_mysql.connect(host="localhost",user="joebob",
- passwd="moonpie",db="thangs")
-
-This does exactly what the last example did, but is arguably easier to
-read. But since the default host is "localhost", and if your login
-name really was "joebob", you could shorten it to this::
-
- db=_mysql.connect(passwd="moonpie",db="thangs")
-
-UNIX sockets and named pipes don't work over a network, so if you
-specify a host other than localhost, TCP will be used, and you can
-specify an odd port if you need to (the default port is 3306)::
-
- db=_mysql.connect(host="outhouse",port=3307,passwd="moonpie",db="thangs")
-
-If you really had to, you could connect to the local host with TCP by
-specifying the full host name, or 127.0.0.1.
-
-Generally speaking, putting passwords in your code is not such a good
-idea::
-
- db=_mysql.connect(host="outhouse",db="thangs",read_default_file="~/.my.cnf")
-
-This does what the previous example does, but gets the username and
-password and other parameters from ~/.my.cnf (UNIX-like systems). Read
-about `option files`_ for more details.
-
-.. _`option files`: http://dev.mysql.com/doc/mysql/en/Option_files.html
-
-So now you have an open connection as ``db`` and want to do a
-query. Well, there are no cursors in MySQL, and no parameter
-substitution, so you have to pass a complete query string to
-``db.query()``::
-
- db.query("""SELECT spam, eggs, sausage FROM breakfast
- WHERE price < 5""")
-
-There's no return value from this, but exceptions can be raised. The
-exceptions are defined in a separate module, ``_mysql_exceptions``,
-but ``_mysql`` exports them. Read DB API specification PEP-249_ to
-find out what they are, or you can use the catch-all ``MySQLError``.
-
-.. _PEP-249: http://www.python.org/peps/pep-0249.html
-
-At this point your query has been executed and you need to get the
-results. You have two options::
-
- r=db.store_result()
- # ...or...
- r=db.use_result()
-
-Both methods return a result object. What's the difference?
-``store_result()`` returns the entire result set to the client
-immediately. If your result set is really large, this could be a
-problem. One way around this is to add a ``LIMIT`` clause to your
-query, to limit the number of rows returned. The other is to use
-``use_result()``, which keeps the result set in the server and sends
-it row-by-row when you fetch. This does, however, tie up server
-resources, and it ties up the connection: You cannot do any more
-queries until you have fetched **all** the rows. Generally I
-recommend using ``store_result()`` unless your result set is really
-huge and you can't use ``LIMIT`` for some reason.
-
-Now, for actually getting real results::
-
- >>> r.fetch_row()
- (('3','2','0'),)
-
-This might look a little odd. The first thing you should know is,
-``fetch_row()`` takes some additional parameters. The first one is,
-how many rows (``maxrows``) should be returned. By default, it returns
-one row. It may return fewer rows than you asked for, but never
-more. If you set ``maxrows=0``, it returns all rows of the result
-set. If you ever get an empty tuple back, you ran out of rows.
-
-The second parameter (``how``) tells it how the row should be
-represented. By default, it is zero which means, return as a tuple.
-``how=1`` means, return it as a dictionary, where the keys are the
-column names, or ``table.column`` if there are two columns with the
-same name (say, from a join). ``how=2`` means the same as ``how=1``
-except that the keys are *always* ``table.column``; this is for
-compatibility with the old ``Mysqldb`` module.
-
-OK, so why did we get a 1-tuple with a tuple inside? Because we
-implicitly asked for one row, since we didn't specify ``maxrows``.
-
-The other oddity is: Assuming these are numeric columns, why are they
-returned as strings? Because MySQL returns all data as strings and
-expects you to convert it yourself. This would be a real pain in the
-ass, but in fact, ``_mysql`` can do this for you. (And ``MySQLdb``
-does do this for you.) To have automatic type conversion done, you
-need to create a type converter dictionary, and pass this to
-``connect()`` as the ``conv`` keyword parameter.
-
-The keys of ``conv`` should be MySQL column types, which in the
-C API are ``FIELD_TYPE_*``. You can get these values like this::
-
- from MySQLdb.constants import FIELD_TYPE
-
-By default, any column type that can't be found in ``conv`` is
-returned as a string, which works for a lot of stuff. For our
-purposes, we probably want this::
-
- my_conv = { FIELD_TYPE.LONG: int }
-
-This means, if it's a ``FIELD_TYPE_LONG``, call the builtin ``int()``
-function on it. Note that ``FIELD_TYPE_LONG`` is an ``INTEGER``
-column, which corresponds to a C ``long``, which is also the type used
-for a normal Python integer. But beware: If it's really an ``UNSIGNED
-INTEGER`` column, this could cause overflows. For this reason,
-``MySQLdb`` actually uses ``long()`` to do the conversion. But we'll
-ignore this potential problem for now.
-
-Then if you use ``db=_mysql.connect(conv=my_conv...)``, the
-results will come back ``((3, 2, 0),)``, which is what you would
-expect.
-
-MySQLdb
--------
-
-MySQLdb is a thin Python wrapper around ``_mysql`` which makes it
-compatible with the Python DB API interface (version 2). In reality,
-a fair amount of the code which implements the API is in ``_mysql``
-for the sake of efficiency.
-
-The DB API specification PEP-249_ should be your primary guide for
-using this module. Only deviations from the spec and other
-database-dependent things will be documented here.
-
-Functions and attributes
-........................
-
-Only a few top-level functions and attributes are defined within
-MySQLdb.
-
-connect(parameters...)
- Constructor for creating a connection to the
- database. Returns a Connection Object. Parameters are the
- same as for the MySQL C API. In addition, there are a few
- additional keywords that correspond to what you would pass
- ``mysql_options()`` before connecting. Note that some
- parameters must be specified as keyword arguments! The
- default value for each parameter is NULL or zero, as
- appropriate. Consult the MySQL documentation for more
- details. The important parameters are:
-
- host
- name of host to connect to. Default: use the local host
- via a UNIX socket (where applicable)
-
- user
- user to authenticate as. Default: current effective user.
-
- passwd
- password to authenticate with. Default: no password.
-
- db
- database to use. Default: no default database.
-
- port
- TCP port of MySQL server. Default: standard port (3306).
-
- unix_socket
- location of UNIX socket. Default: use default location or
- TCP for remote hosts.
-
- conv
- type conversion dictionary. Default: a copy of
- ``MySQLdb.converters.conversions``
-
- compress
- Enable protocol compression. Default: no compression.
-
- connect_timeout
- Abort if connect is not completed within
- given number of seconds. Default: no timeout (?)
-
- named_pipe
- Use a named pipe (Windows). Default: don't.
-
- init_command
- Initial command to issue to server upon
- connection. Default: Nothing.
-
- read_default_file
- MySQL configuration file to read; see
- the MySQL documentation for ``mysql_options()``.
-
- read_default_group
- Default group to read; see the MySQL
- documentation for ``mysql_options()``.
-
- cursorclass
- cursor class that ``cursor()`` uses, unless
- overridden. Default: ``MySQLdb.cursors.Cursor``. *This
- must be a keyword parameter.*
-
- use_unicode
- If True, CHAR and VARCHAR and TEXT columns are returned as
- Unicode strings, using the configured character set. It is
- best to set the default encoding in the server
- configuration, or client configuration (read with
- read_default_file). If you change the character set after
- connecting (MySQL-4.1 and later), you'll need to put the
- correct character set name in connection.charset.
-
- If False, text-like columns are returned as normal strings,
- but you can always write Unicode strings.
-
- *This must be a keyword parameter.*
-
- charset
- If present, the connection character set will be changed
- to this character set, if they are not equal. Support for
- changing the character set requires MySQL-4.1 and later
- server; if the server is too old, UnsupportedError will be
- raised. This option implies use_unicode=True, but you can
- override this with use_unicode=False, though you probably
- shouldn't.
-
- If not present, the default character set is used.
-
- *This must be a keyword parameter.*
-
- sql_mode
- If present, the session SQL mode will be set to the given
- string. For more information on sql_mode, see the MySQL
- documentation. Only available for 4.1 and newer servers.
-
- If not present, the session SQL mode will be unchanged.
-
- *This must be a keyword parameter.*
-
- ssl
- This parameter takes a dictionary or mapping, where the
- keys are parameter names used by the mysql_ssl_set_ MySQL
- C API call. If this is set, it initiates an SSL connection
- to the server; if there is no SSL support in the client,
- an exception is raised. *This must be a keyword
- parameter.*
-
-.. _mysql_ssl_set: http://dev.mysql.com/doc/mysql/en/mysql_ssl_set.html
-
-
-apilevel
- String constant stating the supported DB API level. '2.0'
-
-threadsafety
- Integer constant stating the level of thread safety the
- interface supports. This is set to 1, which means: Threads may
- share the module.
-
- The MySQL protocol can not handle multiple threads using the
- same connection at once. Some earlier versions of MySQLdb
- utilized locking to achieve a threadsafety of 2. While this is
- not terribly hard to accomplish using the standard Cursor class
- (which uses ``mysql_store_result()``), it is complicated by
- SSCursor (which uses ``mysql_use_result()``; with the latter you
- must ensure all the rows have been read before another query can
- be executed. It is further complicated by the addition of
- transactions, since transactions start when a cursor execute a
- query, but end when ``COMMIT`` or ``ROLLBACK`` is executed by
- the Connection object. Two threads simply cannot share a
- connection while a transaction is in progress, in addition to
- not being able to share it during query execution. This
- excessively complicated the code to the point where it just
- isn't worth it.
-
- The general upshot of this is: Don't share connections between
- threads. It's really not worth your effort or mine, and in the
- end, will probably hurt performance, since the MySQL server runs
- a separate thread for each connection. You can certainly do
- things like cache connections in a pool, and give those
- connections to one thread at a time. If you let two threads use
- a connection simultaneously, the MySQL client library will
- probably upchuck and die. You have been warned.
-
- For threaded applications, try using a connection pool.
- This can be done using the `Pool module`_.
-
- .. _`Pool module`: http://dustman.net/andy/python/Pool
-
-charset
- The character set used by the connection. In MySQL-4.1 and newer,
- it is possible (but not recommended) to change the connection's
- character set with an SQL statement. If you do this, you'll also
- need to change this attribute. Otherwise, you'll get encoding
- errors.
-
-paramstyle
- String constant stating the type of parameter marker formatting
- expected by the interface. Set to 'format' = ANSI C printf
- format codes, e.g. '...WHERE name=%s'. If a mapping object is
- used for conn.execute(), then the interface actually uses
- 'pyformat' = Python extended format codes, e.g. '...WHERE
- name=%(name)s'. However, the API does not presently allow the
- specification of more than one style in paramstyle.
-
- Note that any literal percent signs in the query string passed
- to execute() must be escaped, i.e. %%.
-
- Parameter placeholders can **only** be used to insert column
- values. They can **not** be used for other parts of SQL, such as
- table names, statements, etc.
-
-conv
- A dictionary or mapping which controls how types are converted
- from MySQL to Python and vice versa.
-
- If the key is a MySQL type (from ``FIELD_TYPE.*``), then the value
- can be either:
-
- * a callable object which takes a string argument (the MySQL
- value),' returning a Python value
-
- * a sequence of 2-tuples, where the first value is a combination
- of flags from ``MySQLdb.constants.FLAG``, and the second value
- is a function as above. The sequence is tested until the flags
- on the field match those of the first value. If both values
- are None, then the default conversion is done. Presently this
- is only used to distinquish TEXT and BLOB columns.
-
- If the key is a Python type or class, then the value is a
- callable Python object (usually a function) taking two arguments
- (value to convert, and the conversion dictionary) which converts
- values of this type to a SQL literal string value.
-
- This is initialized with reasonable defaults for most
- types. When creating a Connection object, you can pass your own
- type converter dictionary as a keyword parameter. Otherwise, it
- uses a copy of ``MySQLdb.converters.conversions``. Several
- non-standard types are returned as strings, which is how MySQL
- returns all columns. For more details, see the built-in module
- documentation.
-
-
-Connection Objects
-..................
-
-Connection objects are returned by the ``connect()`` function.
-
-commit()
- If the database and the tables support transactions, this
- commits the current transaction; otherwise this method
- successfully does nothing.
-
-rollback()
- If the database and tables support transactions, this rolls back
- (cancels) the current transaction; otherwise a
- ``NotSupportedError`` is raised.
-
-cursor([cursorclass])
- MySQL does not support cursors; however, cursors are easily
- emulated. You can supply an alternative cursor class as an
- optional parameter. If this is not present, it defaults to the
- value given when creating the connection object, or the standard
- ``Cursor`` class. Also see the additional supplied cursor
- classes in the usage section.
-
-There are many more methods defined on the connection object which
-are MySQL-specific. For more information on them, consult the internal
-documentation using ``pydoc``.
-
-
-Cursor Objects
-..............
-
-callproc(procname, args)
- Calls stored procedure procname with the sequence of arguments
- in args. Returns the original arguments. Stored procedure
- support only works with MySQL-5.0 and newer.
-
- **Compatibility note:** PEP-249_ specifies that if there are
- OUT or INOUT parameters, the modified values are to be
- returned. This is not consistently possible with MySQL. Stored
- procedure arguments must be passed as server variables, and
- can only be returned with a SELECT statement. Since a stored
- procedure may return zero or more result sets, it is impossible
- for MySQLdb to determine if there are result sets to fetch
- before the modified parmeters are accessible.
-
- The parameters are stored in the server as @_*procname*_*n*,
- where *n* is the position of the parameter. I.e., if you
- cursor.callproc('foo', (a, b, c)), the parameters will be
- accessible by a SELECT statement as @_foo_0, @_foo_1, and
- @_foo_2.
-
- **Compatibility note:** It appears that the mere act of
- executing the CALL statement produces an empty result set, which
- appears after any result sets which might be generated by the
- stored procedure. Thus, you will always need to use nextset() to
- advance result sets.
-
-close()
- Closes the cursor. Future operations raise ``ProgrammingError``.
- If you are using server-side cursors, it is very important to
- close the cursor when you are done with it and before creating a
- new one.
-
-info()
- Returns some information about the last query. Normally
- you don't need to check this. If there are any MySQL
- warnings, it will cause a Warning to be issued through
- the Python warning module. By default, Warning causes a
- message to appear on the console. However, it is possible
- to filter these out or cause Warning to be raised as exception.
- See the MySQL docs for ``mysql_info()``, and the Python warning
- module. (Non-standard)
-
-setinputsizes()
- Does nothing, successfully.
-
-setoutputsizes()
- Does nothing, successfully.
-
-nextset()
- Advances the cursor to the next result set, discarding the remaining
- rows in the current result set. If there are no additional result
- sets, it returns None; otherwise it returns a true value.
-
- Note that MySQL doesn't support multiple result sets until 4.1.
-
-
-Some examples
-.............
-
-The ``connect()`` method works nearly the same as with `_mysql`_::
-
- import MySQLdb
- db=MySQLdb.connect(passwd="moonpie",db="thangs")
-
-To perform a query, you first need a cursor, and then you can execute
-queries on it::
-
- c=db.cursor()
- max_price=5
- c.execute("""SELECT spam, eggs, sausage FROM breakfast
- WHERE price < %s""", (max_price,))
-
-In this example, ``max_price=5`` Why, then, use ``%s`` in the
-string? Because MySQLdb will convert it to a SQL literal value, which
-is the string '5'. When it's finished, the query will actually say,
-"...WHERE price < 5".
-
-Why the tuple? Because the DB API requires you to pass in any
-parameters as a sequence. Due to the design of the parser, (max_price)
-is interpreted as using algebraic grouping and simply as max_price and
-not a tuple. Adding a comma, i.e. (max_price,) forces it to make a
-tuple.
-
-And now, the results::
-
- >>> c.fetchone()
- (3L, 2L, 0L)
-
-Quite unlike the ``_mysql`` example, this returns a single tuple,
-which is the row, and the values are properly converted by default...
-except... What's with the L's?
-
-As mentioned earlier, while MySQL's INTEGER column translates
-perfectly into a Python integer, UNSIGNED INTEGER could overflow, so
-these values are converted to Python long integers instead.
-
-If you wanted more rows, you could use ``c.fetchmany(n)`` or
-``c.fetchall()``. These do exactly what you think they do. On
-``c.fetchmany(n)``, the ``n`` is optional and defaults to
-``c.arraysize``, which is normally 1. Both of these methods return a
-sequence of rows, or an empty sequence if there are no more rows. If
-you use a weird cursor class, the rows themselves might not be tuples.
-
-Note that in contrast to the above, ``c.fetchone()`` returns ``None``
-when there are no more rows to fetch.
-
-The only other method you are very likely to use is when you have to
-do a multi-row insert::
-
- c.executemany(
- """INSERT INTO breakfast (name, spam, eggs, sausage, price)
- VALUES (%s, %s, %s, %s, %s)""",
- [
- ("Spam and Sausage Lover's Plate", 5, 1, 8, 7.95 ),
- ("Not So Much Spam Plate", 3, 2, 0, 3.95 ),
- ("Don't Wany ANY SPAM! Plate", 0, 4, 3, 5.95 )
- ] )
-
-Here we are inserting three rows of five values. Notice that there is
-a mix of types (strings, ints, floats) though we still only use
-``%s``. And also note that we only included format strings for one
-row. MySQLdb picks those out and duplicates them for each row.
-
-Using and extending
--------------------
-
-In general, it is probably wise to not directly interact with the DB
-API except for small applicatons. Databases, even SQL databases, vary
-widely in capabilities and may have non-standard features. The DB API
-does a good job of providing a reasonably portable interface but some
-methods are non-portable. Specifically, the parameters accepted by
-``connect()`` are completely implementation-dependent.
-
-If you believe your application may need to run on several different
-databases, the author recommends the following approach, based on
-personal experience: Write a simplified API for your application which
-implements the specific queries and operations your application needs
-to perform. Implement this API as a base class which should be have
-few database dependencies, and then derive a subclass from this which
-implements the necessary dependencies. In this way, porting your
-application to a new database should be a relatively simple matter of
-creating a new subclass, assuming the new database is reasonably
-standard.
-
-Because MySQLdb's Connection and Cursor objects are written in Python,
-you can easily derive your own subclasses. There are several Cursor
-classes in MySQLdb.cursors:
-
-BaseCursor
- The base class for Cursor objects. This does not raise Warnings.
-
-CursorStoreResultMixIn
- Causes the Cursor to use the ``mysql_store_result()`` function to
- get the query result. The entire result set is stored on the
- client side.
-
-CursorUseResultMixIn
- Causes the cursor to use the ``mysql_use_result()`` function to
- get the query result. The result set is stored on the server side
- and is transferred row by row using fetch operations.
-
-CursorTupleRowsMixIn
- Causes the cursor to return rows as a tuple of the column values.
-
-CursorDictRowsMixIn
-
- Causes the cursor to return rows as a dictionary, where the keys
- are column names and the values are column values. Note that if
- the column names are not unique, i.e., you are selecting from two
- tables that share column names, some of them will be rewritten as
- ``table.column``. This can be avoided by using the SQL ``AS``
- keyword. (This is yet-another reason not to use ``*`` in SQL
- queries, particularly where ``JOIN`` is involved.)
-
-Cursor
- The default cursor class. This class is composed of
- ``CursorWarningMixIn``, ``CursorStoreResultMixIn``,
- ``CursorTupleRowsMixIn,`` and ``BaseCursor``, i.e. it raises
- ``Warning``, uses ``mysql_store_result()``, and returns rows as
- tuples.
-
-DictCursor
- Like ``Cursor`` except it returns rows as dictionaries.
-
-SSCursor
- A "server-side" cursor. Like ``Cursor`` but uses
- ``CursorUseResultMixIn``. Use only if you are dealing with
- potentially large result sets.
-
-SSDictCursor
- Like ``SSCursor`` except it returns rows as dictionaries.
-
-
-Embedded Server
----------------
-
-Instead of connecting to a stand-alone server over the network,
-the embedded server support lets you run a full server right in
-your Python code or application server.
-
-If you have built MySQLdb with embedded server support, there
-are two additional functions you will need to make use of:
-
- server_init(args, groups)
- Initialize embedded server. If this client is not linked against
- the embedded server library, this function does nothing.
-
- args
- sequence of command-line arguments
- groups
- sequence of groups to use in defaults files
-
- server_end()
- Shut down embedded server. If not using an embedded server, this
- does nothing.
-
-See the MySQL documentation for more information on the embedded
-server.
-
-
-
-:Title: MySQLdb: a Python interface for MySQL
-:Author: Andy Dustman
-:Version: $Revision$
+====================
+MySQLdb User's Guide
+====================
+
+.. contents::
+..
+
+Introduction
+------------
+
+MySQLdb is an thread-compatible interface to the popular MySQL
+database server that provides the Python database API.
+
+Installation
+------------
+
+The ``README`` file has complete installation instructions.
+
+
+_mysql
+------
+
+If you want to write applications which are portable across databases,
+use MySQLdb_, and avoid using this module directly. ``_mysql``
+provides an interface which mostly implements the MySQL C API. For
+more information, see the `MySQL documentation`_. The documentation
+for this module is intentionally weak because you probably should use
+the higher-level MySQLdb module. If you really need it, use the
+standard MySQL docs and transliterate as necessary.
+
+.. _`MySQL documentation`: http://dev.mysql.com/doc/
+
+
+MySQL C API translation
+.......................
+
+The MySQL C API has been wrapped in an object-oriented way. The only
+MySQL data structures which are implemented are the ``MYSQL``
+(database connection handle) and ``MYSQL_RES`` (result handle)
+types. In general, any function which takes ``MYSQL *mysql`` as an
+argument is now a method of the connection object, and any function
+which takes ``MYSQL_RES *result`` as an argument is a method of the
+result object. Functions requiring none of the MySQL data structures
+are implemented as functions in the module. Functions requiring one of
+the other MySQL data structures are generally not implemented.
+Deprecated functions are not implemented. In all cases, the ``mysql_``
+prefix is dropped from the name. Most of the ``conn`` methods listed
+are also available as MySQLdb Connection object methods. Their use is
+non-portable.
+
+MySQL C API function mapping
+............................
+
+=================================== ==================================
+ C API ``_mysql``
+=================================== ==================================
+ ``mysql_affected_rows()`` ``conn.affected_rows()``
+ ``mysql_autocommit()`` ``conn.autocommit()``
+ ``mysql_character_set_name()`` ``conn.character_set_name()``
+ ``mysql_close()`` ``conn.close()``
+ ``mysql_commit()`` ``conn.commit()``
+ ``mysql_connect()`` ``_mysql.connect()``
+ ``mysql_data_seek()`` ``result.data_seek()``
+ ``mysql_debug()`` ``_mysql.debug()``
+ ``mysql_dump_debug_info`` ``conn.dump_debug_info()``
+ ``mysql_escape_string()`` ``_mysql.escape_string()``
+ ``mysql_fetch_row()`` ``result.fetch_row()``
+ ``mysql_get_character_set_info()`` ``conn.get_character_set_info()``
+ ``mysql_get_client_info()`` ``_mysql.get_client_info()``
+ ``mysql_get_host_info()`` ``conn.get_host_info()``
+ ``mysql_get_proto_info()`` ``conn.get_proto_info()``
+ ``mysql_get_server_info()`` ``conn.get_server_info()``
+ ``mysql_info()`` ``conn.info()``
+ ``mysql_insert_id()`` ``conn.insert_id()``
+ ``mysql_num_fields()`` ``result.num_fields()``
+ ``mysql_num_rows()`` ``result.num_rows()``
+ ``mysql_options()`` various options to ``_mysql.connect()``
+ ``mysql_ping()`` ``conn.ping()``
+ ``mysql_query()`` ``conn.query()``
+ ``mysql_real_connect()`` ``_mysql.connect()``
+ ``mysql_real_query()`` ``conn.query()``
+ ``mysql_real_escape_string()`` ``conn.escape_string()``
+ ``mysql_rollback()`` ``conn.rollback()``
+ ``mysql_row_seek()`` ``result.row_seek()``
+ ``mysql_row_tell()`` ``result.row_tell()``
+ ``mysql_select_db()`` ``conn.select_db()``
+ ``mysql_set_character_set()`` ``conn.set_character_set()``
+ ``mysql_ssl_set()`` ``ssl`` option to ``_mysql.connect()``
+ ``mysql_stat()`` ``conn.stat()``
+ ``mysql_store_result()`` ``conn.store_result()``
+ ``mysql_thread_id()`` ``conn.thread_id()``
+ ``mysql_thread_safe_client()`` ``conn.thread_safe_client()``
+ ``mysql_use_result()`` ``conn.use_result()``
+ ``mysql_warning_count()`` ``conn.warning_count()``
+ ``CLIENT_*`` ``MySQLdb.constants.CLIENT.*``
+ ``CR_*`` ``MySQLdb.constants.CR.*``
+ ``ER_*`` ``MySQLdb.constants.ER.*``
+ ``FIELD_TYPE_*`` ``MySQLdb.constants.FIELD_TYPE.*``
+ ``FLAG_*`` ``MySQLdb.constants.FLAG.*``
+=================================== ==================================
+
+
+Some _mysql examples
+....................
+
+Okay, so you want to use ``_mysql`` anyway. Here are some examples.
+
+The simplest possible database connection is::
+
+ import _mysql
+ db=_mysql.connect()
+
+This creates a connection to the MySQL server running on the local
+machine using the standard UNIX socket (or named pipe on Windows),
+your login name (from the USER environment variable), no password, and
+does not ``USE`` a database. Chances are you need to supply more
+information.::
+
+ db=_mysql.connect("localhost","joebob","moonpie","thangs")
+
+This creates a connection to the MySQL server running on the local
+machine via a UNIX socket (or named pipe), the user name "joebob", the
+password "moonpie", and selects the initial database "thangs".
+
+We haven't even begun to touch upon all the parameters ``connect()``
+can take. For this reason, I prefer to use keyword parameters::
+
+ db=_mysql.connect(host="localhost",user="joebob",
+ passwd="moonpie",db="thangs")
+
+This does exactly what the last example did, but is arguably easier to
+read. But since the default host is "localhost", and if your login
+name really was "joebob", you could shorten it to this::
+
+ db=_mysql.connect(passwd="moonpie",db="thangs")
+
+UNIX sockets and named pipes don't work over a network, so if you
+specify a host other than localhost, TCP will be used, and you can
+specify an odd port if you need to (the default port is 3306)::
+
+ db=_mysql.connect(host="outhouse",port=3307,passwd="moonpie",db="thangs")
+
+If you really had to, you could connect to the local host with TCP by
+specifying the full host name, or 127.0.0.1.
+
+Generally speaking, putting passwords in your code is not such a good
+idea::
+
+ db=_mysql.connect(host="outhouse",db="thangs",read_default_file="~/.my.cnf")
+
+This does what the previous example does, but gets the username and
+password and other parameters from ~/.my.cnf (UNIX-like systems). Read
+about `option files`_ for more details.
+
+.. _`option files`: http://dev.mysql.com/doc/mysql/en/Option_files.html
+
+So now you have an open connection as ``db`` and want to do a
+query. Well, there are no cursors in MySQL, and no parameter
+substitution, so you have to pass a complete query string to
+``db.query()``::
+
+ db.query("""SELECT spam, eggs, sausage FROM breakfast
+ WHERE price < 5""")
+
+There's no return value from this, but exceptions can be raised. The
+exceptions are defined in a separate module, ``_mysql_exceptions``,
+but ``_mysql`` exports them. Read DB API specification PEP-249_ to
+find out what they are, or you can use the catch-all ``MySQLError``.
+
+.. _PEP-249: http://www.python.org/peps/pep-0249.html
+
+At this point your query has been executed and you need to get the
+results. You have two options::
+
+ r=db.store_result()
+ # ...or...
+ r=db.use_result()
+
+Both methods return a result object. What's the difference?
+``store_result()`` returns the entire result set to the client
+immediately. If your result set is really large, this could be a
+problem. One way around this is to add a ``LIMIT`` clause to your
+query, to limit the number of rows returned. The other is to use
+``use_result()``, which keeps the result set in the server and sends
+it row-by-row when you fetch. This does, however, tie up server
+resources, and it ties up the connection: You cannot do any more
+queries until you have fetched **all** the rows. Generally I
+recommend using ``store_result()`` unless your result set is really
+huge and you can't use ``LIMIT`` for some reason.
+
+Now, for actually getting real results::
+
+ >>> r.fetch_row()
+ (('3','2','0'),)
+
+This might look a little odd. The first thing you should know is,
+``fetch_row()`` takes some additional parameters. The first one is,
+how many rows (``maxrows``) should be returned. By default, it returns
+one row. It may return fewer rows than you asked for, but never
+more. If you set ``maxrows=0``, it returns all rows of the result
+set. If you ever get an empty tuple back, you ran out of rows.
+
+The second parameter (``how``) tells it how the row should be
+represented. By default, it is zero which means, return as a tuple.
+``how=1`` means, return it as a dictionary, where the keys are the
+column names, or ``table.column`` if there are two columns with the
+same name (say, from a join). ``how=2`` means the same as ``how=1``
+except that the keys are *always* ``table.column``; this is for
+compatibility with the old ``Mysqldb`` module.
+
+OK, so why did we get a 1-tuple with a tuple inside? Because we
+implicitly asked for one row, since we didn't specify ``maxrows``.
+
+The other oddity is: Assuming these are numeric columns, why are they
+returned as strings? Because MySQL returns all data as strings and
+expects you to convert it yourself. This would be a real pain in the
+ass, but in fact, ``_mysql`` can do this for you. (And ``MySQLdb``
+does do this for you.) To have automatic type conversion done, you
+need to create a type converter dictionary, and pass this to
+``connect()`` as the ``conv`` keyword parameter.
+
+The keys of ``conv`` should be MySQL column types, which in the
+C API are ``FIELD_TYPE_*``. You can get these values like this::
+
+ from MySQLdb.constants import FIELD_TYPE
+
+By default, any column type that can't be found in ``conv`` is
+returned as a string, which works for a lot of stuff. For our
+purposes, we probably want this::
+
+ my_conv = { FIELD_TYPE.LONG: int }
+
+This means, if it's a ``FIELD_TYPE_LONG``, call the builtin ``int()``
+function on it. Note that ``FIELD_TYPE_LONG`` is an ``INTEGER``
+column, which corresponds to a C ``long``, which is also the type used
+for a normal Python integer. But beware: If it's really an ``UNSIGNED
+INTEGER`` column, this could cause overflows. For this reason,
+``MySQLdb`` actually uses ``long()`` to do the conversion. But we'll
+ignore this potential problem for now.
+
+Then if you use ``db=_mysql.connect(conv=my_conv...)``, the
+results will come back ``((3, 2, 0),)``, which is what you would
+expect.
+
+MySQLdb
+-------
+
+MySQLdb is a thin Python wrapper around ``_mysql`` which makes it
+compatible with the Python DB API interface (version 2). In reality,
+a fair amount of the code which implements the API is in ``_mysql``
+for the sake of efficiency.
+
+The DB API specification PEP-249_ should be your primary guide for
+using this module. Only deviations from the spec and other
+database-dependent things will be documented here.
+
+Functions and attributes
+........................
+
+Only a few top-level functions and attributes are defined within
+MySQLdb.
+
+connect(parameters...)
+ Constructor for creating a connection to the
+ database. Returns a Connection Object. Parameters are the
+ same as for the MySQL C API. In addition, there are a few
+ additional keywords that correspond to what you would pass
+ ``mysql_options()`` before connecting. Note that some
+ parameters must be specified as keyword arguments! The
+ default value for each parameter is NULL or zero, as
+ appropriate. Consult the MySQL documentation for more
+ details. The important parameters are:
+
+ host
+ name of host to connect to. Default: use the local host
+ via a UNIX socket (where applicable)
+
+ user
+ user to authenticate as. Default: current effective user.
+
+ passwd
+ password to authenticate with. Default: no password.
+
+ db
+ database to use. Default: no default database.
+
+ port
+ TCP port of MySQL server. Default: standard port (3306).
+
+ unix_socket
+ location of UNIX socket. Default: use default location or
+ TCP for remote hosts.
+
+ conv
+ type conversion dictionary. Default: a copy of
+ ``MySQLdb.converters.conversions``
+
+ compress
+ Enable protocol compression. Default: no compression.
+
+ connect_timeout
+ Abort if connect is not completed within
+ given number of seconds. Default: no timeout (?)
+
+ named_pipe
+ Use a named pipe (Windows). Default: don't.
+
+ init_command
+ Initial command to issue to server upon
+ connection. Default: Nothing.
+
+ read_default_file
+ MySQL configuration file to read; see
+ the MySQL documentation for ``mysql_options()``.
+
+ read_default_group
+ Default group to read; see the MySQL
+ documentation for ``mysql_options()``.
+
+ cursorclass
+ cursor class that ``cursor()`` uses, unless
+ overridden. Default: ``MySQLdb.cursors.Cursor``. *This
+ must be a keyword parameter.*
+
+ use_unicode
+ If True, CHAR and VARCHAR and TEXT columns are returned as
+ Unicode strings, using the configured character set. It is
+ best to set the default encoding in the server
+ configuration, or client configuration (read with
+ read_default_file). If you change the character set after
+ connecting (MySQL-4.1 and later), you'll need to put the
+ correct character set name in connection.charset.
+
+ If False, text-like columns are returned as normal strings,
+ but you can always write Unicode strings.
+
+ *This must be a keyword parameter.*
+
+ charset
+ If present, the connection character set will be changed
+ to this character set, if they are not equal. Support for
+ changing the character set requires MySQL-4.1 and later
+ server; if the server is too old, UnsupportedError will be
+ raised. This option implies use_unicode=True, but you can
+ override this with use_unicode=False, though you probably
+ shouldn't.
+
+ If not present, the default character set is used.
+
+ *This must be a keyword parameter.*
+
+ sql_mode
+ If present, the session SQL mode will be set to the given
+ string. For more information on sql_mode, see the MySQL
+ documentation. Only available for 4.1 and newer servers.
+
+ If not present, the session SQL mode will be unchanged.
+
+ *This must be a keyword parameter.*
+
+ ssl
+ This parameter takes a dictionary or mapping, where the
+ keys are parameter names used by the mysql_ssl_set_ MySQL
+ C API call. If this is set, it initiates an SSL connection
+ to the server; if there is no SSL support in the client,
+ an exception is raised. *This must be a keyword
+ parameter.*
+
+.. _mysql_ssl_set: http://dev.mysql.com/doc/mysql/en/mysql_ssl_set.html
+
+
+apilevel
+ String constant stating the supported DB API level. '2.0'
+
+threadsafety
+ Integer constant stating the level of thread safety the
+ interface supports. This is set to 1, which means: Threads may
+ share the module.
+
+ The MySQL protocol can not handle multiple threads using the
+ same connection at once. Some earlier versions of MySQLdb
+ utilized locking to achieve a threadsafety of 2. While this is
+ not terribly hard to accomplish using the standard Cursor class
+ (which uses ``mysql_store_result()``), it is complicated by
+ SSCursor (which uses ``mysql_use_result()``; with the latter you
+ must ensure all the rows have been read before another query can
+ be executed. It is further complicated by the addition of
+ transactions, since transactions start when a cursor execute a
+ query, but end when ``COMMIT`` or ``ROLLBACK`` is executed by
+ the Connection object. Two threads simply cannot share a
+ connection while a transaction is in progress, in addition to
+ not being able to share it during query execution. This
+ excessively complicated the code to the point where it just
+ isn't worth it.
+
+ The general upshot of this is: Don't share connections between
+ threads. It's really not worth your effort or mine, and in the
+ end, will probably hurt performance, since the MySQL server runs
+ a separate thread for each connection. You can certainly do
+ things like cache connections in a pool, and give those
+ connections to one thread at a time. If you let two threads use
+ a connection simultaneously, the MySQL client library will
+ probably upchuck and die. You have been warned.
+
+ For threaded applications, try using a connection pool.
+ This can be done using the `Pool module`_.
+
+ .. _`Pool module`: http://dustman.net/andy/python/Pool
+
+charset
+ The character set used by the connection. In MySQL-4.1 and newer,
+ it is possible (but not recommended) to change the connection's
+ character set with an SQL statement. If you do this, you'll also
+ need to change this attribute. Otherwise, you'll get encoding
+ errors.
+
+paramstyle
+ String constant stating the type of parameter marker formatting
+ expected by the interface. Set to 'format' = ANSI C printf
+ format codes, e.g. '...WHERE name=%s'. If a mapping object is
+ used for conn.execute(), then the interface actually uses
+ 'pyformat' = Python extended format codes, e.g. '...WHERE
+ name=%(name)s'. However, the API does not presently allow the
+ specification of more than one style in paramstyle.
+
+ Note that any literal percent signs in the query string passed
+ to execute() must be escaped, i.e. %%.
+
+ Parameter placeholders can **only** be used to insert column
+ values. They can **not** be used for other parts of SQL, such as
+ table names, statements, etc.
+
+conv
+ A dictionary or mapping which controls how types are converted
+ from MySQL to Python and vice versa.
+
+ If the key is a MySQL type (from ``FIELD_TYPE.*``), then the value
+ can be either:
+
+ * a callable object which takes a string argument (the MySQL
+ value),' returning a Python value
+
+ * a sequence of 2-tuples, where the first value is a combination
+ of flags from ``MySQLdb.constants.FLAG``, and the second value
+ is a function as above. The sequence is tested until the flags
+ on the field match those of the first value. If both values
+ are None, then the default conversion is done. Presently this
+ is only used to distinquish TEXT and BLOB columns.
+
+ If the key is a Python type or class, then the value is a
+ callable Python object (usually a function) taking two arguments
+ (value to convert, and the conversion dictionary) which converts
+ values of this type to a SQL literal string value.
+
+ This is initialized with reasonable defaults for most
+ types. When creating a Connection object, you can pass your own
+ type converter dictionary as a keyword parameter. Otherwise, it
+ uses a copy of ``MySQLdb.converters.conversions``. Several
+ non-standard types are returned as strings, which is how MySQL
+ returns all columns. For more details, see the built-in module
+ documentation.
+
+
+Connection Objects
+..................
+
+Connection objects are returned by the ``connect()`` function.
+
+commit()
+ If the database and the tables support transactions, this
+ commits the current transaction; otherwise this method
+ successfully does nothing.
+
+rollback()
+ If the database and tables support transactions, this rolls back
+ (cancels) the current transaction; otherwise a
+ ``NotSupportedError`` is raised.
+
+cursor([cursorclass])
+ MySQL does not support cursors; however, cursors are easily
+ emulated. You can supply an alternative cursor class as an
+ optional parameter. If this is not present, it defaults to the
+ value given when creating the connection object, or the standard
+ ``Cursor`` class. Also see the additional supplied cursor
+ classes in the usage section.
+
+There are many more methods defined on the connection object which
+are MySQL-specific. For more information on them, consult the internal
+documentation using ``pydoc``.
+
+
+Cursor Objects
+..............
+
+callproc(procname, args)
+ Calls stored procedure procname with the sequence of arguments
+ in args. Returns the original arguments. Stored procedure
+ support only works with MySQL-5.0 and newer.
+
+ **Compatibility note:** PEP-249_ specifies that if there are
+ OUT or INOUT parameters, the modified values are to be
+ returned. This is not consistently possible with MySQL. Stored
+ procedure arguments must be passed as server variables, and
+ can only be returned with a SELECT statement. Since a stored
+ procedure may return zero or more result sets, it is impossible
+ for MySQLdb to determine if there are result sets to fetch
+ before the modified parmeters are accessible.
+
+ The parameters are stored in the server as @_*procname*_*n*,
+ where *n* is the position of the parameter. I.e., if you
+ cursor.callproc('foo', (a, b, c)), the parameters will be
+ accessible by a SELECT statement as @_foo_0, @_foo_1, and
+ @_foo_2.
+
+ **Compatibility note:** It appears that the mere act of
+ executing the CALL statement produces an empty result set, which
+ appears after any result sets which might be generated by the
+ stored procedure. Thus, you will always need to use nextset() to
+ advance result sets.
+
+close()
+ Closes the cursor. Future operations raise ``ProgrammingError``.
+ If you are using server-side cursors, it is very important to
+ close the cursor when you are done with it and before creating a
+ new one.
+
+info()
+ Returns some information about the last query. Normally
+ you don't need to check this. If there are any MySQL
+ warnings, it will cause a Warning to be issued through
+ the Python warning module. By default, Warning causes a
+ message to appear on the console. However, it is possible
+ to filter these out or cause Warning to be raised as exception.
+ See the MySQL docs for ``mysql_info()``, and the Python warning
+ module. (Non-standard)
+
+setinputsizes()
+ Does nothing, successfully.
+
+setoutputsizes()
+ Does nothing, successfully.
+
+nextset()
+ Advances the cursor to the next result set, discarding the remaining
+ rows in the current result set. If there are no additional result
+ sets, it returns None; otherwise it returns a true value.
+
+ Note that MySQL doesn't support multiple result sets until 4.1.
+
+
+Some examples
+.............
+
+The ``connect()`` method works nearly the same as with `_mysql`_::
+
+ import MySQLdb
+ db=MySQLdb.connect(passwd="moonpie",db="thangs")
+
+To perform a query, you first need a cursor, and then you can execute
+queries on it::
+
+ c=db.cursor()
+ max_price=5
+ c.execute("""SELECT spam, eggs, sausage FROM breakfast
+ WHERE price < %s""", (max_price,))
+
+In this example, ``max_price=5`` Why, then, use ``%s`` in the
+string? Because MySQLdb will convert it to a SQL literal value, which
+is the string '5'. When it's finished, the query will actually say,
+"...WHERE price < 5".
+
+Why the tuple? Because the DB API requires you to pass in any
+parameters as a sequence. Due to the design of the parser, (max_price)
+is interpreted as using algebraic grouping and simply as max_price and
+not a tuple. Adding a comma, i.e. (max_price,) forces it to make a
+tuple.
+
+And now, the results::
+
+ >>> c.fetchone()
+ (3L, 2L, 0L)
+
+Quite unlike the ``_mysql`` example, this returns a single tuple,
+which is the row, and the values are properly converted by default...
+except... What's with the L's?
+
+As mentioned earlier, while MySQL's INTEGER column translates
+perfectly into a Python integer, UNSIGNED INTEGER could overflow, so
+these values are converted to Python long integers instead.
+
+If you wanted more rows, you could use ``c.fetchmany(n)`` or
+``c.fetchall()``. These do exactly what you think they do. On
+``c.fetchmany(n)``, the ``n`` is optional and defaults to
+``c.arraysize``, which is normally 1. Both of these methods return a
+sequence of rows, or an empty sequence if there are no more rows. If
+you use a weird cursor class, the rows themselves might not be tuples.
+
+Note that in contrast to the above, ``c.fetchone()`` returns ``None``
+when there are no more rows to fetch.
+
+The only other method you are very likely to use is when you have to
+do a multi-row insert::
+
+ c.executemany(
+ """INSERT INTO breakfast (name, spam, eggs, sausage, price)
+ VALUES (%s, %s, %s, %s, %s)""",
+ [
+ ("Spam and Sausage Lover's Plate", 5, 1, 8, 7.95 ),
+ ("Not So Much Spam Plate", 3, 2, 0, 3.95 ),
+ ("Don't Wany ANY SPAM! Plate", 0, 4, 3, 5.95 )
+ ] )
+
+Here we are inserting three rows of five values. Notice that there is
+a mix of types (strings, ints, floats) though we still only use
+``%s``. And also note that we only included format strings for one
+row. MySQLdb picks those out and duplicates them for each row.
+
+Using and extending
+-------------------
+
+In general, it is probably wise to not directly interact with the DB
+API except for small applicatons. Databases, even SQL databases, vary
+widely in capabilities and may have non-standard features. The DB API
+does a good job of providing a reasonably portable interface but some
+methods are non-portable. Specifically, the parameters accepted by
+``connect()`` are completely implementation-dependent.
+
+If you believe your application may need to run on several different
+databases, the author recommends the following approach, based on
+personal experience: Write a simplified API for your application which
+implements the specific queries and operations your application needs
+to perform. Implement this API as a base class which should be have
+few database dependencies, and then derive a subclass from this which
+implements the necessary dependencies. In this way, porting your
+application to a new database should be a relatively simple matter of
+creating a new subclass, assuming the new database is reasonably
+standard.
+
+Because MySQLdb's Connection and Cursor objects are written in Python,
+you can easily derive your own subclasses. There are several Cursor
+classes in MySQLdb.cursors:
+
+BaseCursor
+ The base class for Cursor objects. This does not raise Warnings.
+
+CursorStoreResultMixIn
+ Causes the Cursor to use the ``mysql_store_result()`` function to
+ get the query result. The entire result set is stored on the
+ client side.
+
+CursorUseResultMixIn
+ Causes the cursor to use the ``mysql_use_result()`` function to
+ get the query result. The result set is stored on the server side
+ and is transferred row by row using fetch operations.
+
+CursorTupleRowsMixIn
+ Causes the cursor to return rows as a tuple of the column values.
+
+CursorDictRowsMixIn
+
+ Causes the cursor to return rows as a dictionary, where the keys
+ are column names and the values are column values. Note that if
+ the column names are not unique, i.e., you are selecting from two
+ tables that share column names, some of them will be rewritten as
+ ``table.column``. This can be avoided by using the SQL ``AS``
+ keyword. (This is yet-another reason not to use ``*`` in SQL
+ queries, particularly where ``JOIN`` is involved.)
+
+Cursor
+ The default cursor class. This class is composed of
+ ``CursorWarningMixIn``, ``CursorStoreResultMixIn``,
+ ``CursorTupleRowsMixIn,`` and ``BaseCursor``, i.e. it raises
+ ``Warning``, uses ``mysql_store_result()``, and returns rows as
+ tuples.
+
+DictCursor
+ Like ``Cursor`` except it returns rows as dictionaries.
+
+SSCursor
+ A "server-side" cursor. Like ``Cursor`` but uses
+ ``CursorUseResultMixIn``. Use only if you are dealing with
+ potentially large result sets.
+
+SSDictCursor
+ Like ``SSCursor`` except it returns rows as dictionaries.
+
+
+Embedded Server
+---------------
+
+Instead of connecting to a stand-alone server over the network,
+the embedded server support lets you run a full server right in
+your Python code or application server.
+
+If you have built MySQLdb with embedded server support, there
+are two additional functions you will need to make use of:
+
+ server_init(args, groups)
+ Initialize embedded server. If this client is not linked against
+ the embedded server library, this function does nothing.
+
+ args
+ sequence of command-line arguments
+ groups
+ sequence of groups to use in defaults files
+
+ server_end()
+ Shut down embedded server. If not using an embedded server, this
+ does nothing.
+
+See the MySQL documentation for more information on the embedded
+server.
+
+
+
+:Title: MySQLdb: a Python interface for MySQL
+:Author: Andy Dustman
+:Version: $Revision$
diff --git a/MySQLdb/ez_setup.py b/MySQLdb/ez_setup.py
index 1ff1d3e..73c0e56 100644
--- a/MySQLdb/ez_setup.py
+++ b/MySQLdb/ez_setup.py
@@ -1,284 +1,284 @@
-#!python
-"""Bootstrap setuptools installation
-
-If you want to use setuptools in your package's setup.py, just include this
-file in the same directory with it, and add this to the top of your setup.py::
-
- from ez_setup import use_setuptools
- use_setuptools()
-
-If you want to require a specific version of setuptools, set a download
-mirror, or use an alternate download directory, you can do so by supplying
-the appropriate options to ``use_setuptools()``.
-
-This file can also be run as a script to install or upgrade setuptools.
-"""
-import sys
-DEFAULT_VERSION = "0.6c11"
-DEFAULT_URL = "http://pypi.python.org/packages/%s/s/setuptools/" % sys.version[:3]
-
-md5_data = {
- 'setuptools-0.6b1-py2.3.egg': '8822caf901250d848b996b7f25c6e6ca',
- 'setuptools-0.6b1-py2.4.egg': 'b79a8a403e4502fbb85ee3f1941735cb',
- 'setuptools-0.6b2-py2.3.egg': '5657759d8a6d8fc44070a9d07272d99b',
- 'setuptools-0.6b2-py2.4.egg': '4996a8d169d2be661fa32a6e52e4f82a',
- 'setuptools-0.6b3-py2.3.egg': 'bb31c0fc7399a63579975cad9f5a0618',
- 'setuptools-0.6b3-py2.4.egg': '38a8c6b3d6ecd22247f179f7da669fac',
- 'setuptools-0.6b4-py2.3.egg': '62045a24ed4e1ebc77fe039aa4e6f7e5',
- 'setuptools-0.6b4-py2.4.egg': '4cb2a185d228dacffb2d17f103b3b1c4',
- 'setuptools-0.6c1-py2.3.egg': 'b3f2b5539d65cb7f74ad79127f1a908c',
- 'setuptools-0.6c1-py2.4.egg': 'b45adeda0667d2d2ffe14009364f2a4b',
- 'setuptools-0.6c10-py2.3.egg': 'ce1e2ab5d3a0256456d9fc13800a7090',
- 'setuptools-0.6c10-py2.4.egg': '57d6d9d6e9b80772c59a53a8433a5dd4',
- 'setuptools-0.6c10-py2.5.egg': 'de46ac8b1c97c895572e5e8596aeb8c7',
- 'setuptools-0.6c10-py2.6.egg': '58ea40aef06da02ce641495523a0b7f5',
- 'setuptools-0.6c11-py2.3.egg': '2baeac6e13d414a9d28e7ba5b5a596de',
- 'setuptools-0.6c11-py2.4.egg': 'bd639f9b0eac4c42497034dec2ec0c2b',
- 'setuptools-0.6c11-py2.5.egg': '64c94f3bf7a72a13ec83e0b24f2749b2',
- 'setuptools-0.6c11-py2.6.egg': 'bfa92100bd772d5a213eedd356d64086',
- 'setuptools-0.6c2-py2.3.egg': 'f0064bf6aa2b7d0f3ba0b43f20817c27',
- 'setuptools-0.6c2-py2.4.egg': '616192eec35f47e8ea16cd6a122b7277',
- 'setuptools-0.6c3-py2.3.egg': 'f181fa125dfe85a259c9cd6f1d7b78fa',
- 'setuptools-0.6c3-py2.4.egg': 'e0ed74682c998bfb73bf803a50e7b71e',
- 'setuptools-0.6c3-py2.5.egg': 'abef16fdd61955514841c7c6bd98965e',
- 'setuptools-0.6c4-py2.3.egg': 'b0b9131acab32022bfac7f44c5d7971f',
- 'setuptools-0.6c4-py2.4.egg': '2a1f9656d4fbf3c97bf946c0a124e6e2',
- 'setuptools-0.6c4-py2.5.egg': '8f5a052e32cdb9c72bcf4b5526f28afc',
- 'setuptools-0.6c5-py2.3.egg': 'ee9fd80965da04f2f3e6b3576e9d8167',
- 'setuptools-0.6c5-py2.4.egg': 'afe2adf1c01701ee841761f5bcd8aa64',
- 'setuptools-0.6c5-py2.5.egg': 'a8d3f61494ccaa8714dfed37bccd3d5d',
- 'setuptools-0.6c6-py2.3.egg': '35686b78116a668847237b69d549ec20',
- 'setuptools-0.6c6-py2.4.egg': '3c56af57be3225019260a644430065ab',
- 'setuptools-0.6c6-py2.5.egg': 'b2f8a7520709a5b34f80946de5f02f53',
- 'setuptools-0.6c7-py2.3.egg': '209fdf9adc3a615e5115b725658e13e2',
- 'setuptools-0.6c7-py2.4.egg': '5a8f954807d46a0fb67cf1f26c55a82e',
- 'setuptools-0.6c7-py2.5.egg': '45d2ad28f9750e7434111fde831e8372',
- 'setuptools-0.6c8-py2.3.egg': '50759d29b349db8cfd807ba8303f1902',
- 'setuptools-0.6c8-py2.4.egg': 'cba38d74f7d483c06e9daa6070cce6de',
- 'setuptools-0.6c8-py2.5.egg': '1721747ee329dc150590a58b3e1ac95b',
- 'setuptools-0.6c9-py2.3.egg': 'a83c4020414807b496e4cfbe08507c03',
- 'setuptools-0.6c9-py2.4.egg': '260a2be2e5388d66bdaee06abec6342a',
- 'setuptools-0.6c9-py2.5.egg': 'fe67c3e5a17b12c0e7c541b7ea43a8e6',
- 'setuptools-0.6c9-py2.6.egg': 'ca37b1ff16fa2ede6e19383e7b59245a',
-}
-
-import sys, os
-try: from hashlib import md5
-except ImportError: from md5 import md5
-
-def _validate_md5(egg_name, data):
- if egg_name in md5_data:
- digest = md5(data).hexdigest()
- if digest != md5_data[egg_name]:
- print >>sys.stderr, (
- "md5 validation of %s failed! (Possible download problem?)"
- % egg_name
- )
- sys.exit(2)
- return data
-
-def use_setuptools(
- version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir,
- download_delay=15
-):
- """Automatically find/download setuptools and make it available on sys.path
-
- `version` should be a valid setuptools version number that is available
- as an egg for download under the `download_base` URL (which should end with
- a '/'). `to_dir` is the directory where setuptools will be downloaded, if
- it is not already available. If `download_delay` is specified, it should
- be the number of seconds that will be paused before initiating a download,
- should one be required. If an older version of setuptools is installed,
- this routine will print a message to ``sys.stderr`` and raise SystemExit in
- an attempt to abort the calling script.
- """
- was_imported = 'pkg_resources' in sys.modules or 'setuptools' in sys.modules
- def do_download():
- egg = download_setuptools(version, download_base, to_dir, download_delay)
- sys.path.insert(0, egg)
- import setuptools; setuptools.bootstrap_install_from = egg
- try:
- import pkg_resources
- except ImportError:
- return do_download()
- try:
- pkg_resources.require("setuptools>="+version); return
- except pkg_resources.VersionConflict, e:
- if was_imported:
- print >>sys.stderr, (
- "The required version of setuptools (>=%s) is not available, and\n"
- "can't be installed while this script is running. Please install\n"
- " a more recent version first, using 'easy_install -U setuptools'."
- "\n\n(Currently using %r)"
- ) % (version, e.args[0])
- sys.exit(2)
- else:
- del pkg_resources, sys.modules['pkg_resources'] # reload ok
- return do_download()
- except pkg_resources.DistributionNotFound:
- return do_download()
-
-def download_setuptools(
- version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir,
- delay = 15
-):
- """Download setuptools from a specified location and return its filename
-
- `version` should be a valid setuptools version number that is available
- as an egg for download under the `download_base` URL (which should end
- with a '/'). `to_dir` is the directory where the egg will be downloaded.
- `delay` is the number of seconds to pause before an actual download attempt.
- """
- import urllib2, shutil
- egg_name = "setuptools-%s-py%s.egg" % (version,sys.version[:3])
- url = download_base + egg_name
- saveto = os.path.join(to_dir, egg_name)
- src = dst = None
- if not os.path.exists(saveto): # Avoid repeated downloads
- try:
- from distutils import log
- if delay:
- log.warn("""
----------------------------------------------------------------------------
-This script requires setuptools version %s to run (even to display
-help). I will attempt to download it for you (from
-%s), but
-you may need to enable firewall access for this script first.
-I will start the download in %d seconds.
-
-(Note: if this machine does not have network access, please obtain the file
-
- %s
-
-and place it in this directory before rerunning this script.)
----------------------------------------------------------------------------""",
- version, download_base, delay, url
- ); from time import sleep; sleep(delay)
- log.warn("Downloading %s", url)
- src = urllib2.urlopen(url)
- # Read/write all in one block, so we don't create a corrupt file
- # if the download is interrupted.
- data = _validate_md5(egg_name, src.read())
- dst = open(saveto,"wb"); dst.write(data)
- finally:
- if src: src.close()
- if dst: dst.close()
- return os.path.realpath(saveto)
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-def main(argv, version=DEFAULT_VERSION):
- """Install or upgrade setuptools and EasyInstall"""
- try:
- import setuptools
- except ImportError:
- egg = None
- try:
- egg = download_setuptools(version, delay=0)
- sys.path.insert(0,egg)
- from setuptools.command.easy_install import main
- return main(list(argv)+[egg]) # we're done here
- finally:
- if egg and os.path.exists(egg):
- os.unlink(egg)
- else:
- if setuptools.__version__ == '0.0.1':
- print >>sys.stderr, (
- "You have an obsolete version of setuptools installed. Please\n"
- "remove it from your system entirely before rerunning this script."
- )
- sys.exit(2)
-
- req = "setuptools>="+version
- import pkg_resources
- try:
- pkg_resources.require(req)
- except pkg_resources.VersionConflict:
- try:
- from setuptools.command.easy_install import main
- except ImportError:
- from easy_install import main
- main(list(argv)+[download_setuptools(delay=0)])
- sys.exit(0) # try to force an exit
- else:
- if argv:
- from setuptools.command.easy_install import main
- main(argv)
- else:
- print "Setuptools version",version,"or greater has been installed."
- print '(Run "ez_setup.py -U setuptools" to reinstall or upgrade.)'
-
-def update_md5(filenames):
- """Update our built-in md5 registry"""
-
- import re
-
- for name in filenames:
- base = os.path.basename(name)
- f = open(name,'rb')
- md5_data[base] = md5(f.read()).hexdigest()
- f.close()
-
- data = [" %r: %r,\n" % it for it in md5_data.items()]
- data.sort()
- repl = "".join(data)
-
- import inspect
- srcfile = inspect.getsourcefile(sys.modules[__name__])
- f = open(srcfile, 'rb'); src = f.read(); f.close()
-
- match = re.search("\nmd5_data = {\n([^}]+)}", src)
- if not match:
- print >>sys.stderr, "Internal error!"
- sys.exit(2)
-
- src = src[:match.start(1)] + repl + src[match.end(1):]
- f = open(srcfile,'w')
- f.write(src)
- f.close()
-
-
-if __name__=='__main__':
- if len(sys.argv)>2 and sys.argv[1]=='--md5update':
- update_md5(sys.argv[2:])
- else:
- main(sys.argv[1:])
-
-
-
-
-
-
+#!python
+"""Bootstrap setuptools installation
+
+If you want to use setuptools in your package's setup.py, just include this
+file in the same directory with it, and add this to the top of your setup.py::
+
+ from ez_setup import use_setuptools
+ use_setuptools()
+
+If you want to require a specific version of setuptools, set a download
+mirror, or use an alternate download directory, you can do so by supplying
+the appropriate options to ``use_setuptools()``.
+
+This file can also be run as a script to install or upgrade setuptools.
+"""
+import sys
+DEFAULT_VERSION = "0.6c11"
+DEFAULT_URL = "http://pypi.python.org/packages/%s/s/setuptools/" % sys.version[:3]
+
+md5_data = {
+ 'setuptools-0.6b1-py2.3.egg': '8822caf901250d848b996b7f25c6e6ca',
+ 'setuptools-0.6b1-py2.4.egg': 'b79a8a403e4502fbb85ee3f1941735cb',
+ 'setuptools-0.6b2-py2.3.egg': '5657759d8a6d8fc44070a9d07272d99b',
+ 'setuptools-0.6b2-py2.4.egg': '4996a8d169d2be661fa32a6e52e4f82a',
+ 'setuptools-0.6b3-py2.3.egg': 'bb31c0fc7399a63579975cad9f5a0618',
+ 'setuptools-0.6b3-py2.4.egg': '38a8c6b3d6ecd22247f179f7da669fac',
+ 'setuptools-0.6b4-py2.3.egg': '62045a24ed4e1ebc77fe039aa4e6f7e5',
+ 'setuptools-0.6b4-py2.4.egg': '4cb2a185d228dacffb2d17f103b3b1c4',
+ 'setuptools-0.6c1-py2.3.egg': 'b3f2b5539d65cb7f74ad79127f1a908c',
+ 'setuptools-0.6c1-py2.4.egg': 'b45adeda0667d2d2ffe14009364f2a4b',
+ 'setuptools-0.6c10-py2.3.egg': 'ce1e2ab5d3a0256456d9fc13800a7090',
+ 'setuptools-0.6c10-py2.4.egg': '57d6d9d6e9b80772c59a53a8433a5dd4',
+ 'setuptools-0.6c10-py2.5.egg': 'de46ac8b1c97c895572e5e8596aeb8c7',
+ 'setuptools-0.6c10-py2.6.egg': '58ea40aef06da02ce641495523a0b7f5',
+ 'setuptools-0.6c11-py2.3.egg': '2baeac6e13d414a9d28e7ba5b5a596de',
+ 'setuptools-0.6c11-py2.4.egg': 'bd639f9b0eac4c42497034dec2ec0c2b',
+ 'setuptools-0.6c11-py2.5.egg': '64c94f3bf7a72a13ec83e0b24f2749b2',
+ 'setuptools-0.6c11-py2.6.egg': 'bfa92100bd772d5a213eedd356d64086',
+ 'setuptools-0.6c2-py2.3.egg': 'f0064bf6aa2b7d0f3ba0b43f20817c27',
+ 'setuptools-0.6c2-py2.4.egg': '616192eec35f47e8ea16cd6a122b7277',
+ 'setuptools-0.6c3-py2.3.egg': 'f181fa125dfe85a259c9cd6f1d7b78fa',
+ 'setuptools-0.6c3-py2.4.egg': 'e0ed74682c998bfb73bf803a50e7b71e',
+ 'setuptools-0.6c3-py2.5.egg': 'abef16fdd61955514841c7c6bd98965e',
+ 'setuptools-0.6c4-py2.3.egg': 'b0b9131acab32022bfac7f44c5d7971f',
+ 'setuptools-0.6c4-py2.4.egg': '2a1f9656d4fbf3c97bf946c0a124e6e2',
+ 'setuptools-0.6c4-py2.5.egg': '8f5a052e32cdb9c72bcf4b5526f28afc',
+ 'setuptools-0.6c5-py2.3.egg': 'ee9fd80965da04f2f3e6b3576e9d8167',
+ 'setuptools-0.6c5-py2.4.egg': 'afe2adf1c01701ee841761f5bcd8aa64',
+ 'setuptools-0.6c5-py2.5.egg': 'a8d3f61494ccaa8714dfed37bccd3d5d',
+ 'setuptools-0.6c6-py2.3.egg': '35686b78116a668847237b69d549ec20',
+ 'setuptools-0.6c6-py2.4.egg': '3c56af57be3225019260a644430065ab',
+ 'setuptools-0.6c6-py2.5.egg': 'b2f8a7520709a5b34f80946de5f02f53',
+ 'setuptools-0.6c7-py2.3.egg': '209fdf9adc3a615e5115b725658e13e2',
+ 'setuptools-0.6c7-py2.4.egg': '5a8f954807d46a0fb67cf1f26c55a82e',
+ 'setuptools-0.6c7-py2.5.egg': '45d2ad28f9750e7434111fde831e8372',
+ 'setuptools-0.6c8-py2.3.egg': '50759d29b349db8cfd807ba8303f1902',
+ 'setuptools-0.6c8-py2.4.egg': 'cba38d74f7d483c06e9daa6070cce6de',
+ 'setuptools-0.6c8-py2.5.egg': '1721747ee329dc150590a58b3e1ac95b',
+ 'setuptools-0.6c9-py2.3.egg': 'a83c4020414807b496e4cfbe08507c03',
+ 'setuptools-0.6c9-py2.4.egg': '260a2be2e5388d66bdaee06abec6342a',
+ 'setuptools-0.6c9-py2.5.egg': 'fe67c3e5a17b12c0e7c541b7ea43a8e6',
+ 'setuptools-0.6c9-py2.6.egg': 'ca37b1ff16fa2ede6e19383e7b59245a',
+}
+
+import sys, os
+try: from hashlib import md5
+except ImportError: from md5 import md5
+
+def _validate_md5(egg_name, data):
+ if egg_name in md5_data:
+ digest = md5(data).hexdigest()
+ if digest != md5_data[egg_name]:
+ print >>sys.stderr, (
+ "md5 validation of %s failed! (Possible download problem?)"
+ % egg_name
+ )
+ sys.exit(2)
+ return data
+
+def use_setuptools(
+ version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir,
+ download_delay=15
+):
+ """Automatically find/download setuptools and make it available on sys.path
+
+ `version` should be a valid setuptools version number that is available
+ as an egg for download under the `download_base` URL (which should end with
+ a '/'). `to_dir` is the directory where setuptools will be downloaded, if
+ it is not already available. If `download_delay` is specified, it should
+ be the number of seconds that will be paused before initiating a download,
+ should one be required. If an older version of setuptools is installed,
+ this routine will print a message to ``sys.stderr`` and raise SystemExit in
+ an attempt to abort the calling script.
+ """
+ was_imported = 'pkg_resources' in sys.modules or 'setuptools' in sys.modules
+ def do_download():
+ egg = download_setuptools(version, download_base, to_dir, download_delay)
+ sys.path.insert(0, egg)
+ import setuptools; setuptools.bootstrap_install_from = egg
+ try:
+ import pkg_resources
+ except ImportError:
+ return do_download()
+ try:
+ pkg_resources.require("setuptools>="+version); return
+ except pkg_resources.VersionConflict, e:
+ if was_imported:
+ print >>sys.stderr, (
+ "The required version of setuptools (>=%s) is not available, and\n"
+ "can't be installed while this script is running. Please install\n"
+ " a more recent version first, using 'easy_install -U setuptools'."
+ "\n\n(Currently using %r)"
+ ) % (version, e.args[0])
+ sys.exit(2)
+ else:
+ del pkg_resources, sys.modules['pkg_resources'] # reload ok
+ return do_download()
+ except pkg_resources.DistributionNotFound:
+ return do_download()
+
+def download_setuptools(
+ version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir,
+ delay = 15
+):
+ """Download setuptools from a specified location and return its filename
+
+ `version` should be a valid setuptools version number that is available
+ as an egg for download under the `download_base` URL (which should end
+ with a '/'). `to_dir` is the directory where the egg will be downloaded.
+ `delay` is the number of seconds to pause before an actual download attempt.
+ """
+ import urllib2, shutil
+ egg_name = "setuptools-%s-py%s.egg" % (version,sys.version[:3])
+ url = download_base + egg_name
+ saveto = os.path.join(to_dir, egg_name)
+ src = dst = None
+ if not os.path.exists(saveto): # Avoid repeated downloads
+ try:
+ from distutils import log
+ if delay:
+ log.warn("""
+---------------------------------------------------------------------------
+This script requires setuptools version %s to run (even to display
+help). I will attempt to download it for you (from
+%s), but
+you may need to enable firewall access for this script first.
+I will start the download in %d seconds.
+
+(Note: if this machine does not have network access, please obtain the file
+
+ %s
+
+and place it in this directory before rerunning this script.)
+---------------------------------------------------------------------------""",
+ version, download_base, delay, url
+ ); from time import sleep; sleep(delay)
+ log.warn("Downloading %s", url)
+ src = urllib2.urlopen(url)
+ # Read/write all in one block, so we don't create a corrupt file
+ # if the download is interrupted.
+ data = _validate_md5(egg_name, src.read())
+ dst = open(saveto,"wb"); dst.write(data)
+ finally:
+ if src: src.close()
+ if dst: dst.close()
+ return os.path.realpath(saveto)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+def main(argv, version=DEFAULT_VERSION):
+ """Install or upgrade setuptools and EasyInstall"""
+ try:
+ import setuptools
+ except ImportError:
+ egg = None
+ try:
+ egg = download_setuptools(version, delay=0)
+ sys.path.insert(0,egg)
+ from setuptools.command.easy_install import main
+ return main(list(argv)+[egg]) # we're done here
+ finally:
+ if egg and os.path.exists(egg):
+ os.unlink(egg)
+ else:
+ if setuptools.__version__ == '0.0.1':
+ print >>sys.stderr, (
+ "You have an obsolete version of setuptools installed. Please\n"
+ "remove it from your system entirely before rerunning this script."
+ )
+ sys.exit(2)
+
+ req = "setuptools>="+version
+ import pkg_resources
+ try:
+ pkg_resources.require(req)
+ except pkg_resources.VersionConflict:
+ try:
+ from setuptools.command.easy_install import main
+ except ImportError:
+ from easy_install import main
+ main(list(argv)+[download_setuptools(delay=0)])
+ sys.exit(0) # try to force an exit
+ else:
+ if argv:
+ from setuptools.command.easy_install import main
+ main(argv)
+ else:
+ print "Setuptools version",version,"or greater has been installed."
+ print '(Run "ez_setup.py -U setuptools" to reinstall or upgrade.)'
+
+def update_md5(filenames):
+ """Update our built-in md5 registry"""
+
+ import re
+
+ for name in filenames:
+ base = os.path.basename(name)
+ f = open(name,'rb')
+ md5_data[base] = md5(f.read()).hexdigest()
+ f.close()
+
+ data = [" %r: %r,\n" % it for it in md5_data.items()]
+ data.sort()
+ repl = "".join(data)
+
+ import inspect
+ srcfile = inspect.getsourcefile(sys.modules[__name__])
+ f = open(srcfile, 'rb'); src = f.read(); f.close()
+
+ match = re.search("\nmd5_data = {\n([^}]+)}", src)
+ if not match:
+ print >>sys.stderr, "Internal error!"
+ sys.exit(2)
+
+ src = src[:match.start(1)] + repl + src[match.end(1):]
+ f = open(srcfile,'w')
+ f.write(src)
+ f.close()
+
+
+if __name__=='__main__':
+ if len(sys.argv)>2 and sys.argv[1]=='--md5update':
+ update_md5(sys.argv[2:])
+ else:
+ main(sys.argv[1:])
+
+
+
+
+
+
diff --git a/MySQLdb/metadata.cfg b/MySQLdb/metadata.cfg
index 469b478..c461643 100644
--- a/MySQLdb/metadata.cfg
+++ b/MySQLdb/metadata.cfg
@@ -1,60 +1,60 @@
-[metadata]
-version: 1.2.3
-version_info: (1,2,3,'final',0)
-description: Python interface to MySQL
-long_description:
- =========================
- Python interface to MySQL
- =========================
- \n
- MySQLdb is an interface to the popular MySQL_ database server for
- Python. The design goals are:
- \n
- - Compliance with Python database API version 2.0 [PEP-0249]_
- \n
- - Thread-safety
- \n
- - Thread-friendliness (threads will not block each other)
- \n
- MySQL-3.23 through 5.0 and Python-2.3 through 2.6 are currently
- supported. Python-3.0 will be supported in a future release.
- \n
- MySQLdb is `Free Software`_.
- \n
- .. _MySQL: http://www.mysql.com/
- .. _`Free Software`: http://www.gnu.org/
- .. [PEP-0249] http://www.python.org/peps/pep-0249.html
-author: Andy Dustman
-author_email: adustman@users.sourceforge.net
-license: GPL
-platforms: ALL
-url: http://sourceforge.net/projects/mysql-python
-download_url: http://osdn.dl.sourceforge.net/sourceforge/mysql-python/MySQL-python-%(version)s.tar.gz
-classifiers:
- Development Status :: 5 - Production/Stable
- Environment :: Other Environment
- License :: OSI Approved :: GNU General Public License (GPL)
- Operating System :: MacOS :: MacOS X
- Operating System :: Microsoft :: Windows :: Windows NT/2000
- Operating System :: OS Independent
- Operating System :: POSIX
- Operating System :: POSIX :: Linux
- Operating System :: Unix
- Programming Language :: C
- Programming Language :: Python
- Topic :: Database
- Topic :: Database :: Database Engines/Servers
-py_modules:
- _mysql_exceptions
- MySQLdb.converters
- MySQLdb.connections
- MySQLdb.cursors
- MySQLdb.release
- MySQLdb.times
- MySQLdb.constants.CR
- MySQLdb.constants.FIELD_TYPE
- MySQLdb.constants.ER
- MySQLdb.constants.FLAG
- MySQLdb.constants.REFRESH
- MySQLdb.constants.CLIENT
-
+[metadata]
+version: 1.2.3
+version_info: (1,2,3,'final',0)
+description: Python interface to MySQL
+long_description:
+ =========================
+ Python interface to MySQL
+ =========================
+ \n
+ MySQLdb is an interface to the popular MySQL_ database server for
+ Python. The design goals are:
+ \n
+ - Compliance with Python database API version 2.0 [PEP-0249]_
+ \n
+ - Thread-safety
+ \n
+ - Thread-friendliness (threads will not block each other)
+ \n
+ MySQL-3.23 through 5.0 and Python-2.3 through 2.6 are currently
+ supported. Python-3.0 will be supported in a future release.
+ \n
+ MySQLdb is `Free Software`_.
+ \n
+ .. _MySQL: http://www.mysql.com/
+ .. _`Free Software`: http://www.gnu.org/
+ .. [PEP-0249] http://www.python.org/peps/pep-0249.html
+author: Andy Dustman
+author_email: adustman@users.sourceforge.net
+license: GPL
+platforms: ALL
+url: http://sourceforge.net/projects/mysql-python
+download_url: http://osdn.dl.sourceforge.net/sourceforge/mysql-python/MySQL-python-%(version)s.tar.gz
+classifiers:
+ Development Status :: 5 - Production/Stable
+ Environment :: Other Environment
+ License :: OSI Approved :: GNU General Public License (GPL)
+ Operating System :: MacOS :: MacOS X
+ Operating System :: Microsoft :: Windows :: Windows NT/2000
+ Operating System :: OS Independent
+ Operating System :: POSIX
+ Operating System :: POSIX :: Linux
+ Operating System :: Unix
+ Programming Language :: C
+ Programming Language :: Python
+ Topic :: Database
+ Topic :: Database :: Database Engines/Servers
+py_modules:
+ _mysql_exceptions
+ MySQLdb.converters
+ MySQLdb.connections
+ MySQLdb.cursors
+ MySQLdb.release
+ MySQLdb.times
+ MySQLdb.constants.CR
+ MySQLdb.constants.FIELD_TYPE
+ MySQLdb.constants.ER
+ MySQLdb.constants.FLAG
+ MySQLdb.constants.REFRESH
+ MySQLdb.constants.CLIENT
+
diff --git a/MySQLdb/pymemcompat.h b/MySQLdb/pymemcompat.h
index e7c538c..d0ea09e 100644
--- a/MySQLdb/pymemcompat.h
+++ b/MySQLdb/pymemcompat.h
@@ -1,87 +1,87 @@
-
-/* The idea of this file is that you bundle it with your extension,
- #include it, program to Python 2.3's memory API and have your
- extension build with any version of Python from 1.5.2 through to
- 2.3 (and hopefully beyond). */
-
-#ifndef Py_PYMEMCOMPAT_H
-#define Py_PYMEMCOMPAT_H
-
-#include "Python.h"
-
-/* There are three "families" of memory API: the "raw memory", "object
- memory" and "object" families. (This is ignoring the matter of the
- cycle collector, about which more is said below).
-
- Raw Memory:
-
- PyMem_Malloc, PyMem_Realloc, PyMem_Free
-
- Object Memory:
-
- PyObject_Malloc, PyObject_Realloc, PyObject_Free
-
- Object:
-
- PyObject_New, PyObject_NewVar, PyObject_Del
-
- The raw memory and object memory allocators both mimic the
- malloc/realloc/free interface from ANSI C, but the object memory
- allocator can (and, since 2.3, does by default) use a different
- allocation strategy biased towards lots of lots of "small"
- allocations.
-
- The object family is used for allocating Python objects, and the
- initializers take care of some basic initialization (setting the
- refcount to 1 and filling out the ob_type field) as well as having
- a somewhat different interface.
-
- Do not mix the families! E.g. do not allocate memory with
- PyMem_Malloc and free it with PyObject_Free. You may get away with
- it quite a lot of the time, but there *are* scenarios where this
- will break. You Have Been Warned.
-
- Also, in many versions of Python there are an insane amount of
- memory interfaces to choose from. Use the ones described above. */
-
-#if PY_VERSION_HEX < 0x01060000
-/* raw memory interface already present */
-
-/* there is no object memory interface in 1.5.2 */
-#define PyObject_Malloc PyMem_Malloc
-#define PyObject_Realloc PyMem_Realloc
-#define PyObject_Free PyMem_Free
-
-/* the object interface is there, but the names have changed */
-#define PyObject_New PyObject_NEW
-#define PyObject_NewVar PyObject_NEW_VAR
-#define PyObject_Del PyMem_Free
-#endif
-
-/* If your object is a container you probably want to support the
- cycle collector, which was new in Python 2.0.
-
- Unfortunately, the interface to the collector that was present in
- Python 2.0 and 2.1 proved to be tricky to use, and so changed in
- 2.2 -- in a way that can't easily be papered over with macros.
-
- This file contains macros that let you program to the 2.2 GC API.
- Your module will compile against any Python since version 1.5.2,
- but the type will only participate in the GC in versions 2.2 and
- up. Some work is still necessary on your part to only fill out the
- tp_traverse and tp_clear fields when they exist and set tp_flags
- appropriately.
-
- It is possible to support both the 2.0 and 2.2 GC APIs, but it's
- not pretty and this comment block is too narrow to contain a
- desciption of what's required... */
-
-#if PY_VERSION_HEX < 0x020200B1
-#define PyObject_GC_New PyObject_New
-#define PyObject_GC_NewVar PyObject_NewVar
-#define PyObject_GC_Del PyObject_Del
-#define PyObject_GC_Track(op)
-#define PyObject_GC_UnTrack(op)
-#endif
-
-#endif /* !Py_PYMEMCOMPAT_H */
+
+/* The idea of this file is that you bundle it with your extension,
+ #include it, program to Python 2.3's memory API and have your
+ extension build with any version of Python from 1.5.2 through to
+ 2.3 (and hopefully beyond). */
+
+#ifndef Py_PYMEMCOMPAT_H
+#define Py_PYMEMCOMPAT_H
+
+#include "Python.h"
+
+/* There are three "families" of memory API: the "raw memory", "object
+ memory" and "object" families. (This is ignoring the matter of the
+ cycle collector, about which more is said below).
+
+ Raw Memory:
+
+ PyMem_Malloc, PyMem_Realloc, PyMem_Free
+
+ Object Memory:
+
+ PyObject_Malloc, PyObject_Realloc, PyObject_Free
+
+ Object:
+
+ PyObject_New, PyObject_NewVar, PyObject_Del
+
+ The raw memory and object memory allocators both mimic the
+ malloc/realloc/free interface from ANSI C, but the object memory
+ allocator can (and, since 2.3, does by default) use a different
+ allocation strategy biased towards lots of lots of "small"
+ allocations.
+
+ The object family is used for allocating Python objects, and the
+ initializers take care of some basic initialization (setting the
+ refcount to 1 and filling out the ob_type field) as well as having
+ a somewhat different interface.
+
+ Do not mix the families! E.g. do not allocate memory with
+ PyMem_Malloc and free it with PyObject_Free. You may get away with
+ it quite a lot of the time, but there *are* scenarios where this
+ will break. You Have Been Warned.
+
+ Also, in many versions of Python there are an insane amount of
+ memory interfaces to choose from. Use the ones described above. */
+
+#if PY_VERSION_HEX < 0x01060000
+/* raw memory interface already present */
+
+/* there is no object memory interface in 1.5.2 */
+#define PyObject_Malloc PyMem_Malloc
+#define PyObject_Realloc PyMem_Realloc
+#define PyObject_Free PyMem_Free
+
+/* the object interface is there, but the names have changed */
+#define PyObject_New PyObject_NEW
+#define PyObject_NewVar PyObject_NEW_VAR
+#define PyObject_Del PyMem_Free
+#endif
+
+/* If your object is a container you probably want to support the
+ cycle collector, which was new in Python 2.0.
+
+ Unfortunately, the interface to the collector that was present in
+ Python 2.0 and 2.1 proved to be tricky to use, and so changed in
+ 2.2 -- in a way that can't easily be papered over with macros.
+
+ This file contains macros that let you program to the 2.2 GC API.
+ Your module will compile against any Python since version 1.5.2,
+ but the type will only participate in the GC in versions 2.2 and
+ up. Some work is still necessary on your part to only fill out the
+ tp_traverse and tp_clear fields when they exist and set tp_flags
+ appropriately.
+
+ It is possible to support both the 2.0 and 2.2 GC APIs, but it's
+ not pretty and this comment block is too narrow to contain a
+ desciption of what's required... */
+
+#if PY_VERSION_HEX < 0x020200B1
+#define PyObject_GC_New PyObject_New
+#define PyObject_GC_NewVar PyObject_NewVar
+#define PyObject_GC_Del PyObject_Del
+#define PyObject_GC_Track(op)
+#define PyObject_GC_UnTrack(op)
+#endif
+
+#endif /* !Py_PYMEMCOMPAT_H */
diff --git a/MySQLdb/setup.cfg b/MySQLdb/setup.cfg
index e357362..b20c898 100644
--- a/MySQLdb/setup.cfg
+++ b/MySQLdb/setup.cfg
@@ -1,20 +1,20 @@
-[test]
-test_suite = nose.collector
-
-[build_ext]
-## Only uncomment/set these if the default configuration doesn't work
-## Also see http://docs.python.org/dist/setup-config.html
-# include-dirs = ?
-# library-dirs = ?
-# link-objects = ?
-# rpath = ?
-# libraries = ?
-
-[bdist_rpm]
-doc_files = README MANIFEST doc/*.txt
-vendor = MySQL-python SourceForge Project
-packager = Andy Dustman <adustman@users.sourceforge.net>
-distribution-name = Red Stains Linux
-requires = python
-install-requires = distribute
-build-requires = python-devel mysql-devel zlib-devel openssl-devel
+[test]
+test_suite = nose.collector
+
+[build_ext]
+## Only uncomment/set these if the default configuration doesn't work
+## Also see http://docs.python.org/dist/setup-config.html
+# include-dirs = ?
+# library-dirs = ?
+# link-objects = ?
+# rpath = ?
+# libraries = ?
+
+[bdist_rpm]
+doc_files = README MANIFEST doc/*.txt
+vendor = MySQL-python SourceForge Project
+packager = Andy Dustman <adustman@users.sourceforge.net>
+distribution-name = Red Stains Linux
+requires = python
+install-requires = distribute
+build-requires = python-devel mysql-devel zlib-devel openssl-devel
diff --git a/MySQLdb/setup.py b/MySQLdb/setup.py
index 798f96f..56619fb 100644
--- a/MySQLdb/setup.py
+++ b/MySQLdb/setup.py
@@ -1,21 +1,21 @@
-#!/usr/bin/env python
-
-import os
-import sys
-
-from distribute_setup import use_setuptools
-use_setuptools()
-from setuptools import setup, Extension
-
-if not hasattr(sys, "hexversion") or sys.hexversion < 0x02040000:
- raise Error("Python 2.4 or newer is required")
-
-if os.name == "posix":
- from setup_posix import get_config
-else: # assume windows
- from setup_windows import get_config
-
-metadata, options = get_config()
-metadata['ext_modules'] = [Extension(sources=['_mysql.c'], **options)]
-metadata['long_description'] = metadata['long_description'].replace(r'\n', '')
-setup(**metadata)
+#!/usr/bin/env python
+
+import os
+import sys
+
+from distribute_setup import use_setuptools
+use_setuptools()
+from setuptools import setup, Extension
+
+if not hasattr(sys, "hexversion") or sys.hexversion < 0x02040000:
+ raise Error("Python 2.4 or newer is required")
+
+if os.name == "posix":
+ from setup_posix import get_config
+else: # assume windows
+ from setup_windows import get_config
+
+metadata, options = get_config()
+metadata['ext_modules'] = [Extension(sources=['_mysql.c'], **options)]
+metadata['long_description'] = metadata['long_description'].replace(r'\n', '')
+setup(**metadata)
diff --git a/MySQLdb/setup_common.py b/MySQLdb/setup_common.py
index 03c39bb..6a25411 100644
--- a/MySQLdb/setup_common.py
+++ b/MySQLdb/setup_common.py
@@ -1,37 +1,37 @@
-try:
- # Python 2.x
- from ConfigParser import SafeConfigParser
-except ImportError:
- # Python 3.x
- from configparser import ConfigParser as SafeConfigParser
-
-def get_metadata_and_options():
- config = SafeConfigParser()
- config.read(['metadata.cfg', 'site.cfg'])
-
- metadata = dict(config.items('metadata'))
- options = dict(config.items('options'))
-
- metadata['py_modules'] = list(filter(None, metadata['py_modules'].split('\n')))
- metadata['classifiers'] = list(filter(None, metadata['classifiers'].split('\n')))
-
- return metadata, options
-
-def enabled(options, option):
- value = options[option]
- s = value.lower()
- if s in ('yes','true','1','y'):
- return True
- elif s in ('no', 'false', '0', 'n'):
- return False
- else:
- raise ValueError("Unknown value %s for option %s" % (value, option))
-
-def create_release_file(metadata):
- rel = open("MySQLdb/release.py",'w')
- rel.write("""
-__author__ = "%(author)s <%(author_email)s>"
-version_info = %(version_info)s
-__version__ = "%(version)s"
-""" % metadata)
- rel.close()
+try:
+ # Python 2.x
+ from ConfigParser import SafeConfigParser
+except ImportError:
+ # Python 3.x
+ from configparser import ConfigParser as SafeConfigParser
+
+def get_metadata_and_options():
+ config = SafeConfigParser()
+ config.read(['metadata.cfg', 'site.cfg'])
+
+ metadata = dict(config.items('metadata'))
+ options = dict(config.items('options'))
+
+ metadata['py_modules'] = list(filter(None, metadata['py_modules'].split('\n')))
+ metadata['classifiers'] = list(filter(None, metadata['classifiers'].split('\n')))
+
+ return metadata, options
+
+def enabled(options, option):
+ value = options[option]
+ s = value.lower()
+ if s in ('yes','true','1','y'):
+ return True
+ elif s in ('no', 'false', '0', 'n'):
+ return False
+ else:
+ raise ValueError("Unknown value %s for option %s" % (value, option))
+
+def create_release_file(metadata):
+ rel = open("MySQLdb/release.py",'w')
+ rel.write("""
+__author__ = "%(author)s <%(author_email)s>"
+version_info = %(version_info)s
+__version__ = "%(version)s"
+""" % metadata)
+ rel.close()
diff --git a/MySQLdb/setup_posix.py b/MySQLdb/setup_posix.py
index f7cb588..6fc52a3 100644
--- a/MySQLdb/setup_posix.py
+++ b/MySQLdb/setup_posix.py
@@ -1,102 +1,102 @@
-import os, sys
-from ConfigParser import SafeConfigParser
-
-# This dequote() business is required for some older versions
-# of mysql_config
-
-def dequote(s):
- if s[0] in "\"'" and s[0] == s[-1]:
- s = s[1:-1]
- return s
-
-def compiler_flag(f):
- return "-%s" % f
-
-def mysql_config(what):
- from os import popen
-
- f = popen("%s --%s" % (mysql_config.path, what))
- data = f.read().strip().split()
- ret = f.close()
- if ret:
- if ret/256:
- data = []
- if ret/256 > 1:
- raise EnvironmentError("%s not found" % (mysql_config.path,))
- return data
-mysql_config.path = "mysql_config"
-
-def get_config():
- from setup_common import get_metadata_and_options, enabled, create_release_file
-
- metadata, options = get_metadata_and_options()
-
- if 'mysql_config' in options:
- mysql_config.path = options['mysql_config']
-
- extra_objects = []
- static = enabled(options, 'static')
- if enabled(options, 'embedded'):
- libs = mysql_config("libmysqld-libs")
- client = "mysqld"
- elif enabled(options, 'threadsafe'):
- libs = mysql_config("libs_r")
- client = "mysqlclient_r"
- if not libs:
- libs = mysql_config("libs")
- client = "mysqlclient"
- else:
- libs = mysql_config("libs")
- client = "mysqlclient"
-
- library_dirs = [ dequote(i[2:]) for i in libs if i.startswith(compiler_flag("L")) ]
- libraries = [ dequote(i[2:]) for i in libs if i.startswith(compiler_flag("l")) ]
-
- removable_compile_args = [ compiler_flag(f) for f in "ILl" ]
- extra_compile_args = [ i.replace("%", "%%") for i in mysql_config("cflags")
- if i[:2] not in removable_compile_args ]
-
- # Copy the arch flags for linking as well
- extra_link_args = list()
- for i in range(len(extra_compile_args)):
- if extra_compile_args[i] == '-arch':
- extra_link_args += ['-arch', extra_compile_args[i + 1]]
-
- include_dirs = [ dequote(i[2:])
- for i in mysql_config('include')
- if i.startswith(compiler_flag('I')) ]
- if not include_dirs: # fix for MySQL-3.23
- include_dirs = [ dequote(i[2:])
- for i in mysql_config('cflags')
- if i.startswith(compiler_flag('I')) ]
-
- if static:
- extra_objects.append(os.path.join(
- library_dirs[0],'lib%s.a' % client))
-
- name = "MySQL-python"
- if enabled(options, 'embedded'):
- name = name + "-embedded"
- metadata['name'] = name
-
- define_macros = [
- ('version_info', metadata['version_info']),
- ('__version__', metadata['version']),
- ]
- create_release_file(metadata)
- del metadata['version_info']
- ext_options = dict(
- name = "_mysql",
- library_dirs = library_dirs,
- libraries = libraries,
- extra_compile_args = extra_compile_args,
- extra_link_args = extra_link_args,
- include_dirs = include_dirs,
- extra_objects = extra_objects,
- define_macros = define_macros,
- )
- return metadata, ext_options
-
-if __name__ == "__main__":
- sys.stderr.write("""You shouldn't be running this directly; it is used by setup.py.""")
-
+import os, sys
+from ConfigParser import SafeConfigParser
+
+# This dequote() business is required for some older versions
+# of mysql_config
+
+def dequote(s):
+ if s[0] in "\"'" and s[0] == s[-1]:
+ s = s[1:-1]
+ return s
+
+def compiler_flag(f):
+ return "-%s" % f
+
+def mysql_config(what):
+ from os import popen
+
+ f = popen("%s --%s" % (mysql_config.path, what))
+ data = f.read().strip().split()
+ ret = f.close()
+ if ret:
+ if ret/256:
+ data = []
+ if ret/256 > 1:
+ raise EnvironmentError("%s not found" % (mysql_config.path,))
+ return data
+mysql_config.path = "mysql_config"
+
+def get_config():
+ from setup_common import get_metadata_and_options, enabled, create_release_file
+
+ metadata, options = get_metadata_and_options()
+
+ if 'mysql_config' in options:
+ mysql_config.path = options['mysql_config']
+
+ extra_objects = []
+ static = enabled(options, 'static')
+ if enabled(options, 'embedded'):
+ libs = mysql_config("libmysqld-libs")
+ client = "mysqld"
+ elif enabled(options, 'threadsafe'):
+ libs = mysql_config("libs_r")
+ client = "mysqlclient_r"
+ if not libs:
+ libs = mysql_config("libs")
+ client = "mysqlclient"
+ else:
+ libs = mysql_config("libs")
+ client = "mysqlclient"
+
+ library_dirs = [ dequote(i[2:]) for i in libs if i.startswith(compiler_flag("L")) ]
+ libraries = [ dequote(i[2:]) for i in libs if i.startswith(compiler_flag("l")) ]
+
+ removable_compile_args = [ compiler_flag(f) for f in "ILl" ]
+ extra_compile_args = [ i.replace("%", "%%") for i in mysql_config("cflags")
+ if i[:2] not in removable_compile_args ]
+
+ # Copy the arch flags for linking as well
+ extra_link_args = list()
+ for i in range(len(extra_compile_args)):
+ if extra_compile_args[i] == '-arch':
+ extra_link_args += ['-arch', extra_compile_args[i + 1]]
+
+ include_dirs = [ dequote(i[2:])
+ for i in mysql_config('include')
+ if i.startswith(compiler_flag('I')) ]
+ if not include_dirs: # fix for MySQL-3.23
+ include_dirs = [ dequote(i[2:])
+ for i in mysql_config('cflags')
+ if i.startswith(compiler_flag('I')) ]
+
+ if static:
+ extra_objects.append(os.path.join(
+ library_dirs[0],'lib%s.a' % client))
+
+ name = "MySQL-python"
+ if enabled(options, 'embedded'):
+ name = name + "-embedded"
+ metadata['name'] = name
+
+ define_macros = [
+ ('version_info', metadata['version_info']),
+ ('__version__', metadata['version']),
+ ]
+ create_release_file(metadata)
+ del metadata['version_info']
+ ext_options = dict(
+ name = "_mysql",
+ library_dirs = library_dirs,
+ libraries = libraries,
+ extra_compile_args = extra_compile_args,
+ extra_link_args = extra_link_args,
+ include_dirs = include_dirs,
+ extra_objects = extra_objects,
+ define_macros = define_macros,
+ )
+ return metadata, ext_options
+
+if __name__ == "__main__":
+ sys.stderr.write("""You shouldn't be running this directly; it is used by setup.py.""")
+
diff --git a/MySQLdb/setup_windows.py b/MySQLdb/setup_windows.py
index ffe6397..1d0ad7e 100644
--- a/MySQLdb/setup_windows.py
+++ b/MySQLdb/setup_windows.py
@@ -1,46 +1,46 @@
-import os, sys
-
-def get_config():
- from setup_common import get_metadata_and_options, enabled, create_release_file
-
- metadata, options = get_metadata_and_options()
-
- connector = options["connector"]
-
- extra_objects = []
-
- if enabled(options, 'embedded'):
- client = "mysqld"
- else:
- client = "mysqlclient"
-
- library_dirs = [ os.path.join(connector, r'lib\opt') ]
- libraries = [ 'kernel32', 'advapi32', 'wsock32', client ]
- include_dirs = [ os.path.join(connector, r'include') ]
- extra_compile_args = [ '/Zl' ]
-
- name = "MySQL-python"
- if enabled(options, 'embedded'):
- name = name + "-embedded"
- metadata['name'] = name
-
- define_macros = [
- ('version_info', metadata['version_info']),
- ('__version__', metadata['version']),
- ]
- create_release_file(metadata)
- del metadata['version_info']
- ext_options = dict(
- name = "_mysql",
- library_dirs = library_dirs,
- libraries = libraries,
- extra_compile_args = extra_compile_args,
- include_dirs = include_dirs,
- extra_objects = extra_objects,
- define_macros = define_macros,
- )
- return metadata, ext_options
-
-if __name__ == "__main__":
- sys.stderr.write("""You shouldn't be running this directly; it is used by setup.py.""")
-
+import os, sys
+
+def get_config():
+ from setup_common import get_metadata_and_options, enabled, create_release_file
+
+ metadata, options = get_metadata_and_options()
+
+ connector = options["connector"]
+
+ extra_objects = []
+
+ if enabled(options, 'embedded'):
+ client = "mysqld"
+ else:
+ client = "mysqlclient"
+
+ library_dirs = [ os.path.join(connector, r'lib\opt') ]
+ libraries = [ 'kernel32', 'advapi32', 'wsock32', client ]
+ include_dirs = [ os.path.join(connector, r'include') ]
+ extra_compile_args = [ '/Zl' ]
+
+ name = "MySQL-python"
+ if enabled(options, 'embedded'):
+ name = name + "-embedded"
+ metadata['name'] = name
+
+ define_macros = [
+ ('version_info', metadata['version_info']),
+ ('__version__', metadata['version']),
+ ]
+ create_release_file(metadata)
+ del metadata['version_info']
+ ext_options = dict(
+ name = "_mysql",
+ library_dirs = library_dirs,
+ libraries = libraries,
+ extra_compile_args = extra_compile_args,
+ include_dirs = include_dirs,
+ extra_objects = extra_objects,
+ define_macros = define_macros,
+ )
+ return metadata, ext_options
+
+if __name__ == "__main__":
+ sys.stderr.write("""You shouldn't be running this directly; it is used by setup.py.""")
+
diff --git a/MySQLdb/site.cfg b/MySQLdb/site.cfg
index 2bceb2b..c685fca 100644
--- a/MySQLdb/site.cfg
+++ b/MySQLdb/site.cfg
@@ -1,17 +1,17 @@
-[options]
-# embedded: link against the embedded server library
-# threadsafe: use the threadsafe client
-# static: link against a static library (probably required for embedded)
-
-embedded = False
-threadsafe = True
-static = False
-
-# The path to mysql_config.
-# Only use this if mysql_config is not on your PATH, or you have some weird
-# setup that requires it.
-#mysql_config = /usr/local/bin/mysql_config
-
-# http://stackoverflow.com/questions/1972259/mysql-python-install-problem-using-virtualenv-windows-pip
-# Windows connector libs for MySQL. You need a 32-bit connector for your 32-bit Python build.
+[options]
+# embedded: link against the embedded server library
+# threadsafe: use the threadsafe client
+# static: link against a static library (probably required for embedded)
+
+embedded = False
+threadsafe = True
+static = False
+
+# The path to mysql_config.
+# Only use this if mysql_config is not on your PATH, or you have some weird
+# setup that requires it.
+#mysql_config = /usr/local/bin/mysql_config
+
+# http://stackoverflow.com/questions/1972259/mysql-python-install-problem-using-virtualenv-windows-pip
+# Windows connector libs for MySQL. You need a 32-bit connector for your 32-bit Python build.
connector = C:\Program Files (x86)\MySQL\MySQL Connector C 6.0.2 \ No newline at end of file
diff --git a/MySQLdb/tests/capabilities.py b/MySQLdb/tests/capabilities.py
index 6bb7436..dd302b9 100644
--- a/MySQLdb/tests/capabilities.py
+++ b/MySQLdb/tests/capabilities.py
@@ -1,280 +1,280 @@
-#!/usr/bin/env python -O
-""" Script to test database capabilities and the DB-API interface
- for functionality and memory leaks.
-
- Adapted from a script by M-A Lemburg.
-
-"""
-from time import time
-import array
-import unittest
-
-
-class DatabaseTest(unittest.TestCase):
-
- db_module = None
- connect_args = ()
- connect_kwargs = dict()
- create_table_extra = ''
- rows = 10
- debug = False
-
- def setUp(self):
- import gc
- db = self.db_module.connect(*self.connect_args, **self.connect_kwargs)
- self.connection = db
- self.cursor = db.cursor()
- # TODO: this needs to be re-evaluated for Python 3
- self.BLOBText = ''.join([chr(i) for i in range(256)] * 100);
- self.BLOBUText = u''.join([unichr(i) for i in range(16384)])
- self.BLOBBinary = self.db_module.Binary(''.join([chr(i) for i in range(256)] * 16))
-
- leak_test = True
-
- def tearDown(self):
- if self.leak_test:
- import gc
- del self.cursor
- orphans = gc.collect()
- self.failIf(orphans, "%d orphaned objects found after deleting cursor" % orphans)
-
- del self.connection
- orphans = gc.collect()
- self.failIf(orphans, "%d orphaned objects found after deleting connection" % orphans)
-
- def table_exists(self, name):
- try:
- self.cursor.execute('select * from %s where 1=0' % name)
- except:
- return False
- else:
- return True
-
- def quote_identifier(self, ident):
- return '"%s"' % ident
-
- def new_table_name(self):
- i = id(self.cursor)
- while True:
- name = self.quote_identifier('tb%08x' % i)
- if not self.table_exists(name):
- return name
- i = i + 1
-
- def create_table(self, columndefs):
-
- """ Create a table using a list of column definitions given in
- columndefs.
-
- generator must be a function taking arguments (row_number,
- col_number) returning a suitable data object for insertion
- into the table.
-
- """
- self.table = self.new_table_name()
- self.cursor.execute('CREATE TABLE %s (%s) %s' %
- (self.table,
- ',\n'.join(columndefs),
- self.create_table_extra))
-
- def check_data_integrity(self, columndefs, generator):
- # insert
- self.create_table(columndefs)
- insert_statement = ('INSERT INTO %s VALUES (%s)' %
- (self.table,
- ','.join(['%s'] * len(columndefs))))
- data = [ [ generator(i,j) for j in range(len(columndefs)) ]
- for i in range(self.rows) ]
- self.cursor.executemany(insert_statement, data)
- self.connection.commit()
- # verify
- self.cursor.execute('select * from %s' % self.table)
- l = self.cursor.fetchall()
- self.assertEquals(len(l), self.rows)
- try:
- for i in range(self.rows):
- for j in range(len(columndefs)):
- self.assertEquals(l[i][j], generator(i,j))
- finally:
- if not self.debug:
- self.cursor.execute('drop table %s' % (self.table))
-
- def test_transactions(self):
- columndefs = ( 'col1 INT', 'col2 VARCHAR(255)')
- def generator(row, col):
- if col == 0: return row
- else: return ('%i' % (row%10))*255
- self.create_table(columndefs)
- insert_statement = ('INSERT INTO %s VALUES (%s)' %
- (self.table,
- ','.join(['%s'] * len(columndefs))))
- data = [ [ generator(i,j) for j in range(len(columndefs)) ]
- for i in range(self.rows) ]
- self.cursor.executemany(insert_statement, data)
- # verify
- self.connection.commit()
- self.cursor.execute('select * from %s' % self.table)
- l = self.cursor.fetchall()
- self.assertEquals(len(l), self.rows)
- for i in range(self.rows):
- for j in range(len(columndefs)):
- self.assertEquals(l[i][j], generator(i,j))
- delete_statement = 'delete from %s where col1=%%s' % self.table
- self.cursor.execute(delete_statement, (0,))
- self.cursor.execute('select col1 from %s where col1=%s' % \
- (self.table, 0))
- l = self.cursor.fetchall()
- self.assertFalse(l, "DELETE didn't work")
- self.connection.rollback()
- self.cursor.execute('select col1 from %s where col1=%s' % \
- (self.table, 0))
- l = self.cursor.fetchall()
- self.assertTrue(len(l) == 1, "ROLLBACK didn't work")
- self.cursor.execute('drop table %s' % (self.table))
-
- def test_truncation(self):
- columndefs = ( 'col1 INT', 'col2 VARCHAR(255)')
- def generator(row, col):
- if col == 0: return row
- else: return ('%i' % (row%10))*((255-self.rows/2)+row)
- self.create_table(columndefs)
- insert_statement = ('INSERT INTO %s VALUES (%s)' %
- (self.table,
- ','.join(['%s'] * len(columndefs))))
-
- try:
- self.cursor.execute(insert_statement, (0, '0'*256))
- except self.connection.DataError:
- pass
- else:
- self.fail("Over-long column did not generate warnings/exception with single insert")
-
- self.connection.rollback()
-
- try:
- for i in range(self.rows):
- data = []
- for j in range(len(columndefs)):
- data.append(generator(i,j))
- self.cursor.execute(insert_statement,tuple(data))
- except self.connection.DataError:
- pass
- else:
- self.fail("Over-long columns did not generate warnings/exception with execute()")
-
- self.connection.rollback()
-
- try:
- data = [ [ generator(i,j) for j in range(len(columndefs)) ]
- for i in range(self.rows) ]
- self.cursor.executemany(insert_statement, data)
- except self.connection.DataError:
- pass
- else:
- self.fail("Over-long columns did not generate warnings/exception with executemany()")
-
- self.connection.rollback()
- self.cursor.execute('drop table %s' % (self.table))
-
- def test_CHAR(self):
- # Character data
- def generator(row,col):
- return ('%i' % ((row+col) % 10)) * 255
- self.check_data_integrity(
- ('col1 char(255)','col2 char(255)'),
- generator)
-
- def test_INT(self):
- # Number data
- def generator(row,col):
- return row*row
- self.check_data_integrity(
- ('col1 INT',),
- generator)
-
- def test_DECIMAL(self):
- # DECIMAL
- def generator(row,col):
- from decimal import Decimal
- return Decimal("%d.%02d" % (row, col))
- self.check_data_integrity(
- ('col1 DECIMAL(5,2)',),
- generator)
-
- def test_DATE(self):
- ticks = time()
- def generator(row,col):
- return self.db_module.DateFromTicks(ticks+row*86400-col*1313)
- self.check_data_integrity(
- ('col1 DATE',),
- generator)
-
- def test_TIME(self):
- ticks = time()
- def generator(row,col):
- return self.db_module.TimeFromTicks(ticks+row*86400-col*1313)
- self.check_data_integrity(
- ('col1 TIME',),
- generator)
-
- def test_DATETIME(self):
- ticks = time()
- def generator(row,col):
- return self.db_module.TimestampFromTicks(ticks+row*86400-col*1313)
- self.check_data_integrity(
- ('col1 DATETIME',),
- generator)
-
- def test_TIMESTAMP(self):
- ticks = time()
- def generator(row,col):
- return self.db_module.TimestampFromTicks(ticks+row*86400-col*1313)
- self.check_data_integrity(
- ('col1 TIMESTAMP',),
- generator)
-
- def test_fractional_TIMESTAMP(self):
- ticks = time()
- def generator(row,col):
- return self.db_module.TimestampFromTicks(ticks+row*86400-col*1313+row*0.7*col/3.0)
- self.check_data_integrity(
- ('col1 TIMESTAMP',),
- generator)
-
- def test_LONG(self):
- def generator(row,col):
- if col == 0:
- return row
- else:
- return self.BLOBUText # 'BLOB Text ' * 1024
- self.check_data_integrity(
- ('col1 INT','col2 LONG'),
- generator)
-
- def test_TEXT(self):
- def generator(row,col):
- return self.BLOBUText # 'BLOB Text ' * 1024
- self.check_data_integrity(
- ('col2 TEXT',),
- generator)
-
- def test_LONG_BYTE(self):
- def generator(row,col):
- if col == 0:
- return row
- else:
- return self.BLOBBinary # 'BLOB\000Binary ' * 1024
- self.check_data_integrity(
- ('col1 INT','col2 LONG BYTE'),
- generator)
-
- def test_BLOB(self):
- def generator(row,col):
- if col == 0:
- return row
- else:
- return self.BLOBBinary # 'BLOB\000Binary ' * 1024
- self.check_data_integrity(
- ('col1 INT','col2 BLOB'),
- generator)
-
+#!/usr/bin/env python -O
+""" Script to test database capabilities and the DB-API interface
+ for functionality and memory leaks.
+
+ Adapted from a script by M-A Lemburg.
+
+"""
+from time import time
+import array
+import unittest
+
+
+class DatabaseTest(unittest.TestCase):
+
+ db_module = None
+ connect_args = ()
+ connect_kwargs = dict()
+ create_table_extra = ''
+ rows = 10
+ debug = False
+
+ def setUp(self):
+ import gc
+ db = self.db_module.connect(*self.connect_args, **self.connect_kwargs)
+ self.connection = db
+ self.cursor = db.cursor()
+ # TODO: this needs to be re-evaluated for Python 3
+ self.BLOBText = ''.join([chr(i) for i in range(256)] * 100);
+ self.BLOBUText = u''.join([unichr(i) for i in range(16384)])
+ self.BLOBBinary = self.db_module.Binary(''.join([chr(i) for i in range(256)] * 16))
+
+ leak_test = True
+
+ def tearDown(self):
+ if self.leak_test:
+ import gc
+ del self.cursor
+ orphans = gc.collect()
+ self.failIf(orphans, "%d orphaned objects found after deleting cursor" % orphans)
+
+ del self.connection
+ orphans = gc.collect()
+ self.failIf(orphans, "%d orphaned objects found after deleting connection" % orphans)
+
+ def table_exists(self, name):
+ try:
+ self.cursor.execute('select * from %s where 1=0' % name)
+ except:
+ return False
+ else:
+ return True
+
+ def quote_identifier(self, ident):
+ return '"%s"' % ident
+
+ def new_table_name(self):
+ i = id(self.cursor)
+ while True:
+ name = self.quote_identifier('tb%08x' % i)
+ if not self.table_exists(name):
+ return name
+ i = i + 1
+
+ def create_table(self, columndefs):
+
+ """ Create a table using a list of column definitions given in
+ columndefs.
+
+ generator must be a function taking arguments (row_number,
+ col_number) returning a suitable data object for insertion
+ into the table.
+
+ """
+ self.table = self.new_table_name()
+ self.cursor.execute('CREATE TABLE %s (%s) %s' %
+ (self.table,
+ ',\n'.join(columndefs),
+ self.create_table_extra))
+
+ def check_data_integrity(self, columndefs, generator):
+ # insert
+ self.create_table(columndefs)
+ insert_statement = ('INSERT INTO %s VALUES (%s)' %
+ (self.table,
+ ','.join(['%s'] * len(columndefs))))
+ data = [ [ generator(i,j) for j in range(len(columndefs)) ]
+ for i in range(self.rows) ]
+ self.cursor.executemany(insert_statement, data)
+ self.connection.commit()
+ # verify
+ self.cursor.execute('select * from %s' % self.table)
+ l = self.cursor.fetchall()
+ self.assertEquals(len(l), self.rows)
+ try:
+ for i in range(self.rows):
+ for j in range(len(columndefs)):
+ self.assertEquals(l[i][j], generator(i,j))
+ finally:
+ if not self.debug:
+ self.cursor.execute('drop table %s' % (self.table))
+
+ def test_transactions(self):
+ columndefs = ( 'col1 INT', 'col2 VARCHAR(255)')
+ def generator(row, col):
+ if col == 0: return row
+ else: return ('%i' % (row%10))*255
+ self.create_table(columndefs)
+ insert_statement = ('INSERT INTO %s VALUES (%s)' %
+ (self.table,
+ ','.join(['%s'] * len(columndefs))))
+ data = [ [ generator(i,j) for j in range(len(columndefs)) ]
+ for i in range(self.rows) ]
+ self.cursor.executemany(insert_statement, data)
+ # verify
+ self.connection.commit()
+ self.cursor.execute('select * from %s' % self.table)
+ l = self.cursor.fetchall()
+ self.assertEquals(len(l), self.rows)
+ for i in range(self.rows):
+ for j in range(len(columndefs)):
+ self.assertEquals(l[i][j], generator(i,j))
+ delete_statement = 'delete from %s where col1=%%s' % self.table
+ self.cursor.execute(delete_statement, (0,))
+ self.cursor.execute('select col1 from %s where col1=%s' % \
+ (self.table, 0))
+ l = self.cursor.fetchall()
+ self.assertFalse(l, "DELETE didn't work")
+ self.connection.rollback()
+ self.cursor.execute('select col1 from %s where col1=%s' % \
+ (self.table, 0))
+ l = self.cursor.fetchall()
+ self.assertTrue(len(l) == 1, "ROLLBACK didn't work")
+ self.cursor.execute('drop table %s' % (self.table))
+
+ def test_truncation(self):
+ columndefs = ( 'col1 INT', 'col2 VARCHAR(255)')
+ def generator(row, col):
+ if col == 0: return row
+ else: return ('%i' % (row%10))*((255-self.rows/2)+row)
+ self.create_table(columndefs)
+ insert_statement = ('INSERT INTO %s VALUES (%s)' %
+ (self.table,
+ ','.join(['%s'] * len(columndefs))))
+
+ try:
+ self.cursor.execute(insert_statement, (0, '0'*256))
+ except self.connection.DataError:
+ pass
+ else:
+ self.fail("Over-long column did not generate warnings/exception with single insert")
+
+ self.connection.rollback()
+
+ try:
+ for i in range(self.rows):
+ data = []
+ for j in range(len(columndefs)):
+ data.append(generator(i,j))
+ self.cursor.execute(insert_statement,tuple(data))
+ except self.connection.DataError:
+ pass
+ else:
+ self.fail("Over-long columns did not generate warnings/exception with execute()")
+
+ self.connection.rollback()
+
+ try:
+ data = [ [ generator(i,j) for j in range(len(columndefs)) ]
+ for i in range(self.rows) ]
+ self.cursor.executemany(insert_statement, data)
+ except self.connection.DataError:
+ pass
+ else:
+ self.fail("Over-long columns did not generate warnings/exception with executemany()")
+
+ self.connection.rollback()
+ self.cursor.execute('drop table %s' % (self.table))
+
+ def test_CHAR(self):
+ # Character data
+ def generator(row,col):
+ return ('%i' % ((row+col) % 10)) * 255
+ self.check_data_integrity(
+ ('col1 char(255)','col2 char(255)'),
+ generator)
+
+ def test_INT(self):
+ # Number data
+ def generator(row,col):
+ return row*row
+ self.check_data_integrity(
+ ('col1 INT',),
+ generator)
+
+ def test_DECIMAL(self):
+ # DECIMAL
+ def generator(row,col):
+ from decimal import Decimal
+ return Decimal("%d.%02d" % (row, col))
+ self.check_data_integrity(
+ ('col1 DECIMAL(5,2)',),
+ generator)
+
+ def test_DATE(self):
+ ticks = time()
+ def generator(row,col):
+ return self.db_module.DateFromTicks(ticks+row*86400-col*1313)
+ self.check_data_integrity(
+ ('col1 DATE',),
+ generator)
+
+ def test_TIME(self):
+ ticks = time()
+ def generator(row,col):
+ return self.db_module.TimeFromTicks(ticks+row*86400-col*1313)
+ self.check_data_integrity(
+ ('col1 TIME',),
+ generator)
+
+ def test_DATETIME(self):
+ ticks = time()
+ def generator(row,col):
+ return self.db_module.TimestampFromTicks(ticks+row*86400-col*1313)
+ self.check_data_integrity(
+ ('col1 DATETIME',),
+ generator)
+
+ def test_TIMESTAMP(self):
+ ticks = time()
+ def generator(row,col):
+ return self.db_module.TimestampFromTicks(ticks+row*86400-col*1313)
+ self.check_data_integrity(
+ ('col1 TIMESTAMP',),
+ generator)
+
+ def test_fractional_TIMESTAMP(self):
+ ticks = time()
+ def generator(row,col):
+ return self.db_module.TimestampFromTicks(ticks+row*86400-col*1313+row*0.7*col/3.0)
+ self.check_data_integrity(
+ ('col1 TIMESTAMP',),
+ generator)
+
+ def test_LONG(self):
+ def generator(row,col):
+ if col == 0:
+ return row
+ else:
+ return self.BLOBUText # 'BLOB Text ' * 1024
+ self.check_data_integrity(
+ ('col1 INT','col2 LONG'),
+ generator)
+
+ def test_TEXT(self):
+ def generator(row,col):
+ return self.BLOBUText # 'BLOB Text ' * 1024
+ self.check_data_integrity(
+ ('col2 TEXT',),
+ generator)
+
+ def test_LONG_BYTE(self):
+ def generator(row,col):
+ if col == 0:
+ return row
+ else:
+ return self.BLOBBinary # 'BLOB\000Binary ' * 1024
+ self.check_data_integrity(
+ ('col1 INT','col2 LONG BYTE'),
+ generator)
+
+ def test_BLOB(self):
+ def generator(row,col):
+ if col == 0:
+ return row
+ else:
+ return self.BLOBBinary # 'BLOB\000Binary ' * 1024
+ self.check_data_integrity(
+ ('col1 INT','col2 BLOB'),
+ generator)
+
diff --git a/MySQLdb/tests/dbapi20.py b/MySQLdb/tests/dbapi20.py
index ad292ae..9851908 100644
--- a/MySQLdb/tests/dbapi20.py
+++ b/MySQLdb/tests/dbapi20.py
@@ -1,853 +1,853 @@
-#!/usr/bin/env python
-''' Python DB API 2.0 driver compliance unit test suite.
-
- This software is Public Domain and may be used without restrictions.
-
- "Now we have booze and barflies entering the discussion, plus rumours of
- DBAs on drugs... and I won't tell you what flashes through my mind each
- time I read the subject line with 'Anal Compliance' in it. All around
- this is turning out to be a thoroughly unwholesome unit test."
-
- -- Ian Bicking
-'''
-
-__rcs_id__ = '$Id$'
-__version__ = '$Revision$'[11:-2]
-__author__ = 'Stuart Bishop <zen@shangri-la.dropbear.id.au>'
-
-import unittest
-import time
-
-# $Log$
-# Revision 1.1.2.1 2006/02/25 03:44:32 adustman
-# Generic DB-API unit test module
-#
-# Revision 1.10 2003/10/09 03:14:14 zenzen
-# Add test for DB API 2.0 optional extension, where database exceptions
-# are exposed as attributes on the Connection object.
-#
-# Revision 1.9 2003/08/13 01:16:36 zenzen
-# Minor tweak from Stefan Fleiter
-#
-# Revision 1.8 2003/04/10 00:13:25 zenzen
-# Changes, as per suggestions by M.-A. Lemburg
-# - Add a table prefix, to ensure namespace collisions can always be avoided
-#
-# Revision 1.7 2003/02/26 23:33:37 zenzen
-# Break out DDL into helper functions, as per request by David Rushby
-#
-# Revision 1.6 2003/02/21 03:04:33 zenzen
-# Stuff from Henrik Ekelund:
-# added test_None
-# added test_nextset & hooks
-#
-# Revision 1.5 2003/02/17 22:08:43 zenzen
-# Implement suggestions and code from Henrik Eklund - test that cursor.arraysize
-# defaults to 1 & generic cursor.callproc test added
-#
-# Revision 1.4 2003/02/15 00:16:33 zenzen
-# Changes, as per suggestions and bug reports by M.-A. Lemburg,
-# Matthew T. Kromer, Federico Di Gregorio and Daniel Dittmar
-# - Class renamed
-# - Now a subclass of TestCase, to avoid requiring the driver stub
-# to use multiple inheritance
-# - Reversed the polarity of buggy test in test_description
-# - Test exception heirarchy correctly
-# - self.populate is now self._populate(), so if a driver stub
-# overrides self.ddl1 this change propogates
-# - VARCHAR columns now have a width, which will hopefully make the
-# DDL even more portible (this will be reversed if it causes more problems)
-# - cursor.rowcount being checked after various execute and fetchXXX methods
-# - Check for fetchall and fetchmany returning empty lists after results
-# are exhausted (already checking for empty lists if select retrieved
-# nothing
-# - Fix bugs in test_setoutputsize_basic and test_setinputsizes
-#
-
-class DatabaseAPI20Test(unittest.TestCase):
- ''' Test a database self.driver for DB API 2.0 compatibility.
- This implementation tests Gadfly, but the TestCase
- is structured so that other self.drivers can subclass this
- test case to ensure compiliance with the DB-API. It is
- expected that this TestCase may be expanded in the future
- if ambiguities or edge conditions are discovered.
-
- The 'Optional Extensions' are not yet being tested.
-
- self.drivers should subclass this test, overriding setUp, tearDown,
- self.driver, connect_args and connect_kw_args. Class specification
- should be as follows:
-
- import dbapi20
- class mytest(dbapi20.DatabaseAPI20Test):
- [...]
-
- Don't 'import DatabaseAPI20Test from dbapi20', or you will
- confuse the unit tester - just 'import dbapi20'.
- '''
-
- # The self.driver module. This should be the module where the 'connect'
- # method is to be found
- driver = None
- connect_args = () # List of arguments to pass to connect
- connect_kw_args = {} # Keyword arguments for connect
- table_prefix = 'dbapi20test_' # If you need to specify a prefix for tables
-
- ddl1 = 'create table %sbooze (name varchar(20))' % table_prefix
- ddl2 = 'create table %sbarflys (name varchar(20))' % table_prefix
- xddl1 = 'drop table %sbooze' % table_prefix
- xddl2 = 'drop table %sbarflys' % table_prefix
-
- lowerfunc = 'lower' # Name of stored procedure to convert string->lowercase
-
- # Some drivers may need to override these helpers, for example adding
- # a 'commit' after the execute.
- def executeDDL1(self,cursor):
- cursor.execute(self.ddl1)
-
- def executeDDL2(self,cursor):
- cursor.execute(self.ddl2)
-
- def setUp(self):
- ''' self.drivers should override this method to perform required setup
- if any is necessary, such as creating the database.
- '''
- pass
-
- def tearDown(self):
- ''' self.drivers should override this method to perform required cleanup
- if any is necessary, such as deleting the test database.
- The default drops the tables that may be created.
- '''
- con = self._connect()
- try:
- cur = con.cursor()
- for ddl in (self.xddl1,self.xddl2):
- try:
- cur.execute(ddl)
- con.commit()
- except self.driver.Error:
- # Assume table didn't exist. Other tests will check if
- # execute is busted.
- pass
- finally:
- con.close()
-
- def _connect(self):
- try:
- return self.driver.connect(
- *self.connect_args,**self.connect_kw_args
- )
- except AttributeError:
- self.fail("No connect method found in self.driver module")
-
- def test_connect(self):
- con = self._connect()
- con.close()
-
- def test_apilevel(self):
- try:
- # Must exist
- apilevel = self.driver.apilevel
- # Must equal 2.0
- self.assertEqual(apilevel,'2.0')
- except AttributeError:
- self.fail("Driver doesn't define apilevel")
-
- def test_threadsafety(self):
- try:
- # Must exist
- threadsafety = self.driver.threadsafety
- # Must be a valid value
- self.assertTrue(threadsafety in (0,1,2,3))
- except AttributeError:
- self.fail("Driver doesn't define threadsafety")
-
- def test_paramstyle(self):
- try:
- # Must exist
- paramstyle = self.driver.paramstyle
- # Must be a valid value
- self.assertTrue(paramstyle in (
- 'qmark','numeric','named','format','pyformat'
- ))
- except AttributeError:
- self.fail("Driver doesn't define paramstyle")
-
- def test_Exceptions(self):
- # Make sure required exceptions exist, and are in the
- # defined heirarchy.
- self.assertTrue(issubclass(self.driver.Warning,StandardError))
- self.assertTrue(issubclass(self.driver.Error,StandardError))
- self.assertTrue(
- issubclass(self.driver.InterfaceError,self.driver.Error)
- )
- self.assertTrue(
- issubclass(self.driver.DatabaseError,self.driver.Error)
- )
- self.assertTrue(
- issubclass(self.driver.OperationalError,self.driver.Error)
- )
- self.assertTrue(
- issubclass(self.driver.IntegrityError,self.driver.Error)
- )
- self.assertTrue(
- issubclass(self.driver.InternalError,self.driver.Error)
- )
- self.assertTrue(
- issubclass(self.driver.ProgrammingError,self.driver.Error)
- )
- self.assertTrue(
- issubclass(self.driver.NotSupportedError,self.driver.Error)
- )
-
- def test_ExceptionsAsConnectionAttributes(self):
- # OPTIONAL EXTENSION
- # Test for the optional DB API 2.0 extension, where the exceptions
- # are exposed as attributes on the Connection object
- # I figure this optional extension will be implemented by any
- # driver author who is using this test suite, so it is enabled
- # by default.
- con = self._connect()
- drv = self.driver
- self.assertTrue(con.Warning is drv.Warning)
- self.assertTrue(con.Error is drv.Error)
- self.assertTrue(con.InterfaceError is drv.InterfaceError)
- self.assertTrue(con.DatabaseError is drv.DatabaseError)
- self.assertTrue(con.OperationalError is drv.OperationalError)
- self.assertTrue(con.IntegrityError is drv.IntegrityError)
- self.assertTrue(con.InternalError is drv.InternalError)
- self.assertTrue(con.ProgrammingError is drv.ProgrammingError)
- self.assertTrue(con.NotSupportedError is drv.NotSupportedError)
-
-
- def test_commit(self):
- con = self._connect()
- try:
- # Commit must work, even if it doesn't do anything
- con.commit()
- finally:
- con.close()
-
- def test_rollback(self):
- con = self._connect()
- # If rollback is defined, it should either work or throw
- # the documented exception
- if hasattr(con,'rollback'):
- try:
- con.rollback()
- except self.driver.NotSupportedError:
- pass
-
- def test_cursor(self):
- con = self._connect()
- try:
- cur = con.cursor()
- finally:
- con.close()
-
- def test_cursor_isolation(self):
- con = self._connect()
- try:
- # Make sure cursors created from the same connection have
- # the documented transaction isolation level
- cur1 = con.cursor()
- cur2 = con.cursor()
- self.executeDDL1(cur1)
- cur1.execute("insert into %sbooze values ('Victoria Bitter')" % (
- self.table_prefix
- ))
- cur2.execute("select name from %sbooze" % self.table_prefix)
- booze = cur2.fetchall()
- self.assertEqual(len(booze),1)
- self.assertEqual(len(booze[0]),1)
- self.assertEqual(booze[0][0],'Victoria Bitter')
- finally:
- con.close()
-
- def test_description(self):
- con = self._connect()
- try:
- cur = con.cursor()
- self.executeDDL1(cur)
- self.assertEqual(cur.description,None,
- 'cursor.description should be none after executing a '
- 'statement that can return no rows (such as DDL)'
- )
- cur.execute('select name from %sbooze' % self.table_prefix)
- self.assertEqual(len(cur.description),1,
- 'cursor.description describes too many columns'
- )
- self.assertEqual(len(cur.description[0]),7,
- 'cursor.description[x] tuples must have 7 elements'
- )
- self.assertEqual(cur.description[0][0].lower(),'name',
- 'cursor.description[x][0] must return column name'
- )
- self.assertEqual(cur.description[0][1],self.driver.STRING,
- 'cursor.description[x][1] must return column type. Got %r'
- % cur.description[0][1]
- )
-
- # Make sure self.description gets reset
- self.executeDDL2(cur)
- self.assertEqual(cur.description,None,
- 'cursor.description not being set to None when executing '
- 'no-result statements (eg. DDL)'
- )
- finally:
- con.close()
-
- def test_rowcount(self):
- con = self._connect()
- try:
- cur = con.cursor()
- self.executeDDL1(cur)
- self.assertEqual(cur.rowcount,-1,
- 'cursor.rowcount should be -1 after executing no-result '
- 'statements'
- )
- cur.execute("insert into %sbooze values ('Victoria Bitter')" % (
- self.table_prefix
- ))
- self.assertTrue(cur.rowcount in (-1,1),
- 'cursor.rowcount should == number or rows inserted, or '
- 'set to -1 after executing an insert statement'
- )
- cur.execute("select name from %sbooze" % self.table_prefix)
- self.assertTrue(cur.rowcount in (-1,1),
- 'cursor.rowcount should == number of rows returned, or '
- 'set to -1 after executing a select statement'
- )
- self.executeDDL2(cur)
- self.assertEqual(cur.rowcount,-1,
- 'cursor.rowcount not being reset to -1 after executing '
- 'no-result statements'
- )
- finally:
- con.close()
-
- lower_func = 'lower'
- def test_callproc(self):
- con = self._connect()
- try:
- cur = con.cursor()
- if self.lower_func and hasattr(cur,'callproc'):
- r = cur.callproc(self.lower_func,('FOO',))
- self.assertEqual(len(r),1)
- self.assertEqual(r[0],'FOO')
- r = cur.fetchall()
- self.assertEqual(len(r),1,'callproc produced no result set')
- self.assertEqual(len(r[0]),1,
- 'callproc produced invalid result set'
- )
- self.assertEqual(r[0][0],'foo',
- 'callproc produced invalid results'
- )
- finally:
- con.close()
-
- def test_close(self):
- con = self._connect()
- try:
- cur = con.cursor()
- finally:
- con.close()
-
- # cursor.execute should raise an Error if called after connection
- # closed
- self.assertRaises(self.driver.Error,self.executeDDL1,cur)
-
- # connection.commit should raise an Error if called after connection'
- # closed.'
- self.assertRaises(self.driver.Error,con.commit)
-
- # connection.close should raise an Error if called more than once
- self.assertRaises(self.driver.Error,con.close)
-
- def test_execute(self):
- con = self._connect()
- try:
- cur = con.cursor()
- self._paraminsert(cur)
- finally:
- con.close()
-
- def _paraminsert(self,cur):
- self.executeDDL1(cur)
- cur.execute("insert into %sbooze values ('Victoria Bitter')" % (
- self.table_prefix
- ))
- self.assertTrue(cur.rowcount in (-1,1))
-
- if self.driver.paramstyle == 'qmark':
- cur.execute(
- 'insert into %sbooze values (?)' % self.table_prefix,
- ("Cooper's",)
- )
- elif self.driver.paramstyle == 'numeric':
- cur.execute(
- 'insert into %sbooze values (:1)' % self.table_prefix,
- ("Cooper's",)
- )
- elif self.driver.paramstyle == 'named':
- cur.execute(
- 'insert into %sbooze values (:beer)' % self.table_prefix,
- {'beer':"Cooper's"}
- )
- elif self.driver.paramstyle == 'format':
- cur.execute(
- 'insert into %sbooze values (%%s)' % self.table_prefix,
- ("Cooper's",)
- )
- elif self.driver.paramstyle == 'pyformat':
- cur.execute(
- 'insert into %sbooze values (%%(beer)s)' % self.table_prefix,
- {'beer':"Cooper's"}
- )
- else:
- self.fail('Invalid paramstyle')
- self.assertTrue(cur.rowcount in (-1,1))
-
- cur.execute('select name from %sbooze' % self.table_prefix)
- res = cur.fetchall()
- self.assertEqual(len(res),2,'cursor.fetchall returned too few rows')
- beers = [res[0][0],res[1][0]]
- beers.sort()
- self.assertEqual(beers[0],"Cooper's",
- 'cursor.fetchall retrieved incorrect data, or data inserted '
- 'incorrectly'
- )
- self.assertEqual(beers[1],"Victoria Bitter",
- 'cursor.fetchall retrieved incorrect data, or data inserted '
- 'incorrectly'
- )
-
- def test_executemany(self):
- con = self._connect()
- try:
- cur = con.cursor()
- self.executeDDL1(cur)
- largs = [ ("Cooper's",) , ("Boag's",) ]
- margs = [ {'beer': "Cooper's"}, {'beer': "Boag's"} ]
- if self.driver.paramstyle == 'qmark':
- cur.executemany(
- 'insert into %sbooze values (?)' % self.table_prefix,
- largs
- )
- elif self.driver.paramstyle == 'numeric':
- cur.executemany(
- 'insert into %sbooze values (:1)' % self.table_prefix,
- largs
- )
- elif self.driver.paramstyle == 'named':
- cur.executemany(
- 'insert into %sbooze values (:beer)' % self.table_prefix,
- margs
- )
- elif self.driver.paramstyle == 'format':
- cur.executemany(
- 'insert into %sbooze values (%%s)' % self.table_prefix,
- largs
- )
- elif self.driver.paramstyle == 'pyformat':
- cur.executemany(
- 'insert into %sbooze values (%%(beer)s)' % (
- self.table_prefix
- ),
- margs
- )
- else:
- self.fail('Unknown paramstyle')
- self.assertTrue(cur.rowcount in (-1,2),
- 'insert using cursor.executemany set cursor.rowcount to '
- 'incorrect value %r' % cur.rowcount
- )
- cur.execute('select name from %sbooze' % self.table_prefix)
- res = cur.fetchall()
- self.assertEqual(len(res),2,
- 'cursor.fetchall retrieved incorrect number of rows'
- )
- beers = [res[0][0],res[1][0]]
- beers.sort()
- self.assertEqual(beers[0],"Boag's",'incorrect data retrieved')
- self.assertEqual(beers[1],"Cooper's",'incorrect data retrieved')
- finally:
- con.close()
-
- def test_fetchone(self):
- con = self._connect()
- try:
- cur = con.cursor()
-
- # cursor.fetchone should raise an Error if called before
- # executing a select-type query
- self.assertRaises(self.driver.Error,cur.fetchone)
-
- # cursor.fetchone should raise an Error if called after
- # executing a query that cannnot return rows
- self.executeDDL1(cur)
- self.assertRaises(self.driver.Error,cur.fetchone)
-
- cur.execute('select name from %sbooze' % self.table_prefix)
- self.assertEqual(cur.fetchone(),None,
- 'cursor.fetchone should return None if a query retrieves '
- 'no rows'
- )
- self.assertTrue(cur.rowcount in (-1,0))
-
- # cursor.fetchone should raise an Error if called after
- # executing a query that cannnot return rows
- cur.execute("insert into %sbooze values ('Victoria Bitter')" % (
- self.table_prefix
- ))
- self.assertRaises(self.driver.Error,cur.fetchone)
-
- cur.execute('select name from %sbooze' % self.table_prefix)
- r = cur.fetchone()
- self.assertEqual(len(r),1,
- 'cursor.fetchone should have retrieved a single row'
- )
- self.assertEqual(r[0],'Victoria Bitter',
- 'cursor.fetchone retrieved incorrect data'
- )
- self.assertEqual(cur.fetchone(),None,
- 'cursor.fetchone should return None if no more rows available'
- )
- self.assertTrue(cur.rowcount in (-1,1))
- finally:
- con.close()
-
- samples = [
- 'Carlton Cold',
- 'Carlton Draft',
- 'Mountain Goat',
- 'Redback',
- 'Victoria Bitter',
- 'XXXX'
- ]
-
- def _populate(self):
- ''' Return a list of sql commands to setup the DB for the fetch
- tests.
- '''
- populate = [
- "insert into %sbooze values ('%s')" % (self.table_prefix,s)
- for s in self.samples
- ]
- return populate
-
- def test_fetchmany(self):
- con = self._connect()
- try:
- cur = con.cursor()
-
- # cursor.fetchmany should raise an Error if called without
- #issuing a query
- self.assertRaises(self.driver.Error,cur.fetchmany,4)
-
- self.executeDDL1(cur)
- for sql in self._populate():
- cur.execute(sql)
-
- cur.execute('select name from %sbooze' % self.table_prefix)
- r = cur.fetchmany()
- self.assertEqual(len(r),1,
- 'cursor.fetchmany retrieved incorrect number of rows, '
- 'default of arraysize is one.'
- )
- cur.arraysize=10
- r = cur.fetchmany(3) # Should get 3 rows
- self.assertEqual(len(r),3,
- 'cursor.fetchmany retrieved incorrect number of rows'
- )
- r = cur.fetchmany(4) # Should get 2 more
- self.assertEqual(len(r),2,
- 'cursor.fetchmany retrieved incorrect number of rows'
- )
- r = cur.fetchmany(4) # Should be an empty sequence
- self.assertEqual(len(r),0,
- 'cursor.fetchmany should return an empty sequence after '
- 'results are exhausted'
- )
- self.assertTrue(cur.rowcount in (-1,6))
-
- # Same as above, using cursor.arraysize
- cur.arraysize=4
- cur.execute('select name from %sbooze' % self.table_prefix)
- r = cur.fetchmany() # Should get 4 rows
- self.assertEqual(len(r),4,
- 'cursor.arraysize not being honoured by fetchmany'
- )
- r = cur.fetchmany() # Should get 2 more
- self.assertEqual(len(r),2)
- r = cur.fetchmany() # Should be an empty sequence
- self.assertEqual(len(r),0)
- self.assertTrue(cur.rowcount in (-1,6))
-
- cur.arraysize=6
- cur.execute('select name from %sbooze' % self.table_prefix)
- rows = cur.fetchmany() # Should get all rows
- self.assertTrue(cur.rowcount in (-1,6))
- self.assertEqual(len(rows),6)
- self.assertEqual(len(rows),6)
- rows = [r[0] for r in rows]
- rows.sort()
-
- # Make sure we get the right data back out
- for i in range(0,6):
- self.assertEqual(rows[i],self.samples[i],
- 'incorrect data retrieved by cursor.fetchmany'
- )
-
- rows = cur.fetchmany() # Should return an empty list
- self.assertEqual(len(rows),0,
- 'cursor.fetchmany should return an empty sequence if '
- 'called after the whole result set has been fetched'
- )
- self.assertTrue(cur.rowcount in (-1,6))
-
- self.executeDDL2(cur)
- cur.execute('select name from %sbarflys' % self.table_prefix)
- r = cur.fetchmany() # Should get empty sequence
- self.assertEqual(len(r),0,
- 'cursor.fetchmany should return an empty sequence if '
- 'query retrieved no rows'
- )
- self.assertTrue(cur.rowcount in (-1,0))
-
- finally:
- con.close()
-
- def test_fetchall(self):
- con = self._connect()
- try:
- cur = con.cursor()
- # cursor.fetchall should raise an Error if called
- # without executing a query that may return rows (such
- # as a select)
- self.assertRaises(self.driver.Error, cur.fetchall)
-
- self.executeDDL1(cur)
- for sql in self._populate():
- cur.execute(sql)
-
- # cursor.fetchall should raise an Error if called
- # after executing a a statement that cannot return rows
- self.assertRaises(self.driver.Error,cur.fetchall)
-
- cur.execute('select name from %sbooze' % self.table_prefix)
- rows = cur.fetchall()
- self.assertTrue(cur.rowcount in (-1,len(self.samples)))
- self.assertEqual(len(rows),len(self.samples),
- 'cursor.fetchall did not retrieve all rows'
- )
- rows = [r[0] for r in rows]
- rows.sort()
- for i in range(0,len(self.samples)):
- self.assertEqual(rows[i],self.samples[i],
- 'cursor.fetchall retrieved incorrect rows'
- )
- rows = cur.fetchall()
- self.assertEqual(
- len(rows),0,
- 'cursor.fetchall should return an empty list if called '
- 'after the whole result set has been fetched'
- )
- self.assertTrue(cur.rowcount in (-1,len(self.samples)))
-
- self.executeDDL2(cur)
- cur.execute('select name from %sbarflys' % self.table_prefix)
- rows = cur.fetchall()
- self.assertTrue(cur.rowcount in (-1,0))
- self.assertEqual(len(rows),0,
- 'cursor.fetchall should return an empty list if '
- 'a select query returns no rows'
- )
-
- finally:
- con.close()
-
- def test_mixedfetch(self):
- con = self._connect()
- try:
- cur = con.cursor()
- self.executeDDL1(cur)
- for sql in self._populate():
- cur.execute(sql)
-
- cur.execute('select name from %sbooze' % self.table_prefix)
- rows1 = cur.fetchone()
- rows23 = cur.fetchmany(2)
- rows4 = cur.fetchone()
- rows56 = cur.fetchall()
- self.assertTrue(cur.rowcount in (-1,6))
- self.assertEqual(len(rows23),2,
- 'fetchmany returned incorrect number of rows'
- )
- self.assertEqual(len(rows56),2,
- 'fetchall returned incorrect number of rows'
- )
-
- rows = [rows1[0]]
- rows.extend([rows23[0][0],rows23[1][0]])
- rows.append(rows4[0])
- rows.extend([rows56[0][0],rows56[1][0]])
- rows.sort()
- for i in range(0,len(self.samples)):
- self.assertEqual(rows[i],self.samples[i],
- 'incorrect data retrieved or inserted'
- )
- finally:
- con.close()
-
- def help_nextset_setUp(self,cur):
- ''' Should create a procedure called deleteme
- that returns two result sets, first the
- number of rows in booze then "name from booze"
- '''
- raise NotImplementedError('Helper not implemented')
- #sql="""
- # create procedure deleteme as
- # begin
- # select count(*) from booze
- # select name from booze
- # end
- #"""
- #cur.execute(sql)
-
- def help_nextset_tearDown(self,cur):
- 'If cleaning up is needed after nextSetTest'
- raise NotImplementedError('Helper not implemented')
- #cur.execute("drop procedure deleteme")
-
- def test_nextset(self):
- con = self._connect()
- try:
- cur = con.cursor()
- if not hasattr(cur,'nextset'):
- return
-
- try:
- self.executeDDL1(cur)
- sql=self._populate()
- for sql in self._populate():
- cur.execute(sql)
-
- self.help_nextset_setUp(cur)
-
- cur.callproc('deleteme')
- numberofrows=cur.fetchone()
- assert numberofrows[0]== len(self.samples)
- assert cur.nextset()
- names=cur.fetchall()
- assert len(names) == len(self.samples)
- s=cur.nextset()
- assert s == None,'No more return sets, should return None'
- finally:
- self.help_nextset_tearDown(cur)
-
- finally:
- con.close()
-
- def test_nextset(self):
- raise NotImplementedError('Drivers need to override this test')
-
- def test_arraysize(self):
- # Not much here - rest of the tests for this are in test_fetchmany
- con = self._connect()
- try:
- cur = con.cursor()
- self.assertTrue(hasattr(cur,'arraysize'),
- 'cursor.arraysize must be defined'
- )
- finally:
- con.close()
-
- def test_setinputsizes(self):
- con = self._connect()
- try:
- cur = con.cursor()
- cur.setinputsizes( (25,) )
- self._paraminsert(cur) # Make sure cursor still works
- finally:
- con.close()
-
- def test_setoutputsize_basic(self):
- # Basic test is to make sure setoutputsize doesn't blow up
- con = self._connect()
- try:
- cur = con.cursor()
- cur.setoutputsize(1000)
- cur.setoutputsize(2000,0)
- self._paraminsert(cur) # Make sure the cursor still works
- finally:
- con.close()
-
- def test_setoutputsize(self):
- # Real test for setoutputsize is driver dependant
- raise NotImplementedError('Driver need to override this test')
-
- def test_None(self):
- con = self._connect()
- try:
- cur = con.cursor()
- self.executeDDL1(cur)
- cur.execute('insert into %sbooze values (NULL)' % self.table_prefix)
- cur.execute('select name from %sbooze' % self.table_prefix)
- r = cur.fetchall()
- self.assertEqual(len(r),1)
- self.assertEqual(len(r[0]),1)
- self.assertEqual(r[0][0],None,'NULL value not returned as None')
- finally:
- con.close()
-
- def test_Date(self):
- d1 = self.driver.Date(2002,12,25)
- d2 = self.driver.DateFromTicks(time.mktime((2002,12,25,0,0,0,0,0,0)))
- # Can we assume this? API doesn't specify, but it seems implied
- # self.assertEqual(str(d1),str(d2))
-
- def test_Time(self):
- t1 = self.driver.Time(13,45,30)
- t2 = self.driver.TimeFromTicks(time.mktime((2001,1,1,13,45,30,0,0,0)))
- # Can we assume this? API doesn't specify, but it seems implied
- # self.assertEqual(str(t1),str(t2))
-
- def test_Timestamp(self):
- t1 = self.driver.Timestamp(2002,12,25,13,45,30)
- t2 = self.driver.TimestampFromTicks(
- time.mktime((2002,12,25,13,45,30,0,0,0))
- )
- # Can we assume this? API doesn't specify, but it seems implied
- # self.assertEqual(str(t1),str(t2))
-
- def test_Binary(self):
- b = self.driver.Binary('Something')
- b = self.driver.Binary('')
-
- def test_STRING(self):
- self.assertTrue(hasattr(self.driver,'STRING'),
- 'module.STRING must be defined'
- )
-
- def test_BINARY(self):
- self.assertTrue(hasattr(self.driver,'BINARY'),
- 'module.BINARY must be defined.'
- )
-
- def test_NUMBER(self):
- self.assertTrue(hasattr(self.driver,'NUMBER'),
- 'module.NUMBER must be defined.'
- )
-
- def test_DATETIME(self):
- self.assertTrue(hasattr(self.driver,'DATETIME'),
- 'module.DATETIME must be defined.'
- )
-
- def test_ROWID(self):
- self.assertTrue(hasattr(self.driver,'ROWID'),
- 'module.ROWID must be defined.'
- )
-
+#!/usr/bin/env python
+''' Python DB API 2.0 driver compliance unit test suite.
+
+ This software is Public Domain and may be used without restrictions.
+
+ "Now we have booze and barflies entering the discussion, plus rumours of
+ DBAs on drugs... and I won't tell you what flashes through my mind each
+ time I read the subject line with 'Anal Compliance' in it. All around
+ this is turning out to be a thoroughly unwholesome unit test."
+
+ -- Ian Bicking
+'''
+
+__rcs_id__ = '$Id$'
+__version__ = '$Revision$'[11:-2]
+__author__ = 'Stuart Bishop <zen@shangri-la.dropbear.id.au>'
+
+import unittest
+import time
+
+# $Log$
+# Revision 1.1.2.1 2006/02/25 03:44:32 adustman
+# Generic DB-API unit test module
+#
+# Revision 1.10 2003/10/09 03:14:14 zenzen
+# Add test for DB API 2.0 optional extension, where database exceptions
+# are exposed as attributes on the Connection object.
+#
+# Revision 1.9 2003/08/13 01:16:36 zenzen
+# Minor tweak from Stefan Fleiter
+#
+# Revision 1.8 2003/04/10 00:13:25 zenzen
+# Changes, as per suggestions by M.-A. Lemburg
+# - Add a table prefix, to ensure namespace collisions can always be avoided
+#
+# Revision 1.7 2003/02/26 23:33:37 zenzen
+# Break out DDL into helper functions, as per request by David Rushby
+#
+# Revision 1.6 2003/02/21 03:04:33 zenzen
+# Stuff from Henrik Ekelund:
+# added test_None
+# added test_nextset & hooks
+#
+# Revision 1.5 2003/02/17 22:08:43 zenzen
+# Implement suggestions and code from Henrik Eklund - test that cursor.arraysize
+# defaults to 1 & generic cursor.callproc test added
+#
+# Revision 1.4 2003/02/15 00:16:33 zenzen
+# Changes, as per suggestions and bug reports by M.-A. Lemburg,
+# Matthew T. Kromer, Federico Di Gregorio and Daniel Dittmar
+# - Class renamed
+# - Now a subclass of TestCase, to avoid requiring the driver stub
+# to use multiple inheritance
+# - Reversed the polarity of buggy test in test_description
+# - Test exception heirarchy correctly
+# - self.populate is now self._populate(), so if a driver stub
+# overrides self.ddl1 this change propogates
+# - VARCHAR columns now have a width, which will hopefully make the
+# DDL even more portible (this will be reversed if it causes more problems)
+# - cursor.rowcount being checked after various execute and fetchXXX methods
+# - Check for fetchall and fetchmany returning empty lists after results
+# are exhausted (already checking for empty lists if select retrieved
+# nothing
+# - Fix bugs in test_setoutputsize_basic and test_setinputsizes
+#
+
+class DatabaseAPI20Test(unittest.TestCase):
+ ''' Test a database self.driver for DB API 2.0 compatibility.
+ This implementation tests Gadfly, but the TestCase
+ is structured so that other self.drivers can subclass this
+ test case to ensure compiliance with the DB-API. It is
+ expected that this TestCase may be expanded in the future
+ if ambiguities or edge conditions are discovered.
+
+ The 'Optional Extensions' are not yet being tested.
+
+ self.drivers should subclass this test, overriding setUp, tearDown,
+ self.driver, connect_args and connect_kw_args. Class specification
+ should be as follows:
+
+ import dbapi20
+ class mytest(dbapi20.DatabaseAPI20Test):
+ [...]
+
+ Don't 'import DatabaseAPI20Test from dbapi20', or you will
+ confuse the unit tester - just 'import dbapi20'.
+ '''
+
+ # The self.driver module. This should be the module where the 'connect'
+ # method is to be found
+ driver = None
+ connect_args = () # List of arguments to pass to connect
+ connect_kw_args = {} # Keyword arguments for connect
+ table_prefix = 'dbapi20test_' # If you need to specify a prefix for tables
+
+ ddl1 = 'create table %sbooze (name varchar(20))' % table_prefix
+ ddl2 = 'create table %sbarflys (name varchar(20))' % table_prefix
+ xddl1 = 'drop table %sbooze' % table_prefix
+ xddl2 = 'drop table %sbarflys' % table_prefix
+
+ lowerfunc = 'lower' # Name of stored procedure to convert string->lowercase
+
+ # Some drivers may need to override these helpers, for example adding
+ # a 'commit' after the execute.
+ def executeDDL1(self,cursor):
+ cursor.execute(self.ddl1)
+
+ def executeDDL2(self,cursor):
+ cursor.execute(self.ddl2)
+
+ def setUp(self):
+ ''' self.drivers should override this method to perform required setup
+ if any is necessary, such as creating the database.
+ '''
+ pass
+
+ def tearDown(self):
+ ''' self.drivers should override this method to perform required cleanup
+ if any is necessary, such as deleting the test database.
+ The default drops the tables that may be created.
+ '''
+ con = self._connect()
+ try:
+ cur = con.cursor()
+ for ddl in (self.xddl1,self.xddl2):
+ try:
+ cur.execute(ddl)
+ con.commit()
+ except self.driver.Error:
+ # Assume table didn't exist. Other tests will check if
+ # execute is busted.
+ pass
+ finally:
+ con.close()
+
+ def _connect(self):
+ try:
+ return self.driver.connect(
+ *self.connect_args,**self.connect_kw_args
+ )
+ except AttributeError:
+ self.fail("No connect method found in self.driver module")
+
+ def test_connect(self):
+ con = self._connect()
+ con.close()
+
+ def test_apilevel(self):
+ try:
+ # Must exist
+ apilevel = self.driver.apilevel
+ # Must equal 2.0
+ self.assertEqual(apilevel,'2.0')
+ except AttributeError:
+ self.fail("Driver doesn't define apilevel")
+
+ def test_threadsafety(self):
+ try:
+ # Must exist
+ threadsafety = self.driver.threadsafety
+ # Must be a valid value
+ self.assertTrue(threadsafety in (0,1,2,3))
+ except AttributeError:
+ self.fail("Driver doesn't define threadsafety")
+
+ def test_paramstyle(self):
+ try:
+ # Must exist
+ paramstyle = self.driver.paramstyle
+ # Must be a valid value
+ self.assertTrue(paramstyle in (
+ 'qmark','numeric','named','format','pyformat'
+ ))
+ except AttributeError:
+ self.fail("Driver doesn't define paramstyle")
+
+ def test_Exceptions(self):
+ # Make sure required exceptions exist, and are in the
+ # defined heirarchy.
+ self.assertTrue(issubclass(self.driver.Warning,StandardError))
+ self.assertTrue(issubclass(self.driver.Error,StandardError))
+ self.assertTrue(
+ issubclass(self.driver.InterfaceError,self.driver.Error)
+ )
+ self.assertTrue(
+ issubclass(self.driver.DatabaseError,self.driver.Error)
+ )
+ self.assertTrue(
+ issubclass(self.driver.OperationalError,self.driver.Error)
+ )
+ self.assertTrue(
+ issubclass(self.driver.IntegrityError,self.driver.Error)
+ )
+ self.assertTrue(
+ issubclass(self.driver.InternalError,self.driver.Error)
+ )
+ self.assertTrue(
+ issubclass(self.driver.ProgrammingError,self.driver.Error)
+ )
+ self.assertTrue(
+ issubclass(self.driver.NotSupportedError,self.driver.Error)
+ )
+
+ def test_ExceptionsAsConnectionAttributes(self):
+ # OPTIONAL EXTENSION
+ # Test for the optional DB API 2.0 extension, where the exceptions
+ # are exposed as attributes on the Connection object
+ # I figure this optional extension will be implemented by any
+ # driver author who is using this test suite, so it is enabled
+ # by default.
+ con = self._connect()
+ drv = self.driver
+ self.assertTrue(con.Warning is drv.Warning)
+ self.assertTrue(con.Error is drv.Error)
+ self.assertTrue(con.InterfaceError is drv.InterfaceError)
+ self.assertTrue(con.DatabaseError is drv.DatabaseError)
+ self.assertTrue(con.OperationalError is drv.OperationalError)
+ self.assertTrue(con.IntegrityError is drv.IntegrityError)
+ self.assertTrue(con.InternalError is drv.InternalError)
+ self.assertTrue(con.ProgrammingError is drv.ProgrammingError)
+ self.assertTrue(con.NotSupportedError is drv.NotSupportedError)
+
+
+ def test_commit(self):
+ con = self._connect()
+ try:
+ # Commit must work, even if it doesn't do anything
+ con.commit()
+ finally:
+ con.close()
+
+ def test_rollback(self):
+ con = self._connect()
+ # If rollback is defined, it should either work or throw
+ # the documented exception
+ if hasattr(con,'rollback'):
+ try:
+ con.rollback()
+ except self.driver.NotSupportedError:
+ pass
+
+ def test_cursor(self):
+ con = self._connect()
+ try:
+ cur = con.cursor()
+ finally:
+ con.close()
+
+ def test_cursor_isolation(self):
+ con = self._connect()
+ try:
+ # Make sure cursors created from the same connection have
+ # the documented transaction isolation level
+ cur1 = con.cursor()
+ cur2 = con.cursor()
+ self.executeDDL1(cur1)
+ cur1.execute("insert into %sbooze values ('Victoria Bitter')" % (
+ self.table_prefix
+ ))
+ cur2.execute("select name from %sbooze" % self.table_prefix)
+ booze = cur2.fetchall()
+ self.assertEqual(len(booze),1)
+ self.assertEqual(len(booze[0]),1)
+ self.assertEqual(booze[0][0],'Victoria Bitter')
+ finally:
+ con.close()
+
+ def test_description(self):
+ con = self._connect()
+ try:
+ cur = con.cursor()
+ self.executeDDL1(cur)
+ self.assertEqual(cur.description,None,
+ 'cursor.description should be none after executing a '
+ 'statement that can return no rows (such as DDL)'
+ )
+ cur.execute('select name from %sbooze' % self.table_prefix)
+ self.assertEqual(len(cur.description),1,
+ 'cursor.description describes too many columns'
+ )
+ self.assertEqual(len(cur.description[0]),7,
+ 'cursor.description[x] tuples must have 7 elements'
+ )
+ self.assertEqual(cur.description[0][0].lower(),'name',
+ 'cursor.description[x][0] must return column name'
+ )
+ self.assertEqual(cur.description[0][1],self.driver.STRING,
+ 'cursor.description[x][1] must return column type. Got %r'
+ % cur.description[0][1]
+ )
+
+ # Make sure self.description gets reset
+ self.executeDDL2(cur)
+ self.assertEqual(cur.description,None,
+ 'cursor.description not being set to None when executing '
+ 'no-result statements (eg. DDL)'
+ )
+ finally:
+ con.close()
+
+ def test_rowcount(self):
+ con = self._connect()
+ try:
+ cur = con.cursor()
+ self.executeDDL1(cur)
+ self.assertEqual(cur.rowcount,-1,
+ 'cursor.rowcount should be -1 after executing no-result '
+ 'statements'
+ )
+ cur.execute("insert into %sbooze values ('Victoria Bitter')" % (
+ self.table_prefix
+ ))
+ self.assertTrue(cur.rowcount in (-1,1),
+ 'cursor.rowcount should == number or rows inserted, or '
+ 'set to -1 after executing an insert statement'
+ )
+ cur.execute("select name from %sbooze" % self.table_prefix)
+ self.assertTrue(cur.rowcount in (-1,1),
+ 'cursor.rowcount should == number of rows returned, or '
+ 'set to -1 after executing a select statement'
+ )
+ self.executeDDL2(cur)
+ self.assertEqual(cur.rowcount,-1,
+ 'cursor.rowcount not being reset to -1 after executing '
+ 'no-result statements'
+ )
+ finally:
+ con.close()
+
+ lower_func = 'lower'
+ def test_callproc(self):
+ con = self._connect()
+ try:
+ cur = con.cursor()
+ if self.lower_func and hasattr(cur,'callproc'):
+ r = cur.callproc(self.lower_func,('FOO',))
+ self.assertEqual(len(r),1)
+ self.assertEqual(r[0],'FOO')
+ r = cur.fetchall()
+ self.assertEqual(len(r),1,'callproc produced no result set')
+ self.assertEqual(len(r[0]),1,
+ 'callproc produced invalid result set'
+ )
+ self.assertEqual(r[0][0],'foo',
+ 'callproc produced invalid results'
+ )
+ finally:
+ con.close()
+
+ def test_close(self):
+ con = self._connect()
+ try:
+ cur = con.cursor()
+ finally:
+ con.close()
+
+ # cursor.execute should raise an Error if called after connection
+ # closed
+ self.assertRaises(self.driver.Error,self.executeDDL1,cur)
+
+ # connection.commit should raise an Error if called after connection'
+ # closed.'
+ self.assertRaises(self.driver.Error,con.commit)
+
+ # connection.close should raise an Error if called more than once
+ self.assertRaises(self.driver.Error,con.close)
+
+ def test_execute(self):
+ con = self._connect()
+ try:
+ cur = con.cursor()
+ self._paraminsert(cur)
+ finally:
+ con.close()
+
+ def _paraminsert(self,cur):
+ self.executeDDL1(cur)
+ cur.execute("insert into %sbooze values ('Victoria Bitter')" % (
+ self.table_prefix
+ ))
+ self.assertTrue(cur.rowcount in (-1,1))
+
+ if self.driver.paramstyle == 'qmark':
+ cur.execute(
+ 'insert into %sbooze values (?)' % self.table_prefix,
+ ("Cooper's",)
+ )
+ elif self.driver.paramstyle == 'numeric':
+ cur.execute(
+ 'insert into %sbooze values (:1)' % self.table_prefix,
+ ("Cooper's",)
+ )
+ elif self.driver.paramstyle == 'named':
+ cur.execute(
+ 'insert into %sbooze values (:beer)' % self.table_prefix,
+ {'beer':"Cooper's"}
+ )
+ elif self.driver.paramstyle == 'format':
+ cur.execute(
+ 'insert into %sbooze values (%%s)' % self.table_prefix,
+ ("Cooper's",)
+ )
+ elif self.driver.paramstyle == 'pyformat':
+ cur.execute(
+ 'insert into %sbooze values (%%(beer)s)' % self.table_prefix,
+ {'beer':"Cooper's"}
+ )
+ else:
+ self.fail('Invalid paramstyle')
+ self.assertTrue(cur.rowcount in (-1,1))
+
+ cur.execute('select name from %sbooze' % self.table_prefix)
+ res = cur.fetchall()
+ self.assertEqual(len(res),2,'cursor.fetchall returned too few rows')
+ beers = [res[0][0],res[1][0]]
+ beers.sort()
+ self.assertEqual(beers[0],"Cooper's",
+ 'cursor.fetchall retrieved incorrect data, or data inserted '
+ 'incorrectly'
+ )
+ self.assertEqual(beers[1],"Victoria Bitter",
+ 'cursor.fetchall retrieved incorrect data, or data inserted '
+ 'incorrectly'
+ )
+
+ def test_executemany(self):
+ con = self._connect()
+ try:
+ cur = con.cursor()
+ self.executeDDL1(cur)
+ largs = [ ("Cooper's",) , ("Boag's",) ]
+ margs = [ {'beer': "Cooper's"}, {'beer': "Boag's"} ]
+ if self.driver.paramstyle == 'qmark':
+ cur.executemany(
+ 'insert into %sbooze values (?)' % self.table_prefix,
+ largs
+ )
+ elif self.driver.paramstyle == 'numeric':
+ cur.executemany(
+ 'insert into %sbooze values (:1)' % self.table_prefix,
+ largs
+ )
+ elif self.driver.paramstyle == 'named':
+ cur.executemany(
+ 'insert into %sbooze values (:beer)' % self.table_prefix,
+ margs
+ )
+ elif self.driver.paramstyle == 'format':
+ cur.executemany(
+ 'insert into %sbooze values (%%s)' % self.table_prefix,
+ largs
+ )
+ elif self.driver.paramstyle == 'pyformat':
+ cur.executemany(
+ 'insert into %sbooze values (%%(beer)s)' % (
+ self.table_prefix
+ ),
+ margs
+ )
+ else:
+ self.fail('Unknown paramstyle')
+ self.assertTrue(cur.rowcount in (-1,2),
+ 'insert using cursor.executemany set cursor.rowcount to '
+ 'incorrect value %r' % cur.rowcount
+ )
+ cur.execute('select name from %sbooze' % self.table_prefix)
+ res = cur.fetchall()
+ self.assertEqual(len(res),2,
+ 'cursor.fetchall retrieved incorrect number of rows'
+ )
+ beers = [res[0][0],res[1][0]]
+ beers.sort()
+ self.assertEqual(beers[0],"Boag's",'incorrect data retrieved')
+ self.assertEqual(beers[1],"Cooper's",'incorrect data retrieved')
+ finally:
+ con.close()
+
+ def test_fetchone(self):
+ con = self._connect()
+ try:
+ cur = con.cursor()
+
+ # cursor.fetchone should raise an Error if called before
+ # executing a select-type query
+ self.assertRaises(self.driver.Error,cur.fetchone)
+
+ # cursor.fetchone should raise an Error if called after
+ # executing a query that cannnot return rows
+ self.executeDDL1(cur)
+ self.assertRaises(self.driver.Error,cur.fetchone)
+
+ cur.execute('select name from %sbooze' % self.table_prefix)
+ self.assertEqual(cur.fetchone(),None,
+ 'cursor.fetchone should return None if a query retrieves '
+ 'no rows'
+ )
+ self.assertTrue(cur.rowcount in (-1,0))
+
+ # cursor.fetchone should raise an Error if called after
+ # executing a query that cannnot return rows
+ cur.execute("insert into %sbooze values ('Victoria Bitter')" % (
+ self.table_prefix
+ ))
+ self.assertRaises(self.driver.Error,cur.fetchone)
+
+ cur.execute('select name from %sbooze' % self.table_prefix)
+ r = cur.fetchone()
+ self.assertEqual(len(r),1,
+ 'cursor.fetchone should have retrieved a single row'
+ )
+ self.assertEqual(r[0],'Victoria Bitter',
+ 'cursor.fetchone retrieved incorrect data'
+ )
+ self.assertEqual(cur.fetchone(),None,
+ 'cursor.fetchone should return None if no more rows available'
+ )
+ self.assertTrue(cur.rowcount in (-1,1))
+ finally:
+ con.close()
+
+ samples = [
+ 'Carlton Cold',
+ 'Carlton Draft',
+ 'Mountain Goat',
+ 'Redback',
+ 'Victoria Bitter',
+ 'XXXX'
+ ]
+
+ def _populate(self):
+ ''' Return a list of sql commands to setup the DB for the fetch
+ tests.
+ '''
+ populate = [
+ "insert into %sbooze values ('%s')" % (self.table_prefix,s)
+ for s in self.samples
+ ]
+ return populate
+
+ def test_fetchmany(self):
+ con = self._connect()
+ try:
+ cur = con.cursor()
+
+ # cursor.fetchmany should raise an Error if called without
+ #issuing a query
+ self.assertRaises(self.driver.Error,cur.fetchmany,4)
+
+ self.executeDDL1(cur)
+ for sql in self._populate():
+ cur.execute(sql)
+
+ cur.execute('select name from %sbooze' % self.table_prefix)
+ r = cur.fetchmany()
+ self.assertEqual(len(r),1,
+ 'cursor.fetchmany retrieved incorrect number of rows, '
+ 'default of arraysize is one.'
+ )
+ cur.arraysize=10
+ r = cur.fetchmany(3) # Should get 3 rows
+ self.assertEqual(len(r),3,
+ 'cursor.fetchmany retrieved incorrect number of rows'
+ )
+ r = cur.fetchmany(4) # Should get 2 more
+ self.assertEqual(len(r),2,
+ 'cursor.fetchmany retrieved incorrect number of rows'
+ )
+ r = cur.fetchmany(4) # Should be an empty sequence
+ self.assertEqual(len(r),0,
+ 'cursor.fetchmany should return an empty sequence after '
+ 'results are exhausted'
+ )
+ self.assertTrue(cur.rowcount in (-1,6))
+
+ # Same as above, using cursor.arraysize
+ cur.arraysize=4
+ cur.execute('select name from %sbooze' % self.table_prefix)
+ r = cur.fetchmany() # Should get 4 rows
+ self.assertEqual(len(r),4,
+ 'cursor.arraysize not being honoured by fetchmany'
+ )
+ r = cur.fetchmany() # Should get 2 more
+ self.assertEqual(len(r),2)
+ r = cur.fetchmany() # Should be an empty sequence
+ self.assertEqual(len(r),0)
+ self.assertTrue(cur.rowcount in (-1,6))
+
+ cur.arraysize=6
+ cur.execute('select name from %sbooze' % self.table_prefix)
+ rows = cur.fetchmany() # Should get all rows
+ self.assertTrue(cur.rowcount in (-1,6))
+ self.assertEqual(len(rows),6)
+ self.assertEqual(len(rows),6)
+ rows = [r[0] for r in rows]
+ rows.sort()
+
+ # Make sure we get the right data back out
+ for i in range(0,6):
+ self.assertEqual(rows[i],self.samples[i],
+ 'incorrect data retrieved by cursor.fetchmany'
+ )
+
+ rows = cur.fetchmany() # Should return an empty list
+ self.assertEqual(len(rows),0,
+ 'cursor.fetchmany should return an empty sequence if '
+ 'called after the whole result set has been fetched'
+ )
+ self.assertTrue(cur.rowcount in (-1,6))
+
+ self.executeDDL2(cur)
+ cur.execute('select name from %sbarflys' % self.table_prefix)
+ r = cur.fetchmany() # Should get empty sequence
+ self.assertEqual(len(r),0,
+ 'cursor.fetchmany should return an empty sequence if '
+ 'query retrieved no rows'
+ )
+ self.assertTrue(cur.rowcount in (-1,0))
+
+ finally:
+ con.close()
+
+ def test_fetchall(self):
+ con = self._connect()
+ try:
+ cur = con.cursor()
+ # cursor.fetchall should raise an Error if called
+ # without executing a query that may return rows (such
+ # as a select)
+ self.assertRaises(self.driver.Error, cur.fetchall)
+
+ self.executeDDL1(cur)
+ for sql in self._populate():
+ cur.execute(sql)
+
+ # cursor.fetchall should raise an Error if called
+ # after executing a a statement that cannot return rows
+ self.assertRaises(self.driver.Error,cur.fetchall)
+
+ cur.execute('select name from %sbooze' % self.table_prefix)
+ rows = cur.fetchall()
+ self.assertTrue(cur.rowcount in (-1,len(self.samples)))
+ self.assertEqual(len(rows),len(self.samples),
+ 'cursor.fetchall did not retrieve all rows'
+ )
+ rows = [r[0] for r in rows]
+ rows.sort()
+ for i in range(0,len(self.samples)):
+ self.assertEqual(rows[i],self.samples[i],
+ 'cursor.fetchall retrieved incorrect rows'
+ )
+ rows = cur.fetchall()
+ self.assertEqual(
+ len(rows),0,
+ 'cursor.fetchall should return an empty list if called '
+ 'after the whole result set has been fetched'
+ )
+ self.assertTrue(cur.rowcount in (-1,len(self.samples)))
+
+ self.executeDDL2(cur)
+ cur.execute('select name from %sbarflys' % self.table_prefix)
+ rows = cur.fetchall()
+ self.assertTrue(cur.rowcount in (-1,0))
+ self.assertEqual(len(rows),0,
+ 'cursor.fetchall should return an empty list if '
+ 'a select query returns no rows'
+ )
+
+ finally:
+ con.close()
+
+ def test_mixedfetch(self):
+ con = self._connect()
+ try:
+ cur = con.cursor()
+ self.executeDDL1(cur)
+ for sql in self._populate():
+ cur.execute(sql)
+
+ cur.execute('select name from %sbooze' % self.table_prefix)
+ rows1 = cur.fetchone()
+ rows23 = cur.fetchmany(2)
+ rows4 = cur.fetchone()
+ rows56 = cur.fetchall()
+ self.assertTrue(cur.rowcount in (-1,6))
+ self.assertEqual(len(rows23),2,
+ 'fetchmany returned incorrect number of rows'
+ )
+ self.assertEqual(len(rows56),2,
+ 'fetchall returned incorrect number of rows'
+ )
+
+ rows = [rows1[0]]
+ rows.extend([rows23[0][0],rows23[1][0]])
+ rows.append(rows4[0])
+ rows.extend([rows56[0][0],rows56[1][0]])
+ rows.sort()
+ for i in range(0,len(self.samples)):
+ self.assertEqual(rows[i],self.samples[i],
+ 'incorrect data retrieved or inserted'
+ )
+ finally:
+ con.close()
+
+ def help_nextset_setUp(self,cur):
+ ''' Should create a procedure called deleteme
+ that returns two result sets, first the
+ number of rows in booze then "name from booze"
+ '''
+ raise NotImplementedError('Helper not implemented')
+ #sql="""
+ # create procedure deleteme as
+ # begin
+ # select count(*) from booze
+ # select name from booze
+ # end
+ #"""
+ #cur.execute(sql)
+
+ def help_nextset_tearDown(self,cur):
+ 'If cleaning up is needed after nextSetTest'
+ raise NotImplementedError('Helper not implemented')
+ #cur.execute("drop procedure deleteme")
+
+ def test_nextset(self):
+ con = self._connect()
+ try:
+ cur = con.cursor()
+ if not hasattr(cur,'nextset'):
+ return
+
+ try:
+ self.executeDDL1(cur)
+ sql=self._populate()
+ for sql in self._populate():
+ cur.execute(sql)
+
+ self.help_nextset_setUp(cur)
+
+ cur.callproc('deleteme')
+ numberofrows=cur.fetchone()
+ assert numberofrows[0]== len(self.samples)
+ assert cur.nextset()
+ names=cur.fetchall()
+ assert len(names) == len(self.samples)
+ s=cur.nextset()
+ assert s == None,'No more return sets, should return None'
+ finally:
+ self.help_nextset_tearDown(cur)
+
+ finally:
+ con.close()
+
+ def test_nextset(self):
+ raise NotImplementedError('Drivers need to override this test')
+
+ def test_arraysize(self):
+ # Not much here - rest of the tests for this are in test_fetchmany
+ con = self._connect()
+ try:
+ cur = con.cursor()
+ self.assertTrue(hasattr(cur,'arraysize'),
+ 'cursor.arraysize must be defined'
+ )
+ finally:
+ con.close()
+
+ def test_setinputsizes(self):
+ con = self._connect()
+ try:
+ cur = con.cursor()
+ cur.setinputsizes( (25,) )
+ self._paraminsert(cur) # Make sure cursor still works
+ finally:
+ con.close()
+
+ def test_setoutputsize_basic(self):
+ # Basic test is to make sure setoutputsize doesn't blow up
+ con = self._connect()
+ try:
+ cur = con.cursor()
+ cur.setoutputsize(1000)
+ cur.setoutputsize(2000,0)
+ self._paraminsert(cur) # Make sure the cursor still works
+ finally:
+ con.close()
+
+ def test_setoutputsize(self):
+ # Real test for setoutputsize is driver dependant
+ raise NotImplementedError('Driver need to override this test')
+
+ def test_None(self):
+ con = self._connect()
+ try:
+ cur = con.cursor()
+ self.executeDDL1(cur)
+ cur.execute('insert into %sbooze values (NULL)' % self.table_prefix)
+ cur.execute('select name from %sbooze' % self.table_prefix)
+ r = cur.fetchall()
+ self.assertEqual(len(r),1)
+ self.assertEqual(len(r[0]),1)
+ self.assertEqual(r[0][0],None,'NULL value not returned as None')
+ finally:
+ con.close()
+
+ def test_Date(self):
+ d1 = self.driver.Date(2002,12,25)
+ d2 = self.driver.DateFromTicks(time.mktime((2002,12,25,0,0,0,0,0,0)))
+ # Can we assume this? API doesn't specify, but it seems implied
+ # self.assertEqual(str(d1),str(d2))
+
+ def test_Time(self):
+ t1 = self.driver.Time(13,45,30)
+ t2 = self.driver.TimeFromTicks(time.mktime((2001,1,1,13,45,30,0,0,0)))
+ # Can we assume this? API doesn't specify, but it seems implied
+ # self.assertEqual(str(t1),str(t2))
+
+ def test_Timestamp(self):
+ t1 = self.driver.Timestamp(2002,12,25,13,45,30)
+ t2 = self.driver.TimestampFromTicks(
+ time.mktime((2002,12,25,13,45,30,0,0,0))
+ )
+ # Can we assume this? API doesn't specify, but it seems implied
+ # self.assertEqual(str(t1),str(t2))
+
+ def test_Binary(self):
+ b = self.driver.Binary('Something')
+ b = self.driver.Binary('')
+
+ def test_STRING(self):
+ self.assertTrue(hasattr(self.driver,'STRING'),
+ 'module.STRING must be defined'
+ )
+
+ def test_BINARY(self):
+ self.assertTrue(hasattr(self.driver,'BINARY'),
+ 'module.BINARY must be defined.'
+ )
+
+ def test_NUMBER(self):
+ self.assertTrue(hasattr(self.driver,'NUMBER'),
+ 'module.NUMBER must be defined.'
+ )
+
+ def test_DATETIME(self):
+ self.assertTrue(hasattr(self.driver,'DATETIME'),
+ 'module.DATETIME must be defined.'
+ )
+
+ def test_ROWID(self):
+ self.assertTrue(hasattr(self.driver,'ROWID'),
+ 'module.ROWID must be defined.'
+ )
+
diff --git a/MySQLdb/tests/test_MySQLdb_capabilities.py b/MySQLdb/tests/test_MySQLdb_capabilities.py
index 98a2371..d973fbe 100644
--- a/MySQLdb/tests/test_MySQLdb_capabilities.py
+++ b/MySQLdb/tests/test_MySQLdb_capabilities.py
@@ -1,103 +1,103 @@
-#!/usr/bin/env python
-import capabilities
-import unittest
-import MySQLdb
-import warnings
-
-warnings.filterwarnings('error')
-
-class test_MySQLdb(capabilities.DatabaseTest):
-
- db_module = MySQLdb
- connect_args = ()
- connect_kwargs = dict(db='test', host="127.0.0.1", user="test", #read_default_file='~/.my.cnf',
- charset='utf8', sql_mode="ANSI,STRICT_TRANS_TABLES,TRADITIONAL")
- create_table_extra = "ENGINE=INNODB CHARACTER SET UTF8"
- leak_test = False
-
- def quote_identifier(self, ident):
- return "`%s`" % ident
-
- def test_TIME(self):
- from datetime import timedelta
- def generator(row,col):
- return timedelta(0, row*8000)
- self.check_data_integrity(
- ('col1 TIME',),
- generator)
-
- def test_TINYINT(self):
- # Number data
- def generator(row,col):
- v = (row*row) % 256
- if v > 127:
- v = v-256
- return v
- self.check_data_integrity(
- ('col1 TINYINT',),
- generator)
-
- def test_stored_procedures(self):
- db = self.connection
- c = self.cursor
- self.create_table(('pos INT', 'tree CHAR(20)'))
- c.executemany("INSERT INTO %s (pos,tree) VALUES (%%s,%%s)" % self.table,
- list(enumerate('ash birch cedar larch pine'.split())))
- db.commit()
-
- c.execute("""
- CREATE PROCEDURE test_sp(IN t VARCHAR(255))
- BEGIN
- SELECT pos FROM %s WHERE tree = t;
- END
- """ % self.table)
- db.commit()
-
- c.callproc('test_sp', ('larch',))
- rows = c.fetchall()
- self.assertEquals(len(rows), 1)
- self.assertEquals(rows[0][0], 3)
- c.nextset()
-
- c.execute("DROP PROCEDURE test_sp")
- c.execute('drop table %s' % (self.table))
-
- def test_small_CHAR(self):
- # Character data
- def generator(row,col):
- i = (row*col+62)%256
- if i == 62: return ''
- if i == 63: return None
- return chr(i)
- self.check_data_integrity(
- ('col1 char(1)','col2 char(1)'),
- generator)
-
- def test_bug_2671682(self):
- from MySQLdb.constants import ER
- try:
- self.cursor.execute("describe some_non_existent_table");
- except self.connection.ProgrammingError as msg:
- self.assertTrue(msg.args[0].args[0] == ER.NO_SUCH_TABLE)
-
- def test_bug_3514287(self):
- c = self.cursor
- try:
- c.execute("""create table bug_3541287 (
- c1 CHAR(10),
- t1 TIMESTAMP)""")
- c.execute("insert into bug_3541287 (c1,t1) values (%s, NOW())",
- ("blah",))
- finally:
- c.execute("drop table if exists bug_3541287")
-
- def test_ping(self):
- self.connection.ping()
-
-
-if __name__ == '__main__':
- if test_MySQLdb.leak_test:
- import gc
- gc.enable()
- gc.set_debug(gc.DEBUG_LEAK)
- unittest.main()
+#!/usr/bin/env python
+import capabilities
+import unittest
+import MySQLdb
+import warnings
+
+warnings.filterwarnings('error')
+
+class test_MySQLdb(capabilities.DatabaseTest):
+
+ db_module = MySQLdb
+ connect_args = ()
+ connect_kwargs = dict(db='test', host="127.0.0.1", user="test", #read_default_file='~/.my.cnf',
+ charset='utf8', sql_mode="ANSI,STRICT_TRANS_TABLES,TRADITIONAL")
+ create_table_extra = "ENGINE=INNODB CHARACTER SET UTF8"
+ leak_test = False
+
+ def quote_identifier(self, ident):
+ return "`%s`" % ident
+
+ def test_TIME(self):
+ from datetime import timedelta
+ def generator(row,col):
+ return timedelta(0, row*8000)
+ self.check_data_integrity(
+ ('col1 TIME',),
+ generator)
+
+ def test_TINYINT(self):
+ # Number data
+ def generator(row,col):
+ v = (row*row) % 256
+ if v > 127:
+ v = v-256
+ return v
+ self.check_data_integrity(
+ ('col1 TINYINT',),
+ generator)
+
+ def test_stored_procedures(self):
+ db = self.connection
+ c = self.cursor
+ self.create_table(('pos INT', 'tree CHAR(20)'))
+ c.executemany("INSERT INTO %s (pos,tree) VALUES (%%s,%%s)" % self.table,
+ list(enumerate('ash birch cedar larch pine'.split())))
+ db.commit()
+
+ c.execute("""
+ CREATE PROCEDURE test_sp(IN t VARCHAR(255))
+ BEGIN
+ SELECT pos FROM %s WHERE tree = t;
+ END
+ """ % self.table)
+ db.commit()
+
+ c.callproc('test_sp', ('larch',))
+ rows = c.fetchall()
+ self.assertEquals(len(rows), 1)
+ self.assertEquals(rows[0][0], 3)
+ c.nextset()
+
+ c.execute("DROP PROCEDURE test_sp")
+ c.execute('drop table %s' % (self.table))
+
+ def test_small_CHAR(self):
+ # Character data
+ def generator(row,col):
+ i = (row*col+62)%256
+ if i == 62: return ''
+ if i == 63: return None
+ return chr(i)
+ self.check_data_integrity(
+ ('col1 char(1)','col2 char(1)'),
+ generator)
+
+ def test_bug_2671682(self):
+ from MySQLdb.constants import ER
+ try:
+ self.cursor.execute("describe some_non_existent_table");
+ except self.connection.ProgrammingError as msg:
+ self.assertTrue(msg.args[0].args[0] == ER.NO_SUCH_TABLE)
+
+ def test_bug_3514287(self):
+ c = self.cursor
+ try:
+ c.execute("""create table bug_3541287 (
+ c1 CHAR(10),
+ t1 TIMESTAMP)""")
+ c.execute("insert into bug_3541287 (c1,t1) values (%s, NOW())",
+ ("blah",))
+ finally:
+ c.execute("drop table if exists bug_3541287")
+
+ def test_ping(self):
+ self.connection.ping()
+
+
+if __name__ == '__main__':
+ if test_MySQLdb.leak_test:
+ import gc
+ gc.enable()
+ gc.set_debug(gc.DEBUG_LEAK)
+ unittest.main()
diff --git a/MySQLdb/tests/test_MySQLdb_dbapi20.py b/MySQLdb/tests/test_MySQLdb_dbapi20.py
index 4f4527a..ecac412 100644
--- a/MySQLdb/tests/test_MySQLdb_dbapi20.py
+++ b/MySQLdb/tests/test_MySQLdb_dbapi20.py
@@ -1,205 +1,205 @@
-#!/usr/bin/env python
-import dbapi20
-import unittest
-import MySQLdb
-
-class test_MySQLdb(dbapi20.DatabaseAPI20Test):
- driver = MySQLdb
- connect_args = ()
- connect_kw_args = dict(db='test',
- host="127.0.0.1",
- user="test", #read_default_file='~/.my.cnf',
- charset='utf8',
- sql_mode="ANSI,STRICT_TRANS_TABLES,TRADITIONAL")
-
- def test_setoutputsize(self): pass
- def test_setoutputsize_basic(self): pass
- def test_nextset(self): pass
-
- """The tests on fetchone and fetchall and rowcount bogusly
- test for an exception if the statement cannot return a
- result set. MySQL always returns a result set; it's just that
- some things return empty result sets."""
-
- def test_fetchall(self):
- con = self._connect()
- try:
- cur = con.cursor()
- # cursor.fetchall should raise an Error if called
- # without executing a query that may return rows (such
- # as a select)
- self.assertRaises(self.driver.Error, cur.fetchall)
-
- self.executeDDL1(cur)
- for sql in self._populate():
- cur.execute(sql)
-
- # cursor.fetchall should raise an Error if called
- # after executing a a statement that cannot return rows
-## self.assertRaises(self.driver.Error,cur.fetchall)
-
- cur.execute('select name from %sbooze' % self.table_prefix)
- rows = cur.fetchall()
- self.assertTrue(cur.rowcount in (-1,len(self.samples)))
- self.assertEqual(len(rows),len(self.samples),
- 'cursor.fetchall did not retrieve all rows'
- )
- rows = [r[0] for r in rows]
- rows.sort()
- for i in range(0,len(self.samples)):
- self.assertEqual(rows[i],self.samples[i],
- 'cursor.fetchall retrieved incorrect rows'
- )
- rows = cur.fetchall()
- self.assertEqual(
- len(rows),0,
- 'cursor.fetchall should return an empty list if called '
- 'after the whole result set has been fetched'
- )
- self.assertTrue(cur.rowcount in (-1,len(self.samples)))
-
- self.executeDDL2(cur)
- cur.execute('select name from %sbarflys' % self.table_prefix)
- rows = cur.fetchall()
- self.assertTrue(cur.rowcount in (-1,0))
- self.assertEqual(len(rows),0,
- 'cursor.fetchall should return an empty list if '
- 'a select query returns no rows'
- )
-
- finally:
- con.close()
-
- def test_fetchone(self):
- con = self._connect()
- try:
- cur = con.cursor()
-
- # cursor.fetchone should raise an Error if called before
- # executing a select-type query
- self.assertRaises(self.driver.Error,cur.fetchone)
-
- # cursor.fetchone should raise an Error if called after
- # executing a query that cannnot return rows
- self.executeDDL1(cur)
-## self.assertRaises(self.driver.Error,cur.fetchone)
-
- cur.execute('select name from %sbooze' % self.table_prefix)
- self.assertEqual(cur.fetchone(),None,
- 'cursor.fetchone should return None if a query retrieves '
- 'no rows'
- )
- self.assertTrue(cur.rowcount in (-1,0))
-
- # cursor.fetchone should raise an Error if called after
- # executing a query that cannnot return rows
- cur.execute("insert into %sbooze values ('Victoria Bitter')" % (
- self.table_prefix
- ))
-## self.assertRaises(self.driver.Error,cur.fetchone)
-
- cur.execute('select name from %sbooze' % self.table_prefix)
- r = cur.fetchone()
- self.assertEqual(len(r),1,
- 'cursor.fetchone should have retrieved a single row'
- )
- self.assertEqual(r[0],'Victoria Bitter',
- 'cursor.fetchone retrieved incorrect data'
- )
-## self.assertEqual(cur.fetchone(),None,
-## 'cursor.fetchone should return None if no more rows available'
-## )
- self.assertTrue(cur.rowcount in (-1,1))
- finally:
- con.close()
-
- # Same complaint as for fetchall and fetchone
- def test_rowcount(self):
- con = self._connect()
- try:
- cur = con.cursor()
- self.executeDDL1(cur)
-## self.assertEqual(cur.rowcount,-1,
-## 'cursor.rowcount should be -1 after executing no-result '
-## 'statements'
-## )
- cur.execute("insert into %sbooze values ('Victoria Bitter')" % (
- self.table_prefix
- ))
-## self.assertTrue(cur.rowcount in (-1,1),
-## 'cursor.rowcount should == number or rows inserted, or '
-## 'set to -1 after executing an insert statement'
-## )
- cur.execute("select name from %sbooze" % self.table_prefix)
- self.assertTrue(cur.rowcount in (-1,1),
- 'cursor.rowcount should == number of rows returned, or '
- 'set to -1 after executing a select statement'
- )
- self.executeDDL2(cur)
-## self.assertEqual(cur.rowcount,-1,
-## 'cursor.rowcount not being reset to -1 after executing '
-## 'no-result statements'
-## )
- finally:
- con.close()
-
- def test_callproc(self):
- pass # performed in test_MySQL_capabilities
-
- def help_nextset_setUp(self,cur):
- ''' Should create a procedure called deleteme
- that returns two result sets, first the
- number of rows in booze then "name from booze"
- '''
- sql="""
- create procedure deleteme()
- begin
- select count(*) from %(tp)sbooze;
- select name from %(tp)sbooze;
- end
- """ % dict(tp=self.table_prefix)
- cur.execute(sql)
-
- def help_nextset_tearDown(self,cur):
- 'If cleaning up is needed after nextSetTest'
- cur.execute("drop procedure deleteme")
-
- def test_nextset(self):
- from warnings import warn
- con = self._connect()
- try:
- cur = con.cursor()
- if not hasattr(cur,'nextset'):
- return
-
- try:
- self.executeDDL1(cur)
- sql=self._populate()
- for sql in self._populate():
- cur.execute(sql)
-
- self.help_nextset_setUp(cur)
-
- cur.callproc('deleteme')
- numberofrows=cur.fetchone()
- assert numberofrows[0]== len(self.samples)
- assert cur.nextset()
- names=cur.fetchall()
- assert len(names) == len(self.samples)
- s=cur.nextset()
- if s:
- empty = cur.fetchall()
- self.assertEquals(len(empty), 0,
- "non-empty result set after other result sets")
- #warn("Incompatibility: MySQL returns an empty result set for the CALL itself",
- # Warning)
- #assert s == None,'No more return sets, should return None'
- finally:
- self.help_nextset_tearDown(cur)
-
- finally:
- con.close()
-
-
-if __name__ == '__main__':
- unittest.main()
+#!/usr/bin/env python
+import dbapi20
+import unittest
+import MySQLdb
+
+class test_MySQLdb(dbapi20.DatabaseAPI20Test):
+ driver = MySQLdb
+ connect_args = ()
+ connect_kw_args = dict(db='test',
+ host="127.0.0.1",
+ user="test", #read_default_file='~/.my.cnf',
+ charset='utf8',
+ sql_mode="ANSI,STRICT_TRANS_TABLES,TRADITIONAL")
+
+ def test_setoutputsize(self): pass
+ def test_setoutputsize_basic(self): pass
+ def test_nextset(self): pass
+
+ """The tests on fetchone and fetchall and rowcount bogusly
+ test for an exception if the statement cannot return a
+ result set. MySQL always returns a result set; it's just that
+ some things return empty result sets."""
+
+ def test_fetchall(self):
+ con = self._connect()
+ try:
+ cur = con.cursor()
+ # cursor.fetchall should raise an Error if called
+ # without executing a query that may return rows (such
+ # as a select)
+ self.assertRaises(self.driver.Error, cur.fetchall)
+
+ self.executeDDL1(cur)
+ for sql in self._populate():
+ cur.execute(sql)
+
+ # cursor.fetchall should raise an Error if called
+ # after executing a a statement that cannot return rows
+## self.assertRaises(self.driver.Error,cur.fetchall)
+
+ cur.execute('select name from %sbooze' % self.table_prefix)
+ rows = cur.fetchall()
+ self.assertTrue(cur.rowcount in (-1,len(self.samples)))
+ self.assertEqual(len(rows),len(self.samples),
+ 'cursor.fetchall did not retrieve all rows'
+ )
+ rows = [r[0] for r in rows]
+ rows.sort()
+ for i in range(0,len(self.samples)):
+ self.assertEqual(rows[i],self.samples[i],
+ 'cursor.fetchall retrieved incorrect rows'
+ )
+ rows = cur.fetchall()
+ self.assertEqual(
+ len(rows),0,
+ 'cursor.fetchall should return an empty list if called '
+ 'after the whole result set has been fetched'
+ )
+ self.assertTrue(cur.rowcount in (-1,len(self.samples)))
+
+ self.executeDDL2(cur)
+ cur.execute('select name from %sbarflys' % self.table_prefix)
+ rows = cur.fetchall()
+ self.assertTrue(cur.rowcount in (-1,0))
+ self.assertEqual(len(rows),0,
+ 'cursor.fetchall should return an empty list if '
+ 'a select query returns no rows'
+ )
+
+ finally:
+ con.close()
+
+ def test_fetchone(self):
+ con = self._connect()
+ try:
+ cur = con.cursor()
+
+ # cursor.fetchone should raise an Error if called before
+ # executing a select-type query
+ self.assertRaises(self.driver.Error,cur.fetchone)
+
+ # cursor.fetchone should raise an Error if called after
+ # executing a query that cannnot return rows
+ self.executeDDL1(cur)
+## self.assertRaises(self.driver.Error,cur.fetchone)
+
+ cur.execute('select name from %sbooze' % self.table_prefix)
+ self.assertEqual(cur.fetchone(),None,
+ 'cursor.fetchone should return None if a query retrieves '
+ 'no rows'
+ )
+ self.assertTrue(cur.rowcount in (-1,0))
+
+ # cursor.fetchone should raise an Error if called after
+ # executing a query that cannnot return rows
+ cur.execute("insert into %sbooze values ('Victoria Bitter')" % (
+ self.table_prefix
+ ))
+## self.assertRaises(self.driver.Error,cur.fetchone)
+
+ cur.execute('select name from %sbooze' % self.table_prefix)
+ r = cur.fetchone()
+ self.assertEqual(len(r),1,
+ 'cursor.fetchone should have retrieved a single row'
+ )
+ self.assertEqual(r[0],'Victoria Bitter',
+ 'cursor.fetchone retrieved incorrect data'
+ )
+## self.assertEqual(cur.fetchone(),None,
+## 'cursor.fetchone should return None if no more rows available'
+## )
+ self.assertTrue(cur.rowcount in (-1,1))
+ finally:
+ con.close()
+
+ # Same complaint as for fetchall and fetchone
+ def test_rowcount(self):
+ con = self._connect()
+ try:
+ cur = con.cursor()
+ self.executeDDL1(cur)
+## self.assertEqual(cur.rowcount,-1,
+## 'cursor.rowcount should be -1 after executing no-result '
+## 'statements'
+## )
+ cur.execute("insert into %sbooze values ('Victoria Bitter')" % (
+ self.table_prefix
+ ))
+## self.assertTrue(cur.rowcount in (-1,1),
+## 'cursor.rowcount should == number or rows inserted, or '
+## 'set to -1 after executing an insert statement'
+## )
+ cur.execute("select name from %sbooze" % self.table_prefix)
+ self.assertTrue(cur.rowcount in (-1,1),
+ 'cursor.rowcount should == number of rows returned, or '
+ 'set to -1 after executing a select statement'
+ )
+ self.executeDDL2(cur)
+## self.assertEqual(cur.rowcount,-1,
+## 'cursor.rowcount not being reset to -1 after executing '
+## 'no-result statements'
+## )
+ finally:
+ con.close()
+
+ def test_callproc(self):
+ pass # performed in test_MySQL_capabilities
+
+ def help_nextset_setUp(self,cur):
+ ''' Should create a procedure called deleteme
+ that returns two result sets, first the
+ number of rows in booze then "name from booze"
+ '''
+ sql="""
+ create procedure deleteme()
+ begin
+ select count(*) from %(tp)sbooze;
+ select name from %(tp)sbooze;
+ end
+ """ % dict(tp=self.table_prefix)
+ cur.execute(sql)
+
+ def help_nextset_tearDown(self,cur):
+ 'If cleaning up is needed after nextSetTest'
+ cur.execute("drop procedure deleteme")
+
+ def test_nextset(self):
+ from warnings import warn
+ con = self._connect()
+ try:
+ cur = con.cursor()
+ if not hasattr(cur,'nextset'):
+ return
+
+ try:
+ self.executeDDL1(cur)
+ sql=self._populate()
+ for sql in self._populate():
+ cur.execute(sql)
+
+ self.help_nextset_setUp(cur)
+
+ cur.callproc('deleteme')
+ numberofrows=cur.fetchone()
+ assert numberofrows[0]== len(self.samples)
+ assert cur.nextset()
+ names=cur.fetchall()
+ assert len(names) == len(self.samples)
+ s=cur.nextset()
+ if s:
+ empty = cur.fetchall()
+ self.assertEquals(len(empty), 0,
+ "non-empty result set after other result sets")
+ #warn("Incompatibility: MySQL returns an empty result set for the CALL itself",
+ # Warning)
+ #assert s == None,'No more return sets, should return None'
+ finally:
+ self.help_nextset_tearDown(cur)
+
+ finally:
+ con.close()
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/MySQLdb/tests/test_MySQLdb_nonstandard.py b/MySQLdb/tests/test_MySQLdb_nonstandard.py
index 150d013..654a88a 100644
--- a/MySQLdb/tests/test_MySQLdb_nonstandard.py
+++ b/MySQLdb/tests/test_MySQLdb_nonstandard.py
@@ -1,85 +1,85 @@
-import unittest
-
-import _mysql
-import MySQLdb
-from MySQLdb.constants import FIELD_TYPE
-
-
-class TestDBAPISet(unittest.TestCase):
- def test_set_equality(self):
- self.assertTrue(MySQLdb.STRING == MySQLdb.STRING)
-
- def test_set_inequality(self):
- self.assertTrue(MySQLdb.STRING != MySQLdb.NUMBER)
-
- def test_set_equality_membership(self):
- self.assertTrue(FIELD_TYPE.VAR_STRING == MySQLdb.STRING)
-
- def test_set_inequality_membership(self):
- self.assertTrue(FIELD_TYPE.DATE != MySQLdb.STRING)
-
-
-class CoreModule(unittest.TestCase):
- """Core _mysql module features."""
-
- def test_NULL(self):
- """Should have a NULL constant."""
- self.assertEqual(_mysql.NULL, 'NULL')
-
- def test_version(self):
- """Version information sanity."""
- self.assertTrue(isinstance(_mysql.__version__, str))
-
- self.assertTrue(isinstance(_mysql.version_info, tuple))
- self.assertEqual(len(_mysql.version_info), 5)
-
- def test_client_info(self):
- self.assertTrue(isinstance(_mysql.get_client_info(), str))
-
- def test_thread_safe(self):
- self.assertTrue(isinstance(_mysql.thread_safe(), int))
-
-
-class CoreAPI(unittest.TestCase):
- """Test _mysql interaction internals."""
-
- def setUp(self):
- self.conn = _mysql.connect(db='test', host='127.0.0.1', user='test') #read_default_file="~/.my.cnf")
-
- def tearDown(self):
- self.conn.close()
-
- def test_thread_id(self):
- tid = self.conn.thread_id()
- self.assertTrue(isinstance(tid, int),
- "thread_id didn't return an int.")
-
- self.assertRaises(TypeError, self.conn.thread_id, ('evil',),
- "thread_id shouldn't accept arguments.")
-
- def test_affected_rows(self):
- self.assertEquals(self.conn.affected_rows(), 0,
- "Should return 0 before we do anything.")
-
-
- #def test_debug(self):
- ## FIXME Only actually tests if you lack SUPER
- #self.assertRaises(MySQLdb.OperationalError,
- #self.conn.dump_debug_info)
-
- def test_charset_name(self):
- self.assertTrue(isinstance(self.conn.character_set_name(), str),
- "Should return a string.")
-
- def test_host_info(self):
- self.assertTrue(isinstance(self.conn.get_host_info(), str),
- "Should return a string.")
-
- def test_proto_info(self):
- self.assertTrue(isinstance(self.conn.get_proto_info(), int),
- "Should return an int.")
-
- def test_server_info(self):
- self.assertTrue(isinstance(self.conn.get_server_info(), str),
- "Should return an str.")
-
+import unittest
+
+import _mysql
+import MySQLdb
+from MySQLdb.constants import FIELD_TYPE
+
+
+class TestDBAPISet(unittest.TestCase):
+ def test_set_equality(self):
+ self.assertTrue(MySQLdb.STRING == MySQLdb.STRING)
+
+ def test_set_inequality(self):
+ self.assertTrue(MySQLdb.STRING != MySQLdb.NUMBER)
+
+ def test_set_equality_membership(self):
+ self.assertTrue(FIELD_TYPE.VAR_STRING == MySQLdb.STRING)
+
+ def test_set_inequality_membership(self):
+ self.assertTrue(FIELD_TYPE.DATE != MySQLdb.STRING)
+
+
+class CoreModule(unittest.TestCase):
+ """Core _mysql module features."""
+
+ def test_NULL(self):
+ """Should have a NULL constant."""
+ self.assertEqual(_mysql.NULL, 'NULL')
+
+ def test_version(self):
+ """Version information sanity."""
+ self.assertTrue(isinstance(_mysql.__version__, str))
+
+ self.assertTrue(isinstance(_mysql.version_info, tuple))
+ self.assertEqual(len(_mysql.version_info), 5)
+
+ def test_client_info(self):
+ self.assertTrue(isinstance(_mysql.get_client_info(), str))
+
+ def test_thread_safe(self):
+ self.assertTrue(isinstance(_mysql.thread_safe(), int))
+
+
+class CoreAPI(unittest.TestCase):
+ """Test _mysql interaction internals."""
+
+ def setUp(self):
+ self.conn = _mysql.connect(db='test', host='127.0.0.1', user='test') #read_default_file="~/.my.cnf")
+
+ def tearDown(self):
+ self.conn.close()
+
+ def test_thread_id(self):
+ tid = self.conn.thread_id()
+ self.assertTrue(isinstance(tid, int),
+ "thread_id didn't return an int.")
+
+ self.assertRaises(TypeError, self.conn.thread_id, ('evil',),
+ "thread_id shouldn't accept arguments.")
+
+ def test_affected_rows(self):
+ self.assertEquals(self.conn.affected_rows(), 0,
+ "Should return 0 before we do anything.")
+
+
+ #def test_debug(self):
+ ## FIXME Only actually tests if you lack SUPER
+ #self.assertRaises(MySQLdb.OperationalError,
+ #self.conn.dump_debug_info)
+
+ def test_charset_name(self):
+ self.assertTrue(isinstance(self.conn.character_set_name(), str),
+ "Should return a string.")
+
+ def test_host_info(self):
+ self.assertTrue(isinstance(self.conn.get_host_info(), str),
+ "Should return a string.")
+
+ def test_proto_info(self):
+ self.assertTrue(isinstance(self.conn.get_proto_info(), int),
+ "Should return an int.")
+
+ def test_server_info(self):
+ self.assertTrue(isinstance(self.conn.get_server_info(), str),
+ "Should return an str.")
+