commit 45f52ed92f079ca91ce34343630911ca5cb4c00e Author: David G. Johnston Date: Mon May 2 02:00:45 2022 +0000 cache record input functions based on call arguments diff --git a/src/pl/plpgsql/src/pl_comp.c b/src/pl/plpgsql/src/pl_comp.c index b791c23f06..5b3035c560 100644 --- a/src/pl/plpgsql/src/pl_comp.c +++ b/src/pl/plpgsql/src/pl_comp.c @@ -2492,6 +2492,31 @@ compute_function_hashkey(FunctionCallInfo fcinfo, memcpy(hashkey->argtypes, procStruct->proargtypes.values, procStruct->pronargs * sizeof(Oid)); + /* + * Saved compiled functions with record-typed input args to a hashkey + * that substitutes all known actual composite type OIDs in the + * call signature for the corresponding generic record OID from + * the definition signature. This avoids a probable error: + * "type of parameter ... does not match that when preparing the plan" + * when such a record variable is used in a query within the function. + */ + for (int i = 0; i < procStruct->pronargs; i++) + { + if (hashkey->argtypes[i] != RECORDOID) + continue; + + // ??? I presume other parts of the system synchronize these two arrays + // In particular for default arguments not specified in the function call + // or named-argument function call syntax. + + /* Don't bother trying to substitute once we run out of input arguments */ + if (i > fcinfo->nargs - 1) + break; + + hashkey->argtypes[i] = + get_call_expr_argtype(fcinfo->flinfo->fn_expr, i); + } + /* resolve any polymorphic argument types */ plpgsql_resolve_polymorphic_argtypes(procStruct->pronargs, hashkey->argtypes, diff --git a/src/test/regress/expected/plpgsql.out b/src/test/regress/expected/plpgsql.out index 08e42f17dc..c86930c12b 100644 --- a/src/test/regress/expected/plpgsql.out +++ b/src/test/regress/expected/plpgsql.out @@ -5779,3 +5779,32 @@ END; $$ LANGUAGE plpgsql; ERROR: "x" is not a scalar variable LINE 3: GET DIAGNOSTICS x = ROW_COUNT; ^ +CREATE OR REPLACE FUNCTION record_to_form_data(p_r record) + RETURNS text + LANGUAGE plpgsql +AS $function$ +begin + +return (SELECT format('%s',p_r)); + +end; +$function$; +create table fruit1(id varchar not null,name varchar not null,color varchar); +create table fruit2(id varchar not null,name varchar not null); +insert into fruit1 values('1','apple','red'); +insert into fruit2 values('1','apple'); +select record_to_form_data(fruit1) from fruit1; + record_to_form_data +--------------------- + (1,apple,red) +(1 row) + +select record_to_form_data(fruit2) from fruit2; + record_to_form_data +--------------------- + (1,apple) +(1 row) + +DROP FUNCTION record_to_form_data(record); +DROP TABLE fruit1; +DROP TABLE fruit2; diff --git a/src/test/regress/sql/plpgsql.sql b/src/test/regress/sql/plpgsql.sql index 588c331033..b02b20760c 100644 --- a/src/test/regress/sql/plpgsql.sql +++ b/src/test/regress/sql/plpgsql.sql @@ -4711,3 +4711,28 @@ BEGIN GET DIAGNOSTICS x = ROW_COUNT; RETURN; END; $$ LANGUAGE plpgsql; + + +CREATE OR REPLACE FUNCTION record_to_form_data(p_r record) + RETURNS text + LANGUAGE plpgsql +AS $function$ +begin + +return (SELECT format('%s',p_r)); + +end; +$function$; + +create table fruit1(id varchar not null,name varchar not null,color varchar); +create table fruit2(id varchar not null,name varchar not null); + +insert into fruit1 values('1','apple','red'); +insert into fruit2 values('1','apple'); + +select record_to_form_data(fruit1) from fruit1; +select record_to_form_data(fruit2) from fruit2; + +DROP FUNCTION record_to_form_data(record); +DROP TABLE fruit1; +DROP TABLE fruit2;