Age Owner Branch data TLA Line data Source code
1 : : #include "postgres.h"
2 : :
3 : : #include "miscadmin.h"
4 : : #include "plpy_elog.h"
5 : : #include "plpy_typeio.h"
6 : : #include "plpy_util.h"
7 : : #include "utils/fmgrprotos.h"
8 : : #include "utils/jsonb.h"
9 : : #include "utils/numeric.h"
10 : :
461 tgl@sss.pgh.pa.us 11 :CBC 1 : PG_MODULE_MAGIC_EXT(
12 : : .name = "jsonb_plpython",
13 : : .version = PG_VERSION
14 : : );
15 : :
16 : : /* for PLyObject_AsString in plpy_typeio.c */
17 : : typedef char *(*PLyObject_AsString_t) (PyObject *plrv);
18 : : static PLyObject_AsString_t PLyObject_AsString_p;
19 : :
20 : : typedef void (*PLy_elog_impl_t) (int elevel, const char *fmt, ...);
21 : : static PLy_elog_impl_t PLy_elog_impl_p;
22 : :
23 : : /*
24 : : * decimal_constructor is a function from python library and used
25 : : * for transforming strings into python decimal type
26 : : */
27 : : static PyObject *decimal_constructor;
28 : :
29 : : static PyObject *PLyObject_FromJsonbContainer(JsonbContainer *jsonb);
30 : : static void PLyObject_ToJsonbValue(PyObject *obj,
31 : : JsonbInState *jsonb_state, bool is_elem);
32 : :
33 : : typedef PyObject *(*PLyUnicode_FromStringAndSize_t)
34 : : (const char *s, Py_ssize_t size);
35 : : static PLyUnicode_FromStringAndSize_t PLyUnicode_FromStringAndSize_p;
36 : :
37 : : /* Static asserts verify that typedefs above match original declarations */
38 : : StaticAssertVariableIsOfType(&PLyObject_AsString, PLyObject_AsString_t);
39 : : StaticAssertVariableIsOfType(&PLyUnicode_FromStringAndSize, PLyUnicode_FromStringAndSize_t);
40 : : StaticAssertVariableIsOfType(&PLy_elog_impl, PLy_elog_impl_t);
41 : :
42 : :
43 : : /*
44 : : * Module initialize function: fetch function pointers for cross-module calls.
45 : : */
46 : : void
3016 peter_e@gmx.net 47 : 1 : _PG_init(void)
48 : : {
49 : 1 : PLyObject_AsString_p = (PLyObject_AsString_t)
50 : 1 : load_external_function("$libdir/" PLPYTHON_LIBNAME, "PLyObject_AsString",
51 : : true, NULL);
52 : 1 : PLyUnicode_FromStringAndSize_p = (PLyUnicode_FromStringAndSize_t)
53 : 1 : load_external_function("$libdir/" PLPYTHON_LIBNAME, "PLyUnicode_FromStringAndSize",
54 : : true, NULL);
55 : 1 : PLy_elog_impl_p = (PLy_elog_impl_t)
56 : 1 : load_external_function("$libdir/" PLPYTHON_LIBNAME, "PLy_elog_impl",
57 : : true, NULL);
58 : 1 : }
59 : :
60 : : /* These defines must be after the _PG_init */
61 : : #define PLyObject_AsString (PLyObject_AsString_p)
62 : : #define PLyUnicode_FromStringAndSize (PLyUnicode_FromStringAndSize_p)
63 : : #undef PLy_elog
64 : : #define PLy_elog (PLy_elog_impl_p)
65 : :
66 : : /*
67 : : * PLyUnicode_FromJsonbValue
68 : : *
69 : : * Transform string JsonbValue to Python string.
70 : : */
71 : : static PyObject *
1576 andres@anarazel.de 72 : 21 : PLyUnicode_FromJsonbValue(JsonbValue *jbv)
73 : : {
3016 peter_e@gmx.net 74 [ - + ]: 21 : Assert(jbv->type == jbvString);
75 : :
1576 andres@anarazel.de 76 : 21 : return PLyUnicode_FromStringAndSize(jbv->val.string.val, jbv->val.string.len);
77 : : }
78 : :
79 : : /*
80 : : * PLyUnicode_ToJsonbValue
81 : : *
82 : : * Transform Python string to JsonbValue.
83 : : */
84 : : static void
85 : 13 : PLyUnicode_ToJsonbValue(PyObject *obj, JsonbValue *jbvElem)
86 : : {
3016 peter_e@gmx.net 87 : 13 : jbvElem->type = jbvString;
88 : 13 : jbvElem->val.string.val = PLyObject_AsString(obj);
89 : 13 : jbvElem->val.string.len = strlen(jbvElem->val.string.val);
90 : 13 : }
91 : :
92 : : /*
93 : : * PLyObject_FromJsonbValue
94 : : *
95 : : * Transform JsonbValue to PyObject.
96 : : */
97 : : static PyObject *
98 : 40 : PLyObject_FromJsonbValue(JsonbValue *jsonbValue)
99 : : {
100 [ + + + + : 40 : switch (jsonbValue->type)
+ - ]
101 : : {
102 : 5 : case jbvNull:
103 : 5 : Py_RETURN_NONE;
104 : :
105 : 4 : case jbvBinary:
106 : 4 : return PLyObject_FromJsonbContainer(jsonbValue->val.binary.data);
107 : :
108 : 18 : case jbvNumeric:
109 : : {
110 : : Datum num;
111 : : char *str;
112 : :
113 : 18 : num = NumericGetDatum(jsonbValue->val.numeric);
114 : 18 : str = DatumGetCString(DirectFunctionCall1(numeric_out, num));
115 : :
116 : 18 : return PyObject_CallFunction(decimal_constructor, "s", str);
117 : : }
118 : :
119 : 8 : case jbvString:
1576 andres@anarazel.de 120 : 8 : return PLyUnicode_FromJsonbValue(jsonbValue);
121 : :
3016 peter_e@gmx.net 122 : 5 : case jbvBool:
123 [ + - ]: 5 : if (jsonbValue->val.boolean)
124 : 5 : Py_RETURN_TRUE;
125 : : else
3016 peter_e@gmx.net 126 :UBC 0 : Py_RETURN_FALSE;
127 : :
128 : 0 : default:
129 [ # # ]: 0 : elog(ERROR, "unexpected jsonb value type: %d", jsonbValue->type);
130 : : return NULL;
131 : : }
132 : : }
133 : :
134 : : /*
135 : : * PLyObject_FromJsonbContainer
136 : : *
137 : : * Transform JsonbContainer to PyObject.
138 : : */
139 : : static PyObject *
3016 peter_e@gmx.net 140 :CBC 30 : PLyObject_FromJsonbContainer(JsonbContainer *jsonb)
141 : : {
142 : : JsonbIteratorToken r;
143 : : JsonbValue v;
144 : : JsonbIterator *it;
145 : : PyObject *result;
146 : :
147 : : /* this can recurse via PLyObject_FromJsonbValue() */
13 tgl@sss.pgh.pa.us 148 : 30 : check_stack_depth();
149 : :
3016 peter_e@gmx.net 150 : 30 : it = JsonbIteratorInit(jsonb);
151 : 30 : r = JsonbIteratorNext(&it, &v, true);
152 : :
153 [ + + - ]: 30 : switch (r)
154 : : {
155 : 20 : case WJB_BEGIN_ARRAY:
156 [ + + ]: 20 : if (v.val.array.rawScalar)
157 : : {
158 : : JsonbValue tmp;
159 : :
160 [ + - ]: 9 : if ((r = JsonbIteratorNext(&it, &v, true)) != WJB_ELEM ||
161 [ + - ]: 9 : (r = JsonbIteratorNext(&it, &tmp, true)) != WJB_END_ARRAY ||
162 [ - + ]: 9 : (r = JsonbIteratorNext(&it, &tmp, true)) != WJB_DONE)
3016 peter_e@gmx.net 163 [ # # ]:UBC 0 : elog(ERROR, "unexpected jsonb token: %d", r);
164 : :
3016 peter_e@gmx.net 165 :CBC 9 : result = PLyObject_FromJsonbValue(&v);
166 : : }
167 : : else
168 : : {
2642 tgl@sss.pgh.pa.us 169 : 11 : PyObject *volatile elem = NULL;
170 : :
3016 peter_e@gmx.net 171 : 11 : result = PyList_New(0);
172 [ - + ]: 11 : if (!result)
3016 peter_e@gmx.net 173 :UBC 0 : return NULL;
174 : :
2642 tgl@sss.pgh.pa.us 175 [ + - ]:CBC 11 : PG_TRY();
176 : : {
177 [ + + ]: 40 : while ((r = JsonbIteratorNext(&it, &v, true)) != WJB_DONE)
178 : : {
179 [ + + ]: 29 : if (r != WJB_ELEM)
180 : 11 : continue;
181 : :
182 : 18 : elem = PLyObject_FromJsonbValue(&v);
183 : :
3016 peter_e@gmx.net 184 : 18 : PyList_Append(result, elem);
185 : 18 : Py_XDECREF(elem);
2642 tgl@sss.pgh.pa.us 186 : 18 : elem = NULL;
187 : : }
188 : : }
2642 tgl@sss.pgh.pa.us 189 :UBC 0 : PG_CATCH();
190 : : {
191 : 0 : Py_XDECREF(elem);
192 : 0 : Py_XDECREF(result);
193 : 0 : PG_RE_THROW();
194 : : }
2642 tgl@sss.pgh.pa.us 195 [ - + ]:CBC 11 : PG_END_TRY();
196 : : }
3016 peter_e@gmx.net 197 : 20 : break;
198 : :
199 : 10 : case WJB_BEGIN_OBJECT:
200 : : {
2642 tgl@sss.pgh.pa.us 201 : 10 : PyObject *volatile result_v = PyDict_New();
202 : 10 : PyObject *volatile key = NULL;
203 : 10 : PyObject *volatile val = NULL;
204 : :
205 [ - + ]: 10 : if (!result_v)
2642 tgl@sss.pgh.pa.us 206 :UBC 0 : return NULL;
207 : :
2642 tgl@sss.pgh.pa.us 208 [ + - ]:CBC 10 : PG_TRY();
209 : : {
210 [ + + ]: 33 : while ((r = JsonbIteratorNext(&it, &v, true)) != WJB_DONE)
211 : : {
212 [ + + ]: 23 : if (r != WJB_KEY)
213 : 10 : continue;
214 : :
1576 andres@anarazel.de 215 : 13 : key = PLyUnicode_FromJsonbValue(&v);
2642 tgl@sss.pgh.pa.us 216 [ - + ]: 13 : if (!key)
217 : : {
2642 tgl@sss.pgh.pa.us 218 :UBC 0 : Py_XDECREF(result_v);
219 : 0 : result_v = NULL;
220 : 0 : break;
221 : : }
222 : :
2642 tgl@sss.pgh.pa.us 223 [ - + ]:CBC 13 : if ((r = JsonbIteratorNext(&it, &v, true)) != WJB_VALUE)
2642 tgl@sss.pgh.pa.us 224 [ # # ]:UBC 0 : elog(ERROR, "unexpected jsonb token: %d", r);
225 : :
2642 tgl@sss.pgh.pa.us 226 :CBC 13 : val = PLyObject_FromJsonbValue(&v);
227 [ - + ]: 13 : if (!val)
228 : : {
3016 peter_e@gmx.net 229 :UBC 0 : Py_XDECREF(key);
2642 tgl@sss.pgh.pa.us 230 : 0 : key = NULL;
231 : 0 : Py_XDECREF(result_v);
232 : 0 : result_v = NULL;
233 : 0 : break;
234 : : }
235 : :
2642 tgl@sss.pgh.pa.us 236 :CBC 13 : PyDict_SetItem(result_v, key, val);
237 : :
238 : 13 : Py_XDECREF(key);
239 : 13 : key = NULL;
240 : 13 : Py_XDECREF(val);
241 : 13 : val = NULL;
242 : : }
243 : : }
2642 tgl@sss.pgh.pa.us 244 :UBC 0 : PG_CATCH();
245 : : {
246 : 0 : Py_XDECREF(result_v);
3016 peter_e@gmx.net 247 : 0 : Py_XDECREF(key);
2642 tgl@sss.pgh.pa.us 248 : 0 : Py_XDECREF(val);
249 : 0 : PG_RE_THROW();
250 : : }
2642 tgl@sss.pgh.pa.us 251 [ - + ]:CBC 10 : PG_END_TRY();
252 : :
253 : 10 : result = result_v;
254 : : }
3016 peter_e@gmx.net 255 : 10 : break;
256 : :
3016 peter_e@gmx.net 257 :UBC 0 : default:
258 [ # # ]: 0 : elog(ERROR, "unexpected jsonb token: %d", r);
259 : : return NULL;
260 : : }
261 : :
3016 peter_e@gmx.net 262 :CBC 30 : return result;
263 : : }
264 : :
265 : : /*
266 : : * PLyMapping_ToJsonbValue
267 : : *
268 : : * Transform Python dict to JsonbValue.
269 : : */
270 : : static void
205 tgl@sss.pgh.pa.us 271 :GNC 9 : PLyMapping_ToJsonbValue(PyObject *obj, JsonbInState *jsonb_state)
272 : : {
273 : : Py_ssize_t pcount;
274 : : PyObject *volatile items;
275 : :
3016 peter_e@gmx.net 276 :CBC 9 : pcount = PyMapping_Size(obj);
1 rguo@postgresql.org 277 [ + + ]: 9 : if (pcount < 0)
278 : 1 : PLy_elog(ERROR, "could not get size of Python mapping");
279 : :
2665 peter@eisentraut.org 280 : 8 : items = PyMapping_Items(obj);
1 rguo@postgresql.org 281 [ + + ]: 8 : if (items == NULL)
282 : 1 : PLy_elog(ERROR, "could not get items from Python mapping");
283 : :
3016 peter_e@gmx.net 284 [ + + ]: 7 : PG_TRY();
285 : : {
286 : : Py_ssize_t i;
287 : :
288 : 7 : pushJsonbValue(jsonb_state, WJB_BEGIN_OBJECT, NULL);
289 : :
290 [ + + ]: 14 : for (i = 0; i < pcount; i++)
291 : : {
292 : : JsonbValue jbvKey;
293 : 9 : PyObject *item = PyList_GetItem(items, i);
294 : : PyObject *key;
295 : : PyObject *value;
296 : :
297 : : /* The mapping's items() must yield key/value pairs */
1 rguo@postgresql.org 298 [ + + + + : 9 : if (item == NULL || !PyTuple_Check(item) || PyTuple_Size(item) < 2)
- + ]
299 : 2 : PLy_elog(ERROR, "items() of a Python mapping must return key/value pairs");
300 : :
301 : 7 : key = PyTuple_GetItem(item, 0);
302 : 7 : value = PyTuple_GetItem(item, 1);
303 : :
304 : : /* Python dictionary can have None as key */
3016 peter_e@gmx.net 305 [ + + ]: 7 : if (key == Py_None)
306 : : {
307 : 1 : jbvKey.type = jbvString;
308 : 1 : jbvKey.val.string.len = 0;
309 : 1 : jbvKey.val.string.val = "";
310 : : }
311 : : else
312 : : {
313 : : /* All others types of keys we serialize to string */
1576 andres@anarazel.de 314 : 6 : PLyUnicode_ToJsonbValue(key, &jbvKey);
315 : : }
316 : :
205 tgl@sss.pgh.pa.us 317 :GNC 7 : pushJsonbValue(jsonb_state, WJB_KEY, &jbvKey);
318 : 7 : PLyObject_ToJsonbValue(value, jsonb_state, false);
319 : : }
320 : :
321 : 5 : pushJsonbValue(jsonb_state, WJB_END_OBJECT, NULL);
322 : : }
2433 peter@eisentraut.org 323 :CBC 2 : PG_FINALLY();
324 : : {
2665 325 : 7 : Py_DECREF(items);
326 : : }
3016 peter_e@gmx.net 327 [ + + ]: 7 : PG_END_TRY();
3016 peter_e@gmx.net 328 :GIC 5 : }
329 : :
330 : : /*
331 : : * PLySequence_ToJsonbValue
332 : : *
333 : : * Transform python list to JsonbValue. Expects transformed PyObject and
334 : : * a state required for jsonb construction.
335 : : */
336 : : static void
205 tgl@sss.pgh.pa.us 337 :GNC 11 : PLySequence_ToJsonbValue(PyObject *obj, JsonbInState *jsonb_state)
338 : : {
339 : : Py_ssize_t i;
340 : : Py_ssize_t pcount;
2642 tgl@sss.pgh.pa.us 341 :CBC 11 : PyObject *volatile value = NULL;
342 : :
3016 peter_e@gmx.net 343 : 11 : pcount = PySequence_Size(obj);
344 : :
345 : 11 : pushJsonbValue(jsonb_state, WJB_BEGIN_ARRAY, NULL);
346 : :
2642 tgl@sss.pgh.pa.us 347 [ + + ]: 11 : PG_TRY();
348 : : {
349 [ + + ]: 29 : for (i = 0; i < pcount; i++)
350 : : {
351 : 19 : value = PySequence_GetItem(obj, i);
352 : :
353 : : /* PySequence_GetItem() can return NULL, with an exception set */
1 rguo@postgresql.org 354 [ + + ]: 19 : if (value == NULL)
355 : 1 : PLy_elog(ERROR, "could not get element %d from sequence", (int) i);
356 : :
205 tgl@sss.pgh.pa.us 357 :GNC 18 : PLyObject_ToJsonbValue(value, jsonb_state, true);
2642 tgl@sss.pgh.pa.us 358 :CBC 18 : Py_XDECREF(value);
359 : 18 : value = NULL;
360 : : }
361 : : }
362 : 1 : PG_CATCH();
363 : : {
2937 akorotkov@postgresql 364 : 1 : Py_XDECREF(value);
2642 tgl@sss.pgh.pa.us 365 : 1 : PG_RE_THROW();
366 : : }
367 [ - + ]: 10 : PG_END_TRY();
368 : :
205 tgl@sss.pgh.pa.us 369 :GNC 10 : pushJsonbValue(jsonb_state, WJB_END_ARRAY, NULL);
3016 peter_e@gmx.net 370 :GIC 10 : }
371 : :
372 : : /*
373 : : * PLyNumber_ToJsonbValue(PyObject *obj)
374 : : *
375 : : * Transform python number to JsonbValue.
376 : : */
377 : : static JsonbValue *
3016 peter_e@gmx.net 378 :CBC 16 : PLyNumber_ToJsonbValue(PyObject *obj, JsonbValue *jbvNum)
379 : : {
380 : : Numeric num;
381 : 16 : char *str = PLyObject_AsString(obj);
382 : :
383 [ + + ]: 16 : PG_TRY();
384 : : {
385 : : Datum numd;
386 : :
2981 tgl@sss.pgh.pa.us 387 : 16 : numd = DirectFunctionCall3(numeric_in,
388 : : CStringGetDatum(str),
389 : : ObjectIdGetDatum(InvalidOid),
390 : : Int32GetDatum(-1));
391 : 15 : num = DatumGetNumeric(numd);
392 : : }
3016 peter_e@gmx.net 393 : 1 : PG_CATCH();
394 : : {
395 [ + - ]: 1 : ereport(ERROR,
396 : : (errcode(ERRCODE_DATATYPE_MISMATCH),
397 : : errmsg("could not convert value \"%s\" to jsonb", str)));
398 : : }
399 [ - + ]: 15 : PG_END_TRY();
400 : :
401 : 15 : pfree(str);
402 : :
403 : : /*
404 : : * jsonb doesn't allow NaN or infinity (per JSON specification), so we
405 : : * have to reject those here explicitly.
406 : : */
2981 407 [ - + ]: 15 : if (numeric_is_nan(num))
2981 peter_e@gmx.net 408 [ # # ]:UBC 0 : ereport(ERROR,
409 : : (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
410 : : errmsg("cannot convert NaN to jsonb")));
2169 tgl@sss.pgh.pa.us 411 [ - + ]:CBC 15 : if (numeric_is_inf(num))
2169 tgl@sss.pgh.pa.us 412 [ # # ]:UBC 0 : ereport(ERROR,
413 : : (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
414 : : errmsg("cannot convert infinity to jsonb")));
415 : :
3016 peter_e@gmx.net 416 :CBC 15 : jbvNum->type = jbvNumeric;
417 : 15 : jbvNum->val.numeric = num;
418 : :
419 : 15 : return jbvNum;
420 : : }
421 : :
422 : : /*
423 : : * PLyObject_ToJsonbValue(PyObject *obj)
424 : : *
425 : : * Transform python object to JsonbValue.
426 : : */
427 : : static void
205 tgl@sss.pgh.pa.us 428 :GNC 52 : PLyObject_ToJsonbValue(PyObject *obj, JsonbInState *jsonb_state, bool is_elem)
429 : : {
430 : : JsonbValue *out;
431 : :
432 : : /* this can recurse via PLyMapping_ToJsonbValue() */
13 tgl@sss.pgh.pa.us 433 :CBC 52 : check_stack_depth();
434 : :
1576 andres@anarazel.de 435 [ + + ]: 52 : if (!PyUnicode_Check(obj))
436 : : {
3016 peter_e@gmx.net 437 [ + + ]: 45 : if (PySequence_Check(obj))
438 : : {
205 tgl@sss.pgh.pa.us 439 :GNC 11 : PLySequence_ToJsonbValue(obj, jsonb_state);
440 : 10 : return;
441 : : }
3016 peter_e@gmx.net 442 [ + + ]:CBC 34 : else if (PyMapping_Check(obj))
443 : : {
205 tgl@sss.pgh.pa.us 444 :GNC 9 : PLyMapping_ToJsonbValue(obj, jsonb_state);
445 : 5 : return;
446 : : }
447 : : }
448 : :
207 michael@paquier.xyz 449 : 32 : out = palloc_object(JsonbValue);
450 : :
3016 peter_e@gmx.net 451 [ + + ]:CBC 32 : if (obj == Py_None)
452 : 4 : out->type = jbvNull;
1576 andres@anarazel.de 453 [ + + ]: 28 : else if (PyUnicode_Check(obj))
454 : 7 : PLyUnicode_ToJsonbValue(obj, out);
455 : :
456 : : /*
457 : : * PyNumber_Check() returns true for booleans, so boolean check should
458 : : * come first.
459 : : */
3016 peter_e@gmx.net 460 [ + + ]: 21 : else if (PyBool_Check(obj))
461 : : {
462 : 5 : out->type = jbvBool;
463 : 5 : out->val.boolean = (obj == Py_True);
464 : : }
465 [ + - ]: 16 : else if (PyNumber_Check(obj))
466 : 16 : out = PLyNumber_ToJsonbValue(obj, out);
467 : : else
3016 peter_e@gmx.net 468 [ # # ]:UBC 0 : ereport(ERROR,
469 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
470 : : errmsg("Python type \"%s\" cannot be transformed to jsonb",
471 : : PLyObject_AsString((PyObject *) obj->ob_type))));
472 : :
205 tgl@sss.pgh.pa.us 473 [ + + ]:GNC 31 : if (jsonb_state->parseState)
474 : : {
475 : : /* We're in an array or object, so push value as element or field. */
476 [ + + ]: 25 : pushJsonbValue(jsonb_state, is_elem ? WJB_ELEM : WJB_VALUE, out);
477 : : }
478 : : else
479 : : {
480 : : /*
481 : : * We are at top level, so it's a raw scalar. If we just shove the
482 : : * scalar value into jsonb_state->result, JsonbValueToJsonb will take
483 : : * care of wrapping it into a dummy array.
484 : : */
485 : 6 : jsonb_state->result = out;
486 : : }
487 : : }
488 : :
489 : : /*
490 : : * plpython_to_jsonb
491 : : *
492 : : * Transform python object to Jsonb datum
493 : : */
3016 peter_e@gmx.net 494 :CBC 2 : PG_FUNCTION_INFO_V1(plpython_to_jsonb);
495 : : Datum
496 : 27 : plpython_to_jsonb(PG_FUNCTION_ARGS)
497 : : {
205 tgl@sss.pgh.pa.us 498 :GNC 27 : PyObject *obj = (PyObject *) PG_GETARG_POINTER(0);
499 : 27 : JsonbInState jsonb_state = {0};
500 : :
501 : 27 : PLyObject_ToJsonbValue(obj, &jsonb_state, true);
502 : 21 : PG_RETURN_POINTER(JsonbValueToJsonb(jsonb_state.result));
503 : : }
504 : :
505 : : /*
506 : : * jsonb_to_plpython
507 : : *
508 : : * Transform Jsonb datum to PyObject and return it as internal.
509 : : */
3016 peter_e@gmx.net 510 :CBC 2 : PG_FUNCTION_INFO_V1(jsonb_to_plpython);
511 : : Datum
512 : 26 : jsonb_to_plpython(PG_FUNCTION_ARGS)
513 : : {
514 : : PyObject *result;
515 : 26 : Jsonb *in = PG_GETARG_JSONB_P(0);
516 : :
517 : : /*
518 : : * Initialize pointer to Decimal constructor. First we try "cdecimal", C
519 : : * version of decimal library. In case of failure we use slower "decimal"
520 : : * module.
521 : : */
522 [ + + ]: 26 : if (!decimal_constructor)
523 : : {
524 : 1 : PyObject *decimal_module = PyImport_ImportModule("cdecimal");
525 : :
526 [ + - ]: 1 : if (!decimal_module)
527 : : {
528 : 1 : PyErr_Clear();
529 : 1 : decimal_module = PyImport_ImportModule("decimal");
530 : : }
531 [ - + ]: 1 : Assert(decimal_module);
532 : 1 : decimal_constructor = PyObject_GetAttrString(decimal_module, "Decimal");
533 : : }
534 : :
535 : 26 : result = PLyObject_FromJsonbContainer(&in->root);
536 [ - + ]: 26 : if (!result)
3016 peter_e@gmx.net 537 :UBC 0 : PLy_elog(ERROR, "transformation from jsonb to Python failed");
538 : :
3016 peter_e@gmx.net 539 :CBC 26 : return PointerGetDatum(result);
540 : : }
|