Skip to content

Commit df38157

Browse files
committed
In hstore_plpython, avoid crashing when return value isn't a mapping.
Python 3 changed the behavior of PyMapping_Check(), breaking the test in plpython_to_hstore() that verifies whether a function result to be transformed is acceptable. A backwards-compatible fix is to first verify that the object doesn't pass PySequence_Check(). Perhaps accidentally, our other uses of PyMapping_Check() already follow uses of PySequence_Check(), so that no other bugs were created by this change. Per bug #17908 from Alexander Lakhin. Back-patch to all supported branches. Dmitry Dolgov and Tom Lane Discussion: https://postgr.es/m/17908-3f19a125d56a11d6@postgresql.org
1 parent 376dc82 commit df38157

File tree

3 files changed

+29
-1
lines changed

3 files changed

+29
-1
lines changed

contrib/hstore_plpython/expected/hstore_plpython.out

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,17 @@ INFO: [('aa', 'bb'), ('cc', None)]
3232
2
3333
(1 row)
3434

35+
-- test that a non-mapping result is correctly rejected
36+
CREATE FUNCTION test1bad() RETURNS hstore
37+
LANGUAGE plpython3u
38+
TRANSFORM FOR TYPE hstore
39+
AS $$
40+
return "foo"
41+
$$;
42+
SELECT test1bad();
43+
ERROR: not a Python mapping
44+
CONTEXT: while creating return value
45+
PL/Python function "test1bad"
3546
-- test hstore[] -> python
3647
CREATE FUNCTION test1arr(val hstore[]) RETURNS int
3748
LANGUAGE plpython3u

contrib/hstore_plpython/hstore_plpython.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,13 @@ plpython_to_hstore(PG_FUNCTION_ARGS)
127127
HStore *volatile out;
128128

129129
dict = (PyObject *) PG_GETARG_POINTER(0);
130-
if (!PyMapping_Check(dict))
130+
131+
/*
132+
* As of Python 3, PyMapping_Check() is unreliable unless one first checks
133+
* that the object isn't a sequence. (Cleaner solutions exist, but not
134+
* before Python 3.10, which we're not prepared to require yet.)
135+
*/
136+
if (PySequence_Check(dict) || !PyMapping_Check(dict))
131137
ereport(ERROR,
132138
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
133139
errmsg("not a Python mapping")));

contrib/hstore_plpython/sql/hstore_plpython.sql

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,17 @@ $$;
2727
SELECT test1n('aa=>bb, cc=>NULL'::hstore);
2828

2929

30+
-- test that a non-mapping result is correctly rejected
31+
CREATE FUNCTION test1bad() RETURNS hstore
32+
LANGUAGE plpython3u
33+
TRANSFORM FOR TYPE hstore
34+
AS $$
35+
return "foo"
36+
$$;
37+
38+
SELECT test1bad();
39+
40+
3041
-- test hstore[] -> python
3142
CREATE FUNCTION test1arr(val hstore[]) RETURNS int
3243
LANGUAGE plpython3u

0 commit comments

Comments
 (0)