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 1 : 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 1 : _PG_init(void)
46 : {
47 1 : PLyObject_AsString_p = (PLyObject_AsString_t)
48 1 : load_external_function("$libdir/" PLPYTHON_LIBNAME, "PLyObject_AsString",
49 : true, NULL);
50 1 : PLyUnicode_FromStringAndSize_p = (PLyUnicode_FromStringAndSize_t)
51 1 : load_external_function("$libdir/" PLPYTHON_LIBNAME, "PLyUnicode_FromStringAndSize",
52 : true, NULL);
53 1 : hstoreUpgrade_p = (hstoreUpgrade_t)
54 1 : load_external_function("$libdir/hstore", "hstoreUpgrade",
55 : true, NULL);
56 1 : hstoreUniquePairs_p = (hstoreUniquePairs_t)
57 1 : load_external_function("$libdir/hstore", "hstoreUniquePairs",
58 : true, NULL);
59 1 : hstorePairs_p = (hstorePairs_t)
60 1 : load_external_function("$libdir/hstore", "hstorePairs",
61 : true, NULL);
62 1 : hstoreCheckKeyLen_p = (hstoreCheckKeyLen_t)
63 1 : load_external_function("$libdir/hstore", "hstoreCheckKeyLen",
64 : true, NULL);
65 1 : hstoreCheckValLen_p = (hstoreCheckValLen_t)
66 1 : load_external_function("$libdir/hstore", "hstoreCheckValLen",
67 : true, NULL);
68 1 : }
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 2 : PG_FUNCTION_INFO_V1(hstore_to_plpython);
82 :
83 : Datum
84 7 : hstore_to_plpython(PG_FUNCTION_ARGS)
85 : {
86 7 : HStore *in = PG_GETARG_HSTORE_P(0);
87 : int i;
88 7 : int count = HS_COUNT(in);
89 7 : char *base = STRPTR(in);
90 7 : HEntry *entries = ARRPTR(in);
91 : PyObject *dict;
92 :
93 7 : dict = PyDict_New();
94 7 : if (!dict)
95 0 : ereport(ERROR,
96 : (errcode(ERRCODE_OUT_OF_MEMORY),
97 : errmsg("out of memory")));
98 :
99 20 : for (i = 0; i < count; i++)
100 : {
101 : PyObject *key;
102 :
103 13 : key = PLyUnicode_FromStringAndSize(HSTORE_KEY(entries, base, i),
104 13 : HSTORE_KEYLEN(entries, i));
105 13 : if (HSTORE_VALISNULL(entries, i))
106 6 : PyDict_SetItem(dict, key, Py_None);
107 : else
108 : {
109 : PyObject *value;
110 :
111 7 : value = PLyUnicode_FromStringAndSize(HSTORE_VAL(entries, base, i),
112 7 : HSTORE_VALLEN(entries, i));
113 7 : PyDict_SetItem(dict, key, value);
114 7 : Py_XDECREF(value);
115 : }
116 13 : Py_XDECREF(key);
117 : }
118 :
119 7 : return PointerGetDatum(dict);
120 : }
121 :
122 :
123 2 : PG_FUNCTION_INFO_V1(plpython_to_hstore);
124 :
125 : Datum
126 8 : 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 8 : 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 8 : if (PySequence_Check(dict) || !PyMapping_Check(dict))
141 1 : ereport(ERROR,
142 : (errcode(ERRCODE_WRONG_OBJECT_TYPE),
143 : errmsg("not a Python mapping")));
144 :
145 7 : pcount = PyMapping_Size(dict);
146 7 : items = PyMapping_Items(dict);
147 :
148 7 : PG_TRY();
149 : {
150 : int32 buflen;
151 : Py_ssize_t i;
152 : Pairs *pairs;
153 :
154 7 : pairs = palloc(pcount * sizeof(*pairs));
155 :
156 26 : for (i = 0; i < pcount; i++)
157 : {
158 : PyObject *tuple;
159 : PyObject *key;
160 : PyObject *value;
161 :
162 19 : tuple = PyList_GetItem(items, i);
163 19 : key = PyTuple_GetItem(tuple, 0);
164 19 : value = PyTuple_GetItem(tuple, 1);
165 :
166 19 : pairs[i].key = PLyObject_AsString(key);
167 19 : pairs[i].keylen = hstoreCheckKeyLen(strlen(pairs[i].key));
168 19 : pairs[i].needfree = true;
169 :
170 19 : if (value == Py_None)
171 : {
172 6 : pairs[i].val = NULL;
173 6 : pairs[i].vallen = 0;
174 6 : pairs[i].isnull = true;
175 : }
176 : else
177 : {
178 13 : pairs[i].val = PLyObject_AsString(value);
179 13 : pairs[i].vallen = hstoreCheckValLen(strlen(pairs[i].val));
180 13 : pairs[i].isnull = false;
181 : }
182 : }
183 :
184 7 : pcount = hstoreUniquePairs(pairs, pcount, &buflen);
185 7 : out = hstorePairs(pairs, pcount, buflen);
186 : }
187 0 : PG_FINALLY();
188 : {
189 7 : Py_DECREF(items);
190 : }
191 7 : PG_END_TRY();
192 :
193 7 : PG_RETURN_POINTER(out);
194 : }
|