diff --git a/src/pl/plpgsql/src/pl_comp.c b/src/pl/plpgsql/src/pl_comp.c index 650cc48..de5fa54 100644 --- a/src/pl/plpgsql/src/pl_comp.c +++ b/src/pl/plpgsql/src/pl_comp.c @@ -430,7 +430,8 @@ do_compile(FunctionCallInfo fcinfo, /* (note we already replaced polymorphic types) */ /* (build_variable would do this, but wrong message) */ if (argdtype->ttype != PLPGSQL_TTYPE_SCALAR && - argdtype->ttype != PLPGSQL_TTYPE_ROW) + argdtype->ttype != PLPGSQL_TTYPE_ROW && + argdtype->ttype != PLPGSQL_TTYPE_REC) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("PL/pgSQL functions cannot accept type %s", diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c index deefb1f..4c35f44 100644 --- a/src/pl/plpgsql/src/pl_exec.c +++ b/src/pl/plpgsql/src/pl_exec.c @@ -335,6 +335,28 @@ plpgsql_exec_function(PLpgSQL_function *func, FunctionCallInfo fcinfo, } break; + case PLPGSQL_DTYPE_REC: + { + /* + * Target is a record variable + */ + PLpgSQL_rec *rec = (PLpgSQL_rec *) estate.datums[n]; + + if (!fcinfo->argnull[i]) + { + exec_move_row_from_datum(&estate, rec, NULL, + fcinfo->arg[i]); + } + else + { + /* If source is null, just assign nulls to the record */ + exec_move_row(&estate, rec, NULL, NULL, NULL); + } + /* clean up after exec_move_row() */ + exec_eval_cleanup(&estate); + } + break; + default: elog(ERROR, "unrecognized dtype: %d", func->datums[i]->dtype); } diff --git a/src/pl/plpgsql/src/pl_handler.c b/src/pl/plpgsql/src/pl_handler.c index 266c314..486d270 100644 --- a/src/pl/plpgsql/src/pl_handler.c +++ b/src/pl/plpgsql/src/pl_handler.c @@ -442,7 +442,8 @@ plpgsql_validator(PG_FUNCTION_ARGS) { if (get_typtype(argtypes[i]) == TYPTYPE_PSEUDO) { - if (!IsPolymorphicType(argtypes[i])) + if (!IsPolymorphicType(argtypes[i]) && + argtypes[i] != RECORDOID) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("PL/pgSQL functions cannot accept type %s", diff --git a/src/test/regress/expected/plpgsql.out b/src/test/regress/expected/plpgsql.out index 78e5a85..28fa092 100644 --- a/src/test/regress/expected/plpgsql.out +++ b/src/test/regress/expected/plpgsql.out @@ -1828,13 +1828,28 @@ begin k := 'foot'; return next; end$$ language plpgsql; -select * from f1(42); - j | k -----+------ - 43 | foo - 44 | foot +\set VERBOSITY verbose +create function f2(r record) returns regtype as $$ +begin + raise notice 'r = %', r; + return pg_typeof(r); +end$$ language plpgsql; +select *, f2(row(f1.*)), f2((SELECT row(d.*) FROM pg_shdescription d LIMIT 1)) from f1(42); +NOTICE: 00000: r = (43,foo) +LOCATION: exec_stmt_raise, pl_exec.c:3124 +NOTICE: 00000: r = (1,1262,"default template for new databases") +LOCATION: exec_stmt_raise, pl_exec.c:3124 +NOTICE: 00000: r = (44,foot) +LOCATION: exec_stmt_raise, pl_exec.c:3124 +NOTICE: 00000: r = (1,1262,"default template for new databases") +LOCATION: exec_stmt_raise, pl_exec.c:3124 + j | k | f2 | f2 +----+------+--------+-------- + 43 | foo | record | record + 44 | foot | record | record (2 rows) +\set VERBOSITY default drop function f1(int); create function duplic(in i anyelement, out j anyelement, out k anyarray) as $$ begin diff --git a/src/test/regress/sql/plpgsql.sql b/src/test/regress/sql/plpgsql.sql index e19e415..0f0e657 100644 --- a/src/test/regress/sql/plpgsql.sql +++ b/src/test/regress/sql/plpgsql.sql @@ -1623,7 +1623,15 @@ begin return next; end$$ language plpgsql; -select * from f1(42); +\set VERBOSITY verbose +create function f2(r record) returns regtype as $$ +begin + raise notice 'r = %', r; + return pg_typeof(r); +end$$ language plpgsql; + +select *, f2(row(f1.*)), f2((SELECT row(d.*) FROM pg_shdescription d LIMIT 1)) from f1(42); +\set VERBOSITY default drop function f1(int);