mirror of
https://github.com/PyMySQL/mysqlclient.git
synced 2025-08-16 03:50:43 +08:00
More major code heaving.
All the threading stuff is ripped out and burned. Too much code for not enough benefit. Still thread-safe, just don't share connections. Made a nice Set class for SET columns. Updated the docs.
This commit is contained in:
@ -20,7 +20,7 @@ version_info = (
|
|||||||
9,
|
9,
|
||||||
0,
|
0,
|
||||||
"beta",
|
"beta",
|
||||||
1)
|
2)
|
||||||
if version_info[3] == "final": __version__ = "%d.%d.%d" % version_info[:3]
|
if version_info[3] == "final": __version__ = "%d.%d.%d" % version_info[:3]
|
||||||
else: __version__ = "%d.%d.%d%1.1s%d" % version_info[:5]
|
else: __version__ = "%d.%d.%d%1.1s%d" % version_info[:5]
|
||||||
|
|
||||||
@ -31,46 +31,28 @@ if __version__ != getattr(_mysql, '__version__', None):
|
|||||||
(__version__, _mysql.__version__)
|
(__version__, _mysql.__version__)
|
||||||
|
|
||||||
|
|
||||||
threadsafety = 2
|
threadsafety = 1
|
||||||
apilevel = "2.0"
|
apilevel = "2.0"
|
||||||
paramstyle = "format"
|
paramstyle = "format"
|
||||||
|
|
||||||
|
|
||||||
class DBAPITypeObject:
|
|
||||||
|
|
||||||
"""Helper class for determining column types; required by DB API."""
|
|
||||||
|
|
||||||
def __init__(self,*values):
|
|
||||||
self.values = values
|
|
||||||
|
|
||||||
def __cmp__(self,other):
|
|
||||||
if other in self.values:
|
|
||||||
return 0
|
|
||||||
if other < self.values:
|
|
||||||
return 1
|
|
||||||
else:
|
|
||||||
return -1
|
|
||||||
|
|
||||||
|
|
||||||
_Set = DBAPITypeObject
|
|
||||||
from constants import FIELD_TYPE
|
|
||||||
|
|
||||||
STRING = _Set(FIELD_TYPE.CHAR, FIELD_TYPE.ENUM, FIELD_TYPE.INTERVAL,
|
|
||||||
FIELD_TYPE.SET, FIELD_TYPE.STRING, FIELD_TYPE.VAR_STRING)
|
|
||||||
BINARY = _Set(FIELD_TYPE.BLOB, FIELD_TYPE.LONG_BLOB, FIELD_TYPE.MEDIUM_BLOB,
|
|
||||||
FIELD_TYPE.TINY_BLOB)
|
|
||||||
NUMBER = _Set(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 = _Set(FIELD_TYPE.DATE, FIELD_TYPE.NEWDATE)
|
|
||||||
TIME = _Set(FIELD_TYPE.TIME)
|
|
||||||
TIMESTAMP = _Set(FIELD_TYPE.TIMESTAMP, FIELD_TYPE.DATETIME)
|
|
||||||
ROWID = _Set()
|
|
||||||
|
|
||||||
def Binary(x): return str(x)
|
|
||||||
|
|
||||||
from _mysql import *
|
from _mysql import *
|
||||||
from connections import Connection
|
from connections import Connection
|
||||||
|
from converters import *
|
||||||
|
from constants import FIELD_TYPE
|
||||||
|
|
||||||
|
STRING = Set(FIELD_TYPE.CHAR, FIELD_TYPE.ENUM, FIELD_TYPE.STRING,
|
||||||
|
FIELD_TYPE.VAR_STRING)
|
||||||
|
BINARY = Set(FIELD_TYPE.BLOB, FIELD_TYPE.LONG_BLOB, FIELD_TYPE.MEDIUM_BLOB,
|
||||||
|
FIELD_TYPE.TINY_BLOB)
|
||||||
|
NUMBER = Set(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 = Set(FIELD_TYPE.DATE, FIELD_TYPE.NEWDATE)
|
||||||
|
TIME = Set(FIELD_TYPE.TIME)
|
||||||
|
TIMESTAMP = Set(FIELD_TYPE.TIMESTAMP, FIELD_TYPE.DATETIME)
|
||||||
|
ROWID = Set()
|
||||||
|
|
||||||
|
def Binary(x): return str(x)
|
||||||
|
|
||||||
def Connect(*args, **kwargs):
|
def Connect(*args, **kwargs):
|
||||||
"""Factory function for connections.Connection."""
|
"""Factory function for connections.Connection."""
|
||||||
@ -78,5 +60,17 @@ def Connect(*args, **kwargs):
|
|||||||
|
|
||||||
connect = Connect
|
connect = Connect
|
||||||
|
|
||||||
__all__ = ['BINARY', 'Binary', 'Connect', 'Connection', 'DATE', 'DataError', 'DatabaseError', 'Error', 'FIELD_TYPE', 'IntegrityError', 'InterfaceError', 'InternalError', 'MySQLError', 'NULL', 'NUMBER', 'NotSupportedError', 'OperationalError', 'ProgrammingError', 'ROWID', 'STRING', 'TIME', 'TIMESTAMP', 'Warning', 'apilevel', 'connect', 'connections', 'constants', 'cursors', 'debug', 'escape', 'escape_dict', 'escape_sequence', 'escape_string', 'get_client_info', 'paramstyle', 'string_literal', 'threadsafety', 'version_info']
|
__all__ = [ 'BINARY', 'Binary', 'Connect', 'Connection', 'DATE',
|
||||||
|
'Date', 'Time', 'Timestamp', 'DateFromTicks', 'TimeFromTicks',
|
||||||
|
'TimestampFromTicks', 'DataError', 'DatabaseError', 'Error',
|
||||||
|
'FIELD_TYPE', 'IntegrityError', 'InterfaceError', 'InternalError',
|
||||||
|
'MySQLError', 'NULL', 'NUMBER', 'NotSupportedError',
|
||||||
|
'OperationalError', 'ProgrammingError', 'ROWID', 'STRING', 'TIME',
|
||||||
|
'TIMESTAMP', 'Set', 'Warning', 'apilevel', 'connect', 'connections',
|
||||||
|
'constants', 'cursors', 'debug', 'escape', 'escape_dict',
|
||||||
|
'escape_sequence', 'escape_string', 'get_client_info',
|
||||||
|
'paramstyle', 'string_literal', 'threadsafety', 'version_info']
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -33,8 +33,6 @@ class Connection:
|
|||||||
read_default_group -- see the MySQL documentation for mysql_options()
|
read_default_group -- see the MySQL documentation for mysql_options()
|
||||||
cursorclass -- class object, used to create cursors or cursors.Cursor.
|
cursorclass -- class object, used to create cursors or cursors.Cursor.
|
||||||
This parameter MUST be specified as a keyword parameter.
|
This parameter MUST be specified as a keyword parameter.
|
||||||
threads -- boolean, if false threading is disabled, otherwise threads
|
|
||||||
are enabled by default. (MUST be a keyword parameter.)
|
|
||||||
|
|
||||||
Returns a Connection object.
|
Returns a Connection object.
|
||||||
|
|
||||||
@ -50,9 +48,6 @@ class Connection:
|
|||||||
from converters import conversions
|
from converters import conversions
|
||||||
import types
|
import types
|
||||||
kwargs2 = kwargs.copy()
|
kwargs2 = kwargs.copy()
|
||||||
self.__threads = kwargs.get('threads',1)
|
|
||||||
if kwargs.has_key('threads'):
|
|
||||||
del kwargs2['threads']
|
|
||||||
if not kwargs.has_key('conv'):
|
if not kwargs.has_key('conv'):
|
||||||
kwargs2['conv'] = conversions.copy()
|
kwargs2['conv'] = conversions.copy()
|
||||||
if kwargs.has_key('cursorclass'):
|
if kwargs.has_key('cursorclass'):
|
||||||
@ -64,69 +59,9 @@ class Connection:
|
|||||||
self._db.converter[types.StringType] = self._db.string_literal
|
self._db.converter[types.StringType] = self._db.string_literal
|
||||||
self._transactional = self._db.server_capabilities & CLIENT.TRANSACTIONS
|
self._transactional = self._db.server_capabilities & CLIENT.TRANSACTIONS
|
||||||
self._autocommit = 1
|
self._autocommit = 1
|
||||||
if self.__threads:
|
|
||||||
# __c_lock: connection lock. Cursors must always obtain the
|
|
||||||
# connection lock before doing any queries. A blocking
|
|
||||||
# call is used. If the same thread tries to acquire the
|
|
||||||
# lock, produce an error.
|
|
||||||
#
|
|
||||||
# _t_lock: transaction lock. If operating transactionally,
|
|
||||||
# Cursors must acquire the transaction lock on the first
|
|
||||||
# query. The same thread may acquire the lock more than
|
|
||||||
# once. commit() or rollback() or an error releases this
|
|
||||||
# lock.
|
|
||||||
import threading
|
|
||||||
self.__c_lock = threading.Lock()
|
|
||||||
self.__c_locker = None
|
|
||||||
self.__t_lock = threading.Lock()
|
|
||||||
self.__t_locker = None
|
|
||||||
|
|
||||||
def __del__(self):
|
def __del__(self):
|
||||||
self.close()
|
if hasattr(self, '_db'): self.close()
|
||||||
|
|
||||||
def _begin(self):
|
|
||||||
"""Obtain the transaction lock. A thread may try to obtain this
|
|
||||||
lock multiple times."""
|
|
||||||
if not self.__threads: return
|
|
||||||
import threading
|
|
||||||
me = threading.currentThread()
|
|
||||||
if self.__t_locker == me: return
|
|
||||||
self.__t_lock.acquire()
|
|
||||||
self.__t_locker = me
|
|
||||||
|
|
||||||
def _end(self):
|
|
||||||
"""Release the transaction lock. If a thread tries to release this
|
|
||||||
lock when it is not currently locking it, it does nothing."""
|
|
||||||
if not self.__threads: return
|
|
||||||
import threading
|
|
||||||
me = threading.currentThread()
|
|
||||||
if self.__t_locker != me: return
|
|
||||||
self.__t_locker = None
|
|
||||||
self.__t_lock.release()
|
|
||||||
|
|
||||||
def _acquire(self):
|
|
||||||
"""Acquire the connection. ProgrammingError is raised if the
|
|
||||||
thread has already acquired the connection."""
|
|
||||||
if not self.__threads: return
|
|
||||||
import threading
|
|
||||||
me = threading.currentThread()
|
|
||||||
if self.__c_locker == me:
|
|
||||||
raise ProgrammingError, "would produce deadlock"
|
|
||||||
self.__c_lock.acquire()
|
|
||||||
self.__c_locker = me
|
|
||||||
|
|
||||||
def _release(self):
|
|
||||||
"""Release the connection. If a thread tries to release this
|
|
||||||
lock when it is not currently locking it, ProgrammingError
|
|
||||||
is raised (this shouldn't happen)."""
|
|
||||||
if not self.__threads: return
|
|
||||||
import threading
|
|
||||||
me = threading.currentThread()
|
|
||||||
if self.__c_locker != me:
|
|
||||||
if not self.__c_locker: return
|
|
||||||
raise ProgrammingError, "tried to release another %s's lock" % self.__c_locker
|
|
||||||
self.__c_locker = None
|
|
||||||
self.__c_lock.release()
|
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
"""Close the connection. No further activity possible."""
|
"""Close the connection. No further activity possible."""
|
||||||
@ -149,7 +84,6 @@ class Connection:
|
|||||||
if self._transactional:
|
if self._transactional:
|
||||||
self._db.query("COMMIT")
|
self._db.query("COMMIT")
|
||||||
finally:
|
finally:
|
||||||
self._end()
|
|
||||||
self._transactional = not self._autocommit
|
self._transactional = not self._autocommit
|
||||||
|
|
||||||
def rollback(self):
|
def rollback(self):
|
||||||
@ -160,7 +94,6 @@ class Connection:
|
|||||||
else:
|
else:
|
||||||
raise NotSupportedError, "Not supported by server"
|
raise NotSupportedError, "Not supported by server"
|
||||||
finally:
|
finally:
|
||||||
self._end()
|
|
||||||
self._transactional = not self._autocommit
|
self._transactional = not self._autocommit
|
||||||
|
|
||||||
def cursor(self, cursorclass=None):
|
def cursor(self, cursorclass=None):
|
||||||
|
@ -27,9 +27,15 @@ MySQL.connect().
|
|||||||
|
|
||||||
from _mysql import string_literal, escape_sequence, escape_dict, escape, NULL
|
from _mysql import string_literal, escape_sequence, escape_dict, escape, NULL
|
||||||
from constants import FIELD_TYPE
|
from constants import FIELD_TYPE
|
||||||
from time import localtime, strftime
|
from data import *
|
||||||
|
from string import split
|
||||||
import types
|
import types
|
||||||
|
|
||||||
|
|
||||||
|
def Str2Set(s):
|
||||||
|
values = split(s, ',')
|
||||||
|
return apply(Set, tuple(values))
|
||||||
|
|
||||||
def Thing2Str(s, d):
|
def Thing2Str(s, d):
|
||||||
"""Convert something into a string via str()."""
|
"""Convert something into a string via str()."""
|
||||||
return str(s)
|
return str(s)
|
||||||
@ -63,8 +69,7 @@ def Instance2Str(o, d):
|
|||||||
converter. If the exact class is not found in d, it will use the
|
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."""
|
first class it can find for which o is an instance."""
|
||||||
|
|
||||||
if d.has_key(o.__class__): return
|
if d.has_key(o.__class__): return d[o.__class__](o, d)
|
||||||
d[o.__class__](o, d)
|
|
||||||
cl = filter(lambda x,o=o:
|
cl = filter(lambda x,o=o:
|
||||||
type(x)==types.ClassType and isinstance(o,x), d.keys())
|
type(x)==types.ClassType and isinstance(o,x), d.keys())
|
||||||
if not cl:
|
if not cl:
|
||||||
@ -82,6 +87,8 @@ conversions = {
|
|||||||
types.DictType: escape_dict,
|
types.DictType: escape_dict,
|
||||||
types.InstanceType: Instance2Str,
|
types.InstanceType: Instance2Str,
|
||||||
types.StringType: Thing2Literal, # default
|
types.StringType: Thing2Literal, # default
|
||||||
|
DateTimeType: DateTime2literal,
|
||||||
|
DateTimeDeltaType: DateTimeDelta2literal,
|
||||||
FIELD_TYPE.TINY: int,
|
FIELD_TYPE.TINY: int,
|
||||||
FIELD_TYPE.SHORT: int,
|
FIELD_TYPE.SHORT: int,
|
||||||
FIELD_TYPE.LONG: long,
|
FIELD_TYPE.LONG: long,
|
||||||
@ -89,99 +96,11 @@ conversions = {
|
|||||||
FIELD_TYPE.DOUBLE: float,
|
FIELD_TYPE.DOUBLE: float,
|
||||||
FIELD_TYPE.LONGLONG: long,
|
FIELD_TYPE.LONGLONG: long,
|
||||||
FIELD_TYPE.INT24: int,
|
FIELD_TYPE.INT24: int,
|
||||||
FIELD_TYPE.YEAR: 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,
|
||||||
}
|
}
|
||||||
|
|
||||||
try:
|
|
||||||
try:
|
|
||||||
# new packaging
|
|
||||||
from mx.DateTime import Date, Time, Timestamp, ISO, \
|
|
||||||
DateTimeType, DateTimeDeltaType
|
|
||||||
except ImportError:
|
|
||||||
# old packaging, deprecated
|
|
||||||
from DateTime import Date, Time, Timestamp, ISO, \
|
|
||||||
DateTimeType, DateTimeDeltaType
|
|
||||||
|
|
||||||
def DateFromTicks(ticks):
|
|
||||||
"""Convert UNIX ticks into a mx.DateTime.Date."""
|
|
||||||
return apply(Date, localtime(ticks)[:3])
|
|
||||||
|
|
||||||
def TimeFromTicks(ticks):
|
|
||||||
"""Convert UNIX ticks into a mx.DateTime.Time."""
|
|
||||||
return apply(Time, localtime(ticks)[3:6])
|
|
||||||
|
|
||||||
def TimestampFromTicks(ticks):
|
|
||||||
"""Convert UNIX ticks into a mx.DateTime.Timestamp."""
|
|
||||||
return apply(Timestamp, localtime(ticks)[:6])
|
|
||||||
|
|
||||||
def format_DATE(d):
|
|
||||||
"""Format a DateTime object as an ISO date."""
|
|
||||||
return d.strftime("%Y-%m-%d")
|
|
||||||
|
|
||||||
def format_TIME(d):
|
|
||||||
"""Format a DateTime object as a time value."""
|
|
||||||
return d.strftime("%H:%M:%S")
|
|
||||||
|
|
||||||
def format_TIMESTAMP(d):
|
|
||||||
"""Format a DateTime object as an ISO timestamp."""
|
|
||||||
return d.strftime("%Y-%m-%d %H:%M:%S")
|
|
||||||
|
|
||||||
def mysql_timestamp_converter(s):
|
|
||||||
"""Convert a MySQL TIMESTAMP to a mx.DateTime.Timestamp."""
|
|
||||||
parts = map(int, filter(None, (s[:4],s[4:6],s[6:8],
|
|
||||||
s[8:10],s[10:12],s[12:14])))
|
|
||||||
try: return apply(Timestamp, tuple(parts))
|
|
||||||
except: return None
|
|
||||||
|
|
||||||
def DateTime_or_None(s):
|
|
||||||
try: return ISO.ParseDateTime(s)
|
|
||||||
except: return None
|
|
||||||
|
|
||||||
def TimeDelta_or_None(s):
|
|
||||||
try: return ISO.ParseTimeDelta(s)
|
|
||||||
except: return None
|
|
||||||
|
|
||||||
def Date_or_None(s):
|
|
||||||
try: return ISO.ParseDate(s)
|
|
||||||
except: return None
|
|
||||||
|
|
||||||
conversions[FIELD_TYPE.TIMESTAMP] = mysql_timestamp_converter
|
|
||||||
conversions[FIELD_TYPE.DATETIME] = DateTime_or_None
|
|
||||||
conversions[FIELD_TYPE.TIME] = TimeDelta_or_None
|
|
||||||
conversions[FIELD_TYPE.DATE] = Date_or_None
|
|
||||||
|
|
||||||
def DateTime2literal(d, c):
|
|
||||||
"""Format a DateTime object as an ISO timestamp."""
|
|
||||||
return escape(format_TIMESTAMP(d),c)
|
|
||||||
|
|
||||||
def DateTimeDelta2literal(d, c):
|
|
||||||
"""Format a DateTimeDelta object as a time."""
|
|
||||||
return escape(format_TIME(d),c)
|
|
||||||
|
|
||||||
conversions[DateTimeType] = DateTime2literal
|
|
||||||
conversions[DateTimeDeltaType] = DateTimeDelta2literal
|
|
||||||
|
|
||||||
except ImportError:
|
|
||||||
# no DateTime? We'll muddle through somehow.
|
|
||||||
|
|
||||||
def DateFromTicks(ticks):
|
|
||||||
"""Convert UNIX ticks to ISO date format."""
|
|
||||||
return strftime("%Y-%m-%d", localtime(ticks))
|
|
||||||
|
|
||||||
def TimeFromTicks(ticks):
|
|
||||||
"""Convert UNIX ticks to time format."""
|
|
||||||
return strftime("%H:%M:%S", localtime(ticks))
|
|
||||||
|
|
||||||
def TimestampFromTicks(ticks):
|
|
||||||
"""Convert UNIX ticks to ISO timestamp format."""
|
|
||||||
return strftime("%Y-%m-%d %H:%M:%S", localtime(ticks))
|
|
||||||
|
|
||||||
def format_DATE(d):
|
|
||||||
"""Format a date as a date (does nothing, you don't have mx.DateTime)."""
|
|
||||||
return d
|
|
||||||
|
|
||||||
format_TIME = format_TIMESTAMP = format_DATE
|
|
||||||
|
|
||||||
__all__ = [ 'conversions', 'DateFromTicks', 'TimeFromTicks',
|
|
||||||
'TimestampFromTicks', 'format_DATE', 'format_TIME',
|
|
||||||
'format_TIMESTAMP' ]
|
|
||||||
|
@ -24,8 +24,6 @@ class BaseCursor:
|
|||||||
self.rowcount = -1
|
self.rowcount = -1
|
||||||
self.arraysize = 100
|
self.arraysize = 100
|
||||||
self._executed = None
|
self._executed = None
|
||||||
self._transaction = 0
|
|
||||||
self.__c_locked = 0
|
|
||||||
|
|
||||||
def __del__(self):
|
def __del__(self):
|
||||||
self.close()
|
self.close()
|
||||||
@ -33,10 +31,7 @@ class BaseCursor:
|
|||||||
def close(self):
|
def close(self):
|
||||||
"""Close the cursor. No further queries will be possible."""
|
"""Close the cursor. No further queries will be possible."""
|
||||||
if not self.__conn: return
|
if not self.__conn: return
|
||||||
self._end()
|
|
||||||
self.__conn = None
|
self.__conn = None
|
||||||
self._executed = None
|
|
||||||
self._transaction = None
|
|
||||||
|
|
||||||
def _check_executed(self):
|
def _check_executed(self):
|
||||||
if not self._executed:
|
if not self._executed:
|
||||||
@ -58,12 +53,12 @@ class BaseCursor:
|
|||||||
"""Execute a query.
|
"""Execute a query.
|
||||||
|
|
||||||
query -- string, query to execute on server
|
query -- string, query to execute on server
|
||||||
args -- sequence or mapping, parameters to use with query.
|
args -- optional sequence or mapping, parameters to use with query.
|
||||||
returns long integer rows affected, if any"""
|
returns long integer rows affected, if any"""
|
||||||
|
|
||||||
from types import ListType, TupleType
|
from types import ListType, TupleType
|
||||||
qc = self._get_db().converter
|
qc = self._get_db().converter
|
||||||
if not args:
|
if args is None:
|
||||||
r = self._query(query)
|
r = self._query(query)
|
||||||
elif type(args) is ListType and type(args[0]) is TupleType:
|
elif type(args) is ListType and type(args[0]) is TupleType:
|
||||||
r = self.executemany(query, args) # deprecated
|
r = self.executemany(query, args) # deprecated
|
||||||
@ -105,7 +100,7 @@ class BaseCursor:
|
|||||||
except TypeError, msg:
|
except TypeError, msg:
|
||||||
if msg.args[0] in ("not enough arguments for format string",
|
if msg.args[0] in ("not enough arguments for format string",
|
||||||
"not all arguments converted"):
|
"not all arguments converted"):
|
||||||
raise ProgrammingError, (0, msg.args[0])
|
raise ProgrammingError, msg.args[0]
|
||||||
else:
|
else:
|
||||||
raise
|
raise
|
||||||
r = self._query(join(q,',\n'))
|
r = self._query(join(q,',\n'))
|
||||||
@ -113,20 +108,16 @@ class BaseCursor:
|
|||||||
return r
|
return r
|
||||||
|
|
||||||
def __do_query(self, q):
|
def __do_query(self, q):
|
||||||
|
|
||||||
from string import split, atoi
|
from string import split, atoi
|
||||||
db = self._get_db()
|
db = self._get_db()
|
||||||
if self._transaction: self._begin()
|
db.query(q)
|
||||||
try:
|
self._result = self._get_result()
|
||||||
db.query(q)
|
self.rowcount = db.affected_rows()
|
||||||
self._result = self._get_result()
|
self.description = self._result and self._result.describe() or None
|
||||||
self.rowcount = db.affected_rows()
|
self._insert_id = db.insert_id()
|
||||||
self.description = self._result and self._result.describe() or None
|
self._info = db.info()
|
||||||
self._insert_id = db.insert_id()
|
self._check_for_warnings()
|
||||||
self._info = db.info()
|
|
||||||
self._check_for_warnings()
|
|
||||||
except:
|
|
||||||
self._end()
|
|
||||||
raise
|
|
||||||
return self.rowcount
|
return self.rowcount
|
||||||
|
|
||||||
def _check_for_warnings(self): pass
|
def _check_for_warnings(self): pass
|
||||||
@ -143,35 +134,9 @@ class BaseCursor:
|
|||||||
self._check_executed()
|
self._check_executed()
|
||||||
return self._insert_id
|
return self._insert_id
|
||||||
|
|
||||||
def nextset(self):
|
|
||||||
"""Does nothing. Required by DB API."""
|
|
||||||
self._check_executed()
|
|
||||||
return None
|
|
||||||
|
|
||||||
def _fetch_row(self, size=1):
|
def _fetch_row(self, size=1):
|
||||||
return self._result.fetch_row(size, self._fetch_type)
|
return self._result.fetch_row(size, self._fetch_type)
|
||||||
|
|
||||||
def _begin(self):
|
|
||||||
self.__conn._begin()
|
|
||||||
self._transaction = 1
|
|
||||||
|
|
||||||
def _end(self):
|
|
||||||
self._transaction = 0
|
|
||||||
self.__conn._end()
|
|
||||||
|
|
||||||
def _acquire(self):
|
|
||||||
if self.__c_locked: return
|
|
||||||
self.__conn._acquire()
|
|
||||||
self.__c_locked = 1
|
|
||||||
|
|
||||||
def _release(self):
|
|
||||||
if not self.__conn: return
|
|
||||||
self.__conn._release()
|
|
||||||
self.__c_locked = 0
|
|
||||||
|
|
||||||
def _is_transactional(self):
|
|
||||||
return self.__conn._transactional
|
|
||||||
|
|
||||||
|
|
||||||
class CursorWarningMixIn:
|
class CursorWarningMixIn:
|
||||||
|
|
||||||
@ -194,10 +159,6 @@ class CursorStoreResultMixIn:
|
|||||||
result set can be very large, consider adding a LIMIT clause to your
|
result set can be very large, consider adding a LIMIT clause to your
|
||||||
query, or using CursorUseResultMixIn instead."""
|
query, or using CursorUseResultMixIn instead."""
|
||||||
|
|
||||||
def __init__(self, connection):
|
|
||||||
BaseCursor.__init__(self, connection)
|
|
||||||
self._acquire()
|
|
||||||
|
|
||||||
def _get_result(self): return self._get_db().store_result()
|
def _get_result(self): return self._get_db().store_result()
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
@ -206,16 +167,11 @@ class CursorStoreResultMixIn:
|
|||||||
BaseCursor.close(self)
|
BaseCursor.close(self)
|
||||||
|
|
||||||
def _query(self, q):
|
def _query(self, q):
|
||||||
self._acquire()
|
rowcount = self._BaseCursor__do_query(q)
|
||||||
try:
|
self._rows = self._result and self._fetch_row(0) or ()
|
||||||
rowcount = self._BaseCursor__do_query(q)
|
self._pos = 0
|
||||||
self._rows = self._result and self._fetch_row(0) or ()
|
del self._result
|
||||||
self._pos = 0
|
return rowcount
|
||||||
del self._result
|
|
||||||
if not self._is_transactional: self._end()
|
|
||||||
return rowcount
|
|
||||||
finally:
|
|
||||||
self._release()
|
|
||||||
|
|
||||||
def fetchone(self):
|
def fetchone(self):
|
||||||
"""Fetches a single row from the cursor."""
|
"""Fetches a single row from the cursor."""
|
||||||
@ -269,7 +225,6 @@ class CursorUseResultMixIn:
|
|||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
"""Close the cursor. No further queries can be executed."""
|
"""Close the cursor. No further queries can be executed."""
|
||||||
self._release()
|
|
||||||
self._result = None
|
self._result = None
|
||||||
BaseCursor.close(self)
|
BaseCursor.close(self)
|
||||||
|
|
||||||
@ -279,19 +234,22 @@ class CursorUseResultMixIn:
|
|||||||
"""Fetches a single row from the cursor."""
|
"""Fetches a single row from the cursor."""
|
||||||
self._check_executed()
|
self._check_executed()
|
||||||
r = self._fetch_row(1)
|
r = self._fetch_row(1)
|
||||||
return r and r[0] or None
|
if r: return r[0]
|
||||||
|
return None
|
||||||
|
|
||||||
def fetchmany(self, size=None):
|
def fetchmany(self, size=None):
|
||||||
"""Fetch up to size rows from the cursor. Result set may be smaller
|
"""Fetch up to size rows from the cursor. Result set may be smaller
|
||||||
than size. If size is not defined, cursor.arraysize is used."""
|
than size. If size is not defined, cursor.arraysize is used."""
|
||||||
self._check_executed()
|
self._check_executed()
|
||||||
return self._fetch_row(size or self.arraysize)
|
r = self._fetch_row(size or self.arraysize)
|
||||||
|
return r
|
||||||
|
|
||||||
def fetchall(self):
|
def fetchall(self):
|
||||||
"""Fetchs all available rows from the cursor."""
|
"""Fetchs all available rows from the cursor."""
|
||||||
self._check_open()
|
self._check_executed()
|
||||||
return self._fetch_row(0)
|
r = self._fetch_row(0)
|
||||||
|
return r
|
||||||
|
|
||||||
|
|
||||||
class CursorTupleRowsMixIn:
|
class CursorTupleRowsMixIn:
|
||||||
|
|
||||||
|
186
MySQLdb/MySQLdb/data.py
Normal file
186
MySQLdb/MySQLdb/data.py
Normal file
@ -0,0 +1,186 @@
|
|||||||
|
"""data module
|
||||||
|
|
||||||
|
This module provides some useful classes for dealing with MySQL data.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from time import strftime, localtime
|
||||||
|
from _mysql import string_literal
|
||||||
|
|
||||||
|
class Set:
|
||||||
|
|
||||||
|
"""A simple class for handling sets. Sets are immutable in the same
|
||||||
|
way numbers are."""
|
||||||
|
|
||||||
|
def __init__(self, *values):
|
||||||
|
"""Use values to initialize the Set."""
|
||||||
|
self._values = values
|
||||||
|
|
||||||
|
def contains(self, value):
|
||||||
|
"""Returns true if the value is contained within the Set."""
|
||||||
|
return value in self._values
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
"""Returns the values as a comma-separated string."""
|
||||||
|
from string import join
|
||||||
|
return join(map(str, self._values),',')
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "Set%s" % `self._values`
|
||||||
|
|
||||||
|
def __add__(self, other):
|
||||||
|
"""Union."""
|
||||||
|
if isinstance(other, Set):
|
||||||
|
for v in other._values:
|
||||||
|
self = self + v
|
||||||
|
elif other not in self._values:
|
||||||
|
self = apply(Set, self._values+(other,))
|
||||||
|
return self
|
||||||
|
|
||||||
|
def __sub__(self, other):
|
||||||
|
if isinstance(other, Set):
|
||||||
|
for v in other._values:
|
||||||
|
if v in self:
|
||||||
|
self = self - v
|
||||||
|
elif other in self:
|
||||||
|
values = list(self._values)
|
||||||
|
values.remove(other)
|
||||||
|
return apply(Set, tuple(values))
|
||||||
|
return self
|
||||||
|
|
||||||
|
def __mul__(self, other):
|
||||||
|
"Intersection."
|
||||||
|
intersection = Set()
|
||||||
|
if isinstance(other, Set):
|
||||||
|
union = self + other
|
||||||
|
intersection = union
|
||||||
|
for v in union._values:
|
||||||
|
if v not in self or v not in other:
|
||||||
|
intersection = intersection - v
|
||||||
|
elif other in self:
|
||||||
|
intersection = apply(Set, (other,))
|
||||||
|
return intersection
|
||||||
|
|
||||||
|
def __mod__(self, other):
|
||||||
|
"Disjoint."
|
||||||
|
return (self+other)-(self*other)
|
||||||
|
|
||||||
|
def __getitem__(self, n):
|
||||||
|
return self._values[n]
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
return len(self._values)
|
||||||
|
|
||||||
|
def __hash__(self):
|
||||||
|
return hash(self._values)
|
||||||
|
|
||||||
|
def __cmp__(self, other):
|
||||||
|
if isinstance(other, Set):
|
||||||
|
d = self % other
|
||||||
|
if d._values:
|
||||||
|
return 1
|
||||||
|
else:
|
||||||
|
return 0
|
||||||
|
if other in self._values:
|
||||||
|
return 0
|
||||||
|
return -1
|
||||||
|
|
||||||
|
try:
|
||||||
|
try:
|
||||||
|
# new packaging
|
||||||
|
from mx.DateTime import Date, Time, Timestamp, ISO, \
|
||||||
|
DateTimeType, DateTimeDeltaType
|
||||||
|
except ImportError:
|
||||||
|
# old packaging, deprecated
|
||||||
|
from DateTime import Date, Time, Timestamp, ISO, \
|
||||||
|
DateTimeType, DateTimeDeltaType
|
||||||
|
|
||||||
|
def DateFromTicks(ticks):
|
||||||
|
"""Convert UNIX ticks into a mx.DateTime.Date."""
|
||||||
|
return apply(Date, localtime(ticks)[:3])
|
||||||
|
|
||||||
|
def TimeFromTicks(ticks):
|
||||||
|
"""Convert UNIX ticks into a mx.DateTime.Time."""
|
||||||
|
return apply(Time, localtime(ticks)[3:6])
|
||||||
|
|
||||||
|
def TimestampFromTicks(ticks):
|
||||||
|
"""Convert UNIX ticks into a mx.DateTime.Timestamp."""
|
||||||
|
return apply(Timestamp, localtime(ticks)[:6])
|
||||||
|
|
||||||
|
def format_DATE(d):
|
||||||
|
"""Format a DateTime object as an ISO date."""
|
||||||
|
return d.strftime("%Y-%m-%d")
|
||||||
|
|
||||||
|
def format_TIME(d):
|
||||||
|
"""Format a DateTime object as a time value."""
|
||||||
|
return d.strftime("%H:%M:%S")
|
||||||
|
|
||||||
|
def format_TIMESTAMP(d):
|
||||||
|
"""Format a DateTime object as an ISO timestamp."""
|
||||||
|
return d.strftime("%Y-%m-%d %H:%M:%S")
|
||||||
|
|
||||||
|
def DateTime_or_None(s):
|
||||||
|
try: return ISO.ParseDateTime(s)
|
||||||
|
except: return None
|
||||||
|
|
||||||
|
def TimeDelta_or_None(s):
|
||||||
|
try: return ISO.ParseTimeDelta(s)
|
||||||
|
except: return None
|
||||||
|
|
||||||
|
def Date_or_None(s):
|
||||||
|
try: return ISO.ParseDate(s)
|
||||||
|
except: return None
|
||||||
|
|
||||||
|
|
||||||
|
except ImportError:
|
||||||
|
# no DateTime? We'll muddle through somehow.
|
||||||
|
|
||||||
|
DateTimeDeltaType = "DateTimeDeltaType"
|
||||||
|
DateTimeType = "DateTimeType"
|
||||||
|
|
||||||
|
def Date(year, month, day):
|
||||||
|
"""Construct an ISO date string."""
|
||||||
|
return "%04d-%02d-%02d" % (year, month, day)
|
||||||
|
|
||||||
|
def Time(hour, min, sec):
|
||||||
|
"""Construct a TIME string."""
|
||||||
|
return "%02d:%02d:%02d" % (hour, min, sec)
|
||||||
|
|
||||||
|
def Timestamp(year, month, day, hour, min, sec):
|
||||||
|
"""Construct an ISO timestamp."""
|
||||||
|
return "%04d-%02d-%02d %02d:%02d:%02d" % \
|
||||||
|
(year, month, day, hour, min, sec)
|
||||||
|
|
||||||
|
def DateFromTicks(ticks):
|
||||||
|
"""Convert UNIX ticks to ISO date format."""
|
||||||
|
return strftime("%Y-%m-%d", localtime(ticks))
|
||||||
|
|
||||||
|
def TimeFromTicks(ticks):
|
||||||
|
"""Convert UNIX ticks to time format."""
|
||||||
|
return strftime("%H:%M:%S", localtime(ticks))
|
||||||
|
|
||||||
|
def TimestampFromTicks(ticks):
|
||||||
|
"""Convert UNIX ticks to ISO timestamp format."""
|
||||||
|
return strftime("%Y-%m-%d %H:%M:%S", localtime(ticks))
|
||||||
|
|
||||||
|
def format_DATE(d):
|
||||||
|
"""Format a date as a date (does nothing, you don't have mx.DateTime)."""
|
||||||
|
return d
|
||||||
|
|
||||||
|
format_TIME = format_TIMESTAMP = format_DATE = \
|
||||||
|
TimeDelta_or_None = Date_or_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_TIME(d),c)
|
||||||
|
|
||||||
|
def mysql_timestamp_converter(s):
|
||||||
|
"""Convert a MySQL TIMESTAMP to a Timestamp object."""
|
||||||
|
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 apply(Timestamp, tuple(parts))
|
||||||
|
except: return None
|
@ -1 +1 @@
|
|||||||
static char _mysql__version__[] = "0.9.0b1";
|
static char _mysql__version__[] = "0.9.0b2";
|
||||||
|
@ -15,8 +15,7 @@ others. However, the older version is a) not thread-friendly (database
|
|||||||
operations could cause all other threads to block), b) written for
|
operations could cause all other threads to block), b) written for
|
||||||
MySQL 3.21 (does not compile against newer versions without patches),
|
MySQL 3.21 (does not compile against newer versions without patches),
|
||||||
c) apparently not actively maintained. MySQLdb is a completely new
|
c) apparently not actively maintained. MySQLdb is a completely new
|
||||||
module, distributed free of charge under a license derived from the
|
module, distributed free of charge under the GNU Public License.
|
||||||
Python license.
|
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<sect1>Platforms
|
<sect1>Platforms
|
||||||
@ -70,14 +69,14 @@ InnoDB. GEMINI tables are slated for MySQL-4.0. Note that MySQL
|
|||||||
generally operates in <tt/AUTOCOMMIT/ mode by default, and MySQLdb
|
generally operates in <tt/AUTOCOMMIT/ mode by default, and MySQLdb
|
||||||
assumes that <tt/AUTOCOMMIT/ is on by default. To change this, use the
|
assumes that <tt/AUTOCOMMIT/ is on by default. To change this, use the
|
||||||
<tt/autocommit(n)/ method; otherwise MySQLdb will not know that that
|
<tt/autocommit(n)/ method; otherwise MySQLdb will not know that that
|
||||||
you have changed it, and this affects locking for transactions.
|
you have changed it.
|
||||||
|
|
||||||
<sect1>DateTime <p>If you have the <htmlurl
|
<sect1>DateTime <p>If you have the <htmlurl
|
||||||
url="http://www.lemburg.com/files/python/mxDateTime.html"
|
url="http://www.lemburg.com/files/python/mxDateTime.html"
|
||||||
name="mx.DateTime"> package installed (recommended), MySQLdb will use
|
name="mx.DateTime"> package installed (recommended), MySQLdb will use
|
||||||
it for date-related objects. Otherwise, these will be returned to
|
it for date-related objects. Otherwise, these will be returned to
|
||||||
Python as strings. You can also modify the type conversion
|
Python as strings. You can also modify the type conversion
|
||||||
dictionaries to return these as other object classes, if you prefer.
|
dictionary to return these as other object classes, if you prefer.
|
||||||
|
|
||||||
<sect1>MySQLmodule<label id="MySQLmodule">
|
<sect1>MySQLmodule<label id="MySQLmodule">
|
||||||
<p>
|
<p>
|
||||||
@ -389,7 +388,7 @@ MySQLdb.
|
|||||||
location of UNIX socket. Default: use TCP.
|
location of UNIX socket. Default: use TCP.
|
||||||
|
|
||||||
<tag>conv</tag> type conversion dictionary.
|
<tag>conv</tag> type conversion dictionary.
|
||||||
Default: a copy of <tt/MySQLdb.converters.conv/
|
Default: a copy of <tt/MySQLdb.converters.conversions/
|
||||||
|
|
||||||
<tag>compress</tag> Enable protocol compression. Default: no compression.
|
<tag>compress</tag> Enable protocol compression. Default: no compression.
|
||||||
|
|
||||||
@ -411,36 +410,36 @@ MySQLdb.
|
|||||||
unless overridden. Default: <tt/MySQLdb.cursors.Cursor/.
|
unless overridden. Default: <tt/MySQLdb.cursors.Cursor/.
|
||||||
<em/This must be a keyword parameter./
|
<em/This must be a keyword parameter./
|
||||||
|
|
||||||
<tag>threads</tag> boolean, to enable use of threading within
|
|
||||||
<tt/MySQLdb/. Default: 1 (enabled). Set this to 0 if you
|
|
||||||
don't want to or can't use threads.
|
|
||||||
<em/This must be a keyword parameter./
|
|
||||||
|
|
||||||
</descrip>
|
</descrip>
|
||||||
|
|
||||||
<tag>apilevel</tag>
|
<tag>apilevel</tag>
|
||||||
String constant stating the supported DB API level. '2.0'
|
String constant stating the supported DB API level. '2.0'
|
||||||
|
|
||||||
<tag>threadsafety</tag> Integer constant stating the level of thread
|
<tag>threadsafety</tag> Integer constant stating the level of thread
|
||||||
safety the interface supports. As of MySQLdb version 0.2.0, this
|
safety the interface supports. As of MySQLdb version 0.9.0, this
|
||||||
is set to 2, which means: Threads may share the module and
|
is set to 1, which means: Threads may share the module.
|
||||||
connections. Cursors employ a lock in the connection object to
|
<p>The MySQL protocol can not handle multiple threads using the
|
||||||
ensure that cursors do not use the connection at the same
|
same connection at once. Some earlier versions of MySQLdb utilized locking
|
||||||
time. Generally, sharing a connection probably reduces
|
to achieve a threadsafety of 2. While this is not terribly hard
|
||||||
performance; the MySQL server maintains a seperate thread for
|
to accomplish using the standard Cursor class (which uses
|
||||||
each connection. It is recommended that connections not be
|
<tt/mysql_store_result()/), it is complicated by SSCursor (which
|
||||||
shared between threads. See the MySQL documentation for more
|
uses <tt/mysql_use_result()/; with the latter you must ensure
|
||||||
details. As of 0.9.0, there is an additional blocking lock that
|
all the rows have been read before another query can be executed.
|
||||||
is used if transactioning is available, to insure a connection
|
It is further complicated by the addition of transactions, since
|
||||||
cannot be shared between two threads if a transaction is in
|
transactions start when a cursor execute a query, but end when
|
||||||
progress. Note that two cursors in the same thread cannot
|
<tt/COMMIT/ or <tt/ROLLBACK/ is executed by the Connection object.
|
||||||
attempt to acquire the connection lock at the same time; this
|
Two threads cannot share a connection while a transaction is in
|
||||||
would produce deadlock, and <tt/ProgrammingError/ is
|
progress, in addition to not being able to share it during query
|
||||||
raised. However, multiple cursors in the same thread can acquire
|
execution. This excessively complicated the code to the point where
|
||||||
the transaction lock. <tt/commit()/ and <tt/rollback()/ release
|
it just isn't worth it. <p>The general upshot of this is: Don't
|
||||||
the transaction lock. The general rule here is, cursors acquire
|
share connections between threads. It's really not worth your effort
|
||||||
locks, commit and rollback release them. Fortunately, you don't
|
or mine, and in the end, will probably hurt performance, since the MySQL
|
||||||
need to think about this too much.
|
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.
|
||||||
|
|
||||||
<tag>paramstyle</tag> String constant stating the type of parameter
|
<tag>paramstyle</tag> String constant stating the type of parameter
|
||||||
marker formatting expected by the interface. Set to 'format' =
|
marker formatting expected by the interface. Set to 'format' =
|
||||||
@ -459,7 +458,7 @@ MySQLdb.
|
|||||||
regardless of type. The interface performs all necessary
|
regardless of type. The interface performs all necessary
|
||||||
quoting.
|
quoting.
|
||||||
|
|
||||||
<tag><label id="type_conv">conv</tag> A dictionary mapping MySQL types
|
<tag><label id="conversions">conv</tag> A dictionary mapping MySQL types
|
||||||
(from <TT>FIELD_TYPE.*</TT>) to callable Python objects (usually
|
(from <TT>FIELD_TYPE.*</TT>) to callable Python objects (usually
|
||||||
functions) which convert from a string to the desired type; and
|
functions) which convert from a string to the desired type; and
|
||||||
mapping Python types to callable Python objects which convert
|
mapping Python types to callable Python objects which convert
|
||||||
@ -467,10 +466,10 @@ MySQLdb.
|
|||||||
initialized with reasonable defaults for most types. When
|
initialized with reasonable defaults for most types. When
|
||||||
creating a Connection object, you can pass your own type
|
creating a Connection object, you can pass your own type
|
||||||
converter dictionary as a keyword parameter. Otherwise, it uses
|
converter dictionary as a keyword parameter. Otherwise, it uses
|
||||||
a copy of <tt>MySQLdb.converters.conv</tt>. The dictionary
|
a copy of <tt>MySQLdb.converters.conversions</tt>. The dictionary
|
||||||
includes some of the factory functions from the
|
includes some of the factory functions from the
|
||||||
<tt>DateTime</tt> module, if it is available. Several
|
<tt>DateTime</tt> module, if it is available. Several
|
||||||
non-standard types (<tt>SET, ENUM</tt>) are returned as strings,
|
non-standard types are returned as strings,
|
||||||
which is how MySQL returns all columns. For more details, see
|
which is how MySQL returns all columns. For more details, see
|
||||||
the built-in module documentation.
|
the built-in module documentation.
|
||||||
|
|
||||||
@ -545,9 +544,6 @@ Compatibility note: The older <ref id="MySQLmodule"> defines this method,
|
|||||||
cursor class without warnings, then you might want to use
|
cursor class without warnings, then you might want to use
|
||||||
this. See the MySQL docs for <tt/mysql_info()/. (Non-standard)
|
this. See the MySQL docs for <tt/mysql_info()/. (Non-standard)
|
||||||
|
|
||||||
<tag>nextset()</tag>
|
|
||||||
Not implemented.
|
|
||||||
|
|
||||||
<tag>setinputsizes()</tag>
|
<tag>setinputsizes()</tag>
|
||||||
Does nothing, successfully.
|
Does nothing, successfully.
|
||||||
|
|
||||||
@ -674,12 +670,7 @@ entire result set is stored on the client side.
|
|||||||
<tag><label id="SSCursor">CursorUseResultMixIn</tag> Causes the cursor to use the
|
<tag><label id="SSCursor">CursorUseResultMixIn</tag> Causes the cursor to use the
|
||||||
<tt>mysql_use_result()</tt> function to get the query result. The
|
<tt>mysql_use_result()</tt> function to get the query result. The
|
||||||
result set is stored on the server side and is transferred row by row
|
result set is stored on the server side and is transferred row by row
|
||||||
using fetch operations. Not recommended, particularly for threaded
|
using fetch operations.
|
||||||
applications that share connections. Note that creating the cursor
|
|
||||||
causes it to acquire a lock on the connection object, and this is
|
|
||||||
not released until the cursor is deleted or <tt/cursor.close()/.
|
|
||||||
If you aren't careful about this, it can result in deadlock, which
|
|
||||||
is bad.
|
|
||||||
|
|
||||||
<tag>CursorTupleRowsMixIn</tag> Causes the cursor to return rows
|
<tag>CursorTupleRowsMixIn</tag> Causes the cursor to return rows
|
||||||
as a tuple of the column values.
|
as a tuple of the column values.
|
||||||
@ -702,8 +693,7 @@ and <tt>BaseCursor</tt>, i.e. it raises <tt>Warning</tt>, uses
|
|||||||
dictionaries.
|
dictionaries.
|
||||||
|
|
||||||
<tag>SSCursor</tag> A "server-side" cursor. Like <tt/Cursor/ but uses
|
<tag>SSCursor</tag> A "server-side" cursor. Like <tt/Cursor/ but uses
|
||||||
<tt/CursorUseResultMixIn/. Thread-safe, but not recommended for
|
<tt/CursorUseResultMixIn/.
|
||||||
threaded applications which share connections.
|
|
||||||
Use only if you are dealing with potentially large result sets.
|
Use only if you are dealing with potentially large result sets.
|
||||||
|
|
||||||
<tag/SSDictCursor/ Like <tt/SSCursor/ except it returns rows as
|
<tag/SSDictCursor/ Like <tt/SSCursor/ except it returns rows as
|
||||||
|
@ -75,7 +75,7 @@ MySQLdb. MySQLdb is free software.
|
|||||||
|
|
||||||
setup (# Distribution meta-data
|
setup (# Distribution meta-data
|
||||||
name = "MySQL-python",
|
name = "MySQL-python",
|
||||||
version = "0.9.0b1",
|
version = "0.9.0b2",
|
||||||
description = "An interface to MySQL",
|
description = "An interface to MySQL",
|
||||||
long_description=long_description,
|
long_description=long_description,
|
||||||
author = "Andy Dustman",
|
author = "Andy Dustman",
|
||||||
@ -89,6 +89,7 @@ setup (# Distribution meta-data
|
|||||||
"MySQLdb.converters",
|
"MySQLdb.converters",
|
||||||
"MySQLdb.connections",
|
"MySQLdb.connections",
|
||||||
"MySQLdb.cursors",
|
"MySQLdb.cursors",
|
||||||
|
"MySQLdb.data",
|
||||||
"MySQLdb.constants.CR",
|
"MySQLdb.constants.CR",
|
||||||
"MySQLdb.constants.FIELD_TYPE",
|
"MySQLdb.constants.FIELD_TYPE",
|
||||||
"MySQLdb.constants.ER",
|
"MySQLdb.constants.ER",
|
||||||
|
Reference in New Issue
Block a user