Thread: PlPerl scope issue
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?
Peter
On Tue, Dec 15, 2009 at 08:35:21AM -0600, Peter wrote: > 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.
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.
On Wed, Dec 16, 2009 at 03:15:21PM -0600, Peter wrote: > 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. Maybe the example below will clear things up for you. I don't understand why you could use anon subs, since they're not a lot of difference between "sub foo {}" and "$foo = sub {}" except the latter doesn't have the problem you're running into. sub main { my $test=shift; test(); return $test; sub test { print "X=".$test."\n"; } } main(1); main(2); Output: X=1 X=1 Have a nice day, -- Martijn van Oosterhout <kleptog@svana.org> http://svana.org/kleptog/ > Please line up in a tree and maintain the heap invariant while > boarding. Thank you for flying nlogn airlines.
Attachment
On 12/16/2009 3:15 PM, Peter wrote: > 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 > Becuase (borrowing Martijn's code), you have this: my $test=shift; test(); return $test; sub test { print "X=".$test."\n"; } And PG is wrapping your entire source code in a sub, so... it sees: sub pg-auto-wrap { my $test=shift; test(); return $test; sub test { print "X=".$test."\n"; } } I'd guess you dont want 'local'. You probably want 'our'. I have the same problems in mod_perl. -Andy