aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2023-04-27 11:55:06 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2023-04-27 11:55:06 -0400
commitce9662598ddac1883d921d47a3fde63859f077ed (patch)
tree38e4e414b71e3f2a045c69fd3ad3d6fa656972f8
parentcba3c8f6dd7fffb63eac2f31d98bd23816959d04 (diff)
downloadpostgresql-ce9662598ddac1883d921d47a3fde63859f077ed.tar.gz
postgresql-ce9662598ddac1883d921d47a3fde63859f077ed.zip
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
-rw-r--r--contrib/hstore_plpython/expected/hstore_plpython.out11
-rw-r--r--contrib/hstore_plpython/hstore_plpython.c8
-rw-r--r--contrib/hstore_plpython/sql/hstore_plpython.sql11
3 files changed, 29 insertions, 1 deletions
diff --git a/contrib/hstore_plpython/expected/hstore_plpython.out b/contrib/hstore_plpython/expected/hstore_plpython.out
index ecf1dd61bc1..57d83fa2db5 100644
--- a/contrib/hstore_plpython/expected/hstore_plpython.out
+++ b/contrib/hstore_plpython/expected/hstore_plpython.out
@@ -32,6 +32,17 @@ INFO: [('aa', 'bb'), ('cc', None)]
2
(1 row)
+-- test that a non-mapping result is correctly rejected
+CREATE FUNCTION test1bad() RETURNS hstore
+LANGUAGE plpythonu
+TRANSFORM FOR TYPE hstore
+AS $$
+return "foo"
+$$;
+SELECT test1bad();
+ERROR: not a Python mapping
+CONTEXT: while creating return value
+PL/Python function "test1bad"
-- test hstore[] -> python
CREATE FUNCTION test1arr(val hstore[]) RETURNS int
LANGUAGE plpythonu
diff --git a/contrib/hstore_plpython/hstore_plpython.c b/contrib/hstore_plpython/hstore_plpython.c
index 93705f0d54c..65ab2053f74 100644
--- a/contrib/hstore_plpython/hstore_plpython.c
+++ b/contrib/hstore_plpython/hstore_plpython.c
@@ -133,7 +133,13 @@ plpython_to_hstore(PG_FUNCTION_ARGS)
HStore *volatile out;
dict = (PyObject *) PG_GETARG_POINTER(0);
- if (!PyMapping_Check(dict))
+
+ /*
+ * As of Python 3, PyMapping_Check() is unreliable unless one first checks
+ * that the object isn't a sequence. (Cleaner solutions exist, but not
+ * before Python 3.10, which we're not prepared to require yet.)
+ */
+ if (PySequence_Check(dict) || !PyMapping_Check(dict))
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("not a Python mapping")));
diff --git a/contrib/hstore_plpython/sql/hstore_plpython.sql b/contrib/hstore_plpython/sql/hstore_plpython.sql
index b6d98b7dd53..1aa4416512a 100644
--- a/contrib/hstore_plpython/sql/hstore_plpython.sql
+++ b/contrib/hstore_plpython/sql/hstore_plpython.sql
@@ -27,6 +27,17 @@ $$;
SELECT test1n('aa=>bb, cc=>NULL'::hstore);
+-- test that a non-mapping result is correctly rejected
+CREATE FUNCTION test1bad() RETURNS hstore
+LANGUAGE plpythonu
+TRANSFORM FOR TYPE hstore
+AS $$
+return "foo"
+$$;
+
+SELECT test1bad();
+
+
-- test hstore[] -> python
CREATE FUNCTION test1arr(val hstore[]) RETURNS int
LANGUAGE plpythonu