Merge remote-tracking branch 'origin/pycurl' into planetlab-4_0-branch
[plcapi.git] / psycopg2 / psycopg / typecast.c
1 /* typecast.c - basic utility functions related to typecasting
2  *
3  * Copyright (C) 2003 Federico Di Gregorio <fog@debian.org>
4  *
5  * This file is part of psycopg.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2,
10  * or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20  */
21
22 #include <Python.h>
23 #include <structmember.h>
24
25 #define PSYCOPG_MODULE
26 #include "psycopg/config.h"
27 #include "psycopg/psycopg.h"
28 #include "psycopg/python.h"
29 #include "psycopg/typecast.h"
30 #include "psycopg/cursor.h"
31
32 /* usefull function used by some typecasters */
33
34 static char *
35 skip_until_space(char *s)
36 {
37     while (*s && *s != ' ') s++;
38     return s;
39 }
40
41 static char *
42 skip_until_space2(char *s, int *len)
43 {
44     while (*len > 0 && *s && *s != ' ') {
45         s++; (*len)--;
46     }
47     return s;
48 }
49
50 static int
51 typecast_parse_date(char* s, char** t, int* len,
52                      int* year, int* month, int* day)
53 {
54     int acc = -1, cz = 0;
55     
56     Dprintf("typecast_parse_date: len = %d, s = %s", *len, s);
57      
58     while (cz < 3 && *len > 0 && *s) {
59         switch (*s) {
60         case '-':
61         case ' ':
62         case 'T':
63             if (cz == 0) *year = acc;
64             else if (cz == 1) *month = acc;
65             else if (cz == 2) *day = acc;
66             acc = -1; cz++;
67             break;
68         default:
69             acc = (acc == -1 ? 0 : acc*10) + ((int)*s - (int)'0');
70             break;            
71         }
72
73         s++; (*len)--;
74     }
75
76     if (acc != -1) {
77         *day = acc;
78         cz += 1;
79     }
80     if (t != NULL) *t = s;    
81
82     return cz;
83 }
84
85 static int
86 typecast_parse_time(char* s, char** t, int* len,
87                      int* hh, int* mm, int* ss, int* us, int* tz)
88 {
89     int acc = -1, cz = 0;
90     int tzs = 1, tzhh = 0, tzmm = 0;
91     int usd = 0;
92     
93     /* sets microseconds and timezone to 0 because they may be missing */
94     *us = *tz = 0;
95     
96     Dprintf("typecast_parse_time: len = %d, s = %s", *len, s);
97      
98     while (cz < 6 && *len > 0 && *s) {
99         switch (*s) {
100         case ':':
101             if (cz == 0) *hh = acc;
102             else if (cz == 1) *mm = acc;
103             else if (cz == 2) *ss = acc;
104             else if (cz == 3) *us = acc;
105             else if (cz == 4) tzhh = acc;
106             acc = -1; cz++;
107             break;
108         case '.':
109             /* we expect seconds and if we don't get them we return an error */
110             if (cz != 2) return -1;
111             *ss = acc;
112             acc = -1; cz++;
113             break;
114         case '+':
115         case '-':
116             /* seconds or microseconds here, anything else is an error */
117             if (cz < 2 || cz > 3) return -1;
118             if (*s == '-') tzs = -1;
119             if      (cz == 2) *ss = acc;
120             else if (cz == 3) *us = acc;
121             acc = -1; cz = 4;
122             break;
123         default:
124             acc = (acc == -1 ? 0 : acc*10) + ((int)*s - (int)'0');
125             if (cz == 3) usd += 1;
126             break;            
127         }
128
129         s++; (*len)--;
130     }
131
132     if (acc != -1) {
133         if (cz == 2)      { *ss = acc; cz += 1; }
134         else if (cz == 3) { *us = acc; cz += 1; }
135         else if (cz == 4) { tzhh = acc; cz += 1; }
136         else if (cz == 5)   tzmm = acc;
137     }
138     if (t != NULL) *t = s;
139     
140     *tz = tzs * tzhh*60 + tzmm;
141     
142     if (*us != 0.0) {
143         while (usd++ < 6) *us *= 10.0;
144     }
145     
146     return cz;
147 }
148
149 /** include casting objects **/
150 #include "psycopg/typecast_basic.c"
151 #include "psycopg/typecast_binary.c"
152
153 #ifdef HAVE_MXDATETIME
154 #include "psycopg/typecast_mxdatetime.c"
155 #endif
156
157 #ifdef HAVE_PYDATETIME
158 #include "psycopg/typecast_datetime.c"
159 #endif
160
161 #include "psycopg/typecast_array.c"
162 #include "psycopg/typecast_builtins.c"
163
164
165 /* a list of initializers, used to make the typecasters accessible anyway */
166 #ifdef HAVE_PYDATETIME
167 typecastObject_initlist typecast_pydatetime[] = {
168     {"PYDATETIME", typecast_DATETIME_types, typecast_PYDATETIME_cast},
169     {"PYTIME", typecast_TIME_types, typecast_PYTIME_cast},
170     {"PYDATE", typecast_DATE_types, typecast_PYDATE_cast},
171     {"PYINTERVAL", typecast_INTERVAL_types, typecast_PYINTERVAL_cast},    
172     {NULL, NULL, NULL}
173 };
174 #endif
175
176 /* a list of initializers, used to make the typecasters accessible anyway */
177 #ifdef HAVE_MXDATETIME
178 typecastObject_initlist typecast_mxdatetime[] = {
179     {"MXDATETIME", typecast_DATETIME_types, typecast_MXDATE_cast},
180     {"MXTIME", typecast_TIME_types, typecast_MXTIME_cast},
181     {"MXDATE", typecast_DATE_types, typecast_MXDATE_cast},
182     {"MXINTERVAL", typecast_INTERVAL_types, typecast_MXINTERVAL_cast},    
183     {NULL, NULL, NULL}
184 };
185 #endif
186
187
188 /** the type dictionary and associated functions **/
189
190 PyObject *psyco_types;
191 PyObject *psyco_default_cast;
192 PyObject *psyco_binary_types;
193 PyObject *psyco_default_binary_cast;
194
195 static long int typecast_default_DEFAULT[] = {0};
196 static typecastObject_initlist typecast_default = {
197     "DEFAULT", typecast_default_DEFAULT, typecast_STRING_cast};
198
199
200 /* typecast_init - initialize the dictionary and create default types */
201
202 int
203 typecast_init(PyObject *dict)
204 {
205     int i;
206     
207     /* create type dictionary and put it in module namespace */
208     psyco_types = PyDict_New();
209     psyco_binary_types = PyDict_New();
210     
211     if (!psyco_types || !psyco_binary_types) {
212         Py_XDECREF(psyco_types);
213         Py_XDECREF(psyco_binary_types);
214         return -1;
215     }                         
216
217     PyDict_SetItemString(dict, "string_types", psyco_types);
218     PyDict_SetItemString(dict, "binary_types", psyco_binary_types);
219     
220     /* insert the cast types into the 'types' dictionary and register them in
221        the module dictionary */
222     for (i = 0; typecast_builtins[i].name != NULL; i++) {
223         typecastObject *t;
224
225         Dprintf("typecast_init: initializing %s", typecast_builtins[i].name);
226
227         t = (typecastObject *)typecast_from_c(&(typecast_builtins[i]), dict);
228         if (t == NULL) return -1;
229         if (typecast_add((PyObject *)t, 0) != 0) return -1;
230
231         PyDict_SetItem(dict, t->name, (PyObject *)t);
232
233         /* export binary object */
234         if (typecast_builtins[i].values == typecast_BINARY_types) {
235             psyco_default_binary_cast = (PyObject *)t;
236         }
237     }
238     
239     /* create and save a default cast object (but does not register it) */
240     psyco_default_cast = typecast_from_c(&typecast_default, dict);
241
242     /* register the date/time typecasters with their original names */
243 #ifdef HAVE_MXDATETIME
244     for (i = 0; typecast_mxdatetime[i].name != NULL; i++) {
245         typecastObject *t;
246         Dprintf("typecast_init: initializing %s", typecast_mxdatetime[i].name);
247         t = (typecastObject *)typecast_from_c(&(typecast_mxdatetime[i]), dict);
248         if (t == NULL) return -1;
249         PyDict_SetItem(dict, t->name, (PyObject *)t);
250     }
251 #endif
252 #ifdef HAVE_PYDATETIME
253     for (i = 0; typecast_pydatetime[i].name != NULL; i++) {
254         typecastObject *t;
255         Dprintf("typecast_init: initializing %s", typecast_pydatetime[i].name);
256         t = (typecastObject *)typecast_from_c(&(typecast_pydatetime[i]), dict);
257         if (t == NULL) return -1;
258         PyDict_SetItem(dict, t->name, (PyObject *)t);
259     }
260 #endif
261     
262     return 0;
263 }
264
265 /* typecast_add - add a type object to the dictionary */
266 int
267 typecast_add(PyObject *obj, int binary)
268 {
269     PyObject *val;
270     int len, i;
271
272     typecastObject *type = (typecastObject *)obj;
273     
274     Dprintf("typecast_add: object at %p, values refcnt = %d",
275             obj, type->values->ob_refcnt);
276
277     len = PyTuple_Size(type->values);
278     for (i = 0; i < len; i++) {
279         val = PyTuple_GetItem(type->values, i);
280         Dprintf("typecast_add:     adding val: %ld", PyInt_AsLong(val));
281         if (binary) {
282             PyDict_SetItem(psyco_binary_types, val, obj);
283         }
284         else {
285             PyDict_SetItem(psyco_types, val, obj);
286         }
287     }
288
289     Dprintf("typecast_add:     base caster: %p", type->bcast);
290
291     return 0;
292 }
293
294
295 /** typecast type **/
296
297 #define OFFSETOF(x) offsetof(typecastObject, x)
298
299 static int
300 typecast_cmp(PyObject *obj1, PyObject* obj2)
301 {
302     typecastObject *self = (typecastObject*)obj1;
303     typecastObject *other = NULL;
304     PyObject *number = NULL;
305     int i, j, res = -1;
306     
307     if (PyObject_TypeCheck(obj2, &typecastType)) {
308         other = (typecastObject*)obj2;
309     }
310     else {
311         number = PyNumber_Int(obj2);
312     }
313
314     Dprintf("typecast_cmp: other = %p, number = %p", other, number);
315     
316     for (i=0; i < PyObject_Length(self->values) && res == -1; i++) {
317         long int val = PyInt_AsLong(PyTuple_GET_ITEM(self->values, i));
318         
319         if (other != NULL) {
320             for (j=0; j < PyObject_Length(other->values); j++) {
321                 if (PyInt_AsLong(PyTuple_GET_ITEM(other->values, j)) == val) {
322                     res = 0; break;   
323                 }
324             }
325         }
326         
327         else if (number != NULL) {
328             if (PyInt_AsLong(number) == val) {
329                 res = 0; break;
330             }
331         }
332     }
333     
334     Py_XDECREF(number);
335     return res;
336 }
337
338 static PyObject*
339 typecast_richcompare(PyObject *obj1, PyObject* obj2, int opid)
340 {
341     PyObject *result = NULL;
342     int res = typecast_cmp(obj1, obj2);
343     
344     if (PyErr_Occurred()) return NULL;
345     
346     if ((opid == Py_EQ && res == 0) || (opid != Py_EQ && res != 0))
347         result = Py_True;
348     else
349         result = Py_False;
350     
351     Py_INCREF(result);
352     return result;
353 }
354      
355 static struct PyMemberDef typecastObject_members[] = {
356     {"name", T_OBJECT, OFFSETOF(name), RO},
357     {"values", T_OBJECT, OFFSETOF(values), RO},
358     {NULL}
359 };
360     
361 static void
362 typecast_dealloc(PyObject *obj)
363 {
364     typecastObject *self = (typecastObject*)obj;
365     
366     Py_XDECREF(self->values);
367     Py_XDECREF(self->name);
368     Py_XDECREF(self->pcast);
369
370     PyObject_Del(self);
371 }
372
373 static PyObject *
374 typecast_call(PyObject *obj, PyObject *args, PyObject *kwargs)
375 {   
376     PyObject *string, *cursor;
377     
378     if (!PyArg_ParseTuple(args, "OO", &string, &cursor)) {
379         return NULL;
380     }
381
382     return typecast_cast(obj,
383                          PyString_AsString(string), PyString_Size(string),
384                          cursor);
385 }
386
387 PyTypeObject typecastType = {
388     PyObject_HEAD_INIT(NULL)
389     0,
390     "psycopg2._psycopg.type",
391     sizeof(typecastObject),
392     0,
393     
394     typecast_dealloc, /*tp_dealloc*/
395     0,          /*tp_print*/ 
396     0,          /*tp_getattr*/
397     0,          /*tp_setattr*/
398     typecast_cmp, /*tp_compare*/
399     0,          /*tp_repr*/
400     0,          /*tp_as_number*/
401     0,          /*tp_as_sequence*/
402     0,          /*tp_as_mapping*/
403     0,          /*tp_hash */
404
405     typecast_call, /*tp_call*/
406     0,          /*tp_str*/
407     0,          /*tp_getattro*/
408     0,          /*tp_setattro*/
409     0,          /*tp_as_buffer*/
410
411     Py_TPFLAGS_HAVE_RICHCOMPARE, /*tp_flags*/
412     "psycopg type-casting object", /*tp_doc*/
413     
414     0,          /*tp_traverse*/
415     0,          /*tp_clear*/
416
417     typecast_richcompare, /*tp_richcompare*/
418     0,          /*tp_weaklistoffset*/
419
420     0,          /*tp_iter*/
421     0,          /*tp_iternext*/
422
423     /* Attribute descriptor and subclassing stuff */
424
425     0, /*tp_methods*/
426     typecastObject_members, /*tp_members*/
427     0,          /*tp_getset*/
428     0,          /*tp_base*/
429     0,          /*tp_dict*/
430     
431     0,          /*tp_descr_get*/
432     0,          /*tp_descr_set*/
433     0,          /*tp_dictoffset*/
434     
435     0, /*tp_init*/
436     0, /*tp_alloc  will be set to PyType_GenericAlloc in module init*/
437     0, /*tp_new*/
438     0, /*tp_free  Low-level free-memory routine */
439     0,          /*tp_is_gc For PyObject_IS_GC */
440     0,          /*tp_bases*/
441     0,          /*tp_mro method resolution order */
442     0,          /*tp_cache*/
443     0,          /*tp_subclasses*/
444     0           /*tp_weaklist*/
445 };
446
447 static PyObject *
448 typecast_new(PyObject *name, PyObject *values, PyObject *cast, PyObject *base)
449 {
450     typecastObject *obj;
451
452     obj = PyObject_NEW(typecastObject, &typecastType);
453     if (obj == NULL) return NULL;
454
455     Dprintf("typecast_new: new type at = %p, refcnt = %d", obj, obj->ob_refcnt);
456              
457     Py_INCREF(values);
458     obj->values = values;
459     
460     if (name) {
461         Py_INCREF(name);
462         obj->name = name;
463     }
464     else {
465         Py_INCREF(Py_None);
466         obj->name = Py_None;
467     }
468
469     obj->pcast = NULL;
470     obj->ccast = NULL;
471     obj->bcast = base;
472
473     if (obj->bcast) Py_INCREF(obj->bcast);
474
475     /* FIXME: raise an exception when None is passed as Python caster */
476     if (cast && cast != Py_None) {
477         Py_INCREF(cast);
478         obj->pcast = cast;
479     }
480     
481     Dprintf("typecast_new: typecast object created at %p", obj);
482     
483     return (PyObject *)obj;
484 }
485
486 PyObject *
487 typecast_from_python(PyObject *self, PyObject *args, PyObject *keywds)
488 {
489     PyObject *v, *name, *cast = NULL, *base = NULL;
490
491     static char *kwlist[] = {"values", "name", "castobj", "baseobj", NULL};
492     
493     if (!PyArg_ParseTupleAndKeywords(args, keywds, "O!|O!OO", kwlist, 
494                                      &PyTuple_Type, &v,
495                                      &PyString_Type, &name,
496                                      &cast, &base)) {
497         return NULL;
498     }
499     
500     return typecast_new(name, v, cast, base);
501 }
502
503 PyObject *
504 typecast_from_c(typecastObject_initlist *type, PyObject *dict)
505 {
506     PyObject *tuple, *base = NULL;
507     typecastObject *obj;
508     int i, len = 0;
509
510     /* before doing anything else we look for the base */
511     if (type->base) {
512         /* NOTE: base is a borrowed reference! */
513         base = PyDict_GetItemString(dict, type->base);
514         if (!base) {
515             PyErr_Format(Error, "typecast base not found: %s", type->base);
516             return NULL;
517         }
518     }
519
520     while (type->values[len] != 0) len++;
521     
522     tuple = PyTuple_New(len);
523     if (!tuple) return NULL;
524     
525     for (i = 0; i < len ; i++) {
526         PyTuple_SET_ITEM(tuple, i, PyInt_FromLong(type->values[i]));
527     }
528
529         
530     obj = (typecastObject *)
531         typecast_new(PyString_FromString(type->name), tuple, NULL, base);
532     
533     if (obj) {
534         obj->ccast = type->cast;
535         obj->pcast = NULL;
536     }
537     return (PyObject *)obj;
538 }
539
540 PyObject *
541 typecast_cast(PyObject *obj, char *str, int len, PyObject *curs)
542 {
543     PyObject *old, *res = NULL;
544     typecastObject *self = (typecastObject *)obj;
545
546     /* we don't incref, the caster *can't* die at this point */
547     old = ((cursorObject*)curs)->caster;
548     ((cursorObject*)curs)->caster = obj;
549     
550     if (self->ccast) {
551         res = self->ccast(str, len, curs);
552     }
553     else if (self->pcast) {
554         res = PyObject_CallFunction(self->pcast, "s#O", str, len, curs);
555     }
556     else {
557         PyErr_SetString(Error, "internal error: no casting function found");
558     }
559
560     ((cursorObject*)curs)->caster = old;
561
562     return res;
563 }