1 #include "postgres.h"
2
3 #include "fmgr.h"
4 #include "plpython.h"
5 #include "plpy_typeio.h"
6 #include "hstore.h"
7
8 PG_MODULE_MAGIC;
9
10 extern void _PG_init(void);
11
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
19
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;
31
32
33 /*
34 * Module initialize function: fetch function pointers for cross-module calls.
35 */
36 void
_PG_init(void)37 _PG_init(void)
38 {
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);
70 }
71
72
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
81
82
83 PG_FUNCTION_INFO_V1(hstore_to_plpython);
84
85 Datum
hstore_to_plpython(PG_FUNCTION_ARGS)86 hstore_to_plpython(PG_FUNCTION_ARGS)
87 {
88 HStore *in = PG_GETARG_HS(0);
89 int i;
90 int count = HS_COUNT(in);
91 char *base = STRPTR(in);
92 HEntry *entries = ARRPTR(in);
93 PyObject *dict;
94
95 dict = PyDict_New();
96
97 for (i = 0; i < count; i++)
98 {
99 PyObject *key;
100
101 key = PyString_FromStringAndSize(HSTORE_KEY(entries, base, i),
102 HSTORE_KEYLEN(entries, i));
103 if (HSTORE_VALISNULL(entries, i))
104 PyDict_SetItem(dict, key, Py_None);
105 else
106 {
107 PyObject *value;
108
109 value = PyString_FromStringAndSize(HSTORE_VAL(entries, base, i),
110 HSTORE_VALLEN(entries, i));
111 PyDict_SetItem(dict, key, value);
112 Py_XDECREF(value);
113 }
114 Py_XDECREF(key);
115 }
116
117 return PointerGetDatum(dict);
118 }
119
120
121 PG_FUNCTION_INFO_V1(plpython_to_hstore);
122
123 Datum
plpython_to_hstore(PG_FUNCTION_ARGS)124 plpython_to_hstore(PG_FUNCTION_ARGS)
125 {
126 PyObject *dict;
127 PyObject *volatile items = NULL;
128 int32 pcount;
129 HStore *out;
130
131 dict = (PyObject *) PG_GETARG_POINTER(0);
132 if (!PyMapping_Check(dict))
133 ereport(ERROR,
134 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
135 errmsg("not a Python mapping")));
136
137 pcount = PyMapping_Size(dict);
138 items = PyMapping_Items(dict);
139
140 PG_TRY();
141 {
142 int32 buflen;
143 int32 i;
144 Pairs *pairs;
145
146 pairs = palloc(pcount * sizeof(*pairs));
147
148 for (i = 0; i < pcount; i++)
149 {
150 PyObject *tuple;
151 PyObject *key;
152 PyObject *value;
153
154 tuple = PyList_GetItem(items, i);
155 key = PyTuple_GetItem(tuple, 0);
156 value = PyTuple_GetItem(tuple, 1);
157
158 pairs[i].key = PLyObject_AsString(key);
159 pairs[i].keylen = hstoreCheckKeyLen(strlen(pairs[i].key));
160 pairs[i].needfree = true;
161
162 if (value == Py_None)
163 {
164 pairs[i].val = NULL;
165 pairs[i].vallen = 0;
166 pairs[i].isnull = true;
167 }
168 else
169 {
170 pairs[i].val = PLyObject_AsString(value);
171 pairs[i].vallen = hstoreCheckValLen(strlen(pairs[i].val));
172 pairs[i].isnull = false;
173 }
174 }
175 Py_DECREF(items);
176
177 pcount = hstoreUniquePairs(pairs, pcount, &buflen);
178 out = hstorePairs(pairs, pcount, buflen);
179 }
180 PG_CATCH();
181 {
182 Py_DECREF(items);
183 PG_RE_THROW();
184 }
185 PG_END_TRY();
186
187 PG_RETURN_POINTER(out);
188 }
189