пн, 17 авг. 2026 г. в 01:26, Tom Lane <[email protected]>:

> But to my previous point, where
> else would we need to call it, if we're going to try to support
> such cases?  Also, what exactly are the preconditions for that
> function?


If we want a tied hash or array to convert like an ordinary one, GETMAGIC
is still needed before SvOK() / SvROK() in plperl_sv_to_datum() and
jsonb_plperl's SV_to_JsonbValue().  plperl_build_tuple_result() still
uses HeVAL() and will crash on a tied hash the same way hstore_plperl
did.  That loop also calls hek2cstr(), which uses FREETMPS, so
hek2cstr() has to run before hv_iterval().

The trigger path does not return a hash.  After "MODIFY",
plperl_modify_tuple() walks $_TD->{new} with HeVAL().  PL/Perl already
filled that hash from the tuple, so it is not tied.  A crash would
need the trigger to tie that hash itself, for example

tie %{$_TD->{new}}, 'SomeTie';
$_TD->{new}{v} = 'from_tie';
return 'MODIFY';

Looking at the perl header files here, it looks like
> sv being nonnull is required and sufficient ... but your patch
> is inconsistent about checking that.
>
> Yes.  Non-NULL is required and sufficient.

The extra NULL checks on the hstore side are not needed after
hv_iterval().  I left the old HeVAL() guards in because the point was
to show that FETCH results are available, and why a NULL check on
HeVAL() always yields SQL NULL.  The if (svp) in the SETOF loop is
only because av_fetch() returns NULL for a missing element.

> That seems odd, given that we use Tie::Hash and Tie::StdHash in
> src/pl/plperl/plc_trusted.pl

Trusted plperl replaces require with pp_require_safe, which only
succeeds if the module is already in %INC. Otherwise it dies with
"Unable to load Tie/Array.pm into plperl". tie itself is allowed.
plperlu can load the modules as usual.

Proof:
```
\set ON_ERROR_STOP off

CREATE EXTENSION IF NOT EXISTS plperl;
CREATE EXTENSION IF NOT EXISTS plperlu;

\echo === 1) plperl: use Tie::Array ===
CREATE OR REPLACE FUNCTION try_use_tie_array() RETURNS text
LANGUAGE plperl AS $$
use Tie::Array;
return 'loaded';
$$;
SELECT try_use_tie_array();

\echo === 3) plperl: tie with inline class (no use) ===
CREATE OR REPLACE FUNCTION try_tie_inline() RETURNS text
LANGUAGE plperl AS $$
{
package PLPerlProofTie;
sub TIEARRAY { bless [], $_[0] }
sub STORE { $_[0][$_[1]] = $_[2] }
sub FETCH { $_[0][$_[1]] }
sub FETCHSIZE { scalar @{$_[0]} }
}
my @a;
tie @a, 'PLPerlProofTie';
$a[0] = 'ok';
return $a[0];
$$;
SELECT try_tie_inline();

\echo === 4) plperlu: use Tie::Array ===
CREATE OR REPLACE FUNCTION try_use_tie_array_u() RETURNS text
LANGUAGE plperlu AS $$
use Tie::Array;
return 'loaded';
$$;
SELECT try_use_tie_array_u();
```

Reply via email to