Thread: pl/perl thoughts

pl/perl thoughts

From
Andrew Dunstan
Date:
Hackers,

FYI here are some of my thoughts I just sent to Joshua Drake.

I would add a couple of points:
. since there is a security advisory for Safe.pm prior to version 2.08, 
maybe we should replace "require Safe;" with "use Safe 2.08;".
. I thought about some sort of precompilation methods for perl functions 
known to the database (store the function refs in a hash so you could 
get at them via syntax like 
&{$func_hash{schema_name}->{func_name}}(@func_args) ). I decided to 
abandon this approach mainly because of postgresql's function 
overloading, making disambiguation very hard. With a full SPI interface 
there will be access to any function, not just plperl functions, and 
postgres will do the disambiguation for you. Also, see below for a 
slightly more klunky but much more lightweight approach which would mean 
there was no necessity for a callback to postgresql.

cheers

andrew

>
> I haven't got past the thinking stage yet, and a few things have held 
> up my progress elsewhere. The one possibly productive thought I have 
> to share with you is this: it is probably overkill to have a separate 
> Safe container for each plperl function. I don't see any reason that 
> they shouldn't all live in one Safe container. Then they could share 
> data and indeed some preloaded functions without doing anything special.
>
> Thus the following perl contained in plperl.c and executed on 
> interpreter startup:
>
>                require Safe; SPI::bootstrap();
>                sub ::mksafefunc { my $x = new Safe; 
> $x->permit_only(':default');$x->permit(':base_math');
>                $x->share(qw[&elog &DEBUG &LOG &INFO &NOTICE &WARNING 
> &ERROR]);
>                 return $x->reval(qq[sub { $_[0] }]); }
>                sub ::mkunsafefunc {return eval(qq[ sub { $_[0] } ]); }
>
> would become something like:
>
>                require Safe; SPI::bootstrap();
>                use vars qw($PLContainer); $PLContainer = new 
> Safe("PLPerl");
>                
> $PLContainer->permit_only(':default');$PLContainer->permit(':base_math');
>                $PLContainer->share(qw[&elog &DEBUG &LOG &INFO &NOTICE 
> &WARNING &ERROR]);
>                sub ::mksafefunc { return $PLContainer->reval(qq[sub { 
> $_[0] }]); }
>                sub ::mkunsafefunc {return eval(qq[ sub { $_[0] } ]); }
>
> Now you could do something like this:
>
> create function myplperlfuncs() returns int language plperl is '
>    $datavar = "foo";
>    $funcvar = sub { return "bar"; };
>    return 1;
> ';
>
> create function f1 () returns text language plperl as '
>  return $datavar;
> ';
>
> create function f2() returns text language plperl as '
>  return &$funcvar();
> ';
>
> At the start of your session you would issue "select myplperlfuncs();" 
> to preload the values, and thereafter you could call f1() and f2() 
> quite happily.
>
> It's actually a bit of a pity that we don't have provision for a per 
> database exec on startup procedure, which could handle this more 
> elegantly (i.e. we would register myplperlfuncs() as something to be 
> run on startup, so the user wouldn't have to worry at all about it.)
>
> I have not tested any of this - it is still straight out of my head.
>
> As others have noted, the biggest need is for full SPI access. I don't 
> think this is hard - just a fair bit of work. After that it would be 
> very nice to have a DBI type handle so that programmers used to doing 
> things the DBI way (and what perl programmer isn't?) will feel right 
> at home with plperl. In most cases I guess that would be a thin layer 
> over the SPI stuff. Alternatively, you could hide the SPI access and 
> just make the DBI handle visible - it would still be mostly calling 
> SPI under the hood, of course. As they say in the perl world, 
> TIMTOWTDI. Providing a DBI handle would also square with what happens 
> in the Java world, where you can write server side methods that access 
> the database via a JDBC interface.
>
>



Re: pl/perl thoughts

From
Andrew Dunstan
Date:
FWIW, I have now tested the scheme below, and it appears to work as 
expected. I can't see any reason it should disturb any existing 
functionality, unless people currently use plperl to store nonlexical 
variables which might now clobber each other. I think it's worth doing, 
for a small but nontrivial functionality gain. If nobody objects, I will 
submit a patch and some docco on how to use it.

cheers

andrew


I wrote:

>>
>> Thus the following perl contained in plperl.c and executed on 
>> interpreter startup:
>>
>>                require Safe; SPI::bootstrap();
>>                sub ::mksafefunc { my $x = new Safe; 
>> $x->permit_only(':default');$x->permit(':base_math');
>>                $x->share(qw[&elog &DEBUG &LOG &INFO &NOTICE &WARNING 
>> &ERROR]);
>>                 return $x->reval(qq[sub { $_[0] }]); }
>>                sub ::mkunsafefunc {return eval(qq[ sub { $_[0] } ]); }
>>
>> would become something like:
>>
>>                require Safe; SPI::bootstrap();
>>                use vars qw($PLContainer); $PLContainer = new 
>> Safe("PLPerl");
>>                
>> $PLContainer->permit_only(':default');$PLContainer->permit(':base_math'); 
>>
>>                $PLContainer->share(qw[&elog &DEBUG &LOG &INFO &NOTICE 
>> &WARNING &ERROR]);
>>                sub ::mksafefunc { return $PLContainer->reval(qq[sub { 
>> $_[0] }]); }
>>                sub ::mkunsafefunc {return eval(qq[ sub { $_[0] } ]); }
>>
>> Now you could do something like this:
>>
>> create function myplperlfuncs() returns int language plperl as '
>>    $datavar = "foo";
>>    $funcvar = sub { return "bar"; };
>>    return 1;
>> ';
>>
>> create function f1 () returns text language plperl as '
>>  return $datavar;
>> ';
>>
>> create function f2() returns text language plperl as '
>>  return &$funcvar();
>> ';
>>
>> At the start of your session you would issue "select 
>> myplperlfuncs();" to preload the values, and thereafter you could 
>> call f1() and f2() quite happily.
>>
>