mirror of
https://github.com/psycopg/psycopg2.git
synced 2025-02-07 12:50:32 +03:00
Array support works, at least for INTEGERS.
This commit is contained in:
parent
07a38c31cd
commit
def14d5925
12
ChangeLog
12
ChangeLog
|
@ -1,3 +1,15 @@
|
||||||
|
2005-03-23 Federico Di Gregorio <fog@debian.org>
|
||||||
|
|
||||||
|
* psycopg/typecast_basic.c: all the basic casters now respect the
|
||||||
|
passed string length.
|
||||||
|
|
||||||
|
* psycopg/typecast.c (typecast_cast): set curs->caster to self
|
||||||
|
during the type-casting.
|
||||||
|
|
||||||
|
* psycopg/cursor_type.c: added "typecaster" attribute to the
|
||||||
|
cursor (this is safe, cursors can't be shared among threads and
|
||||||
|
the attribute is RO.)
|
||||||
|
|
||||||
2005-03-22 Federico Di Gregorio <fog@debian.org>
|
2005-03-22 Federico Di Gregorio <fog@debian.org>
|
||||||
|
|
||||||
* psycopg/typecast_array.c: added some more structure to implement
|
* psycopg/typecast_array.c: added some more structure to implement
|
||||||
|
|
|
@ -56,6 +56,7 @@ typedef struct {
|
||||||
Oid lastoid; /* last oid from an insert or InvalidOid */
|
Oid lastoid; /* last oid from an insert or InvalidOid */
|
||||||
|
|
||||||
PyObject *casts; /* an array (tuple) of typecast functions */
|
PyObject *casts; /* an array (tuple) of typecast functions */
|
||||||
|
PyObject *caster; /* the current typecaster object */
|
||||||
|
|
||||||
PyObject *copyfile; /* file-like used during COPY TO/FROM ops */
|
PyObject *copyfile; /* file-like used during COPY TO/FROM ops */
|
||||||
long int copysize; /* size of the copy buffer during COPY TO/FROM ops */
|
long int copysize; /* size of the copy buffer during COPY TO/FROM ops */
|
||||||
|
|
|
@ -1217,6 +1217,7 @@ static struct PyMemberDef cursorObject_members[] = {
|
||||||
{"query", T_STRING, OFFSETOF(query), RO},
|
{"query", T_STRING, OFFSETOF(query), RO},
|
||||||
{"row_factory", T_OBJECT, OFFSETOF(tuple_factory), 0},
|
{"row_factory", T_OBJECT, OFFSETOF(tuple_factory), 0},
|
||||||
{"tzinfo_factory", T_OBJECT, OFFSETOF(tzinfo_factory), 0},
|
{"tzinfo_factory", T_OBJECT, OFFSETOF(tzinfo_factory), 0},
|
||||||
|
{"typecaster", T_OBJECT, OFFSETOF(caster), RO},
|
||||||
#endif
|
#endif
|
||||||
{NULL}
|
{NULL}
|
||||||
};
|
};
|
||||||
|
|
|
@ -154,6 +154,25 @@ typecast_init(PyObject *dict)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* typecast_get_by_name - get a type object by name (slow!) */
|
||||||
|
|
||||||
|
static PyObject*
|
||||||
|
typecast_get_by_name(unsigned char *name)
|
||||||
|
{
|
||||||
|
PyObject *value, *res = NULL;
|
||||||
|
int ppos = 0;
|
||||||
|
|
||||||
|
while (PyDict_Next(psyco_types, &ppos, NULL, &value)) {
|
||||||
|
if (strcmp(PyString_AsString(((typecastObject*)value)->name),
|
||||||
|
name) == 0) {
|
||||||
|
res = value;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* borrowed reference */
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
/* typecast_add - add a type object to the dictionary */
|
/* typecast_add - add a type object to the dictionary */
|
||||||
int
|
int
|
||||||
|
@ -179,6 +198,8 @@ typecast_add(PyObject *obj, int binary)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Dprintf("typecast_add: base caster: %p", type->bcast);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -196,7 +217,7 @@ static struct memberlist typecastObject_memberlist[] = {
|
||||||
/* numeric methods */
|
/* numeric methods */
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
typecast_new(PyObject *name, PyObject *values, PyObject *cast);
|
typecast_new(PyObject *name, PyObject *values, PyObject *cast, PyObject *base);
|
||||||
|
|
||||||
static int
|
static int
|
||||||
typecast_coerce(PyObject **pv, PyObject **pw)
|
typecast_coerce(PyObject **pv, PyObject **pw)
|
||||||
|
@ -207,7 +228,7 @@ typecast_coerce(PyObject **pv, PyObject **pw)
|
||||||
args = PyTuple_New(1);
|
args = PyTuple_New(1);
|
||||||
Py_INCREF(*pw);
|
Py_INCREF(*pw);
|
||||||
PyTuple_SET_ITEM(args, 0, *pw);
|
PyTuple_SET_ITEM(args, 0, *pw);
|
||||||
coer = typecast_new(NULL, args, NULL);
|
coer = typecast_new(NULL, args, NULL, NULL);
|
||||||
*pw = coer;
|
*pw = coer;
|
||||||
Py_DECREF(args);
|
Py_DECREF(args);
|
||||||
Py_INCREF(*pv);
|
Py_INCREF(*pv);
|
||||||
|
@ -347,7 +368,7 @@ PyTypeObject typecastType = {
|
||||||
};
|
};
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
typecast_new(PyObject *name, PyObject *values, PyObject *cast)
|
typecast_new(PyObject *name, PyObject *values, PyObject *cast, PyObject *base)
|
||||||
{
|
{
|
||||||
typecastObject *obj;
|
typecastObject *obj;
|
||||||
|
|
||||||
|
@ -368,7 +389,11 @@ typecast_new(PyObject *name, PyObject *values, PyObject *cast)
|
||||||
|
|
||||||
obj->pcast = NULL;
|
obj->pcast = NULL;
|
||||||
obj->ccast = NULL;
|
obj->ccast = NULL;
|
||||||
|
obj->bcast = base;
|
||||||
|
|
||||||
|
if (obj->bcast) Py_INCREF(obj->bcast);
|
||||||
|
|
||||||
|
/* FIXME: raise an exception when None is passed as Python caster */
|
||||||
if (cast && cast != Py_None) {
|
if (cast && cast != Py_None) {
|
||||||
Py_INCREF(cast);
|
Py_INCREF(cast);
|
||||||
obj->pcast = cast;
|
obj->pcast = cast;
|
||||||
|
@ -382,27 +407,36 @@ typecast_new(PyObject *name, PyObject *values, PyObject *cast)
|
||||||
PyObject *
|
PyObject *
|
||||||
typecast_from_python(PyObject *self, PyObject *args, PyObject *keywds)
|
typecast_from_python(PyObject *self, PyObject *args, PyObject *keywds)
|
||||||
{
|
{
|
||||||
PyObject *v, *name, *cast = NULL;
|
PyObject *v, *name, *cast = NULL, *base = NULL;
|
||||||
|
|
||||||
static char *kwlist[] = {"values", "name", "castobj", NULL};
|
static char *kwlist[] = {"values", "name", "castobj", "baseobj", NULL};
|
||||||
|
|
||||||
if (!PyArg_ParseTupleAndKeywords(args, keywds, "O!|O!O", kwlist,
|
if (!PyArg_ParseTupleAndKeywords(args, keywds, "O!|O!OO", kwlist,
|
||||||
&PyTuple_Type, &v,
|
&PyTuple_Type, &v,
|
||||||
&PyString_Type, &name,
|
&PyString_Type, &name,
|
||||||
&cast)) {
|
&cast, &base)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return typecast_new(name, v, cast);
|
return typecast_new(name, v, cast, base);
|
||||||
}
|
}
|
||||||
|
|
||||||
PyObject *
|
PyObject *
|
||||||
typecast_from_c(typecastObject_initlist *type)
|
typecast_from_c(typecastObject_initlist *type)
|
||||||
{
|
{
|
||||||
PyObject *tuple;
|
PyObject *tuple, *base = NULL;
|
||||||
typecastObject *obj;
|
typecastObject *obj;
|
||||||
int i, len = 0;
|
int i, len = 0;
|
||||||
|
|
||||||
|
/* before doing anything else we look for the base */
|
||||||
|
if (type->base) {
|
||||||
|
base = typecast_get_by_name(type->base);
|
||||||
|
if (!base) {
|
||||||
|
PyErr_Format(Error, "typecast base not found: %s", type->base);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
while (type->values[len] != 0) len++;
|
while (type->values[len] != 0) len++;
|
||||||
|
|
||||||
tuple = PyTuple_New(len);
|
tuple = PyTuple_New(len);
|
||||||
|
@ -411,9 +445,10 @@ typecast_from_c(typecastObject_initlist *type)
|
||||||
for (i = 0; i < len ; i++) {
|
for (i = 0; i < len ; i++) {
|
||||||
PyTuple_SET_ITEM(tuple, i, PyInt_FromLong(type->values[i]));
|
PyTuple_SET_ITEM(tuple, i, PyInt_FromLong(type->values[i]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
obj = (typecastObject *)
|
obj = (typecastObject *)
|
||||||
typecast_new(PyString_FromString(type->name), tuple, NULL);
|
typecast_new(PyString_FromString(type->name), tuple, NULL, base);
|
||||||
|
|
||||||
if (obj) {
|
if (obj) {
|
||||||
obj->ccast = type->cast;
|
obj->ccast = type->cast;
|
||||||
|
@ -425,18 +460,26 @@ typecast_from_c(typecastObject_initlist *type)
|
||||||
PyObject *
|
PyObject *
|
||||||
typecast_cast(PyObject *obj, unsigned char *str, int len, PyObject *curs)
|
typecast_cast(PyObject *obj, unsigned char *str, int len, PyObject *curs)
|
||||||
{
|
{
|
||||||
|
PyObject *old, *res = NULL;
|
||||||
typecastObject *self = (typecastObject *)obj;
|
typecastObject *self = (typecastObject *)obj;
|
||||||
|
|
||||||
|
/* we don't incref, the caster *can't* die at this point */
|
||||||
|
old = ((cursorObject*)curs)->caster;
|
||||||
|
((cursorObject*)curs)->caster = obj;
|
||||||
|
|
||||||
if (self->ccast) {
|
if (self->ccast) {
|
||||||
Dprintf("typecast_call: calling C cast function");
|
Dprintf("typecast_call: calling C cast function");
|
||||||
return self->ccast(str, len, curs);
|
res = self->ccast(str, len, curs);
|
||||||
}
|
}
|
||||||
else if (self->pcast) {
|
else if (self->pcast) {
|
||||||
Dprintf("typecast_call: calling python callable");
|
Dprintf("typecast_call: calling python callable");
|
||||||
return PyObject_CallFunction(self->pcast, "s#O", str, len, curs);
|
res = PyObject_CallFunction(self->pcast, "s#O", str, len, curs);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
PyErr_SetString(Error, "internal error: no casting function found");
|
PyErr_SetString(Error, "internal error: no casting function found");
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
((cursorObject*)curs)->caster = old;
|
||||||
|
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,6 +43,7 @@ typedef struct {
|
||||||
|
|
||||||
typecast_function ccast; /* the C casting function */
|
typecast_function ccast; /* the C casting function */
|
||||||
PyObject *pcast; /* the python casting function */
|
PyObject *pcast; /* the python casting function */
|
||||||
|
PyObject *bcast; /* base cast, used by array typecasters */
|
||||||
} typecastObject;
|
} typecastObject;
|
||||||
|
|
||||||
/* the initialization values are stored here */
|
/* the initialization values are stored here */
|
||||||
|
|
|
@ -20,23 +20,97 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
/* the pointer to the datetime module API is initialized by the module init
|
/** typecast_array_scan - scan a string looking for array items **/
|
||||||
code, we just need to grab it */
|
|
||||||
extern PyObject* pyDateTimeModuleP;
|
#define ASCAN_EOF 0
|
||||||
extern PyObject *pyDateTypeP;
|
#define ASCAN_BEGIN 1
|
||||||
extern PyObject *pyTimeTypeP;
|
#define ASCAN_END 2
|
||||||
extern PyObject *pyDateTimeTypeP;
|
#define ASCAN_TOKEN 3
|
||||||
extern PyObject *pyDeltaTypeP;
|
|
||||||
|
static int
|
||||||
|
typecast_array_tokenize(unsigned char *str, int strlength,
|
||||||
|
int *pos, unsigned char** token, int *length)
|
||||||
|
{
|
||||||
|
int i = *pos;
|
||||||
|
|
||||||
|
Dprintf("TOKENIZE for %d, pos = %d", strlength, *pos);
|
||||||
|
|
||||||
|
while (i < strlength) {
|
||||||
|
switch (str[i]) {
|
||||||
|
case '{':
|
||||||
|
*pos = i+1;
|
||||||
|
return ASCAN_BEGIN;
|
||||||
|
|
||||||
|
case '}':
|
||||||
|
*pos = i+1;
|
||||||
|
return ASCAN_END;
|
||||||
|
|
||||||
|
case ',':
|
||||||
|
*token = &str[*pos];
|
||||||
|
*length = i - *pos;
|
||||||
|
*pos = i+1;
|
||||||
|
Dprintf("TOKENIZE pos = %d, length = %d", *pos, *length);
|
||||||
|
return ASCAN_TOKEN;
|
||||||
|
|
||||||
|
default:
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*token = &str[*pos];
|
||||||
|
*length = i - *pos;
|
||||||
|
|
||||||
|
return ASCAN_EOF;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
typecast_array_scan(unsigned char *str, int strlength,
|
||||||
|
PyObject *curs, PyObject *base, PyObject *array)
|
||||||
|
{
|
||||||
|
int state, length, pos = 0;
|
||||||
|
unsigned char *token;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
state = typecast_array_tokenize(str, strlength, &pos, &token, &length);
|
||||||
|
|
||||||
|
if (state == ASCAN_TOKEN || state == ASCAN_EOF) {
|
||||||
|
PyObject *obj = typecast_cast(base, token, length, curs);
|
||||||
|
if (obj == NULL) return 0;
|
||||||
|
PyList_Append(array, obj);
|
||||||
|
Py_DECREF(obj);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Dprintf("** RECURSION (not supported right now)!!");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state == ASCAN_EOF) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
/** LONGINTEGERARRAY and INTEGERARRAY - cast integers arrays **/
|
/** LONGINTEGERARRAY and INTEGERARRAY - cast integers arrays **/
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
typecast_INTEGERARRAY_cast(unsigned char *str, int len, PyObject *curs)
|
typecast_INTEGERARRAY_cast(unsigned char *str, int len, PyObject *curs)
|
||||||
{
|
{
|
||||||
PyObject* obj = NULL;
|
PyObject *obj = NULL;
|
||||||
|
PyObject *base = ((typecastObject*)((cursorObject*)curs)->caster)->bcast;
|
||||||
|
|
||||||
if (str == NULL) {Py_INCREF(Py_None); return Py_None;}
|
if (str == NULL) {Py_INCREF(Py_None); return Py_None;}
|
||||||
|
if (str[0] != '{') {
|
||||||
|
PyErr_SetString(Error, "array does not start with '{'");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
obj = PyList_New(0);
|
||||||
|
|
||||||
|
/* scan the array skipping the first level of {} */
|
||||||
|
if (typecast_array_scan(&str[1], len-2, curs, base, obj) == 0) {
|
||||||
|
Py_DECREF(obj);
|
||||||
|
obj = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,8 +27,11 @@
|
||||||
static PyObject *
|
static PyObject *
|
||||||
typecast_INTEGER_cast(unsigned char *s, int len, PyObject *curs)
|
typecast_INTEGER_cast(unsigned char *s, int len, PyObject *curs)
|
||||||
{
|
{
|
||||||
|
unsigned char buffer[12];
|
||||||
|
|
||||||
if (s == NULL) {Py_INCREF(Py_None); return Py_None;}
|
if (s == NULL) {Py_INCREF(Py_None); return Py_None;}
|
||||||
return PyInt_FromString(s, NULL, 0);
|
strncpy(buffer, s, len); buffer[len] = '\0';
|
||||||
|
return PyInt_FromString(buffer, NULL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** LONGINTEGER - cast long integers (8 bytes) to python long **/
|
/** LONGINTEGER - cast long integers (8 bytes) to python long **/
|
||||||
|
@ -36,7 +39,10 @@ typecast_INTEGER_cast(unsigned char *s, int len, PyObject *curs)
|
||||||
static PyObject *
|
static PyObject *
|
||||||
typecast_LONGINTEGER_cast(unsigned char *s, int len, PyObject *curs)
|
typecast_LONGINTEGER_cast(unsigned char *s, int len, PyObject *curs)
|
||||||
{
|
{
|
||||||
|
unsigned char buffer[24];
|
||||||
|
|
||||||
if (s == NULL) {Py_INCREF(Py_None); return Py_None;}
|
if (s == NULL) {Py_INCREF(Py_None); return Py_None;}
|
||||||
|
strncpy(buffer, s, len); buffer[len] = '\0';
|
||||||
return PyLong_FromString(s, NULL, 0);
|
return PyLong_FromString(s, NULL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,7 +51,10 @@ typecast_LONGINTEGER_cast(unsigned char *s, int len, PyObject *curs)
|
||||||
static PyObject *
|
static PyObject *
|
||||||
typecast_FLOAT_cast(unsigned char *s, int len, PyObject *curs)
|
typecast_FLOAT_cast(unsigned char *s, int len, PyObject *curs)
|
||||||
{
|
{
|
||||||
|
unsigned char buffer[64];
|
||||||
|
|
||||||
if (s == NULL) {Py_INCREF(Py_None); return Py_None;}
|
if (s == NULL) {Py_INCREF(Py_None); return Py_None;}
|
||||||
|
strncpy(buffer, s, len); buffer[len] = '\0';
|
||||||
return PyFloat_FromDouble(atof(s));
|
return PyFloat_FromDouble(atof(s));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,7 +79,7 @@ typecast_UNICODE_cast(unsigned char *s, int len, PyObject *curs)
|
||||||
enc = PyDict_GetItemString(psycoEncodings,
|
enc = PyDict_GetItemString(psycoEncodings,
|
||||||
((cursorObject*)curs)->conn->encoding);
|
((cursorObject*)curs)->conn->encoding);
|
||||||
if (enc) {
|
if (enc) {
|
||||||
return PyUnicode_Decode(s, strlen(s), PyString_AsString(enc), NULL);
|
return PyUnicode_Decode(s, len, PyString_AsString(enc), NULL);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
PyErr_Format(InterfaceError,
|
PyErr_Format(InterfaceError,
|
||||||
|
@ -135,13 +144,17 @@ static PyObject *
|
||||||
typecast_BINARY_cast(unsigned char *s, int l, PyObject *curs)
|
typecast_BINARY_cast(unsigned char *s, int l, PyObject *curs)
|
||||||
{
|
{
|
||||||
PyObject *res;
|
PyObject *res;
|
||||||
unsigned char *str;
|
unsigned char *str, saved;
|
||||||
size_t len;
|
size_t len;
|
||||||
|
|
||||||
if (s == NULL) {Py_INCREF(Py_None); return Py_None;}
|
if (s == NULL) {Py_INCREF(Py_None); return Py_None;}
|
||||||
|
|
||||||
|
/* PQunescapeBytea absolutely wants a 0-terminated string and we don't
|
||||||
|
want to copy the whole buffer, right? Wrong... :/ */
|
||||||
|
saved = s[l]; s[l] = '\0';
|
||||||
str = PQunescapeBytea(s, &len);
|
str = PQunescapeBytea(s, &len);
|
||||||
Dprintf("typecast_BINARY_cast: unescaped %d bytes", len);
|
Dprintf("typecast_BINARY_cast: unescaped %d bytes", len);
|
||||||
|
s[l] = saved;
|
||||||
|
|
||||||
/* TODO: using a PyBuffer would make this a zero-copy operation but we'll
|
/* TODO: using a PyBuffer would make this a zero-copy operation but we'll
|
||||||
need to define our own buffer-derived object to keep a reference to the
|
need to define our own buffer-derived object to keep a reference to the
|
||||||
|
@ -178,8 +191,17 @@ typecast_BOOLEAN_cast(unsigned char *s, int len, PyObject *curs)
|
||||||
static PyObject *
|
static PyObject *
|
||||||
typecast_DECIMAL_cast(unsigned char *s, int len, PyObject *curs)
|
typecast_DECIMAL_cast(unsigned char *s, int len, PyObject *curs)
|
||||||
{
|
{
|
||||||
|
PyObject *res = NULL;
|
||||||
|
unsigned char *buffer;
|
||||||
|
|
||||||
if (s == NULL) {Py_INCREF(Py_None); return Py_None;}
|
if (s == NULL) {Py_INCREF(Py_None); return Py_None;}
|
||||||
return PyObject_CallFunction(decimalType, "s", s);
|
|
||||||
|
buffer = PyMem_Malloc(len+1);
|
||||||
|
strncpy(buffer, s, len); buffer[len] = '\0';
|
||||||
|
res = PyObject_CallFunction(decimalType, "s", buffer);
|
||||||
|
PyMem_Free(buffer);
|
||||||
|
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
#define typecast_DECIMAL_cast typecast_FLOAT_cast
|
#define typecast_DECIMAL_cast typecast_FLOAT_cast
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
[build_ext]
|
[build_ext]
|
||||||
define=PSYCOPG_EXTENSIONS,PSYCOPG_DISPLAY_SIZE,HAVE_PQFREEMEM,HAVE_PQPROTOCOL3
|
define=PSYCOPG_EXTENSIONS,PSYCOPG_DISPLAY_SIZE,HAVE_PQFREEMEM,HAVE_PQPROTOCOL3,PSYCOPG_DEBUG
|
||||||
# PSYCOPG_DEBUG can be added to enable verbose debug information
|
# PSYCOPG_DEBUG can be added to enable verbose debug information
|
||||||
# PSYCOPG_OWN_QUOTING can be added above but it is deprecated
|
# PSYCOPG_OWN_QUOTING can be added above but it is deprecated
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user