1414#include "parser/parse_type.h"
1515#include "utils/array.h"
1616#include "utils/builtins.h"
17+ #include "utils/fmgroids.h"
1718#include "utils/lsyscache.h"
1819#include "utils/memutils.h"
1920#include "utils/numeric.h"
@@ -49,21 +50,21 @@ static PyObject *PLyList_FromArray_recurse(PLyDatumToOb *elm, int *dims, int ndi
4950char * * dataptr_p ,bits8 * * bitmap_p ,int * bitmask_p );
5051
5152/* conversion from Python objects to Datums */
52- static Datum PLyObject_ToBool (PLyObToDatum * arg ,int32 typmod ,PyObject * plrv );
53- static Datum PLyObject_ToBytea (PLyObToDatum * arg ,int32 typmod ,PyObject * plrv );
54- static Datum PLyObject_ToComposite (PLyObToDatum * arg ,int32 typmod ,PyObject * plrv );
55- static Datum PLyObject_ToDatum (PLyObToDatum * arg ,int32 typmod ,PyObject * plrv );
56- static Datum PLyObject_ToTransform (PLyObToDatum * arg ,int32 typmod ,PyObject * plrv );
57- static Datum PLySequence_ToArray (PLyObToDatum * arg ,int32 typmod ,PyObject * plrv );
53+ static Datum PLyObject_ToBool (PLyObToDatum * arg ,int32 typmod ,PyObject * plrv , bool inarray );
54+ static Datum PLyObject_ToBytea (PLyObToDatum * arg ,int32 typmod ,PyObject * plrv , bool inarray );
55+ static Datum PLyObject_ToComposite (PLyObToDatum * arg ,int32 typmod ,PyObject * plrv , bool inarray );
56+ static Datum PLyObject_ToDatum (PLyObToDatum * arg ,int32 typmod ,PyObject * plrv , bool inarray );
57+ static Datum PLyObject_ToTransform (PLyObToDatum * arg ,int32 typmod ,PyObject * plrv , bool inarray );
58+ static Datum PLySequence_ToArray (PLyObToDatum * arg ,int32 typmod ,PyObject * plrv , bool inarray );
5859static void PLySequence_ToArray_recurse (PLyObToDatum * elm ,PyObject * list ,
5960int * dims ,int ndim ,int dim ,
6061Datum * elems ,bool * nulls ,int * currelem );
6162
6263/* conversion from Python objects to composite Datums (used by triggers and SRFs) */
63- static Datum PLyString_ToComposite (PLyTypeInfo * info ,TupleDesc desc ,PyObject * string );
64+ static Datum PLyString_ToComposite (PLyTypeInfo * info ,TupleDesc desc ,PyObject * string , bool inarray );
6465static Datum PLyMapping_ToComposite (PLyTypeInfo * info ,TupleDesc desc ,PyObject * mapping );
6566static Datum PLySequence_ToComposite (PLyTypeInfo * info ,TupleDesc desc ,PyObject * sequence );
66- static Datum PLyGenericObject_ToComposite (PLyTypeInfo * info ,TupleDesc desc ,PyObject * object );
67+ static Datum PLyGenericObject_ToComposite (PLyTypeInfo * info ,TupleDesc desc ,PyObject * object , bool inarray );
6768
6869void
6970PLy_typeinfo_init (PLyTypeInfo * arg ,MemoryContext mcxt )
@@ -341,12 +342,12 @@ PLyDict_FromTuple(PLyTypeInfo *info, HeapTuple tuple, TupleDesc desc)
341342 *as an object that has __getattr__ support.
342343 */
343344Datum
344- PLyObject_ToCompositeDatum (PLyTypeInfo * info ,TupleDesc desc ,PyObject * plrv )
345+ PLyObject_ToCompositeDatum (PLyTypeInfo * info ,TupleDesc desc ,PyObject * plrv , bool inarray )
345346{
346347Datum datum ;
347348
348349if (PyString_Check (plrv )|| PyUnicode_Check (plrv ))
349- datum = PLyString_ToComposite (info ,desc ,plrv );
350+ datum = PLyString_ToComposite (info ,desc ,plrv , inarray );
350351else if (PySequence_Check (plrv ))
351352/* composite type as sequence (tuple, list etc) */
352353datum = PLySequence_ToComposite (info ,desc ,plrv );
@@ -355,7 +356,7 @@ PLyObject_ToCompositeDatum(PLyTypeInfo *info, TupleDesc desc, PyObject *plrv)
355356datum = PLyMapping_ToComposite (info ,desc ,plrv );
356357else
357358/* returned as smth, must provide method __getattr__(name) */
358- datum = PLyGenericObject_ToComposite (info ,desc ,plrv );
359+ datum = PLyGenericObject_ToComposite (info ,desc ,plrv , inarray );
359360
360361return datum ;
361362}
@@ -746,7 +747,7 @@ PLyList_FromArray_recurse(PLyDatumToOb *elm, int *dims, int ndim, int dim,
746747 * type can parse.
747748 */
748749static Datum
749- PLyObject_ToBool (PLyObToDatum * arg ,int32 typmod ,PyObject * plrv )
750+ PLyObject_ToBool (PLyObToDatum * arg ,int32 typmod ,PyObject * plrv , bool inarray )
750751{
751752Datum rv ;
752753
@@ -765,7 +766,7 @@ PLyObject_ToBool(PLyObToDatum *arg, int32 typmod, PyObject *plrv)
765766 * with embedded nulls. And it's faster this way.
766767 */
767768static Datum
768- PLyObject_ToBytea (PLyObToDatum * arg ,int32 typmod ,PyObject * plrv )
769+ PLyObject_ToBytea (PLyObToDatum * arg ,int32 typmod ,PyObject * plrv , bool inarray )
769770{
770771PyObject * volatile plrv_so = NULL ;
771772Datum rv ;
@@ -809,7 +810,7 @@ PLyObject_ToBytea(PLyObToDatum *arg, int32 typmod, PyObject *plrv)
809810 * for obtaining PostgreSQL tuples.
810811 */
811812static Datum
812- PLyObject_ToComposite (PLyObToDatum * arg ,int32 typmod ,PyObject * plrv )
813+ PLyObject_ToComposite (PLyObToDatum * arg ,int32 typmod ,PyObject * plrv , bool inarray )
813814{
814815Datum rv ;
815816PLyTypeInfo info ;
@@ -836,7 +837,7 @@ PLyObject_ToComposite(PLyObToDatum *arg, int32 typmod, PyObject *plrv)
836837 * that info instead of looking it up every time a tuple is returned from
837838 * the function.
838839 */
839- rv = PLyObject_ToCompositeDatum (& info ,desc ,plrv );
840+ rv = PLyObject_ToCompositeDatum (& info ,desc ,plrv , inarray );
840841
841842ReleaseTupleDesc (desc );
842843
@@ -908,26 +909,70 @@ PLyObject_AsString(PyObject *plrv)
908909 * cstring into PostgreSQL type.
909910 */
910911static Datum
911- PLyObject_ToDatum (PLyObToDatum * arg ,int32 typmod ,PyObject * plrv )
912+ PLyObject_ToDatum (PLyObToDatum * arg ,int32 typmod ,PyObject * plrv , bool inarray )
912913{
914+ char * str ;
915+
913916Assert (plrv != Py_None );
914917
918+ str = PLyObject_AsString (plrv );
919+
920+ /*
921+ * If we are parsing a composite type within an array, and the string
922+ * isn't a valid record literal, there's a high chance that the function
923+ * did something like:
924+ *
925+ * CREATE FUNCTION .. RETURNS comptype[] AS $$ return [['foo', 'bar']] $$
926+ * LANGUAGE plpython;
927+ *
928+ * Before PostgreSQL 10, that was interpreted as a single-dimensional
929+ * array, containing record ('foo', 'bar'). PostgreSQL 10 added support
930+ * for multi-dimensional arrays, and it is now interpreted as a
931+ * two-dimensional array, containing two records, 'foo', and 'bar'.
932+ * record_in() will throw an error, because "foo" is not a valid record
933+ * literal.
934+ *
935+ * To make that less confusing to users who are upgrading from older
936+ * versions, try to give a hint in the typical instances of that. If we are
937+ * parsing an array of composite types, and we see a string literal that
938+ * is not a valid record literal, give a hint. We only want to give the
939+ * hint in the narrow case of a malformed string literal, not any error
940+ * from record_in(), so check for that case here specifically.
941+ *
942+ * This check better match the one in record_in(), so that we don't forbid
943+ * literals that are actually valid!
944+ */
945+ if (inarray && arg -> typfunc .fn_oid == F_RECORD_IN )
946+ {
947+ char * ptr = str ;
948+
949+ /* Allow leading whitespace */
950+ while (* ptr && isspace ((unsignedchar )* ptr ))
951+ ptr ++ ;
952+ if (* ptr ++ != '(' )
953+ ereport (ERROR ,
954+ (errcode (ERRCODE_INVALID_TEXT_REPRESENTATION ),
955+ errmsg ("malformed record literal: \"%s\"" ,str ),
956+ errdetail ("Missing left parenthesis." ),
957+ errhint ("To return a composite type in an array, return the composite type as a Python tuple, e.g. \"[('foo')]\"" )));
958+ }
959+
915960return InputFunctionCall (& arg -> typfunc ,
916- PLyObject_AsString ( plrv ) ,
961+ str ,
917962arg -> typioparam ,
918963typmod );
919964}
920965
921966
922967static Datum
923- PLyObject_ToTransform (PLyObToDatum * arg ,int32 typmod ,PyObject * plrv )
968+ PLyObject_ToTransform (PLyObToDatum * arg ,int32 typmod ,PyObject * plrv , bool inarray )
924969{
925970return FunctionCall1 (& arg -> typtransform ,PointerGetDatum (plrv ));
926971}
927972
928973
929974static Datum
930- PLySequence_ToArray (PLyObToDatum * arg ,int32 typmod ,PyObject * plrv )
975+ PLySequence_ToArray (PLyObToDatum * arg ,int32 typmod ,PyObject * plrv , bool inarray )
931976{
932977ArrayType * array ;
933978int i ;
@@ -1085,7 +1130,7 @@ PLySequence_ToArray_recurse(PLyObToDatum *elm, PyObject *list,
10851130else
10861131{
10871132nulls [* currelem ]= false;
1088- elems [* currelem ]= elm -> func (elm ,-1 ,obj );
1133+ elems [* currelem ]= elm -> func (elm ,-1 ,obj , true );
10891134}
10901135Py_XDECREF (obj );
10911136(* currelem )++ ;
@@ -1095,7 +1140,7 @@ PLySequence_ToArray_recurse(PLyObToDatum *elm, PyObject *list,
10951140
10961141
10971142static Datum
1098- PLyString_ToComposite (PLyTypeInfo * info ,TupleDesc desc ,PyObject * string )
1143+ PLyString_ToComposite (PLyTypeInfo * info ,TupleDesc desc ,PyObject * string , bool inarray )
10991144{
11001145Datum result ;
11011146HeapTuple typeTup ;
@@ -1120,7 +1165,7 @@ PLyString_ToComposite(PLyTypeInfo *info, TupleDesc desc, PyObject *string)
11201165
11211166ReleaseSysCache (typeTup );
11221167
1123- result = PLyObject_ToDatum (& locinfo .out .d ,desc -> tdtypmod ,string );
1168+ result = PLyObject_ToDatum (& locinfo .out .d ,desc -> tdtypmod ,string , inarray );
11241169
11251170MemoryContextDelete (cxt );
11261171
@@ -1172,7 +1217,7 @@ PLyMapping_ToComposite(PLyTypeInfo *info, TupleDesc desc, PyObject *mapping)
11721217}
11731218else if (value )
11741219{
1175- values [i ]= (att -> func ) (att ,-1 ,value );
1220+ values [i ]= (att -> func ) (att ,-1 ,value , false );
11761221nulls [i ]= false;
11771222}
11781223else
@@ -1265,7 +1310,7 @@ PLySequence_ToComposite(PLyTypeInfo *info, TupleDesc desc, PyObject *sequence)
12651310}
12661311else if (value )
12671312{
1268- values [i ]= (att -> func ) (att ,-1 ,value );
1313+ values [i ]= (att -> func ) (att ,-1 ,value , false );
12691314nulls [i ]= false;
12701315}
12711316
@@ -1294,7 +1339,7 @@ PLySequence_ToComposite(PLyTypeInfo *info, TupleDesc desc, PyObject *sequence)
12941339
12951340
12961341static Datum
1297- PLyGenericObject_ToComposite (PLyTypeInfo * info ,TupleDesc desc ,PyObject * object )
1342+ PLyGenericObject_ToComposite (PLyTypeInfo * info ,TupleDesc desc ,PyObject * object , bool inarray )
12981343{
12991344Datum result ;
13001345HeapTuple tuple ;
@@ -1335,16 +1380,29 @@ PLyGenericObject_ToComposite(PLyTypeInfo *info, TupleDesc desc, PyObject *object
13351380}
13361381else if (value )
13371382{
1338- values [i ]= (att -> func ) (att ,-1 ,value );
1383+ values [i ]= (att -> func ) (att ,-1 ,value , false );
13391384nulls [i ]= false;
13401385}
13411386else
1387+ {
1388+ /*
1389+ * No attribute for this column in the object.
1390+ *
1391+ * If we are parsing a composite type in an array, a likely
1392+ * cause is that the function contained something like "[[123,
1393+ * 'foo']]". Before PostgreSQL 10, that was interpreted as an
1394+ * array, with a composite type (123, 'foo') in it. But now
1395+ * it's interpreted as a two-dimensional array, and we try to
1396+ * interpret "123" as the composite type. See also similar
1397+ * heuristic in PLyObject_ToDatum().
1398+ */
13421399ereport (ERROR ,
13431400(errcode (ERRCODE_UNDEFINED_COLUMN ),
13441401errmsg ("attribute \"%s\" does not exist in Python object" ,key ),
1345- errhint ("To return null in a column, "
1346- "let the returned object have an attribute named "
1347- "after column with value None." )));
1402+ inarray ?
1403+ errhint ("To return a composite type in an array, return the composite type as a Python tuple, e.g. \"[('foo')]\"" ) :
1404+ errhint ("To return null in a column, let the returned object have an attribute named after column with value None." )));
1405+ }
13481406
13491407Py_XDECREF (value );
13501408value = NULL ;