út 30. 1. 2024 v 17:46 odesílatel Dagfinn Ilmari Mannsåker < ilm...@ilmari.org> napsal:
> Pavel Stehule <pavel.steh...@gmail.com> writes: > > > út 30. 1. 2024 v 17:18 odesílatel Dagfinn Ilmari Mannsåker < > > ilm...@ilmari.org> napsal: > > > >> Pavel Stehule <pavel.steh...@gmail.com> writes: > >> > >> > út 30. 1. 2024 v 16:43 odesílatel Dagfinn Ilmari Mannsåker < > >> > ilm...@ilmari.org> napsal: > >> > > >> >> Pavel Stehule <pavel.steh...@gmail.com> writes: > >> >> > >> >> > I inserted perl reference support - hstore_plperl and json_plperl > does > >> >> it. > >> >> > > >> >> > +<->/* Dereference references recursively. */ > >> >> > +<->while (SvROK(in)) > >> >> > +<-><-->in = SvRV(in); > >> >> > >> >> That code in hstore_plperl and json_plperl is only relevant because > they > >> >> deal with non-scalar values (hashes for hstore, and also arrays for > >> >> json) which must be passed as references. The recursive nature of > the > >> >> dereferencing is questionable, and masked the bug fixed by commit > >> >> 1731e3741cbbf8e0b4481665d7d523bc55117f63. > >> >> > >> >> bytea_plperl only deals with scalars (specifically strings), so > should > >> >> not concern itself with references. In fact, this code breaks > returning > >> >> objects with overloaded stringification, for example: > >> >> > >> >> CREATE FUNCTION plperlu_overload() RETURNS bytea LANGUAGE plperlu > >> >> TRANSFORM FOR TYPE bytea > >> >> AS $$ > >> >> package StringOverload { use overload '""' => sub { "stuff" }; } > >> >> return bless {}, "StringOverload"; > >> >> $$; > >> >> > >> >> This makes the server crash with an assertion failure from Perl > because > >> >> SvPVbyte() was passed a non-scalar value: > >> >> > >> >> postgres: ilmari regression_bytea_plperl [local] SELECT: sv.c:2865: > >> >> Perl_sv_2pv_flags: > >> >> Assertion `SvTYPE(sv) != SVt_PVAV && SvTYPE(sv) != SVt_PVHV && > >> SvTYPE(sv) > >> >> != SVt_PVFM' failed. > >> >> > >> >> If I remove the dereferincing loop it succeeds: > >> >> > >> >> SELECT encode(plperlu_overload(), 'escape') AS string; > >> >> string > >> >> -------- > >> >> stuff > >> >> (1 row) > >> >> > >> >> Attached is a v2 patch which removes the dereferencing and includes > the > >> >> above example as a test. > >> >> > >> > > >> > But without dereference it returns bad value. > >> > >> Where exactly does it return a bad value? The existing tests pass, and > >> the one I included shows that it does the right thing in that case too. > >> If you pass it an unblessed reference it returns the stringified version > >> of that, as expected. > >> > > > > ugly test code > > > > (2024-01-30 13:44:28) postgres=# CREATE or replace FUNCTION > > perl_inverse_bytes(bytea) RETURNS bytea > > TRANSFORM FOR TYPE bytea > > AS $$ my $bytes = pack 'H*', '0123'; my $ref = \$bytes; > > You are returning a reference, not a string. > I know, but for this case, should not be raised an error? > > > return $ref; > > $$ LANGUAGE plperlu; > > CREATE FUNCTION > > (2024-01-30 13:44:33) postgres=# select perl_inverse_bytes(''), ' > '::bytea; > > ┌──────────────────────────────────────┬───────┐ > > │ perl_inverse_bytes │ bytea │ > > ╞══════════════════════════════════════╪═══════╡ > > │ \x5343414c41522830783130656134333829 │ \x20 │ > > └──────────────────────────────────────┴───────┘ > > (1 row) > > ~=# select encode('\x5343414c41522830783130656134333829', 'escape'); > ┌───────────────────┐ > │ encode │ > ├───────────────────┤ > │ SCALAR(0x10ea438) │ > └───────────────────┘ > > This is how Perl stringifies references in the absence of overloading. > Return the byte string directly from your function and it will do the > right thing: > > CREATE FUNCTION plperlu_bytes() RETURNS bytea LANGUAGE plperlu > TRANSFORM FOR TYPE bytea > AS $$ return pack 'H*', '0123'; $$; > > SELECT plperlu_bytes(); > plperlu_bytes > --------------- > \x0123 > (1 row) > > > - ilmari >