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