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

Generated by: LCOV version 1.16