Fix leak of oracle storage objects in its _dbh_execute override
Peter Rabbitson [Wed, 14 Mar 2012 12:40:44 +0000 (13:40 +0100)]
Replace with a much cleaner (and leak free) blockrunner instance

Changes
lib/DBIx/Class/Storage/DBI/Oracle/Generic.pm

diff --git a/Changes b/Changes
index a08fcdf..97c47c9 100644 (file)
--- a/Changes
+++ b/Changes
@@ -24,6 +24,7 @@ Revision history for DBIx::Class
           handle
         - Fix leakage of $schema on in-memory new_related() calls
         - Fix more cases of $schema leakage in SQLT::Parser::DBIC
+        - Fix leakage of $storage in ::Storage::DBI::Oracle
         - Remove useless vestigial pessimization in Ordered.pm for cases 
           when the position column is part of a unique constraint
         - Fix dbicadmin to no longer ignore the documented 'config' option
index 3840c34..c107934 100644 (file)
@@ -284,49 +284,41 @@ sub _ping {
 }
 
 sub _dbh_execute {
-  my ($self, $dbh, $sql, @args) = @_;
+  my ($self, $dbh, $sql, $bind) = @_;
 
-  my (@res, $tried);
-  my $want = wantarray;
-  my $next = $self->next::can;
-  do {
-    try {
-      my $exec = sub {
-        # Turn off sth caching for multi-part LOBs. See _prep_for_execute above.
-        local $self->{disable_sth_caching} = 1
-          if first {
-            ($_->[0]{_ora_lob_autosplit_part}||0)
-              > (__cache_queries_with_max_lob_parts-1)
-          } @{ $args[0] };
-
-        $self->$next($dbh, $sql, @args)
-      };
+  # Turn off sth caching for multi-part LOBs. See _prep_for_execute above.
+  local $self->{disable_sth_caching} = 1 if first {
+    ($_->[0]{_ora_lob_autosplit_part}||0)
+      >
+    (__cache_queries_with_max_lob_parts - 1)
+  } @$bind;
 
-      if (!defined $want) {
-        $exec->();
-      }
-      elsif (! $want) {
-        $res[0] = $exec->();
-      }
-      else {
-        @res = $exec->();
-      }
+  my $next = $self->next::can;
 
-      $tried++;
-    }
-    catch {
-      if (! $tried and $_ =~ /ORA-01003/) {
-        # ORA-01003: no statement parsed (someone changed the table somehow,
-        # invalidating your cursor.)
-        delete $dbh->{CachedKids}{$sql};
-      }
-      else {
-        $self->throw_exception($_);
+  # if we are already in a txn we can't retry anything
+  return shift->$next(@_)
+    if $self->transaction_depth;
+
+  # cheat the blockrunner - we do want to rerun things regardless of outer state
+  local $self->{_in_do_block};
+
+  return DBIx::Class::Storage::BlockRunner->new(
+    storage => $self,
+    run_code => $next,
+    run_args => \@_,
+    wrap_txn => 0,
+    retry_handler => sub {
+      # ORA-01003: no statement parsed (someone changed the table somehow,
+      # invalidating your cursor.)
+      return 0 if ($_[0]->retried_count or $_[0]->last_exception !~ /ORA-01003/);
+
+      # re-prepare towards new table data
+      if (my $dbh = $_[0]->storage->_dbh) {
+        delete $dbh->{CachedKids}{$_[0]->run_args->[2]};
       }
-    };
-  } while (! $tried++);
-
-  return wantarray ? @res : $res[0];
+      return 1;
+    },
+  )->run;
 }
 
 sub _dbh_execute_for_fetch {