Changeset 781 for trunk/pgmodule.c


Ignore:
Timestamp:
Jan 25, 2016, 3:44:52 PM (4 years ago)
Author:
cito
Message:

Add full support for PostgreSQL array types

At the core of this patch is a fast parser for the peculiar syntax of
literal array expressions in PostgreSQL that was added to the C module.
This is not trivial, because PostgreSQL arrays can be multidimensional
and the syntax is different from Python and SQL expressions.

The Python pg and pgdb modules make use of this parser so that they can
return database columns containing PostgreSQL arrays to Python as lists.
Also added quoting methods that allow passing PostgreSQL arrays as lists
to insert()/update() and execute/executemany(). These methods are simpler
and were implemented in Python but needed support from the regex module.

The patch also adds makes getresult() in pg automatically return bytea
values in unescaped form as bytes strings. Before, it was necessary to
call unescape_bytea manually. The pgdb module did this already.

The patch includes some more refactorings and simplifications regarding
the quoting and casting in pg and pgdb.

Some references to antique PostgreSQL types that are not used any more
in the supported PostgreSQL versions have been removed.

Also added documentation and tests for the new features.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/pgmodule.c

    r780 r781  
    5454
    5555/* default values */
    56 #define PG_ARRAYSIZE                    1
     56#define PG_ARRAYSIZE            1
    5757
    5858/* flags for object validity checks */
     
    8080
    8181#define MAX_BUFFER_SIZE 8192    /* maximum transaction size */
     82#define MAX_ARRAY_DEPTH 16              /* maximum allowed depth of an array */
    8283
    8384/* MODULE GLOBAL VARIABLES */
     
    188189#endif /* LARGE_OBJECTS */
    189190
    190 /* define internal types */
    191 
    192 #define PYGRES_DEFAULT 0
     191/* PyGreSQL internal types */
     192
     193/* simple types */
    193194#define PYGRES_INT 1
    194195#define PYGRES_LONG 2
     
    197198#define PYGRES_MONEY 5
    198199#define PYGRES_BOOL 6
    199 #define PYGRES_JSON 7
     200/* text based types */
     201#define PYGRES_TEXT 8
     202#define PYGRES_BYTEA 9
     203#define PYGRES_JSON 10
     204#define PYGRES_EXTERNAL 11
     205/* array types */
     206#define PYGRES_ARRAY 16
    200207
    201208/* --------------------------------------------------------------------- */
     
    205212/* shared function for encoding and decoding strings */
    206213
    207 PyObject *
     214static PyObject *
    208215get_decoded_string(char *str, Py_ssize_t size, int encoding)
    209216{
     
    219226}
    220227
    221 PyObject *
     228static PyObject *
    222229get_encoded_string(PyObject *unicode_obj, int encoding)
    223230{
     
    233240}
    234241
    235 /* shared functions for converting PG types to Python types */
     242/* helper functions */
     243
     244/* get PyGreSQL internal types for  a PostgreSQL type */
     245static int
     246get_type(Oid pgtype)
     247{
     248        int t;
     249
     250        switch (pgtype)
     251        {
     252                /* simple types */
     253
     254                case INT2OID:
     255                case INT4OID:
     256                case CIDOID:
     257                case OIDOID:
     258                case XIDOID:
     259                        t = PYGRES_INT;
     260                        break;
     261
     262                case INT8OID:
     263                        t = PYGRES_LONG;
     264                        break;
     265
     266                case FLOAT4OID:
     267                case FLOAT8OID:
     268                        t = PYGRES_FLOAT;
     269                        break;
     270
     271                case NUMERICOID:
     272                        t = PYGRES_DECIMAL;
     273                        break;
     274
     275                case CASHOID:
     276                        t = decimal_point ? PYGRES_MONEY : PYGRES_TEXT;
     277                        break;
     278
     279                case BOOLOID:
     280                        t = PYGRES_BOOL;
     281                        break;
     282
     283                case BYTEAOID:
     284                        t = PYGRES_BYTEA;
     285                        break;
     286
     287                case JSONOID:
     288                case JSONBOID:
     289                        t = jsondecode ? PYGRES_JSON : PYGRES_TEXT;
     290                        break;
     291
     292                /* array types */
     293
     294                case INT2ARRAYOID:
     295                case INT4ARRAYOID:
     296                case CIDARRAYOID:
     297                case OIDARRAYOID:
     298                case XIDARRAYOID:
     299                        t = PYGRES_INT | PYGRES_ARRAY;
     300                        break;
     301
     302                case INT8ARRAYOID:
     303                        t = PYGRES_LONG | PYGRES_ARRAY;
     304                        break;
     305
     306                case FLOAT4ARRAYOID:
     307                case FLOAT8ARRAYOID:
     308                        t = PYGRES_FLOAT | PYGRES_ARRAY;
     309                        break;
     310
     311                case NUMERICARRAYOID:
     312                        t = PYGRES_DECIMAL | PYGRES_ARRAY;
     313                        break;
     314
     315                case CASHARRAYOID:
     316                        t = (decimal_point ?
     317                                PYGRES_MONEY : PYGRES_TEXT) | PYGRES_ARRAY;
     318                        break;
     319
     320                case BOOLARRAYOID:
     321                        t = PYGRES_BOOL | PYGRES_ARRAY;
     322                        break;
     323
     324                case BYTEAARRAYOID:
     325                        t = PYGRES_BYTEA | PYGRES_ARRAY;
     326                        break;
     327
     328                case JSONARRAYOID:
     329                case JSONBARRAYOID:
     330                        t = (jsondecode ? PYGRES_JSON : PYGRES_TEXT) | PYGRES_ARRAY;
     331                        break;
     332
     333                case ANYARRAYOID:
     334                case BPCHARARRAYOID:
     335                case CHARARRAYOID:
     336                case TEXTARRAYOID:
     337                case VARCHARARRAYOID:
     338                case DATEARRAYOID:
     339                case INTERVALARRAYOID:
     340                case TIMEARRAYOID:
     341                case TIMETZARRAYOID:
     342                case TIMESTAMPARRAYOID:
     343                case TIMESTAMPTZARRAYOID:
     344                        t = PYGRES_TEXT | PYGRES_ARRAY;
     345                        break;
     346
     347                default:
     348                        t = PYGRES_TEXT;
     349        }
     350
     351        return t;
     352}
     353
     354/* get PyGreSQL column types for all result columns */
    236355static int *
    237 get_type_array(PGresult *result, int nfields)
    238 {
    239         int *array, *a;
    240         int j;
    241 
    242         if (!(array = PyMem_Malloc(sizeof(int) * nfields)))
    243         {
    244                 PyErr_SetString(PyExc_MemoryError, "Memory error in getresult()");
    245                 return NULL;
    246         }
    247 
    248         for (j = 0, a=array; j < nfields; j++)
    249         {
    250                 switch (PQftype(result, j))
    251                 {
    252                         case INT2OID:
    253                         case INT4OID:
    254                         case OIDOID:
    255                                 *a++ = PYGRES_INT;
    256                                 break;
    257 
    258                         case INT8OID:
    259                                 *a++ = PYGRES_LONG;
    260                                 break;
    261 
    262                         case FLOAT4OID:
    263                         case FLOAT8OID:
    264                                 *a++ = PYGRES_FLOAT;
    265                                 break;
    266 
    267                         case NUMERICOID:
    268                                 *a++ = PYGRES_DECIMAL;
    269                                 break;
    270 
    271                         case CASHOID:
    272                                 *a++ = decimal_point ? PYGRES_MONEY : PYGRES_DEFAULT;
    273                                 break;
    274 
    275                         case BOOLOID:
    276                                 *a++ = PYGRES_BOOL;
    277                                 break;
    278 
    279                         case JSONOID:
    280                         case JSONBOID:
    281                                 *a++ = jsondecode ? PYGRES_JSON : PYGRES_DEFAULT;
    282                                 break;
    283 
    284                         default:
    285                                 *a++ = PYGRES_DEFAULT;
    286                 }
    287         }
    288 
    289         return array;
    290 }
    291 
    292 /* cast string s with type, size and encoding to a Python object */
    293 PyObject *
    294 cast_value(char *s, int type, Py_ssize_t size, int encoding)
     356get_col_types(PGresult *result, int nfields)
     357{
     358        int *types, *t, j;
     359
     360        if (!(types = PyMem_Malloc(sizeof(int) * nfields)))
     361                return (int *)PyErr_NoMemory();
     362
     363        for (j = 0, t=types; j < nfields; ++j)
     364                *t++ = get_type(PQftype(result, j));
     365
     366        return types;
     367}
     368
     369/* Cast a bytea encoded text based type to a Python object.
     370   This assumes the text is null-terminated character string. */
     371static PyObject *
     372cast_bytea_text(char *s)
     373{
     374        PyObject   *obj;
     375        char       *tmp_str;
     376        size_t          str_len;
     377
     378        tmp_str = (char *)PQunescapeBytea((unsigned char*)s, &str_len);
     379        obj = PyBytes_FromStringAndSize(tmp_str, str_len);
     380        if (tmp_str)
     381                PQfreemem(tmp_str);
     382        return obj;
     383}
     384
     385/* Cast a text based type to a Python object.
     386   This needs the character string, size and encoding. */
     387static PyObject *
     388cast_sized_text(char *s, Py_ssize_t size, int encoding, int type)
    295389{
    296390        PyObject   *obj, *tmp_obj;
    297         char            cashbuf[64];
    298         int                     k;
    299 
    300         switch (type)
    301         {
     391        char       *tmp_str;
     392        size_t          str_len;
     393
     394        switch (type) /* this must be the PyGreSQL internal type */
     395        {
     396                case PYGRES_BYTEA:
     397                        /* we need to add a null byte */
     398                        tmp_str = (char *) PyMem_Malloc(size + 1);
     399                        if (!tmp_str) return PyErr_NoMemory();
     400                        memcpy(tmp_str, s, size);
     401                        s = tmp_str; *(s + size) = '\0';
     402                        tmp_str = (char *)PQunescapeBytea((unsigned char*)s, &str_len);
     403                        PyMem_Free(s);
     404                        if (!tmp_str) return PyErr_NoMemory();
     405                        obj = PyBytes_FromStringAndSize(tmp_str, str_len);
     406                        if (tmp_str)
     407                                PQfreemem(tmp_str);
     408                        break;
     409
    302410                case PYGRES_JSON:
    303411                        /* this type should only be passed when jsondecode is set */
    304                         if (!jsondecode)
    305                         {
    306                                 PyErr_SetString(PyExc_ValueError, "JSON decoder is not set");
    307                                 return NULL;
    308                         }
    309 
    310412                        obj = get_decoded_string(s, size, encoding);
    311                         if (obj) /* was able to decode */
     413                        if (obj && jsondecode) /* was able to decode */
    312414                        {
    313415                                tmp_obj = Py_BuildValue("(O)", obj);
     
    317419                        break;
    318420
     421                default:  /* PYGRES_TEXT */
     422#if IS_PY3
     423                        obj = get_decoded_string(s, size, encoding);
     424                        if (!obj) /* cannot decode */
     425#endif
     426                        obj = PyBytes_FromStringAndSize(s, size);
     427        }
     428
     429        return obj;
     430}
     431
     432/* Cast a simple type to a Python object.
     433   This needs a character string representation with a given size. */
     434static PyObject *
     435cast_sized_simple(char *s, Py_ssize_t size, int type)
     436{
     437        PyObject   *obj, *tmp_obj;
     438        char            buf[64], *t;
     439        int                     i, j, n;
     440
     441        switch (type) /* this must be the PyGreSQL internal type */
     442        {
    319443                case PYGRES_INT:
    320                         obj = PyInt_FromString(s, NULL, 10);
     444                        n = sizeof(buf)/sizeof(buf[0]) - 1;
     445                        if (size < n) n = size;
     446                        for (i = 0, t = buf; i < n; ++i) *t++ = *s++;
     447                        *t = '\0';
     448                        obj = PyInt_FromString(buf, NULL, 10);
    321449                        break;
    322450
    323451                case PYGRES_LONG:
    324                         obj = PyLong_FromString(s, NULL, 10);
     452                        n = sizeof(buf)/sizeof(buf[0]) - 1;
     453                        if (size < n) n = size;
     454                        for (i = 0, t = buf; i < n; ++i) *t++ = *s++;
     455                        *t = '\0';
     456                        obj = PyLong_FromString(buf, NULL, 10);
    325457                        break;
    326458
    327459                case PYGRES_FLOAT:
    328                         tmp_obj = PyStr_FromString(s);
     460                        tmp_obj = PyStr_FromStringAndSize(s, size);
    329461                        obj = PyFloat_FromString(tmp_obj);
    330462                        Py_DECREF(tmp_obj);
     
    332464
    333465                case PYGRES_MONEY:
    334                         /* type should only be passed when decimal_point is set */
    335                         if (!decimal_point)
    336                         {
    337                                 PyErr_SetString(PyExc_ValueError, "Decimal point is not set");
    338                                 return NULL;
    339                         }
    340 
    341                         for (k = 0;
    342                                 *s && k < sizeof(cashbuf)/sizeof(cashbuf[0]) - 1;
    343                                 s++)
     466                        /* this type should only be passed when decimal_point is set */
     467                        n = sizeof(buf)/sizeof(buf[0]) - 1;
     468                        for (i = 0, j = 0; i < size && j < n; ++i, ++s)
    344469                        {
    345470                                if (*s >= '0' && *s <= '9')
    346                                         cashbuf[k++] = *s;
     471                                        buf[j++] = *s;
    347472                                else if (*s == decimal_point)
    348                                         cashbuf[k++] = '.';
     473                                        buf[j++] = '.';
    349474                                else if (*s == '(' || *s == '-')
    350                                         cashbuf[k++] = '-';
     475                                        buf[j++] = '-';
    351476                        }
    352                         cashbuf[k] = '\0';
    353                         s = cashbuf;
    354                         /* FALLTHROUGH */ /* no break here */
    355        
    356                 case PYGRES_DECIMAL:
    357477                        if (decimal)
    358478                        {
    359                                 tmp_obj = Py_BuildValue("(s)", s);
    360                                 obj = PyEval_CallObject(decimal, tmp_obj);
     479                                buf[j] = '\0';
     480                                obj = PyObject_CallFunction(decimal, "(s)", buf);
    361481                        }
    362482                        else
    363483                        {
    364                                 tmp_obj = PyStr_FromString(s);
     484                                tmp_obj = PyStr_FromString(buf);
    365485                                obj = PyFloat_FromString(tmp_obj);
     486                                Py_DECREF(tmp_obj);
     487
    366488                        }
     489                        break;
     490
     491                case PYGRES_DECIMAL:
     492                        tmp_obj = PyStr_FromStringAndSize(s, size);
     493                        obj = decimal ? PyObject_CallFunctionObjArgs(
     494                                decimal, tmp_obj, NULL) : PyFloat_FromString(tmp_obj);
    367495                        Py_DECREF(tmp_obj);
    368496                        break;
     
    382510
    383511                default:
     512                        /* other types should never be passed, use cast_sized_text */
     513                        obj = PyStr_FromStringAndSize(s, size);
     514        }
     515
     516        return obj;
     517}
     518
     519/* Cast a simple type to a Python object.
     520   This needs a null-terminated character string representation. */
     521static PyObject *
     522cast_unsized_simple(char *s, int type)
     523{
     524        PyObject   *obj, *tmp_obj;
     525        char            buf[64];
     526        int                     j, n;
     527
     528        switch (type) /* this must be the PyGreSQL internal type */
     529        {
     530                case PYGRES_INT:
     531                        obj = PyInt_FromString(s, NULL, 10);
     532                        break;
     533
     534                case PYGRES_LONG:
     535                        obj = PyLong_FromString(s, NULL, 10);
     536                        break;
     537
     538                case PYGRES_FLOAT:
     539                        tmp_obj = PyStr_FromString(s);
     540                        obj = PyFloat_FromString(tmp_obj);
     541                        Py_DECREF(tmp_obj);
     542                        break;
     543
     544                case PYGRES_MONEY:
     545                        /* this type should only be passed when decimal_point is set */
     546                        n = sizeof(buf)/sizeof(buf[0]) - 1;
     547                        for (j = 0; *s && j < n; ++s)
     548                        {
     549                                if (*s >= '0' && *s <= '9')
     550                                        buf[j++] = *s;
     551                                else if (*s == decimal_point)
     552                                        buf[j++] = '.';
     553                                else if (*s == '(' || *s == '-')
     554                                        buf[j++] = '-';
     555                        }
     556                        buf[j] = '\0'; s = buf;
     557                        /* FALLTHROUGH */ /* no break here */
     558       
     559                case PYGRES_DECIMAL:
     560                        if (decimal)
     561                        {
     562                                obj = PyObject_CallFunction(decimal, "(s)", s);
     563                        }
     564                        else
     565                        {
     566                                tmp_obj = PyStr_FromString(s);
     567                                obj = PyFloat_FromString(tmp_obj);
     568                                Py_DECREF(tmp_obj);
     569                        }
     570                        break;
     571
     572                case PYGRES_BOOL:
     573                        /* convert to bool only if use_bool is set */
     574                        if (use_bool)
     575                        {
     576                                obj = *s == 't' ? Py_True : Py_False;
     577                                Py_INCREF(obj);
     578                        }
     579                        else
     580                        {
     581                                obj = PyStr_FromString(*s == 't' ? "t" : "f");
     582                        }
     583                        break;
     584
     585                default:
     586                        /* other types should never be passed, use cast_sized_text */
     587                        obj = PyStr_FromString(s);
     588        }
     589
     590        return obj;
     591}
     592
     593/* quick case insensitive check if given sized string is null */
     594#define STR_IS_NULL(s, n) (n == 4 \
     595        && (s[0] == 'n' || s[0] == 'N') \
     596        && (s[1] == 'u' || s[1] == 'U') \
     597        && (s[2] == 'l' || s[2] == 'L') \
     598        && (s[3] == 'l' || s[3] == 'L'))
     599
     600/* Cast string s with size and encoding to a Python list.
     601   Use cast function if specified or basetype to cast elements.
     602   The parameter delim specifies the delimiter for the elements,
     603   since some types do not use the default delimiter of a comma. */
     604static PyObject *
     605cast_array(char *s, Py_ssize_t size, int encoding,
     606         int type, PyObject *cast, char delim)
     607{
     608        PyObject   *result, *stack[MAX_ARRAY_DEPTH];
     609        char       *end = s + size, *t;
     610        int                     depth, ranges = 0, level = 0;
     611
     612        if (type)
     613        {
     614                type &= ~PYGRES_ARRAY; /* get the base type */
     615                if (!type) type = PYGRES_TEXT;
     616        }
     617        if (!delim) delim = ',';
     618
     619        /* strip blanks at the beginning */
     620        while (s != end && *s == ' ') ++s;
     621        if (*s == '[') /* dimension ranges */
     622        {
     623                int valid;
     624
     625                for (valid = 0; !valid;)
     626                {
     627                        if (s == end || *s++ != '[') break;
     628                        while (s != end && *s == ' ') ++s;
     629                        if (s != end && (*s == '+' || *s == '-')) ++s;
     630                        if (s == end || *s <= '0' || *s >= '9') break;
     631                        while (s != end && *s >= '0' && *s <= '9') ++s;
     632                        if (s == end || *s++ != ':') break;
     633                        if (s != end && (*s == '+' || *s == '-')) ++s;
     634                        if (s == end || *s <= '0' || *s >= '9') break;
     635                        while (s != end && *s >= '0' && *s <= '9') ++s;
     636                        if (s == end || *s++ != ']') break;
     637                        while (s != end && *s == ' ') ++s;
     638                        ++ranges;
     639                        if (s != end && *s == '=')
     640                        {
     641                                do ++s; while (s != end && *s == ' ');
     642                                valid = 1;
     643                        }
     644                }
     645                if (!valid)
     646                {
     647                        PyErr_SetString(PyExc_ValueError, "Invalid array dimensions");
     648                        return NULL;
     649                }
     650        }
     651        for (t = s, depth = 0; t != end && (*t == '{' || *t == ' '); ++t)
     652                if (*t == '{') ++depth;
     653        if (!depth)
     654        {
     655                PyErr_SetString(PyExc_ValueError,
     656                        "Array must start with an opening brace");
     657                return NULL;
     658        }
     659        if (ranges && depth != ranges)
     660        {
     661                PyErr_SetString(PyExc_ValueError,
     662                        "Array dimensions do not match content");
     663                return NULL;
     664        }
     665        if (depth > MAX_ARRAY_DEPTH)
     666        {
     667                PyErr_SetString(PyExc_ValueError, "Array is too deeply nested");
     668                return NULL;
     669        }
     670        depth--; /* next level of parsing */
     671        result = PyList_New(0);
     672        if (!result) return NULL;
     673        do ++s; while (s != end && *s == ' ');
     674        /* everything is set up, start parsing the array */
     675        while (s != end)
     676        {
     677                if (*s == '}')
     678                {
     679                        PyObject *subresult;
     680
     681                        if (!level) break; /* top level array ended */
     682                        do ++s; while (s != end && *s == ' ');
     683                        if (s == end) break; /* error */
     684                        if (*s == delim)
     685                        {
     686                                do ++s; while (s != end && *s == ' ');
     687                                if (s == end) break; /* error */
     688                                if (*s != '{')
     689                                {
     690                                        PyErr_SetString(PyExc_ValueError,
     691                                                "Subarray expected but not found");
     692                                        return NULL;
     693                                }
     694                        }
     695                        else if (*s != '}') break; /* error */
     696                        subresult = result;
     697                        result = stack[--level];
     698                        if (PyList_Append(result, subresult)) return NULL;
     699                }
     700                else if (level == depth) /* we expect elements at this level */
     701                {
     702                        PyObject   *element;
     703                        char       *estr;
     704                        Py_ssize_t      esize;
     705                        int escaped = 0;
     706
     707                        if (*s == '{')
     708                        {
     709                                PyErr_SetString(PyExc_ValueError,
     710                                        "Subarray found where not expected");
     711                                return NULL;
     712                        }
     713                        if (*s == '"') /* quoted element */
     714                        {
     715                                estr = ++s;
     716                                while (s != end && *s != '"')
     717                                {
     718                                        if (*s == '\\')
     719                                        {
     720                                                ++s; if (s == end) break;
     721                                                escaped = 1;
     722                                        }
     723                                        ++s;
     724                                }
     725                                esize = s - estr;
     726                                do ++s; while (s != end && *s == ' ');
     727                        }
     728                        else /* unquoted element */
     729                        {
     730                                estr = s;
     731                                /* can contain blanks inside */
     732                                while (s != end && *s != '"' &&
     733                                        *s != '{' && *s != '}' && *s != delim)
     734                                {
     735                                        if (*s == '\\')
     736                                        {
     737                                                ++s; if (s == end) break;
     738                                                escaped = 1;
     739                                        }
     740                                        ++s;
     741                                }
     742                                t = s; while (t > estr && *(t - 1) == ' ') --t;
     743                                if (!(esize = t - estr))
     744                                {
     745                                        s = end; break; /* error */
     746                                }
     747                                if (STR_IS_NULL(estr, esize)) /* NULL gives None */
     748                                        estr = NULL;
     749                        }
     750                        if (s == end) break; /* error */
     751                        if (estr)
     752                        {
     753                                if (escaped)
     754                                {
     755                                        char   *r;
     756                                        int             i;
     757
     758                                        /* create unescaped string */
     759                                        t = estr;
     760                                        estr = (char *) PyMem_Malloc(esize);
     761                                        if (!estr) return PyErr_NoMemory();
     762                                        for (i = 0, r = estr; i < esize; ++i)
     763                                        {
     764                                                if (*t == '\\') ++t, ++i;
     765                                                *r++ = *t++;
     766                                        }
     767                                        esize = r - estr;
     768                                }
     769                                if (type) /* internal casting of base type */
     770                                {
     771                                        if (type & PYGRES_TEXT)
     772                                                element = cast_sized_text(estr, esize, encoding, type);
     773                                        else
     774                                                element = cast_sized_simple(estr, esize, type);
     775                                }
     776                                else /* external casting of base type */
     777                                {
    384778#if IS_PY3
    385                         obj = get_decoded_string(s, size, encoding);
    386                         if (!obj) /* cannot decode */
     779                                        element = encoding == pg_encoding_ascii ? NULL :
     780                                                get_decoded_string(estr, esize, encoding);
     781                                        if (!element) /* no decoding necessary or possible */
     782#else
     783                                        element = PyBytes_FromStringAndSize(estr, esize);
    387784#endif
    388                         obj = PyBytes_FromStringAndSize(s, size);
    389         }
    390 
    391         return obj;
    392 }
    393 
     785                                        if (element && cast)
     786                                        {
     787                                                element = PyObject_CallFunctionObjArgs(
     788                                                        cast, element, NULL);
     789                                        }
     790                                }
     791                                if (escaped) PyMem_Free(estr);
     792                                if (!element) return NULL;
     793                        }
     794                        else
     795                        {
     796                                Py_INCREF(Py_None);
     797                                element = Py_None;
     798                        }
     799                        if (PyList_Append(result, element)) return NULL;
     800                        if (*s == delim)
     801                        {
     802                                do ++s; while (s != end && *s == ' ');
     803                                if (s == end) break; /* error */
     804                        }
     805                        else if (*s != '}') break; /* error */
     806                }
     807                else /* we expect arrays at this level */
     808                {
     809                        if (*s != '{')
     810                        {
     811                                PyErr_SetString(PyExc_ValueError,
     812                                        "Subarray must start with an opening brace");
     813                                return NULL;
     814                        }
     815                        do ++s; while (s != end && *s == ' ');
     816                        if (s == end) break; /* error */
     817                        stack[level++] = result;
     818                        if (!(result = PyList_New(0))) return NULL;
     819                }
     820        }
     821        if (s == end || *s != '}')
     822        {
     823                PyErr_SetString(PyExc_ValueError,
     824                        "Unexpected end of array");
     825                return NULL;
     826        }
     827        do ++s; while (s != end && *s == ' ');
     828        if (s != end)
     829        {
     830                PyErr_SetString(PyExc_ValueError,
     831                        "Unexpected characters after end of array");
     832                return NULL;
     833        }
     834        return result;
     835}
    394836
    395837/* internal wrapper for the notice receiver callback */
    396 static void notice_receiver(void *arg, const PGresult *res)
     838static void
     839notice_receiver(void *arg, const PGresult *res)
    397840{
    398841        PyGILState_STATE gstate = PyGILState_Ensure();
     
    402845        {
    403846                noticeObject *notice = PyObject_NEW(noticeObject, &noticeType);
    404                 PyObject *args, *ret;
     847                PyObject *ret;
    405848                if (notice)
    406849                {
     
    413856                        notice = (noticeObject *)(void *)Py_None;
    414857                }
    415                 args = Py_BuildValue("(O)", notice);
    416                 ret = PyObject_CallObject(proc, args);
     858                ret = PyObject_CallFunction(proc, "(O)", notice);
    417859                Py_XDECREF(ret);
    418                 Py_DECREF(args);
    419860        }
    420861        PyGILState_Release(gstate);
     
    482923        const int n = PQnfields(res);
    483924
    484         if (n > 0)
    485         {
    486                 char * const aligns = (char *) PyMem_Malloc(n * sizeof(char));
    487                 int * const sizes = (int *) PyMem_Malloc(n * sizeof(int));
    488 
    489                 if (aligns && sizes)
    490                 {
    491                         const int m = PQntuples(res);
    492                         int i, j;
    493                         size_t size;
    494                         char *buffer;
    495 
    496                         /* calculate sizes and alignments */
    497                         for (j = 0; j < n; j++)
     925        if (n <= 0)
     926                return PyStr_FromString("(nothing selected)");
     927
     928        char * const aligns = (char *) PyMem_Malloc(n * sizeof(char));
     929        int * const sizes = (int *) PyMem_Malloc(n * sizeof(int));
     930
     931        if (!aligns || !sizes)
     932        {
     933                PyMem_Free(aligns); PyMem_Free(sizes); return PyErr_NoMemory();
     934        }
     935
     936        const int m = PQntuples(res);
     937        int i, j;
     938        size_t size;
     939        char *buffer;
     940
     941        /* calculate sizes and alignments */
     942        for (j = 0; j < n; ++j)
     943        {
     944                const char * const s = PQfname(res, j);
     945                const int format = PQfformat(res, j);
     946
     947                sizes[j] = s ? (int)strlen(s) : 0;
     948                if (format)
     949                {
     950                        aligns[j] = '\0';
     951                        if (m && sizes[j] < 8)
     952                                /* "<binary>" must fit */
     953                                sizes[j] = 8;
     954                }
     955                else
     956                {
     957                        const Oid ftype = PQftype(res, j);
     958
     959                        switch (ftype)
    498960                        {
    499                                 const char * const s = PQfname(res, j);
    500                                 const int format = PQfformat(res, j);
    501 
    502                                 sizes[j] = s ? (int)strlen(s) : 0;
    503                                 if (format)
    504                                 {
    505                                         aligns[j] = '\0';
    506                                         if (m && sizes[j] < 8)
    507                                                 /* "<binary>" must fit */
    508                                                 sizes[j] = 8;
    509                                 }
    510                                 else
    511                                 {
    512                                         const Oid ftype = PQftype(res, j);
    513 
    514                                         switch (ftype)
    515                                         {
    516                                                 case INT2OID:
    517                                                 case INT4OID:
    518                                                 case INT8OID:
    519                                                 case FLOAT4OID:
    520                                                 case FLOAT8OID:
    521                                                 case NUMERICOID:
    522                                                 case OIDOID:
    523                                                 case XIDOID:
    524                                                 case CIDOID:
    525                                                 case CASHOID:
    526                                                         aligns[j] = 'r';
    527                                                         break;
    528                                                 default:
    529                                                         aligns[j] = 'l';
    530                                         }
    531                                 }
     961                                case INT2OID:
     962                                case INT4OID:
     963                                case INT8OID:
     964                                case FLOAT4OID:
     965                                case FLOAT8OID:
     966                                case NUMERICOID:
     967                                case OIDOID:
     968                                case XIDOID:
     969                                case CIDOID:
     970                                case CASHOID:
     971                                        aligns[j] = 'r';
     972                                        break;
     973                                default:
     974                                        aligns[j] = 'l';
    532975                        }
    533                         for (i = 0; i < m; i++)
     976                }
     977        }
     978        for (i = 0; i < m; ++i)
     979        {
     980                for (j = 0; j < n; ++j)
     981                {
     982                        if (aligns[j])
    534983                        {
    535                                 for (j = 0; j < n; j++)
    536                                 {
    537                                         if (aligns[j])
    538                                         {
    539                                                 const int k = PQgetlength(res, i, j);
    540 
    541                                                 if (sizes[j] < k)
    542                                                         /* value must fit */
    543                                                         sizes[j] = k;
    544                                         }
    545                                 }
     984                                const int k = PQgetlength(res, i, j);
     985
     986                                if (sizes[j] < k)
     987                                        /* value must fit */
     988                                        sizes[j] = k;
    546989                        }
    547                         size = 0;
    548                         /* size of one row */
    549                         for (j = 0; j < n; j++) size += sizes[j] + 1;
    550                         /* times number of rows incl. heading */
    551                         size *= (m + 2);
    552                         /* plus size of footer */
    553                         size += 40;
    554                         /* is the buffer size that needs to be allocated */
    555                         buffer = (char *) PyMem_Malloc(size);
    556                         if (buffer)
     990                }
     991        }
     992        size = 0;
     993        /* size of one row */
     994        for (j = 0; j < n; ++j) size += sizes[j] + 1;
     995        /* times number of rows incl. heading */
     996        size *= (m + 2);
     997        /* plus size of footer */
     998        size += 40;
     999        /* is the buffer size that needs to be allocated */
     1000        buffer = (char *) PyMem_Malloc(size);
     1001        if (!buffer)
     1002        {
     1003                PyMem_Free(aligns); PyMem_Free(sizes); return PyErr_NoMemory();
     1004        }
     1005        char *p = buffer;
     1006        PyObject *result;
     1007
     1008        /* create the header */
     1009        for (j = 0; j < n; ++j)
     1010        {
     1011                const char * const s = PQfname(res, j);
     1012                const int k = sizes[j];
     1013                const int h = (k - (int)strlen(s)) / 2;
     1014
     1015                sprintf(p, "%*s", h, "");
     1016                sprintf(p + h, "%-*s", k - h, s);
     1017                p += k;
     1018                if (j + 1 < n)
     1019                        *p++ = '|';
     1020        }
     1021        *p++ = '\n';
     1022        for (j = 0; j < n; ++j)
     1023        {
     1024                int k = sizes[j];
     1025
     1026                while (k--)
     1027                        *p++ = '-';
     1028                if (j + 1 < n)
     1029                        *p++ = '+';
     1030        }
     1031        *p++ = '\n';
     1032        /* create the body */
     1033        for (i = 0; i < m; ++i)
     1034        {
     1035                for (j = 0; j < n; ++j)
     1036                {
     1037                        const char align = aligns[j];
     1038                        const int k = sizes[j];
     1039
     1040                        if (align)
    5571041                        {
    558                                 char *p = buffer;
    559                                 PyObject *result;
    560 
    561                                 /* create the header */
    562                                 for (j = 0; j < n; j++)
    563                                 {
    564                                         const char * const s = PQfname(res, j);
    565                                         const int k = sizes[j];
    566                                         const int h = (k - (int)strlen(s)) / 2;
    567 
    568                                         sprintf(p, "%*s", h, "");
    569                                         sprintf(p + h, "%-*s", k - h, s);
    570                                         p += k;
    571                                         if (j + 1 < n)
    572                                                 *p++ = '|';
    573                                 }
    574                                 *p++ = '\n';
    575                                 for (j = 0; j < n; j++)
    576                                 {
    577                                         int k = sizes[j];
    578 
    579                                         while (k--)
    580                                                 *p++ = '-';
    581                                         if (j + 1 < n)
    582                                                 *p++ = '+';
    583                                 }
    584                                 *p++ = '\n';
    585                                 /* create the body */
    586                                 for (i = 0; i < m; i++)
    587                                 {
    588                                         for (j = 0; j < n; j++)
    589                                         {
    590                                                 const char align = aligns[j];
    591                                                 const int k = sizes[j];
    592 
    593                                                 if (align)
    594                                                 {
    595                                                         sprintf(p, align == 'r' ?
    596                                                                 "%*s" : "%-*s", k,
    597                                                                 PQgetvalue(res, i, j));
    598                                                 }
    599                                                 else
    600                                                 {
    601                                                         sprintf(p, "%-*s", k,
    602                                                                 PQgetisnull(res, i, j) ?
    603                                                                 "" : "<binary>");
    604                                                 }
    605                                                 p += k;
    606                                                 if (j + 1 < n)
    607                                                         *p++ = '|';
    608                                         }
    609                                         *p++ = '\n';
    610                                 }
    611                                 /* free memory */
    612                                 PyMem_Free(aligns);
    613                                 PyMem_Free(sizes);
    614                                 /* create the footer */
    615                                 sprintf(p, "(%d row%s)", m, m == 1 ? "" : "s");
    616                                 /* return the result */
    617                                 result = PyStr_FromString(buffer);
    618                                 PyMem_Free(buffer);
    619                                 return result;
     1042                                sprintf(p, align == 'r' ?
     1043                                        "%*s" : "%-*s", k,
     1044                                        PQgetvalue(res, i, j));
    6201045                        }
    6211046                        else
    6221047                        {
    623                                 PyErr_SetString(PyExc_MemoryError,
    624                                         "Not enough memory for formatting the query result");
    625                                 return NULL;
     1048                                sprintf(p, "%-*s", k,
     1049                                        PQgetisnull(res, i, j) ?
     1050                                        "" : "<binary>");
    6261051                        }
    627                 } else {
    628                         PyMem_Free(aligns);
    629                         PyMem_Free(sizes);
    630                         PyErr_SetString(PyExc_MemoryError,
    631                                 "Not enough memory for formatting the query result");
    632                         return NULL;
    633                 }
    634         }
    635         else
    636                 return PyStr_FromString("(nothing selected)");
     1052                        p += k;
     1053                        if (j + 1 < n)
     1054                                *p++ = '|';
     1055                }
     1056                *p++ = '\n';
     1057        }
     1058        /* free memory */
     1059        PyMem_Free(aligns); PyMem_Free(sizes);
     1060        /* create the footer */
     1061        sprintf(p, "(%d row%s)", m, m == 1 ? "" : "s");
     1062        /* return the result */
     1063        result = PyStr_FromString(buffer);
     1064        PyMem_Free(buffer);
     1065        return result;
    6371066}
    6381067
     
    12951724                str = (PyObject **)PyMem_Malloc(nparms * sizeof(*str));
    12961725                parms = (char **)PyMem_Malloc(nparms * sizeof(*parms));
    1297                 if (!str || !parms) {
    1298                         PyMem_Free(parms);
    1299                         PyMem_Free(str);
    1300                         Py_XDECREF(query_obj);
    1301                         Py_XDECREF(param_obj);
    1302                         PyErr_SetString(PyExc_MemoryError, "Memory error in query()");
    1303                         return NULL;
     1726                if (!str || !parms)
     1727                {
     1728                        PyMem_Free(parms); PyMem_Free(str);
     1729                        Py_XDECREF(query_obj); Py_XDECREF(param_obj);
     1730                        return PyErr_NoMemory();
    13041731                }
    13051732
     
    13071734                 * the caller to pass whatever they like, and prevents us
    13081735                 * from having to map types to OIDs */
    1309                 for (i = 0, s=str, p=parms; i < nparms; i++, p++)
     1736                for (i = 0, s=str, p=parms; i < nparms; ++i, ++p)
    13101737                {
    13111738                        PyObject *obj = PySequence_Fast_GET_ITEM(param_obj, i);
     
    14281855
    14291856        if (!(npgobj = PyObject_NEW(queryObject, &queryType)))
    1430         {
    1431                 PyErr_SetString(PyExc_MemoryError, "Can't create query object");
    1432                 return NULL;
    1433         }
     1857                return PyErr_NoMemory();
    14341858
    14351859        /* stores result and returns object */
     
    16142038        /* allocate buffer */
    16152039        if (!(buffer = PyMem_Malloc(MAX_BUFFER_SIZE)))
    1616         {
    1617                 PyErr_SetString(PyExc_MemoryError,
    1618                         "Can't allocate insert buffer");
    1619                 return NULL;
    1620         }
     2040                return PyErr_NoMemory();
    16212041
    16222042        /* starts query */
     
    16412061
    16422062        /* feed table */
    1643         for (i = 0; i < m; i++)
     2063        for (i = 0; i < m; ++i)
    16442064        {
    16452065                sublist = getitem(list, i);
     
    16792099                bufsiz = MAX_BUFFER_SIZE - 1;
    16802100
    1681                 for (j = 0; j < n; j++)
     2101                for (j = 0; j < n; ++j)
    16822102                {
    16832103                        if (j)
     
    17602180                        if (bufsiz <= 0)
    17612181                        {
    1762                                 PyMem_Free(buffer);
    1763                                 PyErr_SetString(PyExc_MemoryError,
    1764                                         "Insert buffer overflow");
    1765                                 return NULL;
     2182                                PyMem_Free(buffer); return PyErr_NoMemory();
    17662183                        }
    17672184
     
    28203237
    28213238        /* allocate list for result */
    2822         if (!(reslist = PyList_New(0)))
    2823                 return NULL;
     3239        if (!(reslist = PyList_New(0))) return NULL;
    28243240
    28253241#if IS_PY3
     
    28283244
    28293245        /* builds result */
    2830         for (i = 0, k = self->current_row; i < size; i++, k++)
     3246        for (i = 0, k = self->current_row; i < size; ++i, ++k)
    28313247        {
    28323248                PyObject   *rowtuple;
     
    28353251                if (!(rowtuple = PyTuple_New(self->num_fields)))
    28363252                {
    2837                         Py_DECREF(reslist);
    2838                         return NULL;
    2839                 }
    2840 
    2841                 for (j = 0; j < self->num_fields; j++)
     3253                        Py_DECREF(reslist); return NULL;
     3254                }
     3255
     3256                for (j = 0; j < self->num_fields; ++j)
    28423257                {
    28433258                        PyObject   *str;
     
    28483263                                str = Py_None;
    28493264                        }
    2850                         else {
     3265                        else
     3266                        {
    28513267                                char *s = PQgetvalue(self->result, k, j);
    28523268                                Py_ssize_t size = PQgetlength(self->result, k, j);
     
    28653281                }
    28663282
    2867                 PyList_Append(reslist, rowtuple);
     3283                if (PyList_Append(reslist, rowtuple))
     3284                {
     3285                        Py_DECREF(rowtuple); Py_DECREF(reslist); return NULL;
     3286                }
    28683287                Py_DECREF(rowtuple);
    28693288        }
     
    29023321                case QUERY_MOVENEXT:
    29033322                        if (self->current_row != self->max_row)
    2904                                 self->current_row++;
     3323                                ++self->current_row;
    29053324                        break;
    29063325                case QUERY_MOVEPREV:
     
    29793398                return NULL;
    29803399
    2981         if (buffer_obj == Py_None) {
     3400        if (buffer_obj == Py_None)
     3401        {
    29823402                /* pass None for terminating the operation */
    29833403                buffer = errormsg = NULL;
     
    32433663                return NULL;
    32443664
    3245         for (i = 0; i < self->num_fields; i++)
     3665        for (i = 0; i < self->num_fields; ++i)
    32463666        {
    32473667                info = pgsource_buildinfo(self, i);
     
    36064026        fieldstuple = PyTuple_New(n);
    36074027
    3608         for (i = 0; i < n; i++)
     4028        for (i = 0; i < n; ++i)
    36094029        {
    36104030                name = PQfname(self->result, i);
     
    36834103{
    36844104        PyObject   *reslist;
    3685         int                     i,
    3686                                 m,
    3687                                 n,
    3688                            *coltypes;
     4105        int                     i, m, n, *col_types;
    36894106        int                     encoding = self->encoding;
    36904107
     
    37004117        m = PQntuples(self->result);
    37014118        n = PQnfields(self->result);
    3702         if (!(reslist = PyList_New(m)))
    3703                 return NULL;
    3704 
    3705         coltypes = get_type_array(self->result, n);
    3706 
    3707         for (i = 0; i < m; i++)
     4119        if (!(reslist = PyList_New(m))) return NULL;
     4120
     4121        if (!(col_types = get_col_types(self->result, n))) return NULL;
     4122
     4123        for (i = 0; i < m; ++i)
    37084124        {
    37094125                PyObject   *rowtuple;
     
    37174133                }
    37184134
    3719                 for (j = 0; j < n; j++)
     4135                for (j = 0; j < n; ++j)
    37204136                {
    37214137                        PyObject * val;
     
    37284144                        else /* not null */
    37294145                        {
    3730                                 char       *s = PQgetvalue(self->result, i, j);
    3731                                 Py_ssize_t      size = PQgetlength(self->result, i, j);;
    3732 
    3733                                 if (PQfformat(self->result, j) == 0) /* text */
    3734                                 {
    3735                                         val = cast_value(s, coltypes[j], size, encoding);
    3736                                 }
    3737                                 else /* not text */
    3738                                 {
    3739                                         val = PyBytes_FromStringAndSize(s, size);
    3740                                 }
     4146                                /* get the string representation of the value */
     4147                                /* note: this is always null-terminated text format */
     4148                                char   *s = PQgetvalue(self->result, i, j);
     4149                                /* get the PyGreSQL type of the column */
     4150                                int             type = col_types[j];
     4151
     4152                                if (type & PYGRES_ARRAY)
     4153                                        val = cast_array(s, PQgetlength(self->result, i, j),
     4154                                                encoding, type, NULL, 0);
     4155                                else if (type == PYGRES_BYTEA)
     4156                                        val = cast_bytea_text(s);
     4157                                else if (type & PYGRES_TEXT)
     4158                                        val = cast_sized_text(s, PQgetlength(self->result, i, j),
     4159                                                encoding, type);
     4160                                else
     4161                                        val = cast_unsized_simple(s, type);
    37414162                        }
    37424163
     
    37564177
    37574178exit:
    3758         PyMem_Free(coltypes);
     4179        PyMem_Free(col_types);
    37594180
    37604181        /* returns list */
     
    37754196                                m,
    37764197                                n,
    3777                            *coltypes;
     4198                           *col_types;
    37784199        int                     encoding = self->encoding;
    37794200
     
    37894210        m = PQntuples(self->result);
    37904211        n = PQnfields(self->result);
    3791         if (!(reslist = PyList_New(m)))
    3792                 return NULL;
    3793 
    3794         coltypes = get_type_array(self->result, n);
    3795 
    3796         for (i = 0; i < m; i++)
     4212        if (!(reslist = PyList_New(m))) return NULL;
     4213
     4214        if (!(col_types = get_col_types(self->result, n))) return NULL;
     4215
     4216        for (i = 0; i < m; ++i)
    37974217        {
    37984218                PyObject   *dict;
     
    38064226                }
    38074227
    3808                 for (j = 0; j < n; j++)
     4228                for (j = 0; j < n; ++j)
    38094229                {
    38104230                        PyObject * val;
     
    38174237                        else /* not null */
    38184238                        {
    3819                                 char       *s = PQgetvalue(self->result, i, j);
    3820                                 Py_ssize_t      size = PQgetlength(self->result, i, j);;
    3821 
    3822                                 if (PQfformat(self->result, j) == 0) /* text */
    3823                                 {
    3824                                         val = cast_value(s, coltypes[j], size, encoding);
    3825                                 }
    3826                                 else /* not text */
    3827                                 {
    3828                                         val = PyBytes_FromStringAndSize(s, size);
    3829                                 }
     4239                                /* get the string representation of the value */
     4240                                /* note: this is always null-terminated text format */
     4241                                char   *s = PQgetvalue(self->result, i, j);
     4242                                /* get the PyGreSQL type of the column */
     4243                                int             type = col_types[j];
     4244
     4245                                if (type & PYGRES_ARRAY)
     4246                                        val = cast_array(s, PQgetlength(self->result, i, j),
     4247                                                encoding, type, NULL, 0);
     4248                                else if (type == PYGRES_BYTEA)
     4249                                        val = cast_bytea_text(s);
     4250                                else if (type & PYGRES_TEXT)
     4251                                        val = cast_sized_text(s, PQgetlength(self->result, i, j),
     4252                                                encoding, type);
     4253                                else
     4254                                        val = cast_unsized_simple(s, type);
    38304255                        }
    38314256
     
    38464271
    38474272exit:
    3848         PyMem_Free(coltypes);
     4273        PyMem_Free(col_types);
    38494274
    38504275        /* returns list */
     
    38614286queryNamedResult(queryObject *self, PyObject *args)
    38624287{
    3863         PyObject   *arglist,
    3864                            *ret;
     4288        PyObject   *ret;
    38654289
    38664290        if (namedresult)
     
    38744298                }
    38754299
    3876                 arglist = Py_BuildValue("(O)", self);
    3877                 ret = PyObject_CallObject(namedresult, arglist);
    3878                 Py_DECREF(arglist);
     4300                ret = PyObject_CallFunction(namedresult, "(O)", self);
    38794301
    38804302                if (ret == NULL)
     
    42044626        Py_XDECREF(from_obj);
    42054627
     4628        if (!to) return PyErr_NoMemory();
     4629
    42064630        to_obj = PyBytes_FromStringAndSize(to, to_length);
    4207         if (to)
    4208                 PQfreemem(to);
     4631        PQfreemem(to);
     4632
    42094633        return to_obj;
    42104634}
     
    42264650                        s[0] = decimal_point; s[1] = '\0';
    42274651                        ret = PyStr_FromString(s);
    4228                 } else {
     4652                }
     4653                else
     4654                {
    42294655                        Py_INCREF(Py_None); ret = Py_None;
    42304656                }
     
    42624688                decimal_point = *s;
    42634689                Py_INCREF(Py_None); ret = Py_None;
    4264         } else {
     4690        }
     4691        else
     4692        {
    42654693                PyErr_SetString(PyExc_TypeError,
    42664694                        "set_decimal_point() expects a decimal mark character");
     
    47385166}
    47395167#endif /* DEFAULT_VARS */
     5168
     5169/* cast a string with a text representation of an array to a list */
     5170static char pgCastArray__doc__[] =
     5171"cast_array(string, cast=None, delim=',') -- cast a string as an array";
     5172
     5173PyObject *
     5174pgCastArray(PyObject *self, PyObject *args, PyObject *dict)
     5175{
     5176        static const char *kwlist[] = {"string", "cast", "delim", NULL};
     5177        PyObject   *string_obj, *cast_obj = NULL;
     5178        char       *string;
     5179        Py_ssize_t      size;
     5180        int                     encoding;
     5181        char            delim = ',';
     5182
     5183        if (!PyArg_ParseTupleAndKeywords(args, dict, "O|Oc",
     5184                        (char **) kwlist, &string_obj, &cast_obj, &delim))
     5185                return NULL;
     5186
     5187        if (PyBytes_Check(string_obj))
     5188        {
     5189                encoding = pg_encoding_ascii;
     5190                PyBytes_AsStringAndSize(string_obj, &string, &size);
     5191                string_obj = NULL;
     5192        }
     5193        else if (PyUnicode_Check(string_obj))
     5194        {
     5195                encoding = pg_encoding_utf8;
     5196                string_obj = get_encoded_string(string_obj, encoding);
     5197                if (!string_obj) return NULL; /* pass the UnicodeEncodeError */
     5198                PyBytes_AsStringAndSize(string_obj, &string, &size);
     5199        }
     5200        else
     5201        {
     5202                PyErr_SetString(PyExc_TypeError, "cast_array() expects a string");
     5203                return NULL;
     5204        }
     5205
     5206        if (!cast_obj || cast_obj == Py_None)
     5207                cast_obj = NULL;
     5208        else if (!PyCallable_Check(cast_obj))
     5209        {
     5210                PyErr_SetString(PyExc_TypeError, "The cast argument must be callable");
     5211                return NULL;
     5212        }
     5213
     5214        return cast_array(string, size, encoding, 0, cast_obj, delim);
     5215}
     5216
    47405217
    47415218/* List of functions defined in the module */
     
    47685245        {"set_jsondecode", (PyCFunction) pgSetJsondecode, METH_VARARGS,
    47695246                        pgSetJsondecode__doc__},
     5247        {"cast_array", (PyCFunction) pgCastArray, METH_VARARGS|METH_KEYWORDS,
     5248                        pgCastArray__doc__},
    47705249
    47715250#ifdef DEFAULT_VARS
Note: See TracChangeset for help on using the changeset viewer.