0001from array import array
0002
0003try:
0004    import mx.DateTime.ISO
0005    origISOStr = mx.DateTime.ISO.strGMT
0006    from mx.DateTime import DateTimeType, DateTimeDeltaType
0007except ImportError:
0008    try:
0009        import DateTime.ISO
0010        origISOStr = DateTime.ISO.strGMT
0011        from DateTime import DateTimeType, DateTimeDeltaType
0012    except ImportError:
0013        origISOStr = None
0014        DateTimeType = None
0015        DateTimeDeltaType = None
0016
0017import time
0018import datetime
0019
0020try:
0021    import Sybase
0022    NumericType=Sybase.NumericType
0023except ImportError:
0024    NumericType = None
0025
0026from decimal import Decimal
0027from sets import Set, ImmutableSet
0028from types import ClassType, InstanceType, NoneType
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'):
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    return "'%s'" % value
0094
0095registerConverter(str, StringLikeConverter)
0096registerConverter(unicode, StringLikeConverter)
0097registerConverter(array, StringLikeConverter)
0098registerConverter(buffer, StringLikeConverter)
0099
0100def IntConverter(value, db):
0101    return repr(int(value))
0102
0103registerConverter(int, IntConverter)
0104
0105def LongConverter(value, db):
0106    return str(value)
0107
0108registerConverter(long, LongConverter)
0109
0110if NumericType:
0111    registerConverter(NumericType, IntConverter)
0112
0113def BoolConverter(value, db):
0114    if db in ('postgres',):
0115        if value:
0116            return "'t'"
0117        else:
0118            return "'f'"
0119    else:
0120        if value:
0121            return '1'
0122        else:
0123            return '0'
0124
0125registerConverter(bool, BoolConverter)
0126
0127def FloatConverter(value, db):
0128    return repr(value)
0129
0130registerConverter(float, FloatConverter)
0131
0132if DateTimeType:
0133    def DateTimeConverter(value, db):
0134        return "'%s'" % isoStr(value)
0135
0136    registerConverter(DateTimeType, DateTimeConverter)
0137
0138    def TimeConverter(value, db):
0139        return "'%s'" % value.strftime("%T")
0140
0141    registerConverter(DateTimeDeltaType, TimeConverter)
0142
0143def NoneConverter(value, db):
0144    return "NULL"
0145
0146registerConverter(NoneType, NoneConverter)
0147
0148def SequenceConverter(value, db):
0149    return "(%s)" % ", ".join([sqlrepr(v, db) for v in value])
0150
0151registerConverter(tuple, SequenceConverter)
0152registerConverter(list, SequenceConverter)
0153registerConverter(dict, SequenceConverter)
0154registerConverter(set, SequenceConverter)
0155registerConverter(frozenset, SequenceConverter)
0156registerConverter(Set, SequenceConverter)
0157registerConverter(ImmutableSet, SequenceConverter)
0158
0159if hasattr(time, 'struct_time'):
0160    def StructTimeConverter(value, db):
0161        return time.strftime("'%Y-%m-%d %H:%M:%S'", value)
0162
0163    registerConverter(time.struct_time, StructTimeConverter)
0164
0165def DateTimeConverter(value, db):
0166    return "'%04d-%02d-%02d %02d:%02d:%02d'" % (
0167        value.year, value.month, value.day,
0168        value.hour, value.minute, value.second)
0169
0170registerConverter(datetime.datetime, DateTimeConverter)
0171
0172def DateConverter(value, db):
0173    return "'%04d-%02d-%02d'" % (value.year, value.month, value.day)
0174
0175registerConverter(datetime.date, DateConverter)
0176
0177def TimeConverter(value, db):
0178    return "'%02d:%02d:%02d'" % (value.hour, value.minute, value.second)
0179
0180registerConverter(datetime.time, TimeConverter)
0181
0182def DecimalConverter(value, db):
0183    # See http://mail.python.org/pipermail/python-dev/2008-March/078189.html
0184    return str(value.to_eng_string()) # Convert to str to work around a bug in Python 2.5.2
0185
0186registerConverter(Decimal, DecimalConverter)
0187
0188def sqlrepr(obj, db=None):
0189    try:
0190        reprFunc = obj.__sqlrepr__
0191    except AttributeError:
0192        converter = lookupConverter(obj)
0193        if converter is None:
0194            raise ValueError, "Unknown SQL builtin type: %s for %s" %                     (type(obj), repr(obj))
0196        return converter(obj, db)
0197    else:
0198        return reprFunc(db)