Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit f535f35

Browse files
committed
Fix handling of polymorphic output arguments for procedures.
Most of the infrastructure for procedure arguments was already okay with polymorphic output arguments, but it turns out that CallStmtResultDesc() was a few bricks shy of a load here. It thought all it needed to do was call build_function_result_tupdesc_t, but that function specifically disclaims responsibility for resolving polymorphic arguments. Failing to handle that doesn't seem to be a problem for CALL in plpgsql, but CALL from plain SQL would get errors like "cannot display a value of type anyelement", or even crash outright. In v14 and later we can simply examine the exposed types of the CallStmt.outargs nodes to get the right type OIDs. But it's a lot more complicated to fix in v12/v13, because those versions don't have CallStmt.outargs, nor do they do expand_function_arguments until ExecuteCallStmt runs. We have to duplicatively run expand_function_arguments, and then re-determine which elements of the args list are output arguments. Per bug #18463 from Drew Kimball. Back-patch to all supported versions, since it's busted in all of them. Discussion: https://postgr.es/m/18463-f8cd77e12564d8a2@postgresql.org
1 parent 245f1ce commit f535f35

File tree

5 files changed

+144
-0
lines changed

5 files changed

+144
-0
lines changed

src/backend/commands/functioncmds.c

+28
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
#include "executor/functions.h"
5353
#include "funcapi.h"
5454
#include "miscadmin.h"
55+
#include "nodes/nodeFuncs.h"
5556
#include "optimizer/optimizer.h"
5657
#include "parser/analyze.h"
5758
#include "parser/parse_coerce.h"
@@ -2364,5 +2365,32 @@ CallStmtResultDesc(CallStmt *stmt)
23642365

23652366
ReleaseSysCache(tuple);
23662367

2368+
/*
2369+
* The result of build_function_result_tupdesc_t has the right column
2370+
* names, but it just has the declared output argument types, which is the
2371+
* wrong thing in polymorphic cases. Get the correct types by examining
2372+
* stmt->outargs. We intentionally keep the atttypmod as -1 and the
2373+
* attcollation as the type's default, since that's always the appropriate
2374+
* thing for function outputs; there's no point in considering any
2375+
* additional info available from outargs. Note that tupdesc is null if
2376+
* there are no outargs.
2377+
*/
2378+
if (tupdesc)
2379+
{
2380+
Assert(tupdesc->natts == list_length(stmt->outargs));
2381+
for (int i = 0; i < tupdesc->natts; i++)
2382+
{
2383+
Form_pg_attribute att = TupleDescAttr(tupdesc, i);
2384+
Node *outarg = (Node *) list_nth(stmt->outargs, i);
2385+
2386+
TupleDescInitEntry(tupdesc,
2387+
i + 1,
2388+
NameStr(att->attname),
2389+
exprType(outarg),
2390+
-1,
2391+
0);
2392+
}
2393+
}
2394+
23672395
return tupdesc;
23682396
}

src/pl/plpgsql/src/expected/plpgsql_call.out

+34
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,40 @@ END
409409
$$;
410410
NOTICE: a: <NULL>, b: {30,7}
411411
NOTICE: _a: 37, _b: 30, _c: 7
412+
-- polymorphic OUT arguments
413+
CREATE PROCEDURE test_proc12(a anyelement, OUT b anyelement, OUT c anyarray)
414+
LANGUAGE plpgsql
415+
AS $$
416+
BEGIN
417+
RAISE NOTICE 'a: %', a;
418+
b := a;
419+
c := array[a];
420+
END;
421+
$$;
422+
DO $$
423+
DECLARE _a int; _b int; _c int[];
424+
BEGIN
425+
_a := 10;
426+
CALL test_proc12(_a, _b, _c);
427+
RAISE NOTICE '_a: %, _b: %, _c: %', _a, _b, _c;
428+
END
429+
$$;
430+
NOTICE: a: 10
431+
NOTICE: _a: 10, _b: 10, _c: {10}
432+
DO $$
433+
DECLARE _a int; _b int; _c text[];
434+
BEGIN
435+
_a := 10;
436+
CALL test_proc12(_a, _b, _c); -- error
437+
RAISE NOTICE '_a: %, _b: %, _c: %', _a, _b, _c;
438+
END
439+
$$;
440+
ERROR: procedure test_proc12(integer, integer, text[]) does not exist
441+
LINE 1: CALL test_proc12(_a, _b, _c)
442+
^
443+
HINT: No procedure matches the given name and argument types. You might need to add explicit type casts.
444+
QUERY: CALL test_proc12(_a, _b, _c)
445+
CONTEXT: PL/pgSQL function inline_code_block line 5 at CALL
412446
-- transition variable assignment
413447
TRUNCATE test1;
414448
CREATE FUNCTION triggerfunc1() RETURNS trigger

src/pl/plpgsql/src/sql/plpgsql_call.sql

+30
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,36 @@ BEGIN
375375
END
376376
$$;
377377

378+
-- polymorphic OUT arguments
379+
380+
CREATE PROCEDURE test_proc12(a anyelement, OUT b anyelement, OUT c anyarray)
381+
LANGUAGE plpgsql
382+
AS $$
383+
BEGIN
384+
RAISE NOTICE 'a: %', a;
385+
b := a;
386+
c := array[a];
387+
END;
388+
$$;
389+
390+
DO $$
391+
DECLARE _a int; _b int; _c int[];
392+
BEGIN
393+
_a := 10;
394+
CALL test_proc12(_a, _b, _c);
395+
RAISE NOTICE '_a: %, _b: %, _c: %', _a, _b, _c;
396+
END
397+
$$;
398+
399+
DO $$
400+
DECLARE _a int; _b int; _c text[];
401+
BEGIN
402+
_a := 10;
403+
CALL test_proc12(_a, _b, _c); -- error
404+
RAISE NOTICE '_a: %, _b: %, _c: %', _a, _b, _c;
405+
END
406+
$$;
407+
378408

379409
-- transition variable assignment
380410

src/test/regress/expected/create_procedure.out

+34
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,40 @@ AS $$
193193
SELECT NULL::int;
194194
$$;
195195
CALL ptest6(1, 2);
196+
CREATE PROCEDURE ptest6a(inout a anyelement, out b anyelement)
197+
LANGUAGE SQL
198+
AS $$
199+
SELECT $1, $1;
200+
$$;
201+
CALL ptest6a(1, null);
202+
a | b
203+
---+---
204+
1 | 1
205+
(1 row)
206+
207+
CALL ptest6a(1.1, null);
208+
a | b
209+
-----+-----
210+
1.1 | 1.1
211+
(1 row)
212+
213+
CREATE PROCEDURE ptest6b(a anyelement, out b anyelement, out c anyarray)
214+
LANGUAGE SQL
215+
AS $$
216+
SELECT $1, array[$1];
217+
$$;
218+
CALL ptest6b(1, null, null);
219+
b | c
220+
---+-----
221+
1 | {1}
222+
(1 row)
223+
224+
CALL ptest6b(1.1, null, null);
225+
b | c
226+
-----+-------
227+
1.1 | {1.1}
228+
(1 row)
229+
196230
-- collation assignment
197231
CREATE PROCEDURE ptest7(a text, b text)
198232
LANGUAGE SQL

src/test/regress/sql/create_procedure.sql

+18
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,24 @@ $$;
131131

132132
CALL ptest6(1, 2);
133133

134+
CREATE PROCEDURE ptest6a(inout a anyelement, out b anyelement)
135+
LANGUAGE SQL
136+
AS $$
137+
SELECT $1, $1;
138+
$$;
139+
140+
CALL ptest6a(1, null);
141+
CALL ptest6a(1.1, null);
142+
143+
CREATE PROCEDURE ptest6b(a anyelement, out b anyelement, out c anyarray)
144+
LANGUAGE SQL
145+
AS $$
146+
SELECT $1, array[$1];
147+
$$;
148+
149+
CALL ptest6b(1, null, null);
150+
CALL ptest6b(1.1, null, null);
151+
134152

135153
-- collation assignment
136154

0 commit comments

Comments
 (0)