Re: Bytea PL/Perl transform - Mailing list pgsql-hackers
From | Dagfinn Ilmari Mannsåker |
---|---|
Subject | Re: Bytea PL/Perl transform |
Date | |
Msg-id | 87o7d2lqgd.fsf@wibble.ilmari.org Whole thread Raw |
In response to | Bytea PL/Perl transform (Иван Панченко <wao@mail.ru>) |
List | pgsql-hackers |
Pavel Stehule <pavel.stehule@gmail.com> writes: > út 30. 1. 2024 v 17:18 odesílatel Dagfinn Ilmari Mannsåker < > ilmari@ilmari.org> napsal: > >> Pavel Stehule <pavel.stehule@gmail.com> writes: >> >> > út 30. 1. 2024 v 16:43 odesílatel Dagfinn Ilmari Mannsåker < >> > ilmari@ilmari.org> napsal: >> > >> >> Pavel Stehule <pavel.stehule@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. > 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
pgsql-hackers by date: