diff --git a/src/pl/plpython/expected/plpython_composite.out b/src/pl/plpython/expected/plpython_composite.out index bb101e07d5..674af93ddc 100644 --- a/src/pl/plpython/expected/plpython_composite.out +++ b/src/pl/plpython/expected/plpython_composite.out @@ -569,6 +569,20 @@ SELECT * FROM return_record_2('v3') AS (v1 int, v2 int, v3 int); 1 | 2 | 3 (1 row) +-- recursion with a different inner result type didn't use to work +CREATE FUNCTION return_record_3(t text) RETURNS record AS $$ +if t == "text": + plpy.execute("SELECT * FROM return_record_3('int') AS (a int)"); + return { "a": "x" } +elif t == "int": + return { "a": 1 } +$$ LANGUAGE plpython3u; +SELECT * FROM return_record_3('text') AS (a text); + a +--- + x +(1 row) + -- multi-dimensional array of composite types. CREATE FUNCTION composite_type_as_list() RETURNS type_record[] AS $$ return [[('first', 1), ('second', 1)], [('first', 2), ('second', 2)], [('first', 3), ('second', 3)]]; diff --git a/src/pl/plpython/plpy_exec.c b/src/pl/plpython/plpy_exec.c index 6f7b5e121d..157229e96f 100644 --- a/src/pl/plpython/plpy_exec.c +++ b/src/pl/plpython/plpy_exec.c @@ -231,7 +231,23 @@ PLy_exec_function(FunctionCallInfo fcinfo, PLyProcedure *proc) } else { - /* Normal conversion of result */ + /* + * Normal conversion of result. However, if the result is of type + * RECORD, we have to set up for that each time through, since it + * might be different from last time. + */ + if (proc->result.typoid == RECORDOID) + { + TupleDesc desc; + + if (get_call_result_type(fcinfo, NULL, &desc) != TYPEFUNC_COMPOSITE) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("function returning record called in context " + "that cannot accept type record"))); + PLy_output_setup_record(&proc->result, desc, proc); + } + rv = PLy_output_convert(&proc->result, plrv, &fcinfo->isnull); } @@ -456,21 +472,6 @@ PLy_function_build_args(FunctionCallInfo fcinfo, PLyProcedure *proc) PLy_elog(ERROR, "PyDict_SetItemString() failed, while setting up arguments"); arg = NULL; } - - /* Set up output conversion for functions returning RECORD */ - if (proc->result.typoid == RECORDOID) - { - TupleDesc desc; - - if (get_call_result_type(fcinfo, NULL, &desc) != TYPEFUNC_COMPOSITE) - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("function returning record called in context " - "that cannot accept type record"))); - - /* cache the output conversion functions */ - PLy_output_setup_record(&proc->result, desc, proc); - } } PG_CATCH(); { diff --git a/src/pl/plpython/sql/plpython_composite.sql b/src/pl/plpython/sql/plpython_composite.sql index 21757701cc..1bb9b83b71 100644 --- a/src/pl/plpython/sql/plpython_composite.sql +++ b/src/pl/plpython/sql/plpython_composite.sql @@ -208,6 +208,17 @@ SELECT * FROM return_record_2('v4') AS (v1 int, v3 int, v2 int); SELECT * FROM return_record_2('v3') AS (v1 int, v3 int, v2 int); SELECT * FROM return_record_2('v3') AS (v1 int, v2 int, v3 int); +-- recursion with a different inner result type didn't use to work +CREATE FUNCTION return_record_3(t text) RETURNS record AS $$ +if t == "text": + plpy.execute("SELECT * FROM return_record_3('int') AS (a int)"); + return { "a": "x" } +elif t == "int": + return { "a": 1 } +$$ LANGUAGE plpython3u; + +SELECT * FROM return_record_3('text') AS (a text); + -- multi-dimensional array of composite types. CREATE FUNCTION composite_type_as_list() RETURNS type_record[] AS $$ return [[('first', 1), ('second', 1)], [('first', 2), ('second', 2)], [('first', 3), ('second', 3)]];