local woes

geoff on 2002-07-17T17:49:37

so today I was trying to pass a database handle into a constructor, alter the handle, then pass the altered handle around in my object without affecting the caller's handle. basically, the equivalent of this:

my $dbh = DBI->connect("dbi:Oracle:HELM", 'user', 'pass',
         {RaiseError => 1, AutoCommit => 0, PrintError => 0})
  or die $DBI::errstr;



my $obj = Foo->new($dbh);



package Foo;



sub new {

  my ($class, $dbh) = @_;



  local $dbh->{RaiseError} = 0;
  local $dbh->{AutoCommit} = 1;



  return bless { _dbh => $dbh }, $class;
}




well, the net result is that my object's $dbh looses its custom settings once new() exits.

after reading the entry for local in perlsub, I'm not entirely convinced that this should work the way I want. However, what I want to do seems perfectly legitimate.



so, is this a bug or a feature of local (or perhaps, and more likely, something wrong with my perl brain)?


local

autarch on 2002-07-17T18:02:26

It's working exactly as documented.

local() changes something for its current scope _until_ it exits that scope _at runtime_. It's a runtime, temporary effect.

You're expected a compile time effect, basically.

I agree that the docs aren't so hot, though.

duh

geoff on 2002-07-17T18:56:22

duh.

I need a vacation.

call me crazy, but...

kasei on 2002-07-18T02:21:33

It seems to me that you could get around this with a blessed closure that would hold onto the dbh. An autoload method would dereference the closure, and pass it the method name you wanted (to call against the dbh), and any arguments you need to pass it. And the closure would then be something like:

sub {
  my ($method, @args) = @_;
  local $dbh->{RaiseError} = 0;
  local $dbh->{AutoCommit} = 1;
  return $dbh->$method( @args );
}

Does that sound like it would work?