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