Changeset 774 for trunk/pgmodule.c


Ignore:
Timestamp:
Jan 21, 2016, 1:49:28 PM (4 years ago)
Author:
cito
Message:

Add support for JSON and JSONB to pg and pgdb

This adds all necessary functions to make PyGreSQL automatically
convert between JSON columns and Python objects representing them.

The documentation has also been updated, see there for the details.

Also, tuples automatically bind to ROW expressions in pgdb now.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/pgmodule.c

    r740 r774  
    9393
    9494static PyObject *decimal = NULL, /* decimal type */
    95                                 *namedresult = NULL; /* function for getting named results */
     95                                *namedresult = NULL, /* function for getting named results */
     96                                *jsondecode = NULL; /* function for decoding json strings */
    9697static char decimal_point = '.'; /* decimal point used in money values */
    9798static int use_bool = 0; /* whether or not bool objects shall be returned */
     
    189190/* define internal types */
    190191
     192#define PYGRES_DEFAULT 0
    191193#define PYGRES_INT 1
    192194#define PYGRES_LONG 2
     
    195197#define PYGRES_MONEY 5
    196198#define PYGRES_BOOL 6
    197 #define PYGRES_DEFAULT 7
     199#define PYGRES_JSON 7
    198200
    199201/* --------------------------------------------------------------------- */
     
    235237get_type_array(PGresult *result, int nfields)
    236238{
    237         int *typ;
     239        int *array, *a;
    238240        int j;
    239241
    240         if (!(typ = PyMem_Malloc(sizeof(int) * nfields)))
     242        if (!(array = PyMem_Malloc(sizeof(int) * nfields)))
    241243        {
    242244                PyErr_SetString(PyExc_MemoryError, "Memory error in getresult()");
     
    244246        }
    245247
    246         for (j = 0; j < nfields; j++)
     248        for (j = 0, a=array; j < nfields; j++)
    247249        {
    248250                switch (PQftype(result, j))
     
    251253                        case INT4OID:
    252254                        case OIDOID:
    253                                 typ[j] = PYGRES_INT;
     255                                *a++ = PYGRES_INT;
    254256                                break;
    255257
    256258                        case INT8OID:
    257                                 typ[j] = PYGRES_LONG;
     259                                *a++ = PYGRES_LONG;
    258260                                break;
    259261
    260262                        case FLOAT4OID:
    261263                        case FLOAT8OID:
    262                                 typ[j] = PYGRES_FLOAT;
     264                                *a++ = PYGRES_FLOAT;
    263265                                break;
    264266
    265267                        case NUMERICOID:
    266                                 typ[j] = PYGRES_DECIMAL;
     268                                *a++ = PYGRES_DECIMAL;
    267269                                break;
    268270
    269271                        case CASHOID:
    270                                 typ[j] = PYGRES_MONEY;
     272                                *a++ = PYGRES_MONEY;
    271273                                break;
    272274
    273275                        case BOOLOID:
    274                                 typ[j] = PYGRES_BOOL;
     276                                *a++ = PYGRES_BOOL;
    275277                                break;
    276278
     279                        case JSONOID:
     280                        case JSONBOID:
     281                                *a++ = PYGRES_JSON;
     282                                break;
     283
    277284                        default:
    278                                 typ[j] = PYGRES_DEFAULT;
     285                                *a++ = PYGRES_DEFAULT;
    279286                }
    280287        }
    281288
    282         return typ;
     289        return array;
    283290}
    284291
     
    36323639                                switch (coltypes[j])
    36333640                                {
     3641                                        case PYGRES_JSON:
     3642                                                if (!jsondecode || /* no JSON decoder available */
     3643                                                        PQfformat(self->result, j) != 0) /* not text */
     3644                                                        goto default_case;
     3645                                                size = PQgetlength(self->result, i, j);
     3646#if IS_PY3
     3647                                                val = get_decoded_string(s, size, encoding);
     3648#else
     3649                                                val = get_decoded_string(s, size, self->encoding);
     3650#endif
     3651                                                if (val) /* was able to decode */
     3652                                                {
     3653                                                        tmp_obj = Py_BuildValue("(O)", val);
     3654                                                        val = PyObject_CallObject(jsondecode, tmp_obj);
     3655                                                        Py_DECREF(tmp_obj);
     3656                                                }
     3657                                                break;
     3658
    36343659                                        case PYGRES_INT:
    36353660                                                val = PyInt_FromString(s, NULL, 10);
     
    38033828                                switch (coltypes[j])
    38043829                                {
     3830                                        case PYGRES_JSON:
     3831                                                if (!jsondecode || /* no JSON decoder available */
     3832                                                        PQfformat(self->result, j) != 0) /* not text */
     3833                                                        goto default_case;
     3834                                                size = PQgetlength(self->result, i, j);
     3835#if IS_PY3
     3836                                                val = get_decoded_string(s, size, encoding);
     3837#else
     3838                                                val = get_decoded_string(s, size, self->encoding);
     3839#endif
     3840                                                if (val) /* was able to decode */
     3841                                                {
     3842                                                        tmp_obj = Py_BuildValue("(O)", val);
     3843                                                        val = PyObject_CallObject(jsondecode, tmp_obj);
     3844                                                        Py_DECREF(tmp_obj);
     3845                                                }
     3846                                                break;
     3847
    38053848                                        case PYGRES_INT:
    38063849                                                val = PyInt_FromString(s, NULL, 10);
     
    39183961                           *ret;
    39193962
    3920         /* checks args (args == NULL for an internal call) */
    3921         if (args && !PyArg_ParseTuple(args, ""))
    3922         {
    3923                 PyErr_SetString(PyExc_TypeError,
    3924                         "Method namedresult() takes no parameters");
    3925                 return NULL;
    3926         }
    3927 
    3928         if (!namedresult)
    3929         {
    3930                 PyErr_SetString(PyExc_TypeError,
    3931                         "Named tuples are not supported");
    3932                 return NULL;
    3933         }
    3934 
    3935         arglist = Py_BuildValue("(O)", self);
    3936         ret = PyObject_CallObject(namedresult, arglist);
    3937         Py_DECREF(arglist);
    3938 
    3939         if (ret == NULL)
    3940                 return NULL;
     3963        if (namedresult)
     3964        {
     3965                /* checks args (args == NULL for an internal call) */
     3966                if (args && !PyArg_ParseTuple(args, ""))
     3967                {
     3968                        PyErr_SetString(PyExc_TypeError,
     3969                                "Method namedresult() takes no parameters");
     3970                        return NULL;
     3971                }
     3972
     3973                arglist = Py_BuildValue("(O)", self);
     3974                ret = PyObject_CallObject(namedresult, arglist);
     3975                Py_DECREF(arglist);
     3976
     3977                if (ret == NULL)
     3978                        return NULL;
     3979                }
     3980        else
     3981        {
     3982                ret = queryGetResult(self, args);
     3983        }
    39413984
    39423985        return ret;
     
    44404483        if (PyArg_ParseTuple(args, "O", &func))
    44414484        {
    4442                 if (PyCallable_Check(func))
     4485                if (func == Py_None)
     4486                {
     4487                        Py_XDECREF(namedresult); namedresult = NULL;
     4488                        Py_INCREF(Py_None); ret = Py_None;
     4489                }
     4490                else if (PyCallable_Check(func))
    44434491                {
    44444492                        Py_XINCREF(func); Py_XDECREF(namedresult); namedresult = func;
     4493                        Py_INCREF(Py_None); ret = Py_None;
     4494                }
     4495                else
     4496                        PyErr_SetString(PyExc_TypeError, "Parameter must be callable");
     4497        }
     4498
     4499        return ret;
     4500}
     4501
     4502/* get json decode function */
     4503static char pgGetJsondecode__doc__[] =
     4504"get_jsondecode(cls) -- get the function used for decoding json results";
     4505
     4506static PyObject *
     4507pgGetJsondecode(PyObject *self, PyObject *args)
     4508{
     4509        PyObject *ret = NULL;
     4510
     4511        if (PyArg_ParseTuple(args, ""))
     4512        {
     4513                ret = jsondecode ? jsondecode : Py_None;
     4514                Py_INCREF(ret);
     4515        }
     4516
     4517        return ret;
     4518}
     4519
     4520/* set json decode function */
     4521static char pgSetJsondecode__doc__[] =
     4522"set_jsondecode(cls) -- set a function to be used for decoding json results";
     4523
     4524static PyObject *
     4525pgSetJsondecode(PyObject *self, PyObject *args)
     4526{
     4527        PyObject *ret = NULL;
     4528        PyObject *func;
     4529
     4530        if (PyArg_ParseTuple(args, "O", &func))
     4531        {
     4532                if (func == Py_None)
     4533                {
     4534                        Py_XDECREF(jsondecode); jsondecode = NULL;
     4535                        Py_INCREF(Py_None); ret = Py_None;
     4536                }
     4537                else if (PyCallable_Check(func))
     4538                {
     4539                        Py_XINCREF(func); Py_XDECREF(jsondecode); jsondecode = func;
    44454540                        Py_INCREF(Py_None); ret = Py_None;
    44464541                }
     
    47664861        {"set_namedresult", (PyCFunction) pgSetNamedresult, METH_VARARGS,
    47674862                        pgSetNamedresult__doc__},
     4863        {"get_jsondecode", (PyCFunction) pgGetJsondecode, METH_VARARGS,
     4864                        pgGetJsondecode__doc__},
     4865        {"set_jsondecode", (PyCFunction) pgSetJsondecode, METH_VARARGS,
     4866                        pgSetJsondecode__doc__},
    47684867
    47694868#ifdef DEFAULT_VARS
Note: See TracChangeset for help on using the changeset viewer.