1 /* typecast.c - basic utility functions related to typecasting
3 * Copyright (C) 2003 Federico Di Gregorio <fog@debian.org>
5 * This file is part of psycopg.
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.
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.
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.
23 #include <structmember.h>
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"
32 /* usefull function used by some typecasters */
35 skip_until_space(char *s)
37 while (*s && *s != ' ') s++;
42 skip_until_space2(char *s, int *len)
44 while (*len > 0 && *s && *s != ' ') {
51 typecast_parse_date(char* s, char** t, int* len,
52 int* year, int* month, int* day)
56 Dprintf("typecast_parse_date: len = %d, s = %s", *len, s);
58 while (cz < 3 && *len > 0 && *s) {
63 if (cz == 0) *year = acc;
64 else if (cz == 1) *month = acc;
65 else if (cz == 2) *day = acc;
69 acc = (acc == -1 ? 0 : acc*10) + ((int)*s - (int)'0');
80 if (t != NULL) *t = s;
86 typecast_parse_time(char* s, char** t, int* len,
87 int* hh, int* mm, int* ss, int* us, int* tz)
90 int tzs = 1, tzhh = 0, tzmm = 0;
93 /* sets microseconds and timezone to 0 because they may be missing */
96 Dprintf("typecast_parse_time: len = %d, s = %s", *len, s);
98 while (cz < 6 && *len > 0 && *s) {
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;
109 /* we expect seconds and if we don't get them we return an error */
110 if (cz != 2) return -1;
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;
124 acc = (acc == -1 ? 0 : acc*10) + ((int)*s - (int)'0');
125 if (cz == 3) usd += 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;
138 if (t != NULL) *t = s;
140 *tz = tzs * tzhh*60 + tzmm;
143 while (usd++ < 6) *us *= 10.0;
149 /** include casting objects **/
150 #include "psycopg/typecast_basic.c"
151 #include "psycopg/typecast_binary.c"
153 #ifdef HAVE_MXDATETIME
154 #include "psycopg/typecast_mxdatetime.c"
157 #ifdef HAVE_PYDATETIME
158 #include "psycopg/typecast_datetime.c"
161 #include "psycopg/typecast_array.c"
162 #include "psycopg/typecast_builtins.c"
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},
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},
188 /** the type dictionary and associated functions **/
190 PyObject *psyco_types;
191 PyObject *psyco_default_cast;
192 PyObject *psyco_binary_types;
193 PyObject *psyco_default_binary_cast;
195 static long int typecast_default_DEFAULT[] = {0};
196 static typecastObject_initlist typecast_default = {
197 "DEFAULT", typecast_default_DEFAULT, typecast_STRING_cast};
200 /* typecast_init - initialize the dictionary and create default types */
203 typecast_init(PyObject *dict)
207 /* create type dictionary and put it in module namespace */
208 psyco_types = PyDict_New();
209 psyco_binary_types = PyDict_New();
211 if (!psyco_types || !psyco_binary_types) {
212 Py_XDECREF(psyco_types);
213 Py_XDECREF(psyco_binary_types);
217 PyDict_SetItemString(dict, "string_types", psyco_types);
218 PyDict_SetItemString(dict, "binary_types", psyco_binary_types);
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++) {
225 Dprintf("typecast_init: initializing %s", typecast_builtins[i].name);
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;
231 PyDict_SetItem(dict, t->name, (PyObject *)t);
233 /* export binary object */
234 if (typecast_builtins[i].values == typecast_BINARY_types) {
235 psyco_default_binary_cast = (PyObject *)t;
239 /* create and save a default cast object (but does not register it) */
240 psyco_default_cast = typecast_from_c(&typecast_default, dict);
242 /* register the date/time typecasters with their original names */
243 #ifdef HAVE_MXDATETIME
244 for (i = 0; typecast_mxdatetime[i].name != NULL; i++) {
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);
252 #ifdef HAVE_PYDATETIME
253 for (i = 0; typecast_pydatetime[i].name != NULL; i++) {
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);
265 /* typecast_add - add a type object to the dictionary */
267 typecast_add(PyObject *obj, int binary)
272 typecastObject *type = (typecastObject *)obj;
274 Dprintf("typecast_add: object at %p, values refcnt = %d",
275 obj, type->values->ob_refcnt);
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));
282 PyDict_SetItem(psyco_binary_types, val, obj);
285 PyDict_SetItem(psyco_types, val, obj);
289 Dprintf("typecast_add: base caster: %p", type->bcast);
295 /** typecast type **/
297 #define OFFSETOF(x) offsetof(typecastObject, x)
300 typecast_cmp(PyObject *obj1, PyObject* obj2)
302 typecastObject *self = (typecastObject*)obj1;
303 typecastObject *other = NULL;
304 PyObject *number = NULL;
307 if (PyObject_TypeCheck(obj2, &typecastType)) {
308 other = (typecastObject*)obj2;
311 number = PyNumber_Int(obj2);
314 Dprintf("typecast_cmp: other = %p, number = %p", other, number);
316 for (i=0; i < PyObject_Length(self->values) && res == -1; i++) {
317 long int val = PyInt_AsLong(PyTuple_GET_ITEM(self->values, i));
320 for (j=0; j < PyObject_Length(other->values); j++) {
321 if (PyInt_AsLong(PyTuple_GET_ITEM(other->values, j)) == val) {
327 else if (number != NULL) {
328 if (PyInt_AsLong(number) == val) {
339 typecast_richcompare(PyObject *obj1, PyObject* obj2, int opid)
341 PyObject *result = NULL;
342 int res = typecast_cmp(obj1, obj2);
344 if (PyErr_Occurred()) return NULL;
346 if ((opid == Py_EQ && res == 0) || (opid != Py_EQ && res != 0))
355 static struct PyMemberDef typecastObject_members[] = {
356 {"name", T_OBJECT, OFFSETOF(name), RO},
357 {"values", T_OBJECT, OFFSETOF(values), RO},
362 typecast_dealloc(PyObject *obj)
364 typecastObject *self = (typecastObject*)obj;
366 Py_XDECREF(self->values);
367 Py_XDECREF(self->name);
368 Py_XDECREF(self->pcast);
374 typecast_call(PyObject *obj, PyObject *args, PyObject *kwargs)
376 PyObject *string, *cursor;
378 if (!PyArg_ParseTuple(args, "OO", &string, &cursor)) {
382 return typecast_cast(obj,
383 PyString_AsString(string), PyString_Size(string),
387 PyTypeObject typecastType = {
388 PyObject_HEAD_INIT(NULL)
390 "psycopg2._psycopg.type",
391 sizeof(typecastObject),
394 typecast_dealloc, /*tp_dealloc*/
398 typecast_cmp, /*tp_compare*/
401 0, /*tp_as_sequence*/
405 typecast_call, /*tp_call*/
411 Py_TPFLAGS_HAVE_RICHCOMPARE, /*tp_flags*/
412 "psycopg type-casting object", /*tp_doc*/
417 typecast_richcompare, /*tp_richcompare*/
418 0, /*tp_weaklistoffset*/
423 /* Attribute descriptor and subclassing stuff */
426 typecastObject_members, /*tp_members*/
436 0, /*tp_alloc will be set to PyType_GenericAlloc in module init*/
438 0, /*tp_free Low-level free-memory routine */
439 0, /*tp_is_gc For PyObject_IS_GC */
441 0, /*tp_mro method resolution order */
448 typecast_new(PyObject *name, PyObject *values, PyObject *cast, PyObject *base)
452 obj = PyObject_NEW(typecastObject, &typecastType);
453 if (obj == NULL) return NULL;
455 Dprintf("typecast_new: new type at = %p, refcnt = %d", obj, obj->ob_refcnt);
458 obj->values = values;
473 if (obj->bcast) Py_INCREF(obj->bcast);
475 /* FIXME: raise an exception when None is passed as Python caster */
476 if (cast && cast != Py_None) {
481 Dprintf("typecast_new: typecast object created at %p", obj);
483 return (PyObject *)obj;
487 typecast_from_python(PyObject *self, PyObject *args, PyObject *keywds)
489 PyObject *v, *name, *cast = NULL, *base = NULL;
491 static char *kwlist[] = {"values", "name", "castobj", "baseobj", NULL};
493 if (!PyArg_ParseTupleAndKeywords(args, keywds, "O!|O!OO", kwlist,
495 &PyString_Type, &name,
500 return typecast_new(name, v, cast, base);
504 typecast_from_c(typecastObject_initlist *type, PyObject *dict)
506 PyObject *tuple, *base = NULL;
510 /* before doing anything else we look for the base */
512 /* NOTE: base is a borrowed reference! */
513 base = PyDict_GetItemString(dict, type->base);
515 PyErr_Format(Error, "typecast base not found: %s", type->base);
520 while (type->values[len] != 0) len++;
522 tuple = PyTuple_New(len);
523 if (!tuple) return NULL;
525 for (i = 0; i < len ; i++) {
526 PyTuple_SET_ITEM(tuple, i, PyInt_FromLong(type->values[i]));
530 obj = (typecastObject *)
531 typecast_new(PyString_FromString(type->name), tuple, NULL, base);
534 obj->ccast = type->cast;
537 return (PyObject *)obj;
541 typecast_cast(PyObject *obj, char *str, int len, PyObject *curs)
543 PyObject *old, *res = NULL;
544 typecastObject *self = (typecastObject *)obj;
546 /* we don't incref, the caster *can't* die at this point */
547 old = ((cursorObject*)curs)->caster;
548 ((cursorObject*)curs)->caster = obj;
551 res = self->ccast(str, len, curs);
553 else if (self->pcast) {
554 res = PyObject_CallFunction(self->pcast, "s#O", str, len, curs);
557 PyErr_SetString(Error, "internal error: no casting function found");
560 ((cursorObject*)curs)->caster = old;