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 : }
|