Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 3f44e3d

Browse files
committedMar 28, 2018
Transforms for jsonb to PL/Python
Add a new contrib module jsonb_plpython that provide a transform between jsonb and PL/Python. jsonb values are converted to appropriate Python types such as dicts and lists, and vice versa. Author: Anthony Bykov <a.bykov@postgrespro.ru> Reviewed-by: Aleksander Alekseev <a.alekseev@postgrespro.ru> Reviewed-by: Nikita Glukhov <n.gluhov@postgrespro.ru>
1 parent a437551 commit 3f44e3d

13 files changed

+1155
-2
lines changed
 

‎contrib/Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,9 +81,9 @@ ALWAYS_SUBDIRS += hstore_plperl
8181
endif
8282

8383
ifeq ($(with_python),yes)
84-
SUBDIRS += hstore_plpython ltree_plpython
84+
SUBDIRS += hstore_plpython jsonb_plpython ltree_plpython
8585
else
86-
ALWAYS_SUBDIRS += hstore_plpython ltree_plpython
86+
ALWAYS_SUBDIRS += hstore_plpython jsonb_plpython ltree_plpython
8787
endif
8888

8989
# Missing:

‎contrib/jsonb_plpython/.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# Generated subdirectories
2+
/expected/python3/
3+
/log/
4+
/results/
5+
/sql/python3/
6+
/tmp_check/

‎contrib/jsonb_plpython/Makefile

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# contrib/jsonb_plpython/Makefile
2+
3+
MODULE_big = jsonb_plpython$(python_majorversion)
4+
OBJS = jsonb_plpython.o $(WIN32RES)
5+
PGFILEDESC = "jsonb_plpython - transform between jsonb and plpythonu"
6+
7+
PG_CPPFLAGS = -I$(top_srcdir)/src/pl/plpython $(python_includespec) -DPLPYTHON_LIBNAME='"plpython$(python_majorversion)"'
8+
9+
EXTENSION = jsonb_plpythonu jsonb_plpython2u jsonb_plpython3u
10+
DATA = jsonb_plpythonu--1.0.sql jsonb_plpython2u--1.0.sql jsonb_plpython3u--1.0.sql
11+
12+
REGRESS = jsonb_plpython
13+
REGRESS_PLPYTHON3_MANGLE := $(REGRESS)
14+
15+
ifdef USE_PGXS
16+
PG_CONFIG = pg_config
17+
PGXS := $(shell $(PG_CONFIG) --pgxs)
18+
include $(PGXS)
19+
else
20+
subdir = contrib/jsonb_plpython
21+
top_builddir = ../..
22+
include $(top_builddir)/src/Makefile.global
23+
include $(top_srcdir)/contrib/contrib-global.mk
24+
endif
25+
26+
# We must link libpython explicitly
27+
ifeq ($(PORTNAME), win32)
28+
# ... see silliness in plpython Makefile ...
29+
SHLIB_LINK += $(sort $(wildcard ../../src/pl/plpython/libpython*.a))
30+
else
31+
rpathdir = $(python_libdir)
32+
SHLIB_LINK += $(python_libspec) $(python_additional_libs)
33+
endif
34+
35+
ifeq ($(python_majorversion),2)
36+
REGRESS_OPTS += --load-extension=plpythonu --load-extension=jsonb_plpythonu
37+
endif
38+
39+
include $(top_srcdir)/src/pl/plpython/regress-python3-mangle.mk
Lines changed: 347 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,347 @@
1+
CREATE EXTENSION jsonb_plpython2u CASCADE;
2+
NOTICE: installing required extension "plpython2u"
3+
-- test jsonb -> python dict
4+
CREATE FUNCTION test1(val jsonb) RETURNS int
5+
LANGUAGE plpythonu
6+
TRANSFORM FOR TYPE jsonb
7+
AS $$
8+
assert isinstance(val, dict)
9+
plpy.info(sorted(val.items()))
10+
return len(val)
11+
$$;
12+
SELECT test1('{"a": 1, "c": "NULL"}'::jsonb);
13+
INFO: [('a', Decimal('1')), ('c', 'NULL')]
14+
test1
15+
-------
16+
2
17+
(1 row)
18+
19+
-- test jsonb -> python dict
20+
-- complex dict with dicts as value
21+
CREATE FUNCTION test1complex(val jsonb) RETURNS int
22+
LANGUAGE plpython2u
23+
TRANSFORM FOR TYPE jsonb
24+
AS $$
25+
assert isinstance(val, dict)
26+
assert(val == {"d": {"d": 1}})
27+
return len(val)
28+
$$;
29+
SELECT test1complex('{"d": {"d": 1}}'::jsonb);
30+
test1complex
31+
--------------
32+
1
33+
(1 row)
34+
35+
-- test jsonb[] -> python dict
36+
-- dict with array as value
37+
CREATE FUNCTION test1arr(val jsonb) RETURNS int
38+
LANGUAGE plpythonu
39+
TRANSFORM FOR TYPE jsonb
40+
AS $$
41+
assert isinstance(val, dict)
42+
assert(val == {"d": [12, 1]})
43+
return len(val)
44+
$$;
45+
SELECT test1arr('{"d":[12, 1]}'::jsonb);
46+
test1arr
47+
----------
48+
1
49+
(1 row)
50+
51+
-- test jsonb[] -> python list
52+
-- simple list
53+
CREATE FUNCTION test2arr(val jsonb) RETURNS int
54+
LANGUAGE plpythonu
55+
TRANSFORM FOR TYPE jsonb
56+
AS $$
57+
assert isinstance(val, list)
58+
assert(val == [12, 1])
59+
return len(val)
60+
$$;
61+
SELECT test2arr('[12, 1]'::jsonb);
62+
test2arr
63+
----------
64+
2
65+
(1 row)
66+
67+
-- test jsonb[] -> python list
68+
-- array of dicts
69+
CREATE FUNCTION test3arr(val jsonb) RETURNS int
70+
LANGUAGE plpythonu
71+
TRANSFORM FOR TYPE jsonb
72+
AS $$
73+
assert isinstance(val, list)
74+
assert(val == [{"a": 1,"b": 2}, {"c": 3,"d": 4}])
75+
return len(val)
76+
$$;
77+
SELECT test3arr('[{"a": 1, "b": 2}, {"c": 3,"d": 4}]'::jsonb);
78+
test3arr
79+
----------
80+
2
81+
(1 row)
82+
83+
-- test jsonb int -> python int
84+
CREATE FUNCTION test1int(val jsonb) RETURNS int
85+
LANGUAGE plpythonu
86+
TRANSFORM FOR TYPE jsonb
87+
AS $$
88+
assert(val == 1)
89+
return val
90+
$$;
91+
SELECT test1int('1'::jsonb);
92+
test1int
93+
----------
94+
1
95+
(1 row)
96+
97+
-- test jsonb string -> python string
98+
CREATE FUNCTION test1string(val jsonb) RETURNS text
99+
LANGUAGE plpythonu
100+
TRANSFORM FOR TYPE jsonb
101+
AS $$
102+
assert(val == "a")
103+
return val
104+
$$;
105+
SELECT test1string('"a"'::jsonb);
106+
test1string
107+
-------------
108+
a
109+
(1 row)
110+
111+
-- test jsonb null -> python None
112+
CREATE FUNCTION test1null(val jsonb) RETURNS int
113+
LANGUAGE plpythonu
114+
TRANSFORM FOR TYPE jsonb
115+
AS $$
116+
assert(val == None)
117+
return 1
118+
$$;
119+
SELECT test1null('null'::jsonb);
120+
test1null
121+
-----------
122+
1
123+
(1 row)
124+
125+
-- test python -> jsonb
126+
CREATE FUNCTION roundtrip(val jsonb) RETURNS jsonb
127+
LANGUAGE plpythonu
128+
TRANSFORM FOR TYPE jsonb
129+
as $$
130+
return val
131+
$$;
132+
SELECT roundtrip('null'::jsonb);
133+
roundtrip
134+
-----------
135+
136+
(1 row)
137+
138+
SELECT roundtrip('1'::jsonb);
139+
roundtrip
140+
-----------
141+
1
142+
(1 row)
143+
144+
SELECT roundtrip('1234567890.0987654321'::jsonb);
145+
roundtrip
146+
-----------------------
147+
1234567890.0987654321
148+
(1 row)
149+
150+
SELECT roundtrip('-1234567890.0987654321'::jsonb);
151+
roundtrip
152+
------------------------
153+
-1234567890.0987654321
154+
(1 row)
155+
156+
SELECT roundtrip('true'::jsonb);
157+
roundtrip
158+
-----------
159+
true
160+
(1 row)
161+
162+
SELECT roundtrip('"string"'::jsonb);
163+
roundtrip
164+
-----------
165+
"string"
166+
(1 row)
167+
168+
SELECT roundtrip('{"1": null}'::jsonb);
169+
roundtrip
170+
-------------
171+
{"1": null}
172+
(1 row)
173+
174+
SELECT roundtrip('{"1": 1}'::jsonb);
175+
roundtrip
176+
-----------
177+
{"1": 1}
178+
(1 row)
179+
180+
SELECT roundtrip('{"1": true}'::jsonb);
181+
roundtrip
182+
-------------
183+
{"1": true}
184+
(1 row)
185+
186+
SELECT roundtrip('{"1": "string"}'::jsonb);
187+
roundtrip
188+
-----------------
189+
{"1": "string"}
190+
(1 row)
191+
192+
SELECT roundtrip('[null]'::jsonb);
193+
roundtrip
194+
-----------
195+
[null]
196+
(1 row)
197+
198+
SELECT roundtrip('[1]'::jsonb);
199+
roundtrip
200+
-----------
201+
[1]
202+
(1 row)
203+
204+
SELECT roundtrip('[true]'::jsonb);
205+
roundtrip
206+
-----------
207+
[true]
208+
(1 row)
209+
210+
SELECT roundtrip('["string"]'::jsonb);
211+
roundtrip
212+
------------
213+
["string"]
214+
(1 row)
215+
216+
SELECT roundtrip('[null, 1]'::jsonb);
217+
roundtrip
218+
-----------
219+
[null, 1]
220+
(1 row)
221+
222+
SELECT roundtrip('[1, true]'::jsonb);
223+
roundtrip
224+
-----------
225+
[1, true]
226+
(1 row)
227+
228+
SELECT roundtrip('[true, "string"]'::jsonb);
229+
roundtrip
230+
------------------
231+
[true, "string"]
232+
(1 row)
233+
234+
SELECT roundtrip('["string", "string2"]'::jsonb);
235+
roundtrip
236+
-----------------------
237+
["string", "string2"]
238+
(1 row)
239+
240+
-- test python infinity -> jsonb
241+
CREATE FUNCTION test1inf() RETURNS jsonb
242+
LANGUAGE plpythonu
243+
TRANSFORM FOR TYPE jsonb
244+
AS $$
245+
x = float('inf')
246+
print(x)
247+
return x
248+
$$;
249+
SELECT test1inf();
250+
ERROR: could not convert value "inf" to jsonb
251+
CONTEXT: while creating return value
252+
PL/Python function "test1inf"
253+
-- test python -infinity -> jsonb
254+
CREATE FUNCTION test2inf() RETURNS jsonb
255+
LANGUAGE plpythonu
256+
TRANSFORM FOR TYPE jsonb
257+
AS $$
258+
x = float('-inf')
259+
print(x)
260+
return x
261+
$$;
262+
SELECT test2inf();
263+
ERROR: could not convert value "-inf" to jsonb
264+
CONTEXT: while creating return value
265+
PL/Python function "test2inf"
266+
-- test python NaN -> jsonb
267+
CREATE FUNCTION test1nan() RETURNS jsonb
268+
LANGUAGE plpythonu
269+
TRANSFORM FOR TYPE jsonb
270+
AS $$
271+
x = float('nan')
272+
return x
273+
$$;
274+
SELECT test1nan();
275+
test1nan
276+
----------
277+
NaN
278+
(1 row)
279+
280+
-- complex numbers -> jsonb
281+
CREATE FUNCTION testComplexNumbers() RETURNS jsonb
282+
LANGUAGE plpythonu
283+
TRANSFORM FOR TYPE jsonb
284+
AS $$
285+
x = 1 + 2j
286+
return x
287+
$$;
288+
SELECT testComplexNumbers();
289+
ERROR: could not convert value "(1+2j)" to jsonb
290+
CONTEXT: while creating return value
291+
PL/Python function "testcomplexnumbers"
292+
-- range -> jsonb
293+
CREATE FUNCTION testRange() RETURNS jsonb
294+
LANGUAGE plpythonu
295+
TRANSFORM FOR TYPE jsonb
296+
AS $$
297+
x = range(3)
298+
return x
299+
$$;
300+
SELECT testRange();
301+
testrange
302+
-----------
303+
[0, 1, 2]
304+
(1 row)
305+
306+
-- 0xff -> jsonb
307+
CREATE FUNCTION testDecimal() RETURNS jsonb
308+
LANGUAGE plpythonu
309+
TRANSFORM FOR TYPE jsonb
310+
AS $$
311+
x = 0xff
312+
return x
313+
$$;
314+
SELECT testDecimal();
315+
testdecimal
316+
-------------
317+
255
318+
(1 row)
319+
320+
-- tuple -> jsonb
321+
CREATE FUNCTION testTuple() RETURNS jsonb
322+
LANGUAGE plpythonu
323+
TRANSFORM FOR TYPE jsonb
324+
AS $$
325+
x = (1, 'String', None)
326+
return x
327+
$$;
328+
SELECT testTuple();
329+
testtuple
330+
---------------------
331+
[1, "String", null]
332+
(1 row)
333+
334+
-- interesting dict -> jsonb
335+
CREATE FUNCTION test_dict1() RETURNS jsonb
336+
LANGUAGE plpythonu
337+
TRANSFORM FOR TYPE jsonb
338+
AS $$
339+
x = {"a": 1, None: 2, 33: 3}
340+
return x
341+
$$;
342+
SELECT test_dict1();
343+
test_dict1
344+
--------------------------
345+
{"": 2, "a": 1, "33": 3}
346+
(1 row)
347+

‎contrib/jsonb_plpython/jsonb_plpython.c

Lines changed: 453 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/* contrib/jsonb_plpython/jsonb_plpython2u--1.0.sql */
2+
3+
-- complain if script is sourced in psql, rather than via CREATE EXTENSION
4+
\echo Use "CREATE EXTENSION jsonb_plpython2u" to load this file. \quit
5+
6+
CREATE FUNCTION jsonb_to_plpython2(val internal) RETURNS internal
7+
LANGUAGE C STRICT IMMUTABLE
8+
AS 'MODULE_PATHNAME', 'jsonb_to_plpython';
9+
10+
CREATE FUNCTION plpython2_to_jsonb(val internal) RETURNS jsonb
11+
LANGUAGE C STRICT IMMUTABLE
12+
AS 'MODULE_PATHNAME', 'plpython_to_jsonb';
13+
14+
CREATE TRANSFORM FOR jsonb LANGUAGE plpython2u (
15+
FROM SQL WITH FUNCTION jsonb_to_plpython2(internal),
16+
TO SQL WITH FUNCTION plpython2_to_jsonb(internal)
17+
);
18+
19+
COMMENT ON TRANSFORM FOR jsonb LANGUAGE plpython2u IS 'transform between jsonb and Python';
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# jsonb_plpython2u extension
2+
comment = 'transform between jsonb and plpython2u'
3+
default_version = '1.0'
4+
module_pathname = '$libdir/jsonb_plpython2'
5+
relocatable = true
6+
requires = 'plpython2u'
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/* contrib/jsonb_plpython/jsonb_plpython3u--1.0.sql */
2+
3+
-- complain if script is sourced in psql, rather than via CREATE EXTENSION
4+
\echo Use "CREATE EXTENSION jsonb_plpython3u" to load this file. \quit
5+
6+
CREATE FUNCTION jsonb_to_plpython3(val internal) RETURNS internal
7+
LANGUAGE C STRICT IMMUTABLE
8+
AS 'MODULE_PATHNAME', 'jsonb_to_plpython';
9+
10+
CREATE FUNCTION plpython3_to_jsonb(val internal) RETURNS jsonb
11+
LANGUAGE C STRICT IMMUTABLE
12+
AS 'MODULE_PATHNAME', 'plpython_to_jsonb';
13+
14+
CREATE TRANSFORM FOR jsonb LANGUAGE plpython3u (
15+
FROM SQL WITH FUNCTION jsonb_to_plpython3(internal),
16+
TO SQL WITH FUNCTION plpython3_to_jsonb(internal)
17+
);
18+
19+
COMMENT ON TRANSFORM FOR jsonb LANGUAGE plpython3u IS 'transform between jsonb and Python';
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# jsonb_plpython3u extension
2+
comment = 'transform between jsonb and plpython3u'
3+
default_version = '1.0'
4+
module_pathname = '$libdir/jsonb_plpython3'
5+
relocatable = true
6+
requires = 'plpython3u'
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/* contrib/jsonb_plpython/jsonb_plpythonu--1.0.sql */
2+
3+
-- complain if script is sourced in psql, rather than via CREATE EXTENSION
4+
\echo Use "CREATE EXTENSION jsonb_plpythonu" to load this file. \quit
5+
6+
CREATE FUNCTION jsonb_to_plpython(val internal) RETURNS internal
7+
LANGUAGE C STRICT IMMUTABLE
8+
AS 'MODULE_PATHNAME';
9+
10+
CREATE FUNCTION plpython_to_jsonb(val internal) RETURNS jsonb
11+
LANGUAGE C STRICT IMMUTABLE
12+
AS 'MODULE_PATHNAME';
13+
14+
CREATE TRANSFORM FOR jsonb LANGUAGE plpythonu (
15+
FROM SQL WITH FUNCTION jsonb_to_plpython(internal),
16+
TO SQL WITH FUNCTION plpython_to_jsonb(internal)
17+
);
18+
19+
COMMENT ON TRANSFORM FOR jsonb LANGUAGE plpythonu IS 'transform between jsonb and Python';
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# jsonb_plpythonu extension
2+
comment = 'transform between jsonb and plpythonu'
3+
default_version = '1.0'
4+
module_pathname = '$libdir/jsonb_plpython2'
5+
relocatable = true
6+
requires = 'plpythonu'
Lines changed: 218 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,218 @@
1+
CREATE EXTENSION jsonb_plpython2u CASCADE;
2+
3+
-- test jsonb -> python dict
4+
CREATE FUNCTION test1(val jsonb) RETURNS int
5+
LANGUAGE plpythonu
6+
TRANSFORM FOR TYPE jsonb
7+
AS $$
8+
assert isinstance(val, dict)
9+
plpy.info(sorted(val.items()))
10+
return len(val)
11+
$$;
12+
13+
SELECT test1('{"a": 1, "c": "NULL"}'::jsonb);
14+
15+
-- test jsonb -> python dict
16+
-- complex dict with dicts as value
17+
CREATE FUNCTION test1complex(val jsonb) RETURNS int
18+
LANGUAGE plpython2u
19+
TRANSFORM FOR TYPE jsonb
20+
AS $$
21+
assert isinstance(val, dict)
22+
assert(val == {"d": {"d": 1}})
23+
return len(val)
24+
$$;
25+
26+
SELECT test1complex('{"d": {"d": 1}}'::jsonb);
27+
28+
29+
-- test jsonb[] -> python dict
30+
-- dict with array as value
31+
CREATE FUNCTION test1arr(val jsonb) RETURNS int
32+
LANGUAGE plpythonu
33+
TRANSFORM FOR TYPE jsonb
34+
AS $$
35+
assert isinstance(val, dict)
36+
assert(val == {"d": [12, 1]})
37+
return len(val)
38+
$$;
39+
40+
SELECT test1arr('{"d":[12, 1]}'::jsonb);
41+
42+
-- test jsonb[] -> python list
43+
-- simple list
44+
CREATE FUNCTION test2arr(val jsonb) RETURNS int
45+
LANGUAGE plpythonu
46+
TRANSFORM FOR TYPE jsonb
47+
AS $$
48+
assert isinstance(val, list)
49+
assert(val == [12, 1])
50+
return len(val)
51+
$$;
52+
53+
SELECT test2arr('[12, 1]'::jsonb);
54+
55+
-- test jsonb[] -> python list
56+
-- array of dicts
57+
CREATE FUNCTION test3arr(val jsonb) RETURNS int
58+
LANGUAGE plpythonu
59+
TRANSFORM FOR TYPE jsonb
60+
AS $$
61+
assert isinstance(val, list)
62+
assert(val == [{"a": 1,"b": 2}, {"c": 3,"d": 4}])
63+
return len(val)
64+
$$;
65+
66+
SELECT test3arr('[{"a": 1, "b": 2}, {"c": 3,"d": 4}]'::jsonb);
67+
68+
-- test jsonb int -> python int
69+
CREATE FUNCTION test1int(val jsonb) RETURNS int
70+
LANGUAGE plpythonu
71+
TRANSFORM FOR TYPE jsonb
72+
AS $$
73+
assert(val == 1)
74+
return val
75+
$$;
76+
77+
SELECT test1int('1'::jsonb);
78+
79+
-- test jsonb string -> python string
80+
CREATE FUNCTION test1string(val jsonb) RETURNS text
81+
LANGUAGE plpythonu
82+
TRANSFORM FOR TYPE jsonb
83+
AS $$
84+
assert(val == "a")
85+
return val
86+
$$;
87+
88+
SELECT test1string('"a"'::jsonb);
89+
90+
-- test jsonb null -> python None
91+
CREATE FUNCTION test1null(val jsonb) RETURNS int
92+
LANGUAGE plpythonu
93+
TRANSFORM FOR TYPE jsonb
94+
AS $$
95+
assert(val == None)
96+
return 1
97+
$$;
98+
99+
SELECT test1null('null'::jsonb);
100+
101+
-- test python -> jsonb
102+
CREATE FUNCTION roundtrip(val jsonb) RETURNS jsonb
103+
LANGUAGE plpythonu
104+
TRANSFORM FOR TYPE jsonb
105+
as $$
106+
return val
107+
$$;
108+
109+
SELECT roundtrip('null'::jsonb);
110+
SELECT roundtrip('1'::jsonb);
111+
SELECT roundtrip('1234567890.0987654321'::jsonb);
112+
SELECT roundtrip('-1234567890.0987654321'::jsonb);
113+
SELECT roundtrip('true'::jsonb);
114+
SELECT roundtrip('"string"'::jsonb);
115+
116+
SELECT roundtrip('{"1": null}'::jsonb);
117+
SELECT roundtrip('{"1": 1}'::jsonb);
118+
SELECT roundtrip('{"1": true}'::jsonb);
119+
SELECT roundtrip('{"1": "string"}'::jsonb);
120+
121+
SELECT roundtrip('[null]'::jsonb);
122+
SELECT roundtrip('[1]'::jsonb);
123+
SELECT roundtrip('[true]'::jsonb);
124+
SELECT roundtrip('["string"]'::jsonb);
125+
SELECT roundtrip('[null, 1]'::jsonb);
126+
SELECT roundtrip('[1, true]'::jsonb);
127+
SELECT roundtrip('[true, "string"]'::jsonb);
128+
SELECT roundtrip('["string", "string2"]'::jsonb);
129+
130+
-- test python infinity -> jsonb
131+
CREATE FUNCTION test1inf() RETURNS jsonb
132+
LANGUAGE plpythonu
133+
TRANSFORM FOR TYPE jsonb
134+
AS $$
135+
x = float('inf')
136+
print(x)
137+
return x
138+
$$;
139+
140+
SELECT test1inf();
141+
142+
-- test python -infinity -> jsonb
143+
CREATE FUNCTION test2inf() RETURNS jsonb
144+
LANGUAGE plpythonu
145+
TRANSFORM FOR TYPE jsonb
146+
AS $$
147+
x = float('-inf')
148+
print(x)
149+
return x
150+
$$;
151+
152+
SELECT test2inf();
153+
154+
-- test python NaN -> jsonb
155+
CREATE FUNCTION test1nan() RETURNS jsonb
156+
LANGUAGE plpythonu
157+
TRANSFORM FOR TYPE jsonb
158+
AS $$
159+
x = float('nan')
160+
return x
161+
$$;
162+
163+
SELECT test1nan();
164+
165+
-- complex numbers -> jsonb
166+
CREATE FUNCTION testComplexNumbers() RETURNS jsonb
167+
LANGUAGE plpythonu
168+
TRANSFORM FOR TYPE jsonb
169+
AS $$
170+
x = 1 + 2j
171+
return x
172+
$$;
173+
174+
SELECT testComplexNumbers();
175+
176+
-- range -> jsonb
177+
CREATE FUNCTION testRange() RETURNS jsonb
178+
LANGUAGE plpythonu
179+
TRANSFORM FOR TYPE jsonb
180+
AS $$
181+
x = range(3)
182+
return x
183+
$$;
184+
185+
SELECT testRange();
186+
187+
-- 0xff -> jsonb
188+
CREATE FUNCTION testDecimal() RETURNS jsonb
189+
LANGUAGE plpythonu
190+
TRANSFORM FOR TYPE jsonb
191+
AS $$
192+
x = 0xff
193+
return x
194+
$$;
195+
196+
SELECT testDecimal();
197+
198+
-- tuple -> jsonb
199+
CREATE FUNCTION testTuple() RETURNS jsonb
200+
LANGUAGE plpythonu
201+
TRANSFORM FOR TYPE jsonb
202+
AS $$
203+
x = (1, 'String', None)
204+
return x
205+
$$;
206+
207+
SELECT testTuple();
208+
209+
-- interesting dict -> jsonb
210+
CREATE FUNCTION test_dict1() RETURNS jsonb
211+
LANGUAGE plpythonu
212+
TRANSFORM FOR TYPE jsonb
213+
AS $$
214+
x = {"a": 1, None: 2, 33: 3}
215+
return x
216+
$$;
217+
218+
SELECT test_dict1();

‎doc/src/sgml/json.sgml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -569,4 +569,19 @@ SELECT jdoc-&gt;'guid', jdoc-&gt;'name' FROM api WHERE jdoc @&gt; '{"tags": ["qu
569569
compared using the default database collation.
570570
</para>
571571
</sect2>
572+
573+
<sect2>
574+
<title>Transforms</title>
575+
576+
<para>
577+
Additional extensions are available that implement transforms for the
578+
<type>jsonb</type> type for the language PL/Python. The extensions for
579+
PL/Python are called <literal>jsonb_plpythonu</literal>,
580+
<literal>jsonb_plpython2u</literal>, and
581+
<literal>jsonb_plpython3u</literal> (see <xref
582+
linkend="plpython-python23"/> for the PL/Python naming convention). If you
583+
use them, <type>jsonb</type> values are mapped to Python dictionaries,
584+
lists, and scalars, as appropriate.
585+
</para>
586+
</sect2>
572587
</sect1>

0 commit comments

Comments
 (0)
Please sign in to comment.