Re: Using Expanded Objects other than Arrays from plpgsql

From: Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us>
To: Michel Pelletier <pelletier(dot)michel(at)gmail(dot)com>
Cc: pgsql-hackers(at)lists(dot)postgresql(dot)org
Subject: Re: Using Expanded Objects other than Arrays from plpgsql
Date: 2024-10-23 15:21:25
Message-ID: 2259890.1729696885@sss.pgh.pa.us
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-general pgsql-hackers

Michel Pelletier <pelletier(dot)michel(at)gmail(dot)com> writes:
> Here's another example:

> CREATE OR REPLACE FUNCTION test2(graph matrix)
> RETURNS bigint LANGUAGE plpgsql AS
> $$
> BEGIN
> perform set_element(graph, 1, 1, 1);
> RETURN nvals(graph);
> end;
> $$;
> CREATE FUNCTION
> postgres=# select test2(matrix('int32'));
> DEBUG: new_matrix
> DEBUG: matrix_get_flat_size
> DEBUG: flatten_matrix
> DEBUG: scalar_int32
> DEBUG: new_scalar
> DEBUG: matrix_set_element
> DEBUG: DatumGetMatrix
> DEBUG: expand_matrix
> DEBUG: new_matrix
> DEBUG: DatumGetScalar
> DEBUG: matrix_get_flat_size
> DEBUG: matrix_get_flat_size
> DEBUG: flatten_matrix
> DEBUG: context_callback_matrix_free
> DEBUG: context_callback_scalar_free
> DEBUG: matrix_nvals
> DEBUG: DatumGetMatrix
> DEBUG: expand_matrix
> DEBUG: new_matrix
> DEBUG: context_callback_matrix_free
> DEBUG: context_callback_matrix_free
> test2
> -------
> 0
> (1 row)

I'm a little confused by your debug output. What are "scalar_int32"
and "new_scalar", and what part of the plpgsql function is causing
them to be invoked?

Another thing that confuses me is why there's a second flatten_matrix
operation happening here. Shouldn't set_element return its result
as a R/W expanded object?

> I would expect that to return 1. If I do "graph = set_element(graph, 1, 1,
> 1)" it works.

I think you have a faulty understanding of PERFORM. It's defined as
"evaluate this expression and throw away the result", so it's *not*
going to change "graph", not even if set_element declares that
argument as INOUT. (Our interpretation of OUT arguments for functions
is that they're just an alternate notation for specifying the function
result.) If you want to avoid the explicit assignment back to "graph"
then the thing to do would be to declare set_element as a procedure,
not a function, with an INOUT argument and then call it with CALL.

That's only cosmetically different though, in that the updated
"graph" value is still passed back much as if it were a function
result, and then the CALL infrastructure knows it has to assign that
back to the argument variable. And, as I tried to explain earlier,
that code path currently has no mechanism for avoiding making a copy
of the graph somewhere along the line: it will pass "graph" to the
procedure as either a flat Datum or a R/O expanded object, so that
set_element will be required to copy that before modifying it.
We can imagine extending whatever we do for "x := f(x)" cases so that
it also works during "CALL p(x)". But I think that's only going to
yield cosmetic or notational improvements so I don't want to start
with doing that. Let's focus first on improving the existing
infrastructure for the f(x) case.

regards, tom lane

In response to

Responses

Browse pgsql-general by date

  From Date Subject
Next Message Laurenz Albe 2024-10-23 15:44:02 Re: CONST :consttype relpartbound pg_class
Previous Message Дмитрий 2024-10-23 14:07:34 CONST :consttype relpartbound pg_class

Browse pgsql-hackers by date

  From Date Subject
Next Message Daniel Gustafsson 2024-10-23 15:46:14 Re: [PoC] Federated Authn/z with OAUTHBEARER
Previous Message Nathan Bossart 2024-10-23 15:18:55 Re: use a non-locking initial test in TAS_SPIN on AArch64