Andreas Karlsson <[email protected]> writes:
> I found this issue while reading the code, so am very unclear if there
> is any sane code which could trigger it.
> In the example below the recursive call to f('int') changes the return
> type of the f('text') call causing it to fail.
> # CREATE OR REPLACE FUNCTION f(t text) RETURNS record LANGUAGE
> plpython3u AS $$
> if t == "text":
> plpy.execute("SELECT * FROM f('int') AS (a int)");
> return { "a": "x" }
> elif t == "int":
> return { "a": 1 }
> $$;
> CREATE FUNCTION
> # SELECT * FROM f('text') AS (a text);
> ERROR: invalid input syntax for type integer: "x"
> CONTEXT: while creating return value
> PL/Python function "f"
Oh, nice one. I think we can fix this trivially though: the problem
is that RECORD return-type setup was stuck into PLy_function_build_args,
where it has no particular business being in the first place, rather
than being done at the point of use. We can just move the code.
regards, tom lane
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();
{