Re: PlPerl scope issue

From: "Peter" <peter(at)greatnowhere(dot)com>
To: "'Tim Bunce'" <Tim(dot)Bunce(at)pobox(dot)com>, "Peteris Zeltins - FORWARD - DO NOT DELETE" <peter(at)greatnowhere(dot)com>
Cc: <pgsql-general(at)postgresql(dot)org>
Subject: Re: PlPerl scope issue
Date: 2009-12-16 21:15:21
Message-ID: 000001ca7e94$e1aea860$a50bf920$@com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-general

Hello Tim,

Thanks for the reply! I'm still not sure why it's bad to have named
subroutines. At any rate I cant use anon subs since we have a complicated
reporting subsystem that relies on Perl formulas being eval-ed at runtime,
and these refer to various subroutines.

I have since resolved the issue by using 'local' scope, but it still beats
me why variables are not seen in inner subroutines. The same code works in
plain Perl on the same machine as Postgres, and it also works on second
8.4.1 Postgres/FreeBSD box. Glitch Ubuntu Karmic debs perhaps?

Sorry for top-posting... me is being forced to use stooped Outlook...

Peter

> After upgrade to 8.4.1 Perl "my" variables are no longer being seen by
subroutines:
>
> CREATE OR REPLACE FUNCTION global.perl_test()
> RETURNS "varchar" AS
> $BODY$
> my $test="x";
> test();
> return $test;
> sub test {
> elog(NOTICE,"X=".$test);
> }
> $BODY$
> language 'plperlu';
>
> Now, "select global.perl_test()" returns "x" but the value is missing
from notice statement. This worked
> just fine in 8.3, and Perl scoping rules say `my' variables are visible
by subroutines within the same
> code block. I'm running Ubuntu Karmic, installed from stock PG
repositories. Whats going on here?

The docs at http://www.postgresql.org/docs/8.4/static/plperl-funcs.html
say

Note: The use of named nested subroutines is dangerous in Perl,
especially if they refer to lexical variables in the enclosing scope.
Because a PL/Perl function is wrapped in a subroutine, any named
subroutine you create will be nested. In general, it is far safer to
create anonymous subroutines which you call via a coderef. See the
perldiag man page for more details.

I believe the section of perldiag it's refering to is this one:

=item Variable "%s" will not stay shared

(W closure) An inner (nested) I<named> subroutine is referencing a
lexical variable defined in an outer named subroutine.

When the inner subroutine is called, it will see the value of
the outer subroutine's variable as it was before and during the *first*
call to the outer subroutine; in this case, after the first call to the
outer subroutine is complete, the inner and outer subroutines will no
longer share a common value for the variable. In other words, the
variable will no longer be shared.

This problem can usually be solved by making the inner subroutine
anonymous, using the C<sub {}> syntax. When inner anonymous subs that
reference variables in outer subroutines are created, they
are automatically rebound to the current values of such variables.

In other words:

my $test="x";

my $test_sub = sub {
elog(NOTICE,"X=".$test);
};

$test_sub->();
return $test;

Tim.

In response to

Responses

Browse pgsql-general by date

  From Date Subject
Next Message Tom Lane 2009-12-16 21:16:39 Re: make check fails on OS X 10.6.2
Previous Message Gauthier, Dave 2009-12-16 21:02:04 Justifying a PG over MySQL approach to a project