/* * Copyright (C) 2001 Federico Di Gregorio * * This file is part of the psycopg module. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2, * or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* * typemod.c -- types available to the psycopg module * $Id: typemod.c 839 2005-08-22 22:55:21Z fog $ */ #include "module.h" #include "typemod.h" #include /**** DateTimeObject OBJECT DEFINITIONS ****/ /* object member list */ #define OFFSETOF(x) offsetof(psyco_DateTimeObject, x) static struct memberlist psyco_DateTimeObject_memberlist[] = { {"_o", T_OBJECT, OFFSETOF(datetime), RO}, {NULL} }; /**** DateTimeObject METHODS ****/ /* the python object interface for the date and time object */ static PyObject * psyco_DateTimeObject_str(psyco_DateTimeObject *self) { PyObject *res = NULL; char *buffer = NULL; mxDateTimeObject *obj = (mxDateTimeObject*)self->datetime; switch (self->type) { case 0: asprintf(&buffer, "'%02d:%02d:%.6f'", (int)obj->hour, (int)obj->minute, (float)obj->second); if (buffer) res = PyString_FromString(buffer); break; case 1: asprintf(&buffer, "'%ld-%02d-%02d'", obj->year, (int)obj->month, (int)obj->day); if (buffer) res = PyString_FromString(buffer); break; case 2: asprintf(&buffer, "'%ld-%02d-%02d %02d:%02d:%.6f'", obj->year, (int)obj->month, (int)obj->day, (int)obj->hour, (int)obj->minute, (float)obj->second); if (buffer) res = PyString_FromString(buffer); break; } if (buffer) free(buffer); return res; } static struct PyMethodDef psyco_DateTimeObject_methods[] = { /*{"datetime", (PyCFunction)psyco_DateTimeObject_datetime, METH_VARARGS, NULL},*/ {NULL, NULL} }; static PyObject * psyco_DateTimeObject_getattr(psyco_DateTimeObject *self, char *name) { PyObject *rv; rv = PyMember_Get((char *)self, psyco_DateTimeObject_memberlist, name); if (rv) return rv; PyErr_Clear(); return Py_FindMethod(psyco_DateTimeObject_methods, (PyObject *)self, name); } static void psyco_DateTimeObject_destroy(psyco_DateTimeObject *self) { Py_XDECREF(self->datetime); PyObject_Del(self); Dprintf("DateTimeObject at %p destroyed\n", self); } static char psyco_DateTimeObject__doc__[] = "Object to pass (in a portable way) dates and times to the database."; PyTypeObject psyco_DateTimeObject_Type = { #if !defined(_WIN32) && !defined(__CYGWIN__) PyObject_HEAD_INIT(&PyType_Type) #else PyObject_HEAD_INIT(NULL) #endif 0, /*ob_size*/ "datetime", /*tp_name*/ sizeof(psyco_DateTimeObject), /*tp_basicsize*/ 0, /*tp_itemsize*/ /* methods */ (destructor)psyco_DateTimeObject_destroy, /*tp_dealloc*/ (printfunc)0, /*tp_print*/ (getattrfunc)psyco_DateTimeObject_getattr, /*tp_getattr*/ (setattrfunc)0, /*tp_setattr*/ (cmpfunc)0, /*tp_compare*/ (reprfunc)0, /*tp_repr*/ 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ (hashfunc)0, /*tp_hash*/ (ternaryfunc)0, /*tp_call*/ (reprfunc)psyco_DateTimeObject_str, /*tp_str*/ /* Space for future expansion */ 0L,0L,0L,0L, psyco_DateTimeObject__doc__ /* Documentation string */ }; static PyObject * new_psyco_datetimeobject(PyObject *datetime, int type) { psyco_DateTimeObject *obj; #if defined(_WIN32) || defined(__CYGWIN__) /* For MSVC workaround */ psyco_DateTimeObject_Type.ob_type = &PyType_Type; #endif obj = PyObject_NEW(psyco_DateTimeObject, &psyco_DateTimeObject_Type); if (obj == NULL) return NULL; obj->datetime = datetime; obj->type = type; Dprintf("new_psyco_datetimeobject: object of type %d created at %p\n", type, obj); return (PyObject *)obj; } /**** BufferObject OBJECT DEFINITIONS ****/ /* object member list */ #undef OFFSETOF #define OFFSETOF(x) offsetof(psyco_BufferObject, x) static struct memberlist psyco_BufferObject_memberlist[] = { {NULL} }; /**** BufferObject METHODS ****/ /* the python object interface for the buffer object */ static PyObject * psyco_BufferObject_str(psyco_BufferObject *self) { Py_INCREF(self->buffer); return self->buffer; } static struct PyMethodDef psyco_BufferObject_methods[] = { /*{"datetime", (PyCFunction)psyco_BufferObject_datetime, METH_VARARGS, NULL},*/ {NULL, NULL} }; static PyObject * psyco_BufferObject_getattr(psyco_BufferObject *self, char *name) { PyObject *rv; rv = PyMember_Get((char *)self, psyco_BufferObject_memberlist, name); if (rv) return rv; PyErr_Clear(); return Py_FindMethod(psyco_BufferObject_methods, (PyObject *)self, name); } static void psyco_BufferObject_destroy(psyco_BufferObject *self) { Py_DECREF(self->buffer); PyObject_Del(self); Dprintf("psyco_BufferObject_destroy(): bufferobject at %p destroyed\n", self); } static char psyco_BufferObject__doc__[] = "Object to pass (in a portable way) binary data to the database."; PyTypeObject psyco_BufferObject_Type = { #if !defined(_WIN32) && !defined(__CYGWIN__) PyObject_HEAD_INIT(&PyType_Type) #else PyObject_HEAD_INIT(NULL) #endif 0, /*ob_size*/ "buffer", /*tp_name*/ sizeof(psyco_BufferObject), /*tp_basicsize*/ 0, /*tp_itemsize*/ /* methods */ (destructor)psyco_BufferObject_destroy, /*tp_dealloc*/ (printfunc)0, /*tp_print*/ (getattrfunc)psyco_BufferObject_getattr, /*tp_getattr*/ (setattrfunc)0, /*tp_setattr*/ (cmpfunc)0, /*tp_compare*/ (reprfunc)0, /*tp_repr*/ 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ (hashfunc)0, /*tp_hash*/ (ternaryfunc)0, /*tp_call*/ (reprfunc)psyco_BufferObject_str, /*tp_str*/ /* Space for future expansion */ 0L,0L,0L,0L, psyco_BufferObject__doc__ /* Documentation string */ }; static PyObject * new_psyco_bufferobject(PyObject *buffer) { psyco_BufferObject *obj; unsigned char *original, *quoted, *chptr, *newptr; int i, len, space, new_space; #if defined(_WIN32) || defined(__CYGWIN__) /* For MSVC workaround */ psyco_BufferObject_Type.ob_type = &PyType_Type; #endif obj = PyObject_NEW(psyco_BufferObject, &psyco_BufferObject_Type); if (obj == NULL) return NULL; original = (unsigned char*)PyString_AS_STRING(buffer); len = PyString_GET_SIZE(buffer); space = len + 2; Py_BEGIN_ALLOW_THREADS; quoted = (unsigned char*)calloc(space, sizeof(char)); if (quoted == NULL) return NULL; chptr = quoted; *chptr = '\''; chptr++; for (i=0; i < len; i++) { if (chptr - quoted > space - 6) { new_space = space * ((space) / (i + 1)) + 2 + 6; if (new_space - space < 1024) space += 1024; else space = new_space; newptr = (unsigned char *)realloc(quoted, space); if (newptr == NULL) { free(quoted); return NULL; } /*chptr has to be moved to the new location*/ chptr = newptr + (chptr - quoted); quoted = newptr; Dprintf("new_psyco_bufferobject(): reallocated %i bytes at %p \n", space, quoted); } if (original[i]) { if (original[i] >= ' ' && original[i] <= '~') { if (original[i] == '\'') { *chptr = '\\'; chptr++; *chptr = '\''; chptr++; } else if (original[i] == '\\') { memcpy(chptr, "\\\\\\\\", 4); chptr += 4; } else { /* leave it as it is if ascii printable */ *chptr = original[i]; chptr++; } } else { unsigned char c; /* escape to octal notation \nnn */ *chptr++ = '\\'; *chptr++ = '\\'; c = original[i]; *chptr = ((c >> 6) & 0x07) + 0x30; chptr++; *chptr = ((c >> 3) & 0x07) + 0x30; chptr++; *chptr = (c & 0x07) + 0x30; chptr++; } } else { /* escape null as \\000 */ memcpy(chptr, "\\\\000", 5); chptr += 5; } } *chptr = '\''; Py_END_ALLOW_THREADS; Dprintf("new_psyco_bufferobject(): quoted = %s\n", quoted); obj->buffer = PyString_FromStringAndSize((char*)quoted, chptr - quoted + 1 ); free(quoted); Dprintf("new_psyco_bufferobject: object created at %p\n", obj); return (PyObject *)obj; } /**** QuotedStringObject OBJECT DEFINITIONS ****/ /* object member list */ #undef OFFSETOF #define OFFSETOF(x) offsetof(psyco_QuotedStringObject, x) static struct memberlist psyco_QuotedStringObject_memberlist[] = { {NULL} }; /**** QuotedStringObject METHODS ****/ /* the python object interface for the buffer object */ static PyObject * psyco_QuotedStringObject_str(psyco_QuotedStringObject *self) { Py_INCREF(self->buffer); return self->buffer; } static struct PyMethodDef psyco_QuotedStringObject_methods[] = { {NULL, NULL} }; static PyObject * psyco_QuotedStringObject_getattr(psyco_BufferObject *self, char *name) { PyObject *rv; rv = PyMember_Get((char *)self, psyco_QuotedStringObject_memberlist, name); if (rv) return rv; PyErr_Clear(); return Py_FindMethod(psyco_QuotedStringObject_methods, (PyObject *)self, name); } static void psyco_QuotedStringObject_destroy(psyco_QuotedStringObject *self) { Dprintf("psyco_QuotedStringObject_destroy: " "self->buffer->refcnt = %d\n", self->buffer->ob_refcnt); Py_DECREF(self->buffer); PyObject_Del(self); Dprintf("psyco_QuotedStringObject_destroy: " "quotedstringobject at %p destroyed\n", self); } static char psyco_QuotedStringObject__doc__[] = "A string that quotes itself following PostgreSQL quoting convention."; PyTypeObject psyco_QuotedStringObject_Type = { #if !defined(_WIN32) && !defined(__CYGWIN__) PyObject_HEAD_INIT(&PyType_Type) #else PyObject_HEAD_INIT(NULL) #endif 0, /*ob_size*/ "buffer", /*tp_name*/ sizeof(psyco_QuotedStringObject), /*tp_basicsize*/ 0, /*tp_itemsize*/ /* methods */ (destructor)psyco_QuotedStringObject_destroy, /*tp_dealloc*/ (printfunc)0, /*tp_print*/ (getattrfunc)psyco_QuotedStringObject_getattr, /*tp_getattr*/ (setattrfunc)0, /*tp_setattr*/ (cmpfunc)0, /*tp_compare*/ (reprfunc)0, /*tp_repr*/ 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ (hashfunc)0, /*tp_hash*/ (ternaryfunc)0, /*tp_call*/ (reprfunc)psyco_QuotedStringObject_str, /*tp_str*/ /* Space for future expansion */ 0L,0L,0L,0L, psyco_QuotedStringObject__doc__ /* Documentation string */ }; PyObject * new_psyco_quotedstringobject(PyObject *buffer) { psyco_QuotedStringObject *obj; char *original, *quoted; int i, j, len; #if defined(_WIN32) || defined(__CYGWIN__) /* For MSVC workaround */ psyco_QuotedStringObject_Type.ob_type = &PyType_Type; #endif obj = PyObject_NEW(psyco_QuotedStringObject, &psyco_QuotedStringObject_Type); if (obj == NULL) return NULL; original = PyString_AS_STRING(buffer); len = PyString_GET_SIZE(buffer); Dprintf("new_psyco_quotedstringobject: len = %d\n", len); quoted = (char*)malloc(len*2+3); if (quoted == NULL) return NULL; for (i=0, j=1; ibuffer = PyString_FromStringAndSize(quoted, j); free(quoted); Dprintf("new_psyco_quotedstringobject: object created at %p\n", obj); return (PyObject *)obj; } /**** PYTHON TO POSTGRESQL CONVERSION OBJECTS ****/ PyObject * psyco_Date(PyObject *self, PyObject *args) { PyObject *datetime; /* datetime object */ long year; int month, day; if (!PyArg_ParseTuple(args, "lii", &year, &month, &day)) return NULL; if (!(datetime = mxDateTimeP->DateTime_FromDateAndTime(year, month, day, 0, 0, 0.0))) return NULL; return new_psyco_datetimeobject(datetime, PSYCO_DATETIME_DATE); } PyObject * psyco_Time(PyObject *self, PyObject *args) { PyObject *datetime; /* datetime object */ int hours, minutes=0; double seconds=0.0; if (!PyArg_ParseTuple(args, "iid", &hours, &minutes, &seconds)) return NULL; if (!(datetime= mxDateTimeP->DateTimeDelta_FromTime(hours, minutes, seconds))) return NULL; return new_psyco_datetimeobject(datetime, PSYCO_DATETIME_TIME); } PyObject * psyco_Timestamp(PyObject *self, PyObject *args) { PyObject *datetime; /* datetime object */ long year; int month, day; int hour=0, minute=0; /* default to midnight */ double second=0.0; if (!PyArg_ParseTuple(args, "lii|iid", &year, &month, &day, &hour, &minute, &second)) return NULL; if (!(datetime= mxDateTimeP->DateTime_FromDateAndTime(year, month, day, hour, minute, second))) return NULL; return new_psyco_datetimeobject(datetime, PSYCO_DATETIME_TIMESTAMP); } PyObject * psyco_DateFromTicks(PyObject *self, PyObject *args) { PyObject *datetime; /* datetime object */ double ticks; long year; int month, day; if (!PyArg_ParseTuple(args,"d", &ticks)) return NULL; if (!(datetime = mxDateTimeP->DateTime_FromTicks(ticks))) return NULL; if (mxDateTimeP->DateTime_BrokenDown((mxDateTimeObject *)datetime, &year, &month, &day, (int *)NULL, (int *)NULL, (double *)NULL) == -1) return NULL; /* reset hour, minute, second to 00:00:00.0 (midnight) */ if (!(datetime = mxDateTimeP->DateTime_FromDateAndTime(year, month, day, 0, 0, 0.0))) return NULL; return new_psyco_datetimeobject(datetime, PSYCO_DATETIME_DATE); } PyObject * psyco_TimeFromTicks(PyObject *self, PyObject *args) { PyObject *datetime; /* datetime object */ double ticks; int hours, minutes; double seconds; if (!PyArg_ParseTuple(args,"d", &ticks)) return NULL; if (!(datetime = mxDateTimeP->DateTime_FromTicks(ticks))) return NULL; if (mxDateTimeP->DateTime_BrokenDown((mxDateTimeObject *)datetime, (long *)NULL, (int *)NULL, (int *)NULL, &hours, &minutes, &seconds) == -1) return NULL; /* consider only Delta using hours, minutes, seconds */ if (!(datetime = mxDateTimeP->DateTimeDelta_FromTime(hours,minutes, seconds))) return NULL; return new_psyco_datetimeobject(datetime, PSYCO_DATETIME_TIME); } PyObject * psyco_TimestampFromTicks(PyObject *self, PyObject *args) { PyObject *datetime; /* datetime object */ double ticks; if (!PyArg_ParseTuple(args, "d", &ticks)) return NULL; if (!(datetime = mxDateTimeP->DateTime_FromTicks(ticks))) return NULL; return new_psyco_datetimeobject(datetime, PSYCO_DATETIME_TIMESTAMP); } PyObject * psyco_DateFromMx(PyObject *self, PyObject *args) { PyObject *o; if (!PyArg_ParseTuple(args, "O!", mxDateTimeP->DateTime_Type, &o)) return NULL; Py_INCREF(o); return new_psyco_datetimeobject(o, PSYCO_DATETIME_DATE); } PyObject * psyco_TimeFromMx(PyObject *self, PyObject *args) { PyObject *o; if (!PyArg_ParseTuple(args, "O!", mxDateTimeP->DateTime_Type, &o)) return NULL; Py_INCREF(o); return new_psyco_datetimeobject(o, PSYCO_DATETIME_TIME); } PyObject * psyco_TimestampFromMx(PyObject *self, PyObject *args) { PyObject *o; if (!PyArg_ParseTuple(args, "O!", mxDateTimeP->DateTime_Type, &o)) return NULL; Py_INCREF(o); return new_psyco_datetimeobject(o, PSYCO_DATETIME_TIMESTAMP); } PyObject * psyco_Binary(PyObject *self, PyObject *args) { PyObject *str; if (!PyArg_ParseTuple(args, "O!", &PyString_Type, &str)) return NULL; return new_psyco_bufferobject(str); } PyObject * psyco_QuotedString(PyObject *self, PyObject *args) { PyObject *str; if (!PyArg_ParseTuple(args, "O!", &PyString_Type, &str)) return NULL; return new_psyco_quotedstringobject(str); }