LCOV - code coverage report
Current view: top level - contrib/hstore_plpython - hstore_plpython.c (source / functions) Hit Total Coverage
Test: PostgreSQL 18devel Lines: 64 66 97.0 %
Date: 2025-04-01 15:15:16 Functions: 6 6 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : #include "postgres.h"
       2             : 
       3             : #include "fmgr.h"
       4             : #include "hstore/hstore.h"
       5             : #include "plpy_typeio.h"
       6             : #include "plpython.h"
       7             : 
       8           2 : PG_MODULE_MAGIC_EXT(
       9             :                     .name = "hstore_plpython",
      10             :                     .version = PG_VERSION
      11             : );
      12             : 
      13             : /* Linkage to functions in plpython module */
      14             : typedef char *(*PLyObject_AsString_t) (PyObject *plrv);
      15             : static PLyObject_AsString_t PLyObject_AsString_p;
      16             : typedef PyObject *(*PLyUnicode_FromStringAndSize_t) (const char *s, Py_ssize_t size);
      17             : static PLyUnicode_FromStringAndSize_t PLyUnicode_FromStringAndSize_p;
      18             : 
      19             : /* Linkage to functions in hstore module */
      20             : typedef HStore *(*hstoreUpgrade_t) (Datum orig);
      21             : static hstoreUpgrade_t hstoreUpgrade_p;
      22             : typedef int (*hstoreUniquePairs_t) (Pairs *a, int32 l, int32 *buflen);
      23             : static hstoreUniquePairs_t hstoreUniquePairs_p;
      24             : typedef HStore *(*hstorePairs_t) (Pairs *pairs, int32 pcount, int32 buflen);
      25             : static hstorePairs_t hstorePairs_p;
      26             : typedef size_t (*hstoreCheckKeyLen_t) (size_t len);
      27             : static hstoreCheckKeyLen_t hstoreCheckKeyLen_p;
      28             : typedef size_t (*hstoreCheckValLen_t) (size_t len);
      29             : static hstoreCheckValLen_t hstoreCheckValLen_p;
      30             : 
      31             : 
      32             : /*
      33             :  * Module initialize function: fetch function pointers for cross-module calls.
      34             :  */
      35             : void
      36           2 : _PG_init(void)
      37             : {
      38             :     /* Asserts verify that typedefs above match original declarations */
      39             :     AssertVariableIsOfType(&PLyObject_AsString, PLyObject_AsString_t);
      40           2 :     PLyObject_AsString_p = (PLyObject_AsString_t)
      41           2 :         load_external_function("$libdir/" PLPYTHON_LIBNAME, "PLyObject_AsString",
      42             :                                true, NULL);
      43             :     AssertVariableIsOfType(&PLyUnicode_FromStringAndSize, PLyUnicode_FromStringAndSize_t);
      44           2 :     PLyUnicode_FromStringAndSize_p = (PLyUnicode_FromStringAndSize_t)
      45           2 :         load_external_function("$libdir/" PLPYTHON_LIBNAME, "PLyUnicode_FromStringAndSize",
      46             :                                true, NULL);
      47             :     AssertVariableIsOfType(&hstoreUpgrade, hstoreUpgrade_t);
      48           2 :     hstoreUpgrade_p = (hstoreUpgrade_t)
      49           2 :         load_external_function("$libdir/hstore", "hstoreUpgrade",
      50             :                                true, NULL);
      51             :     AssertVariableIsOfType(&hstoreUniquePairs, hstoreUniquePairs_t);
      52           2 :     hstoreUniquePairs_p = (hstoreUniquePairs_t)
      53           2 :         load_external_function("$libdir/hstore", "hstoreUniquePairs",
      54             :                                true, NULL);
      55             :     AssertVariableIsOfType(&hstorePairs, hstorePairs_t);
      56           2 :     hstorePairs_p = (hstorePairs_t)
      57           2 :         load_external_function("$libdir/hstore", "hstorePairs",
      58             :                                true, NULL);
      59             :     AssertVariableIsOfType(&hstoreCheckKeyLen, hstoreCheckKeyLen_t);
      60           2 :     hstoreCheckKeyLen_p = (hstoreCheckKeyLen_t)
      61           2 :         load_external_function("$libdir/hstore", "hstoreCheckKeyLen",
      62             :                                true, NULL);
      63             :     AssertVariableIsOfType(&hstoreCheckValLen, hstoreCheckValLen_t);
      64           2 :     hstoreCheckValLen_p = (hstoreCheckValLen_t)
      65           2 :         load_external_function("$libdir/hstore", "hstoreCheckValLen",
      66             :                                true, NULL);
      67           2 : }
      68             : 
      69             : 
      70             : /* These defines must be after the module init function */
      71             : #define PLyObject_AsString PLyObject_AsString_p
      72             : #define PLyUnicode_FromStringAndSize PLyUnicode_FromStringAndSize_p
      73             : #define hstoreUpgrade hstoreUpgrade_p
      74             : #define hstoreUniquePairs hstoreUniquePairs_p
      75             : #define hstorePairs hstorePairs_p
      76             : #define hstoreCheckKeyLen hstoreCheckKeyLen_p
      77             : #define hstoreCheckValLen hstoreCheckValLen_p
      78             : 
      79             : 
      80           4 : PG_FUNCTION_INFO_V1(hstore_to_plpython);
      81             : 
      82             : Datum
      83          14 : hstore_to_plpython(PG_FUNCTION_ARGS)
      84             : {
      85          14 :     HStore     *in = PG_GETARG_HSTORE_P(0);
      86             :     int         i;
      87          14 :     int         count = HS_COUNT(in);
      88          14 :     char       *base = STRPTR(in);
      89          14 :     HEntry     *entries = ARRPTR(in);
      90             :     PyObject   *dict;
      91             : 
      92          14 :     dict = PyDict_New();
      93          14 :     if (!dict)
      94           0 :         ereport(ERROR,
      95             :                 (errcode(ERRCODE_OUT_OF_MEMORY),
      96             :                  errmsg("out of memory")));
      97             : 
      98          40 :     for (i = 0; i < count; i++)
      99             :     {
     100             :         PyObject   *key;
     101             : 
     102          26 :         key = PLyUnicode_FromStringAndSize(HSTORE_KEY(entries, base, i),
     103          26 :                                            HSTORE_KEYLEN(entries, i));
     104          26 :         if (HSTORE_VALISNULL(entries, i))
     105          12 :             PyDict_SetItem(dict, key, Py_None);
     106             :         else
     107             :         {
     108             :             PyObject   *value;
     109             : 
     110          14 :             value = PLyUnicode_FromStringAndSize(HSTORE_VAL(entries, base, i),
     111          14 :                                                  HSTORE_VALLEN(entries, i));
     112          14 :             PyDict_SetItem(dict, key, value);
     113          14 :             Py_XDECREF(value);
     114             :         }
     115          26 :         Py_XDECREF(key);
     116             :     }
     117             : 
     118          14 :     return PointerGetDatum(dict);
     119             : }
     120             : 
     121             : 
     122           4 : PG_FUNCTION_INFO_V1(plpython_to_hstore);
     123             : 
     124             : Datum
     125          16 : plpython_to_hstore(PG_FUNCTION_ARGS)
     126             : {
     127             :     PyObject   *dict;
     128             :     PyObject   *volatile items;
     129             :     Py_ssize_t  pcount;
     130             :     HStore     *volatile out;
     131             : 
     132          16 :     dict = (PyObject *) PG_GETARG_POINTER(0);
     133             : 
     134             :     /*
     135             :      * As of Python 3, PyMapping_Check() is unreliable unless one first checks
     136             :      * that the object isn't a sequence.  (Cleaner solutions exist, but not
     137             :      * before Python 3.10, which we're not prepared to require yet.)
     138             :      */
     139          16 :     if (PySequence_Check(dict) || !PyMapping_Check(dict))
     140           2 :         ereport(ERROR,
     141             :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
     142             :                  errmsg("not a Python mapping")));
     143             : 
     144          14 :     pcount = PyMapping_Size(dict);
     145          14 :     items = PyMapping_Items(dict);
     146             : 
     147          14 :     PG_TRY();
     148             :     {
     149             :         int32       buflen;
     150             :         Py_ssize_t  i;
     151             :         Pairs      *pairs;
     152             : 
     153          14 :         pairs = palloc(pcount * sizeof(*pairs));
     154             : 
     155          52 :         for (i = 0; i < pcount; i++)
     156             :         {
     157             :             PyObject   *tuple;
     158             :             PyObject   *key;
     159             :             PyObject   *value;
     160             : 
     161          38 :             tuple = PyList_GetItem(items, i);
     162          38 :             key = PyTuple_GetItem(tuple, 0);
     163          38 :             value = PyTuple_GetItem(tuple, 1);
     164             : 
     165          38 :             pairs[i].key = PLyObject_AsString(key);
     166          38 :             pairs[i].keylen = hstoreCheckKeyLen(strlen(pairs[i].key));
     167          38 :             pairs[i].needfree = true;
     168             : 
     169          38 :             if (value == Py_None)
     170             :             {
     171          12 :                 pairs[i].val = NULL;
     172          12 :                 pairs[i].vallen = 0;
     173          12 :                 pairs[i].isnull = true;
     174             :             }
     175             :             else
     176             :             {
     177          26 :                 pairs[i].val = PLyObject_AsString(value);
     178          26 :                 pairs[i].vallen = hstoreCheckValLen(strlen(pairs[i].val));
     179          26 :                 pairs[i].isnull = false;
     180             :             }
     181             :         }
     182             : 
     183          14 :         pcount = hstoreUniquePairs(pairs, pcount, &buflen);
     184          14 :         out = hstorePairs(pairs, pcount, buflen);
     185             :     }
     186           0 :     PG_FINALLY();
     187             :     {
     188          14 :         Py_DECREF(items);
     189             :     }
     190          14 :     PG_END_TRY();
     191             : 
     192          14 :     PG_RETURN_POINTER(out);
     193             : }

Generated by: LCOV version 1.14