Package osh :: Package external :: Package pg8000 :: Module types
[frames] | no frames]

Source Code for Module osh.external.pg8000.types

  1  # vim: sw=4:expandtab:foldmethod=marker 
  2  # 
  3  # Copyright (c) 2007, Mathieu Fenniak 
  4  # All rights reserved. 
  5  # 
  6  # Redistribution and use in source and binary forms, with or without 
  7  # modification, are permitted provided that the following conditions are 
  8  # met: 
  9  # 
 10  # * Redistributions of source code must retain the above copyright notice, 
 11  # this list of conditions and the following disclaimer. 
 12  # * Redistributions in binary form must reproduce the above copyright notice, 
 13  # this list of conditions and the following disclaimer in the documentation 
 14  # and/or other materials provided with the distribution. 
 15  # * The name of the author may not be used to endorse or promote products 
 16  # derived from this software without specific prior written permission. 
 17  # 
 18  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
 19  # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
 20  # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
 21  # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
 22  # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
 23  # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
 24  # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
 25  # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
 26  # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
 27  # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
 28  # POSSIBILITY OF SUCH DAMAGE. 
 29   
 30  __author__ = "Mathieu Fenniak" 
 31   
 32  import datetime 
 33  import decimal 
 34  import struct 
 35  from errors import NotSupportedError 
 36   
37 -class Bytea(str):
38 pass
39
40 -class Interval(object):
41 - def __init__(self, microseconds, days, months):
42 self.microseconds = microseconds 43 self.days = days 44 self.months = months
45
46 - def __repr__(self):
47 return "<Interval %s months %s days %s microseconds>" % (self.months, self.days, self.microseconds)
48
49 - def __cmp__(self, other):
50 c = cmp(self.months, other.months) 51 if c != 0: return c 52 c = cmp(self.days, other.days) 53 if c != 0: return c 54 return cmp(self.microseconds, other.microseconds)
55
56 -def pg_type_info(typ):
57 data = py_types.get(typ) 58 if data == None: 59 raise NotSupportedError("type %r not mapped to pg type" % typ) 60 type_oid = data.get("tid") 61 if type_oid == None: 62 raise InternalError("type %r has no type_oid" % typ) 63 elif type_oid == -1: 64 # special case: NULL values 65 return type_oid, 0 66 # prefer bin, but go with whatever exists 67 if data.get("bin_out"): 68 format = 1 69 elif data.get("txt_out"): 70 format = 0 71 else: 72 raise InternalError("no conversion fuction for type %r" % typ) 73 return type_oid, format
74
75 -def pg_value(v, fc, **kwargs):
76 typ = type(v) 77 data = py_types.get(typ) 78 if data == None: 79 raise NotSupportedError("type %r not mapped to pg type" % typ) 80 elif data.get("tid") == -1: 81 # special case: NULL values 82 return None 83 if fc == 0: 84 func = data.get("txt_out") 85 elif fc == 1: 86 func = data.get("bin_out") 87 else: 88 raise InternalError("unrecognized format code %r" % fc) 89 if func == None: 90 raise NotSupportedError("type %r, format code %r not supported" % (typ, fc)) 91 return func(v, **kwargs)
92
93 -def py_type_info(description):
94 type_oid = description['type_oid'] 95 data = pg_types.get(type_oid) 96 if data == None: 97 raise NotSupportedError("type oid %r not mapped to py type" % type_oid) 98 # prefer bin, but go with whatever exists 99 if data.get("bin_in"): 100 format = 1 101 elif data.get("txt_in"): 102 format = 0 103 else: 104 raise InternalError("no conversion fuction for type oid %r" % type_oid) 105 return format
106
107 -def py_value(v, description, **kwargs):
108 if v == None: 109 # special case - NULL value 110 return None 111 type_oid = description['type_oid'] 112 format = description['format'] 113 data = pg_types.get(type_oid) 114 if data == None: 115 raise NotSupportedError("type oid %r not supported" % type_oid) 116 if format == 0: 117 func = data.get("txt_in") 118 elif format == 1: 119 func = data.get("bin_in") 120 else: 121 raise NotSupportedError("format code %r not supported" % format) 122 if func == None: 123 raise NotSupportedError("data response format %r, type %r not supported" % (format, type_oid)) 124 return func(v, **kwargs)
125
126 -def boolrecv(data, **kwargs):
127 return data == "\x01"
128
129 -def boolout(v, **kwargs):
130 if v: 131 return 't' 132 else: 133 return 'f'
134
135 -def int2recv(data, **kwargs):
136 return struct.unpack("!h", data)[0]
137
138 -def int4recv(data, **kwargs):
139 return struct.unpack("!i", data)[0]
140
141 -def int4send(v, **kwargs):
142 return struct.pack("!i", v)
143
144 -def int8recv(data, **kwargs):
145 return struct.unpack("!q", data)[0]
146
147 -def float4recv(data, **kwargs):
148 return struct.unpack("!f", data)[0]
149
150 -def float8recv(data, **kwargs):
151 return struct.unpack("!d", data)[0]
152
153 -def float8send(v, **kwargs):
154 return struct.pack("!d", v)
155
156 -def timestamp_recv(data, integer_datetimes, **kwargs):
157 if integer_datetimes: 158 # data is 64-bit integer representing milliseconds since 2000-01-01 159 val = struct.unpack("!q", data)[0] 160 return datetime.datetime(2000, 1, 1) + datetime.timedelta(microseconds = val) 161 else: 162 # data is double-precision float representing seconds since 2000-01-01 163 val = struct.unpack("!d", data)[0] 164 return datetime.datetime(2000, 1, 1) + datetime.timedelta(seconds = val)
165
166 -def timestamp_send(v, integer_datetimes, **kwargs):
167 delta = v - datetime.datetime(2000, 1, 1) 168 val = delta.microseconds + (delta.seconds * 1000000) + (delta.days * 86400000000) 169 if integer_datetimes: 170 return struct.pack("!q", val) 171 else: 172 return struct.pack("!d", val / 1000.0 / 1000.0)
173
174 -def date_in(data, **kwargs):
175 year = int(data[0:4]) 176 month = int(data[5:7]) 177 day = int(data[8:10]) 178 return datetime.date(year, month, day)
179
180 -def date_out(v, **kwargs):
181 return v.isoformat()
182
183 -def time_in(data, **kwargs):
184 hour = int(data[0:2]) 185 minute = int(data[3:5]) 186 sec = decimal.Decimal(data[6:]) 187 return datetime.time(hour, minute, int(sec), int((sec - int(sec)) * 1000000))
188
189 -def time_out(v, **kwargs):
190 return v.isoformat()
191
192 -def numeric_in(data, **kwargs):
193 if data.find(".") == -1: 194 return int(data) 195 else: 196 return decimal.Decimal(data)
197
198 -def numeric_out(v, **kwargs):
199 return str(v)
200 201 # PostgreSQL encodings: 202 # http://www.postgresql.org/docs/8.3/interactive/multibyte.html 203 # Python encodings: 204 # http://www.python.org/doc/2.4/lib/standard-encodings.html 205 # 206 # Commented out encodings don't require a name change between PostgreSQL and 207 # Python. If the py side is None, then the encoding isn't supported. 208 pg_to_py_encodings = { 209 # Not supported: 210 "mule_internal": None, 211 "euc_tw": None, 212 213 # Name fine as-is: 214 #"euc_jp", 215 #"euc_jis_2004", 216 #"euc_kr", 217 #"gb18030", 218 #"gbk", 219 #"johab", 220 #"sjis", 221 #"shift_jis_2004", 222 #"uhc", 223 #"utf8", 224 225 # Different name: 226 "euc_cn": "gb2312", 227 "iso_8859_5": "is8859_5", 228 "iso_8859_6": "is8859_6", 229 "iso_8859_7": "is8859_7", 230 "iso_8859_8": "is8859_8", 231 "koi8": "koi8_r", 232 "latin1": "iso8859-1", 233 "latin2": "iso8859_2", 234 "latin3": "iso8859_3", 235 "latin4": "iso8859_4", 236 "latin5": "iso8859_9", 237 "latin6": "iso8859_10", 238 "latin7": "iso8859_13", 239 "latin8": "iso8859_14", 240 "latin9": "iso8859_15", 241 "sql_ascii": "ascii", 242 "win866": "cp886", 243 "win874": "cp874", 244 "win1250": "cp1250", 245 "win1251": "cp1251", 246 "win1252": "cp1252", 247 "win1253": "cp1253", 248 "win1254": "cp1254", 249 "win1255": "cp1255", 250 "win1256": "cp1256", 251 "win1257": "cp1257", 252 "win1258": "cp1258", 253 } 254
255 -def encoding_convert(encoding):
256 return pg_to_py_encodings.get(encoding.lower(), encoding)
257
258 -def varcharin(data, client_encoding, **kwargs):
259 return unicode(data, encoding_convert(client_encoding))
260
261 -def textout(v, client_encoding, **kwargs):
262 return v.encode(encoding_convert(client_encoding))
263
264 -def timestamptz_in(data, **kwargs):
265 year = int(data[0:4]) 266 month = int(data[5:7]) 267 day = int(data[8:10]) 268 hour = int(data[11:13]) 269 minute = int(data[14:16]) 270 tz_sep = data.rfind("-") 271 sec = decimal.Decimal(data[17:tz_sep]) 272 tz = data[tz_sep:] 273 return datetime.datetime(year, month, day, hour, minute, int(sec), int((sec - int(sec)) * 1000000), FixedOffsetTz(tz))
274
275 -class FixedOffsetTz(datetime.tzinfo):
276 - def __init__(self, hrs):
277 self.hrs = int(hrs) 278 self.name = hrs
279
280 - def utcoffset(self, dt):
281 return datetime.timedelta(hours=1) * self.hrs
282
283 - def tzname(self, dt):
284 return self.name
285
286 - def dst(self, dt):
287 return datetime.timedelta(0)
288
289 - def __eq__(self, other):
290 if not isinstance(other, FixedOffsetTz): 291 return False 292 return self.hrs == other.hrs
293
294 -def byteasend(v, **kwargs):
295 return str(v)
296
297 -def bytearecv(data, **kwargs):
298 return Bytea(data)
299 300 # interval support does not provide a Python-usable interval object yet
301 -def interval_recv(data, integer_datetimes, **kwargs):
302 if integer_datetimes: 303 microseconds, days, months = struct.unpack("!qii", data) 304 else: 305 seconds, days, months = struct.unpack("!dii", data) 306 microseconds = int(seconds * 1000 * 1000) 307 return Interval(microseconds, days, months)
308
309 -def interval_send(data, integer_datetimes, **kwargs):
310 if integer_datetimes: 311 return struct.pack("!qii", data.microseconds, data.days, data.months) 312 else: 313 return struct.pack("!dii", data.microseconds / 1000.0 / 1000.0, data.days, data.months)
314 315 py_types = { 316 bool: {"tid": 16, "txt_out": boolout}, 317 int: {"tid": 23, "bin_out": int4send}, 318 long: {"tid": 1700, "txt_out": numeric_out}, 319 str: {"tid": 25, "txt_out": textout}, 320 unicode: {"tid": 25, "txt_out": textout}, 321 float: {"tid": 701, "bin_out": float8send}, 322 decimal.Decimal: {"tid": 1700, "txt_out": numeric_out}, 323 Bytea: {"tid": 17, "bin_out": byteasend}, 324 datetime.datetime: {"tid": 1114, "bin_out": timestamp_send}, 325 datetime.date: {"tid": 1082, "txt_out": date_out}, 326 datetime.time: {"tid": 1083, "txt_out": time_out}, 327 Interval: {"tid": 1186, "bin_out": interval_send}, 328 type(None): {"tid": -1}, 329 } 330 331 pg_types = { 332 16: {"bin_in": boolrecv}, 333 17: {"bin_in": bytearecv}, 334 19: {"txt_in": varcharin}, # name type 335 20: {"bin_in": int8recv}, 336 21: {"bin_in": int2recv}, 337 23: {"bin_in": int4recv}, 338 25: {"txt_in": varcharin}, # TEXT type 339 26: {"txt_in": numeric_in}, # oid type 340 700: {"bin_in": float4recv}, 341 701: {"bin_in": float8recv}, 342 1042: {"txt_in": varcharin}, # CHAR type 343 1043: {"txt_in": varcharin}, # VARCHAR type 344 1082: {"txt_in": date_in}, 345 1083: {"txt_in": time_in}, 346 1114: {"bin_in": timestamp_recv}, 347 1184: {"txt_in": timestamptz_in}, # timestamp w/ tz 348 1186: {"bin_in": interval_recv}, 349 1700: {"txt_in": numeric_in}, 350 2275: {"txt_in": varcharin}, # cstring 351 } 352