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 types import ClassType, InstanceType, NoneType
0027
0028try:
0029    from decimal import Decimal
0030except ImportError:
0031    Decimal = None
0032
0033########################################
0034## Quoting
0035########################################
0036
0037sqlStringReplace = [
0038    ("'", "''"),
0039    ('\\', '\\\\'),
0040    ('\000', '\\0'),
0041    ('\b', '\\b'),
0042    ('\n', '\\n'),
0043    ('\r', '\\r'),
0044    ('\t', '\\t'),
0045]
0046
0047def isoStr(val):
0048    """
0049    Gets rid of time zone information
0050    (@@: should we convert to GMT?)
0051    """
0052    val = origISOStr(val)
0053    if val.find('+') == -1:
0054        return val
0055    else:
0056        return val[:val.find('+')]
0057
0058class ConverterRegistry:
0059
0060    def __init__(self):
0061        self.basic = {}
0062        self.klass = {}
0063
0064    def registerConverter(self, typ, func):
0065        if type(typ) is ClassType:
0066            self.klass[typ] = func
0067        else:
0068            self.basic[typ] = func
0069
0070    def lookupConverter(self, value, default=None):
0071        if type(value) is InstanceType:
0072            # lookup on klasses dict
0073            return self.klass.get(value.__class__, default)
0074        return self.basic.get(type(value), default)
0075
0076converters = ConverterRegistry()
0077registerConverter = converters.registerConverter
0078lookupConverter = converters.lookupConverter
0079
0080def StringLikeConverter(value, db):
0081    if isinstance(value, array):
0082        try:
0083            value = value.tounicode()
0084        except ValueError:
0085            value = value.tostring()
0086    elif isinstance(value, buffer):
0087        value = str(value)
0088
0089    if db in ('mysql', 'postgres'):
0090        for orig, repl in sqlStringReplace:
0091            value = value.replace(orig, repl)
0092    elif db in ('sqlite', 'firebird', 'sybase', 'maxdb', 'mssql'):
0093        value = value.replace("'", "''")
0094    else:
0095        assert 0, "Database %s unknown" % db
0096    return "'%s'" % value
0097
0098registerConverter(str, StringLikeConverter)
0099registerConverter(unicode, StringLikeConverter)
0100registerConverter(array, StringLikeConverter)
0101registerConverter(buffer, StringLikeConverter)
0102
0103def IntConverter(value, db):
0104    return repr(int(value))
0105
0106registerConverter(int, IntConverter)
0107
0108def LongConverter(value, db):
0109    return str(value)
0110
0111registerConverter(long, LongConverter)
0112
0113if NumericType:
0114    registerConverter(NumericType, IntConverter)
0115
0116def BoolConverter(value, db):
0117    if db in ('postgres',):
0118        if value:
0119            return "'t'"
0120        else:
0121            return "'f'"
0122    else:
0123        if value:
0124            return '1'
0125        else:
0126            return '0'
0127
0128registerConverter(bool, BoolConverter)
0129
0130def FloatConverter(value, db):
0131    return repr(value)
0132
0133registerConverter(float, FloatConverter)
0134
0135if DateTimeType:
0136    def DateTimeConverter(value, db):
0137        return "'%s'" % isoStr(value)
0138
0139    registerConverter(DateTimeType, DateTimeConverter)
0140
0141    def TimeConverter(value, db):
0142        return "'%s'" % value.strftime("%T")
0143
0144    registerConverter(DateTimeDeltaType, TimeConverter)
0145
0146def NoneConverter(value, db):
0147    return "NULL"
0148
0149registerConverter(NoneType, NoneConverter)
0150
0151def SequenceConverter(value, db):
0152    return "(%s)" % ", ".join([sqlrepr(v, db) for v in value])
0153
0154registerConverter(tuple, SequenceConverter)
0155registerConverter(list, SequenceConverter)
0156registerConverter(dict, SequenceConverter)
0157try:
0158    set, frozenset
0159except NameError:
0160    pass
0161else:
0162    registerConverter(set, SequenceConverter)
0163    registerConverter(frozenset, SequenceConverter)
0164try:
0165    from sets import Set, ImmutableSet
0166except ImportError:
0167    pass
0168else:
0169    registerConverter(Set, SequenceConverter)
0170    registerConverter(ImmutableSet, SequenceConverter)
0171
0172if hasattr(time, 'struct_time'):
0173    def StructTimeConverter(value, db):
0174        return time.strftime("'%Y-%m-%d %H:%M:%S'", value)
0175
0176    registerConverter(time.struct_time, StructTimeConverter)
0177
0178def DateTimeConverter(value, db):
0179    return "'%04d-%02d-%02d %02d:%02d:%02d'" % (
0180        value.year, value.month, value.day,
0181        value.hour, value.minute, value.second)
0182
0183registerConverter(datetime.datetime, DateTimeConverter)
0184
0185def DateConverter(value, db):
0186    return "'%04d-%02d-%02d'" % (value.year, value.month, value.day)
0187
0188registerConverter(datetime.date, DateConverter)
0189
0190def TimeConverter(value, db):
0191    return "'%02d:%02d:%02d'" % (value.hour, value.minute, value.second)
0192
0193registerConverter(datetime.time, TimeConverter)
0194
0195if Decimal:
0196    def DecimalConverter(value, db):
0197        return value.to_eng_string()
0198
0199    registerConverter(Decimal, DecimalConverter)
0200
0201def sqlrepr(obj, db=None):
0202    try:
0203        reprFunc = obj.__sqlrepr__
0204    except AttributeError:
0205        converter = lookupConverter(obj)
0206        if converter is None:
0207            raise ValueError, "Unknown SQL builtin type: %s for %s" %                     (type(obj), repr(obj))
0209        return converter(obj, db)
0210    else:
0211        return reprFunc(db)