Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
In hstore_plpython, avoid crashing when return value isn't a mapping.
authorTom Lane <tgl@sss.pgh.pa.us>
Thu, 27 Apr 2023 15:55:06 +0000 (11:55 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Thu, 27 Apr 2023 15:55:06 +0000 (11:55 -0400)
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

contrib/hstore_plpython/expected/hstore_plpython.out
contrib/hstore_plpython/hstore_plpython.c
contrib/hstore_plpython/sql/hstore_plpython.sql

index ecf1dd61bc17f9ec99ca5538b454de5d9e54900a..57d83fa2db5b4a05ddecfa5d42f7221d918b6530 100644 (file)
@@ -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
index 93c39d294dd439f4fa7752283fe643ac4a4d2dc6..8c4a6fd82fc824516d33ea2ac83cdf323c8f0bb2 100644 (file)
@@ -133,7 +133,13 @@ plpython_to_hstore(PG_FUNCTION_ARGS)
    HStore     *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")));
index b6d98b7dd5371df8a2ac1fb04a7e7a2490b00e5b..1aa4416512ae2ae567879d2afaa4de56f9af9430 100644 (file)
@@ -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