Plperl and my() lexical variables bug?

Started by Philippe Langalmost 20 years ago3 messagesgeneral
Jump to latest
#1Philippe Lang
philippe.lang@attiksystem.ch

Hi,

I have something strange here, with Postgresql 8.1.4 under Linux ES 4, installed from the PG Group binaries:

If I run this script:

----------------
CREATE OR REPLACE FUNCTION foo() RETURNS void
AS
$$
my $val;

sub init
{
$val = @_[0];
elog(NOTICE, "1: @_[0]\n");
}

&init(12);
elog(NOTICE, "2: $val\n");
$$
LANGUAGE 'plperl';

select * from foo();
----------------

I get in return something correct:

----------------
NOTICE: 1: 12

NOTICE: 2: 12

Total query runtime: 63 ms.
Data retrieval runtime: 62 ms.
1 rows retrieved.
----------------

But then, if I simply call the function, with:

----------------
select * from foo();
----------------

I get:

----------------
NOTICE: 1: 12

NOTICE: 2:

Total query runtime: 63 ms.
Data retrieval runtime: 62 ms.
1 rows retrieved.
----------------

$val variable is missing.

Even more strange: if I replace "my $val;" with "$val;", this does not happen at all:

----------------
CREATE OR REPLACE FUNCTION foo() RETURNS void
AS
$$
$val;

sub init
{
$val = @_[0];
elog(NOTICE, "1: @_[0]\n");
}

&init(12);
elog(NOTICE, "2: $val\n");
$$
LANGUAGE 'plperl';
----------------

Now I can call the function with

----------------
select * from foo();
----------------

it works as expected:

----------------
NOTICE: 1: 12

NOTICE: 2: 12

Total query runtime: 390 ms.
Data retrieval runtime: 797 ms.
1 rows retrieved.
----------------

Am I missing something maybe? It sounds like a bug with lexical variables to me...

Cheers,

----------------------------------
Philippe Lang, Ing. Dipl. EPFL
Attik System
rte de la Fonderie 2
1700 Fribourg
Switzerland
http://www.attiksystem.ch

Tel: +41 (26) 422 13 75
Fax: +41 (26) 422 13 76

#2Michael Fuhr
mike@fuhr.org
In reply to: Philippe Lang (#1)
Re: Plperl and my() lexical variables bug?

On Fri, Jun 23, 2006 at 11:33:42AM +0200, Philippe Lang wrote:

Am I missing something maybe? It sounds like a bug with lexical variables to me...

I think what's happening is that sub init is created once with $val
referencing the lexically-scoped $val from sub foo's first invocation.
When you call foo again, foo creates a new lexically-scoped $val
but init's $val still refers to the object from foo's first call.
You can see this if you display \$val:

CREATE OR REPLACE FUNCTION foo() RETURNS void AS $$
my $val;

sub init {
$val = $_[0];
elog(NOTICE, "1: $_[0] " . \$val);
}

init(12);
elog(NOTICE, "2: $val " . \$val);
$$ LANGUAGE plperl;

SELECT foo();
NOTICE: 1: 12 SCALAR(0x8447220)
NOTICE: 2: 12 SCALAR(0x8447220)
foo
-----

(1 row)

SELECT foo();
NOTICE: 1: 12 SCALAR(0x8447220)
NOTICE: 2: SCALAR(0x83f5c4c)
foo
-----

(1 row)

This behavior isn't specific to PL/Perl. A standalone Perl program
exhibits the same behavior, so you might find a better explanation
in a Perl-specific forum like the comp.lang.perl.misc newsgroup.

--
Michael Fuhr

#3Martijn van Oosterhout
kleptog@svana.org
In reply to: Michael Fuhr (#2)
Re: Plperl and my() lexical variables bug?

On Fri, Jun 23, 2006 at 07:49:19AM -0600, Michael Fuhr wrote:

This behavior isn't specific to PL/Perl. A standalone Perl program
exhibits the same behavior, so you might find a better explanation
in a Perl-specific forum like the comp.lang.perl.misc newsgroup.

If you run it standalone with warnings enabled, you get this:

Variable "$val" will not stay shared at a.pl line 6.

Which is pretty much what is happening. There's plenty written about
this on the web. This has a good summary as well as solutions:

http://perl.com/pub/a/2002/05/07/mod_perl.html

In particular, if you "use diagnostics" it suggests an anonymous sub
will deal with it.

Hope this helps,

---- a.pl ----
use warnings;
use diagnostics;

sub test
{
my $val;

sub init {
$val = $_[0];
print( "1: $_[0] " . \$val . "\n");
}

init(12);
print("2: $val " . \$val . "\n");

}

test;
test;
--- snip ---
-- 
Martijn van Oosterhout   <kleptog@svana.org>   http://svana.org/kleptog/
Show quoted text

From each according to his ability. To each according to his ability to litigate.