~ubuntu-branches/ubuntu/hardy/psycopg2/hardy

« back to all changes in this revision

Viewing changes to psycopg/typecast.c

  • Committer: Bazaar Package Importer
  • Author(s): Fabio Tranchitella
  • Date: 2006-08-09 10:28:30 UTC
  • Revision ID: james.westby@ubuntu.com-20060809102830-grac1dsp24uyqfp4
Tags: upstream-2.0.4
ImportĀ upstreamĀ versionĀ 2.0.4

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
}