Add a type converter to handle untyped empty arrays.

Empty array can be returned untyped by postgres. To handle
this case, a special handler is added for the type UNKNOWNOID.
If the value return by the database is strictly equal to "{}",
the value is converted. Otherwise, the conversion fallback on
the default handler.
This commit is contained in:
Benjamin Poulain 2011-02-20 02:34:54 +01:00 committed by Daniele Varrazzo
parent 4bc4f85229
commit 5ee60571a5
3 changed files with 34 additions and 4 deletions

View File

@ -177,6 +177,28 @@ typecast_parse_time(const char* s, const char** t, Py_ssize_t* len,
#endif
#include "psycopg/typecast_array.c"
static long int typecast_default_DEFAULT[] = {0};
static typecastObject_initlist typecast_default = {
"DEFAULT", typecast_default_DEFAULT, typecast_STRING_cast};
static PyObject *
typecast_UNKNOWN_cast(const char *str, Py_ssize_t len, PyObject *curs)
{
Dprintf("typecast_UNKNOWN_cast: str = '%s',"
" len = " FORMAT_CODE_PY_SSIZE_T, str, len);
// PostgreSQL returns {} for empty array without explicit type. We convert
// that to list in order to handle empty lists.
if (len == 2 && str[0] == '{' && str[1] == '}') {
return PyList_New(0);
}
Dprintf("typecast_UNKNOWN_cast: fallback to default cast");
return typecast_default.cast(str, len, curs);
}
#include "psycopg/typecast_builtins.c"
#define typecast_PYDATETIMEARRAY_cast typecast_GENERIC_ARRAY_cast
@ -225,10 +247,6 @@ PyObject *psyco_default_cast;
PyObject *psyco_binary_types;
PyObject *psyco_default_binary_cast;
static long int typecast_default_DEFAULT[] = {0};
static typecastObject_initlist typecast_default = {
"DEFAULT", typecast_default_DEFAULT, typecast_STRING_cast};
/* typecast_init - initialize the dictionary and create default types */

View File

@ -25,6 +25,7 @@ static long int typecast_DATEARRAY_types[] = {1182, 0};
static long int typecast_INTERVALARRAY_types[] = {1187, 0};
static long int typecast_BINARYARRAY_types[] = {1001, 0};
static long int typecast_ROWIDARRAY_types[] = {1028, 1013, 0};
static long int typecast_UNKNOWN_types[] = {705, 0};
static typecastObject_initlist typecast_builtins[] = {
@ -55,6 +56,7 @@ static typecastObject_initlist typecast_builtins[] = {
{"INTERVALARRAY", typecast_INTERVALARRAY_types, typecast_INTERVALARRAY_cast, "INTERVAL"},
{"BINARYARRAY", typecast_BINARYARRAY_types, typecast_BINARYARRAY_cast, "BINARY"},
{"ROWIDARRAY", typecast_ROWIDARRAY_types, typecast_ROWIDARRAY_cast, "ROWID"},
{"UNKNOWN", typecast_UNKNOWN_types, typecast_UNKNOWN_cast, NULL},
{NULL, NULL, NULL, NULL}
};

View File

@ -176,6 +176,16 @@ class TypesBasicTests(unittest.TestCase):
curs.execute("select col from array_test where id = 2")
self.assertEqual(curs.fetchone()[0], [])
def testEmptyArray(self):
s = self.execute("SELECT '{}' AS foo")
self.failUnlessEqual(s, [])
s = self.execute("SELECT '{}'::text[] AS foo")
self.failUnlessEqual(s, [])
s = self.execute("SELECT %s AS foo", ([],))
self.failUnlessEqual(s, [])
s = self.execute("SELECT 1 != ALL(%s)", ([],))
self.failUnlessEqual(s, True)
@testutils.skip_from_python(3)
def testTypeRoundtripBuffer(self):
o1 = buffer("".join(map(chr, range(256))))