|
54 | 54 | #include "executor/executor.h"
|
55 | 55 | #include "funcapi.h"
|
56 | 56 | #include "miscadmin.h"
|
| 57 | +#include "nodes/nodeFuncs.h" |
57 | 58 | #include "optimizer/optimizer.h"
|
58 | 59 | #include "parser/parse_coerce.h"
|
59 | 60 | #include "parser/parse_collate.h"
|
@@ -2506,6 +2507,78 @@ CallStmtResultDesc(CallStmt *stmt)
|
2506 | 2507 |
|
2507 | 2508 | tupdesc = build_function_result_tupdesc_t(tuple);
|
2508 | 2509 |
|
| 2510 | + /* |
| 2511 | + * The result of build_function_result_tupdesc_t has the right column |
| 2512 | + * names, but it just has the declared output argument types, which is the |
| 2513 | + * wrong thing in polymorphic cases. Get the correct types by examining |
| 2514 | + * the procedure's resolved argument expressions. We intentionally keep |
| 2515 | + * the atttypmod as -1 and the attcollation as the type's default, since |
| 2516 | + * that's always the appropriate thing for function outputs; there's no |
| 2517 | + * point in considering any additional info available from outargs. Note |
| 2518 | + * that tupdesc is null if there are no outargs. |
| 2519 | + */ |
| 2520 | + if (tupdesc) |
| 2521 | + { |
| 2522 | + Datum proargmodes; |
| 2523 | + bool isnull; |
| 2524 | + ArrayType *arr; |
| 2525 | + char *argmodes; |
| 2526 | + int nargs, |
| 2527 | + noutargs; |
| 2528 | + ListCell *lc; |
| 2529 | + |
| 2530 | + /* |
| 2531 | + * Expand named arguments, defaults, etc. We do not want to scribble |
| 2532 | + * on the passed-in CallStmt parse tree, so first flat-copy fexpr, |
| 2533 | + * allowing us to replace its args field. (Note that |
| 2534 | + * expand_function_arguments will not modify any of the passed-in data |
| 2535 | + * structure.) |
| 2536 | + */ |
| 2537 | + { |
| 2538 | + FuncExpr *nexpr = makeNode(FuncExpr); |
| 2539 | + |
| 2540 | + memcpy(nexpr, fexpr, sizeof(FuncExpr)); |
| 2541 | + fexpr = nexpr; |
| 2542 | + } |
| 2543 | + |
| 2544 | + fexpr->args = expand_function_arguments(fexpr->args, |
| 2545 | + fexpr->funcresulttype, |
| 2546 | + tuple); |
| 2547 | + |
| 2548 | + /* |
| 2549 | + * If we're here, build_function_result_tupdesc_t already validated |
| 2550 | + * that the procedure has non-null proargmodes that is the right kind |
| 2551 | + * of array, so it seems unnecessary to check again. |
| 2552 | + */ |
| 2553 | + proargmodes = SysCacheGetAttr(PROCOID, tuple, |
| 2554 | + Anum_pg_proc_proargmodes, |
| 2555 | + &isnull); |
| 2556 | + Assert(!isnull); |
| 2557 | + arr = DatumGetArrayTypeP(proargmodes); /* ensure not toasted */ |
| 2558 | + argmodes = (char *) ARR_DATA_PTR(arr); |
| 2559 | + |
| 2560 | + nargs = noutargs = 0; |
| 2561 | + foreach(lc, fexpr->args) |
| 2562 | + { |
| 2563 | + Node *arg = (Node *) lfirst(lc); |
| 2564 | + Form_pg_attribute att = TupleDescAttr(tupdesc, noutargs); |
| 2565 | + char argmode = argmodes[nargs++]; |
| 2566 | + |
| 2567 | + /* ignore non-out arguments */ |
| 2568 | + if (argmode == PROARGMODE_IN || |
| 2569 | + argmode == PROARGMODE_VARIADIC) |
| 2570 | + continue; |
| 2571 | + |
| 2572 | + TupleDescInitEntry(tupdesc, |
| 2573 | + ++noutargs, |
| 2574 | + NameStr(att->attname), |
| 2575 | + exprType(arg), |
| 2576 | + -1, |
| 2577 | + 0); |
| 2578 | + } |
| 2579 | + Assert(tupdesc->natts == noutargs); |
| 2580 | + } |
| 2581 | + |
2509 | 2582 | ReleaseSysCache(tuple);
|
2510 | 2583 |
|
2511 | 2584 | return tupdesc;
|
|
0 commit comments