Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitbfd6b3b

Browse files
committed
Improve plpgsql's ability to handle arguments declared as RECORD.
Treat arguments declared as RECORD as if that were a polymorphic type(which it is, sort of), in that we substitute the actual argument typewhile forming the function cache lookup key. This allows the specificcomposite type to be known in some cases where it was not before,at the cost of making a separate function cache entry for each namedcomposite type that's passed to the function during a session. Theparticular symptom discussed in bug #17610 could be solved in othermore-efficient ways, but only at the cost of considerable developmentwork, and there are other cases where we'd still fail without this.Per bug #17610 from Martin Jurča. Back-patch to v11 where we firstallowed plpgsql functions to be declared as taking type RECORD.Discussion:https://postgr.es/m/17610-fb1eef75bf6c2364@postgresql.org
1 parentd08a049 commitbfd6b3b

File tree

3 files changed

+76
-4
lines changed

3 files changed

+76
-4
lines changed

‎src/pl/plpgsql/src/expected/plpgsql_record.out

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
-- Tests for PL/pgSQL handling of composite (record) variables
33
--
44
create type two_int4s as (f1 int4, f2 int4);
5+
create type more_int4s as (f0 text, f1 int4, f2 int4);
56
create type two_int8s as (q1 int8, q2 int8);
67
create type nested_int8s as (c1 two_int8s, c2 two_int8s);
78
-- base-case return of a composite type
@@ -426,6 +427,18 @@ select getf1(row(1,2));
426427
1
427428
(1 row)
428429

430+
select getf1(row(1,2)::two_int4s);
431+
getf1
432+
-------
433+
1
434+
(1 row)
435+
436+
select getf1(row('foo',123,456)::more_int4s);
437+
getf1
438+
-------
439+
123
440+
(1 row)
441+
429442
-- the context stack is different when debug_discard_caches
430443
-- is set, so suppress context output
431444
\set SHOW_CONTEXT never
@@ -438,6 +451,28 @@ select getf1(row(1,2));
438451
1
439452
(1 row)
440453

454+
-- this seemingly-equivalent case behaves a bit differently,
455+
-- because the core parser's handling of $N symbols is simplistic
456+
create function getf2(record) returns int language plpgsql as
457+
$$ begin return $1.f2; end $$;
458+
select getf2(row(1,2)); -- ideally would work, but does not
459+
ERROR: could not identify column "f2" in record data type
460+
LINE 1: $1.f2
461+
^
462+
QUERY: $1.f2
463+
CONTEXT: PL/pgSQL function getf2(record) line 1 at RETURN
464+
select getf2(row(1,2)::two_int4s);
465+
getf2
466+
-------
467+
2
468+
(1 row)
469+
470+
select getf2(row('foo',123,456)::more_int4s);
471+
getf2
472+
-------
473+
456
474+
(1 row)
475+
441476
-- check behavior when assignment to FOR-loop variable requires coercion
442477
do $$
443478
declare r two_int8s;

‎src/pl/plpgsql/src/pl_comp.c

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2498,9 +2498,15 @@ compute_function_hashkey(FunctionCallInfo fcinfo,
24982498

24992499
/*
25002500
* This is the same as the standard resolve_polymorphic_argtypes() function,
2501-
* but with a special case for validation: assume that polymorphic arguments
2502-
* are integer, integer-array or integer-range. Also, we go ahead and report
2503-
* the error if we can't resolve the types.
2501+
* except that:
2502+
* 1. We go ahead and report the error if we can't resolve the types.
2503+
* 2. We treat RECORD-type input arguments (not output arguments) as if
2504+
* they were polymorphic, replacing their types with the actual input
2505+
* types if we can determine those. This allows us to create a separate
2506+
* function cache entry for each named composite type passed to such an
2507+
* argument.
2508+
* 3. In validation mode, we have no inputs to look at, so assume that
2509+
* polymorphic arguments are integer, integer-array or integer-range.
25042510
*/
25052511
staticvoid
25062512
plpgsql_resolve_polymorphic_argtypes(intnumargs,
@@ -2512,6 +2518,8 @@ plpgsql_resolve_polymorphic_argtypes(int numargs,
25122518

25132519
if (!forValidator)
25142520
{
2521+
intinargno;
2522+
25152523
/* normal case, pass to standard routine */
25162524
if (!resolve_polymorphic_argtypes(numargs,argtypes,argmodes,
25172525
call_expr))
@@ -2520,10 +2528,28 @@ plpgsql_resolve_polymorphic_argtypes(int numargs,
25202528
errmsg("could not determine actual argument "
25212529
"type for polymorphic function \"%s\"",
25222530
proname)));
2531+
/* also, treat RECORD inputs (but not outputs) as polymorphic */
2532+
inargno=0;
2533+
for (i=0;i<numargs;i++)
2534+
{
2535+
charargmode=argmodes ?argmodes[i] :PROARGMODE_IN;
2536+
2537+
if (argmode==PROARGMODE_OUT||argmode==PROARGMODE_TABLE)
2538+
continue;
2539+
if (argtypes[i]==RECORDOID||argtypes[i]==RECORDARRAYOID)
2540+
{
2541+
Oidresolvedtype=get_call_expr_argtype(call_expr,
2542+
inargno);
2543+
2544+
if (OidIsValid(resolvedtype))
2545+
argtypes[i]=resolvedtype;
2546+
}
2547+
inargno++;
2548+
}
25232549
}
25242550
else
25252551
{
2526-
/* special validation case */
2552+
/* special validation case(no need to do anything for RECORD)*/
25272553
for (i=0;i<numargs;i++)
25282554
{
25292555
switch (argtypes[i])

‎src/pl/plpgsql/src/sql/plpgsql_record.sql

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
--
44

55
createtypetwo_int4sas (f1 int4, f2 int4);
6+
createtypemore_int4sas (f0text, f1 int4, f2 int4);
67
createtypetwo_int8sas (q1 int8, q2 int8);
78
createtypenested_int8sas (c1 two_int8s, c2 two_int8s);
89

@@ -257,13 +258,23 @@ create function getf1(x record) returns int language plpgsql as
257258
$$begin returnx.f1; end $$;
258259
select getf1(1);
259260
select getf1(row(1,2));
261+
select getf1(row(1,2)::two_int4s);
262+
select getf1(row('foo',123,456)::more_int4s);
260263
-- the context stack is different when debug_discard_caches
261264
-- is set, so suppress context output
262265
\set SHOW_CONTEXT never
263266
select getf1(row(1,2)::two_int8s);
264267
\set SHOW_CONTEXT errors
265268
select getf1(row(1,2));
266269

270+
-- this seemingly-equivalent case behaves a bit differently,
271+
-- because the core parser's handling of $N symbols is simplistic
272+
createfunctiongetf2(record) returnsint language plpgsqlas
273+
$$begin return $1.f2; end $$;
274+
select getf2(row(1,2));-- ideally would work, but does not
275+
select getf2(row(1,2)::two_int4s);
276+
select getf2(row('foo',123,456)::more_int4s);
277+
267278
-- check behavior when assignment to FOR-loop variable requires coercion
268279
do $$
269280
declare r two_int8s;

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp