`0001from array import array
0002import datetime
0003from decimal import Decimal
0004import sys
0005import time
0006from types import ClassType, InstanceType, NoneType
0007
0008
0009try:
0010 import mx.DateTime.ISO
0011 origISOStr = mx.DateTime.ISO.strGMT
0012 from mx.DateTime import DateTimeType, DateTimeDeltaType
0013except ImportError:
0014 try:
0015 import DateTime.ISO
0016 origISOStr = DateTime.ISO.strGMT
0017 from DateTime import DateTimeType, DateTimeDeltaType
0018 except ImportError:
0019 origISOStr = None
0020 DateTimeType = None
0021 DateTimeDeltaType = None
0022
0023try:
0024 import Sybase
0025 NumericType=Sybase.NumericType
0026except ImportError:
0027 NumericType = None
0028
0029
0030########################################
0031## Quoting
0032########################################
0033
0034sqlStringReplace = [
0035 ("'", "''"),
0036 ('\\', '\\\\'),
0037 ('\000', '\\0'),
0038 ('\b', '\\b'),
0039 ('\n', '\\n'),
0040 ('\r', '\\r'),
0041 ('\t', '\\t'),
0042]
0043
0044def isoStr(val):
0045 """
0046 Gets rid of time zone information
0047 (@@: should we convert to GMT?)
0048 """
0049 val = origISOStr(val)
0050 if val.find('+') == -1:
0051 return val
0052 else:
0053 return val[:val.find('+')]
0054
0055class ConverterRegistry:
0056
0057 def __init__(self):
0058 self.basic = {}
0059 self.klass = {}
0060
0061 def registerConverter(self, typ, func):
0062 if type(typ) is ClassType:
0063 self.klass[typ] = func
0064 else:
0065 self.basic[typ] = func
0066
0067 def lookupConverter(self, value, default=None):
0068 if type(value) is InstanceType:
0069 # lookup on klasses dict
0070 return self.klass.get(value.__class__, default)
0071 return self.basic.get(type(value), default)
0072
0073converters = ConverterRegistry()
0074registerConverter = converters.registerConverter
0075lookupConverter = converters.lookupConverter
0076
0077def StringLikeConverter(value, db):
0078 if isinstance(value, array):
0079 try:
0080 value = value.tounicode()
0081 except ValueError:
0082 value = value.tostring()
0083 elif isinstance(value, buffer):
0084 value = str(value)
0085
0086 if db in ('mysql', 'postgres', 'rdbhost'):
0087 for orig, repl in sqlStringReplace:
0088 value = value.replace(orig, repl)
0089 elif db in ('sqlite', 'firebird', 'sybase', 'maxdb', 'mssql'):
0090 value = value.replace("'", "''")
0091 else:
0092 assert 0, "Database %s unknown" % db
0093 if db in ('postgres', 'rdbhost') and ('\\' in value):
0094 return "E'%s'" % value
0095 return "'%s'" % value
0096
0097registerConverter(str, StringLikeConverter)
0098registerConverter(unicode, StringLikeConverter)
0099registerConverter(array, StringLikeConverter)
0100registerConverter(buffer, StringLikeConverter)
0101
0102def IntConverter(value, db):
0103 return repr(int(value))
0104
0105registerConverter(int, IntConverter)
0106
0107def LongConverter(value, db):
0108 return str(value)
0109
0110registerConverter(long, LongConverter)
0111
0112if NumericType:
0113 registerConverter(NumericType, IntConverter)
0114
0115def BoolConverter(value, db):
0116 if db in ('postgres', 'rdbhost'):
0117 if value:
0118 return "'t'"
0119 else:
0120 return "'f'"
0121 else:
0122 if value:
0123 return '1'
0124 else:
0125 return '0'
0126
0127registerConverter(bool, BoolConverter)
0128
0129def FloatConverter(value, db):
0130 return repr(value)
0131
0132registerConverter(float, FloatConverter)
0133
0134if DateTimeType:
0135 def DateTimeConverter(value, db):
0136 return "'%s'" % isoStr(value)
0137
0138 registerConverter(DateTimeType, DateTimeConverter)
0139
0140 def TimeConverter(value, db):
0141 return "'%s'" % value.strftime("%T")
0142
0143 registerConverter(DateTimeDeltaType, TimeConverter)
0144
0145def NoneConverter(value, db):
0146 return "NULL"
0147
0148registerConverter(NoneType, NoneConverter)
0149
0150def SequenceConverter(value, db):
0151 return "(%s)" % ", ".join([sqlrepr(v, db) for v in value])
0152
0153registerConverter(tuple, SequenceConverter)
0154registerConverter(list, SequenceConverter)
0155registerConverter(dict, SequenceConverter)
0156registerConverter(set, SequenceConverter)
0157registerConverter(frozenset, SequenceConverter)
0158if sys.version_info[:3] < (2, 6, 0): # Module sets was deprecated in Python 2.6
0159 from sets import Set, ImmutableSet
0160 registerConverter(Set, SequenceConverter)
0161 registerConverter(ImmutableSet, SequenceConverter)
0162
0163if hasattr(time, 'struct_time'):
0164 def StructTimeConverter(value, db):
0165 return time.strftime("'%Y-%m-%d %H:%M:%S'", value)
0166
0167 registerConverter(time.struct_time, StructTimeConverter)
0168
0169def DateTimeConverter(value, db):
0170 return "'%04d-%02d-%02d %02d:%02d:%02d'" % (
0171 value.year, value.month, value.day,
0172 value.hour, value.minute, value.second)
0173
0174registerConverter(datetime.datetime, DateTimeConverter)
0175
0176def DateConverter(value, db):
0177 return "'%04d-%02d-%02d'" % (value.year, value.month, value.day)
0178
0179registerConverter(datetime.date, DateConverter)
0180
0181def TimeConverter(value, db):
0182 return "'%02d:%02d:%02d'" % (value.hour, value.minute, value.second)
0183
0184registerConverter(datetime.time, TimeConverter)
0185
0186def DecimalConverter(value, db):
0187 # See http://mail.python.org/pipermail/python-dev/2008-March/078189.html
0188 return str(value.to_eng_string()) # Convert to str to work around a bug in Python 2.5.2
0189
0190registerConverter(Decimal, DecimalConverter)
0191
0192def TimedeltaConverter(value, db):
0193
0194 return """INTERVAL '%d days %d seconds'""" % (value.days, value.seconds)
0196
0197registerConverter(datetime.timedelta, TimedeltaConverter)
0198
0199
0200def sqlrepr(obj, db=None):
0201 try:
0202 reprFunc = obj.__sqlrepr__
0203 except AttributeError:
0204 converter = lookupConverter(obj)
0205 if converter is None:
0206 raise ValueError, "Unknown SQL builtin type: %s for %s" % (type(obj), repr(obj))
0208 return converter(obj, db)
0209 else:
0210 return reprFunc(db)
0211
0212
0213def quote_str(s, db):
0214 if db in ('postgres', 'rdbhost') and ('\\' in s):
0215 return "E'%s'" % s
0216 return "'%s'" % s
0217
0218def unquote_str(s):
0219 if s[:2].upper().startswith("E'") and s.endswith("'"):
0220 return s[2:-1]
0221 elif s.startswith("'") and s.endswith("'"):
0222 return s[1:-1]
0223 else:
0224 return s`