2012-06-08 00:08:47 +08:00
|
|
|
from __future__ import unicode_literals
|
|
|
|
|
2006-05-02 09:31:56 +08:00
|
|
|
import datetime
|
2010-05-04 22:00:30 +08:00
|
|
|
import decimal
|
2011-03-28 10:11:19 +08:00
|
|
|
import hashlib
|
2006-05-02 09:31:56 +08:00
|
|
|
from time import time
|
|
|
|
|
2011-11-18 21:01:06 +08:00
|
|
|
from django.conf import settings
|
2010-10-06 23:02:26 +08:00
|
|
|
from django.utils.log import getLogger
|
2011-11-18 21:01:06 +08:00
|
|
|
from django.utils.timezone import utc
|
2008-08-02 13:56:57 +08:00
|
|
|
|
2011-02-12 21:03:34 +08:00
|
|
|
|
2010-10-06 23:02:26 +08:00
|
|
|
logger = getLogger('django.db.backends')
|
2010-10-04 23:12:39 +08:00
|
|
|
|
2011-02-12 21:03:34 +08:00
|
|
|
|
|
|
|
class CursorWrapper(object):
|
2011-02-14 08:06:52 +08:00
|
|
|
def __init__(self, cursor, db):
|
2006-05-02 09:31:56 +08:00
|
|
|
self.cursor = cursor
|
2011-02-14 08:06:52 +08:00
|
|
|
self.db = db
|
2011-02-12 21:03:34 +08:00
|
|
|
|
2012-01-13 05:55:19 +08:00
|
|
|
def set_dirty(self):
|
2011-02-14 08:06:52 +08:00
|
|
|
if self.db.is_managed():
|
|
|
|
self.db.set_dirty()
|
2012-01-13 05:55:19 +08:00
|
|
|
|
|
|
|
def __getattr__(self, attr):
|
|
|
|
self.set_dirty()
|
2011-02-12 21:03:34 +08:00
|
|
|
if attr in self.__dict__:
|
|
|
|
return self.__dict__[attr]
|
|
|
|
else:
|
|
|
|
return getattr(self.cursor, attr)
|
|
|
|
|
|
|
|
def __iter__(self):
|
|
|
|
return iter(self.cursor)
|
|
|
|
|
|
|
|
|
|
|
|
class CursorDebugWrapper(CursorWrapper):
|
2006-05-02 09:31:56 +08:00
|
|
|
|
|
|
|
def execute(self, sql, params=()):
|
2012-01-13 05:55:19 +08:00
|
|
|
self.set_dirty()
|
2006-05-02 09:31:56 +08:00
|
|
|
start = time()
|
|
|
|
try:
|
|
|
|
return self.cursor.execute(sql, params)
|
|
|
|
finally:
|
|
|
|
stop = time()
|
2010-10-04 23:12:39 +08:00
|
|
|
duration = stop - start
|
2011-02-14 08:06:52 +08:00
|
|
|
sql = self.db.ops.last_executed_query(self.cursor, sql, params)
|
|
|
|
self.db.queries.append({
|
2007-10-24 03:00:31 +08:00
|
|
|
'sql': sql,
|
2010-10-04 23:12:39 +08:00
|
|
|
'time': "%.3f" % duration,
|
2006-05-02 09:31:56 +08:00
|
|
|
})
|
2010-10-04 23:12:39 +08:00
|
|
|
logger.debug('(%.3f) %s; args=%s' % (duration, sql, params),
|
2012-01-23 00:41:20 +08:00
|
|
|
extra={'duration': duration, 'sql': sql, 'params': params}
|
2010-10-04 23:12:39 +08:00
|
|
|
)
|
2006-05-02 09:31:56 +08:00
|
|
|
|
|
|
|
def executemany(self, sql, param_list):
|
2012-01-13 05:55:19 +08:00
|
|
|
self.set_dirty()
|
2006-05-02 09:31:56 +08:00
|
|
|
start = time()
|
|
|
|
try:
|
|
|
|
return self.cursor.executemany(sql, param_list)
|
|
|
|
finally:
|
|
|
|
stop = time()
|
2010-10-04 23:12:39 +08:00
|
|
|
duration = stop - start
|
2012-01-23 00:41:20 +08:00
|
|
|
try:
|
|
|
|
times = len(param_list)
|
|
|
|
except TypeError: # param_list could be an iterator
|
|
|
|
times = '?'
|
2011-02-14 08:06:52 +08:00
|
|
|
self.db.queries.append({
|
2012-01-23 00:41:20 +08:00
|
|
|
'sql': '%s times: %s' % (times, sql),
|
2010-10-04 23:12:39 +08:00
|
|
|
'time': "%.3f" % duration,
|
2006-05-02 09:31:56 +08:00
|
|
|
})
|
2010-10-04 23:12:39 +08:00
|
|
|
logger.debug('(%.3f) %s; args=%s' % (duration, sql, param_list),
|
2012-01-23 00:41:20 +08:00
|
|
|
extra={'duration': duration, 'sql': sql, 'params': param_list}
|
2010-10-04 23:12:39 +08:00
|
|
|
)
|
2006-05-02 09:31:56 +08:00
|
|
|
|
2011-02-12 21:03:34 +08:00
|
|
|
|
2006-05-02 09:31:56 +08:00
|
|
|
###############################################
|
|
|
|
# Converters from database (string) to Python #
|
|
|
|
###############################################
|
|
|
|
|
|
|
|
def typecast_date(s):
|
|
|
|
return s and datetime.date(*map(int, s.split('-'))) or None # returns None if s is null
|
|
|
|
|
|
|
|
def typecast_time(s): # does NOT store time zone information
|
|
|
|
if not s: return None
|
|
|
|
hour, minutes, seconds = s.split(':')
|
|
|
|
if '.' in seconds: # check whether seconds have a fractional part
|
|
|
|
seconds, microseconds = seconds.split('.')
|
|
|
|
else:
|
|
|
|
microseconds = '0'
|
|
|
|
return datetime.time(int(hour), int(minutes), int(seconds), int(float('.'+microseconds) * 1000000))
|
|
|
|
|
|
|
|
def typecast_timestamp(s): # does NOT store time zone information
|
|
|
|
# "2005-07-29 15:48:00.590358-05"
|
|
|
|
# "2005-07-29 09:56:00-05"
|
|
|
|
if not s: return None
|
|
|
|
if not ' ' in s: return typecast_date(s)
|
|
|
|
d, t = s.split()
|
|
|
|
# Extract timezone information, if it exists. Currently we just throw
|
|
|
|
# it away, but in the future we may make use of it.
|
|
|
|
if '-' in t:
|
|
|
|
t, tz = t.split('-', 1)
|
|
|
|
tz = '-' + tz
|
|
|
|
elif '+' in t:
|
|
|
|
t, tz = t.split('+', 1)
|
|
|
|
tz = '+' + tz
|
|
|
|
else:
|
|
|
|
tz = ''
|
|
|
|
dates = d.split('-')
|
|
|
|
times = t.split(':')
|
|
|
|
seconds = times[2]
|
|
|
|
if '.' in seconds: # check whether seconds have a fractional part
|
|
|
|
seconds, microseconds = seconds.split('.')
|
|
|
|
else:
|
|
|
|
microseconds = '0'
|
2011-11-18 21:01:06 +08:00
|
|
|
tzinfo = utc if settings.USE_TZ else None
|
2006-05-02 09:31:56 +08:00
|
|
|
return datetime.datetime(int(dates[0]), int(dates[1]), int(dates[2]),
|
2011-11-18 21:01:06 +08:00
|
|
|
int(times[0]), int(times[1]), int(seconds),
|
|
|
|
int((microseconds + '000000')[:6]), tzinfo)
|
2006-05-02 09:31:56 +08:00
|
|
|
|
2007-05-21 09:29:58 +08:00
|
|
|
def typecast_decimal(s):
|
2007-06-10 09:52:56 +08:00
|
|
|
if s is None or s == '':
|
2007-05-21 09:29:58 +08:00
|
|
|
return None
|
|
|
|
return decimal.Decimal(s)
|
|
|
|
|
2006-05-02 09:31:56 +08:00
|
|
|
###############################################
|
|
|
|
# Converters from Python to database (string) #
|
|
|
|
###############################################
|
|
|
|
|
2007-05-21 09:29:58 +08:00
|
|
|
def rev_typecast_decimal(d):
|
|
|
|
if d is None:
|
|
|
|
return None
|
|
|
|
return str(d)
|
|
|
|
|
2010-09-13 13:08:10 +08:00
|
|
|
def truncate_name(name, length=None, hash_len=4):
|
2007-06-23 22:16:00 +08:00
|
|
|
"""Shortens a string to a repeatable mangled version with the given length.
|
|
|
|
"""
|
|
|
|
if length is None or len(name) <= length:
|
|
|
|
return name
|
|
|
|
|
2011-03-28 10:11:19 +08:00
|
|
|
hsh = hashlib.md5(name).hexdigest()[:hash_len]
|
|
|
|
return '%s%s' % (name[:length-hash_len], hsh)
|
2008-07-29 13:09:29 +08:00
|
|
|
|
|
|
|
def format_number(value, max_digits, decimal_places):
|
|
|
|
"""
|
|
|
|
Formats a number into a string with the requisite number of digits and
|
|
|
|
decimal places.
|
|
|
|
"""
|
2008-11-12 08:35:24 +08:00
|
|
|
if isinstance(value, decimal.Decimal):
|
|
|
|
context = decimal.getcontext().copy()
|
|
|
|
context.prec = max_digits
|
2012-06-08 00:08:47 +08:00
|
|
|
return '%s' % str(value.quantize(decimal.Decimal(".1") ** decimal_places, context=context))
|
2008-11-12 08:35:24 +08:00
|
|
|
else:
|
2012-06-08 00:08:47 +08:00
|
|
|
return "%.*f" % (decimal_places, value)
|