mirror of
				https://github.com/psycopg/psycopg2.git
				synced 2025-11-04 01:37:31 +03:00 
			
		
		
		
	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:
		
							parent
							
								
									4bc4f85229
								
							
						
					
					
						commit
						5ee60571a5
					
				| 
						 | 
				
			
			@ -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 */
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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))))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue
	
	Block a user