Hi,

Over the past few months I have posted a couple of fixes in relation to how
Apache::DBI handles are cleaned up. This however is the most complete fix in
that it covers the following issues :-

        TimeOut = 0  : 
                Should always ping even when multiple requests are made in 
                the same secondi

        Setting Attributes post connection :
                $dbh->{AutoCommit}=0 will convert an AutoCommit handle to non 
                AutoCommit so when it is next retunred it behaves incorrectly.
                Other settings can be effected in the same way.

        Using begin_work :
                This is a tempory version of the above. The next commit resets
                the handle to the default value.

I have tested this under mp1 but do not have any active setups for testing 
under mp2. I have not found that this fix degrades performance but I have 
not done exhautive benchmarking on multiple platforms. I would be grateful
for all feedback in relation to this patch both good and bad..

The patch is against the current CVS version.
Thank you all

Paddy

--- Changes     2003-07-20 09:03:15.000000000 +0000
+++ Changes     2003-07-21 09:02:11.000000000 +0000
@@ -1,5 +1,11 @@
 Revision history for ApacheDBI.
 
+patch  July 21, 2003
+        - Fixed issues relating to chanding handle state post connection.
+         Handles now returned in same state as original and incomplete
+         transactions rolled back before re-issuing handle so begin_work
+         should now be safe. "Patrick Mulvany" <[EMAIL PROTECTED]>
+
 0.92-dev
         - Avoid use of uninitialized value warning under mod_perl 2.
 
--- DBI.pm      2003-06-10 12:20:06.000000000 +0000
+++ DBI.cleanup.pm      2003-07-21 09:22:34.000000000 +0000
@@ -23,6 +23,8 @@
 my %LastPingTime; # keeps track of last ping per data_source
 my $Idx;          # key of %Connected and %Rollback.
 
+# Check to see if we need to reset TaintIn and TaintOut
+my $TaintInOut = ($DBI::VERSION>=1.31)?1:0;
 
 # supposed to be called in a startup script.
 # stores the data_source of all connections, which are supposed to be created upon
@@ -87,11 +89,13 @@
     }
 
     # this PerlCleanupHandler is supposed to initiate a rollback after the script has 
finished if AutoCommit is off.
-    my $needCleanup = ($Idx =~ /AutoCommit[^\d]+0/) ? 1 : 0;
+    # however cleanup can only be determined at end of handle life as begin_work may 
have been called to temporarily turn off AutoCommit.
+    #
     # TODO - Fix mod_perl 2.0 here
-    if(!$Rollback{$Idx} and $needCleanup and Apache->can('push_handlers')) {
+    if(!$Rollback{$Idx} and Apache->can('push_handlers')) {
         print STDERR "$prefix push PerlCleanupHandler \n" if $Apache::DBI::DEBUG > 1;
         Apache->push_handlers("PerlCleanupHandler", \&cleanup);
+
         # make sure, that the rollback is called only once for every 
         # request, even if the script calls connect more than once
         $Rollback{$Idx} = 1;
@@ -101,7 +105,8 @@
     $PingTimeOut{$dsn}  = 0 unless $PingTimeOut{$dsn};
     $LastPingTime{$dsn} = 0 unless $LastPingTime{$dsn};
     my $now = time;
-    my $needping = (($PingTimeOut{$dsn} == 0 or $PingTimeOut{$dsn} > 0) and $now - 
$LastPingTime{$dsn} > $PingTimeOut{$dsn}) ? 1 : 0;
+    # Must ping if TimeOut = 0 else base on time
+    my $needping = ($PingTimeOut{$dsn} == 0 or ($PingTimeOut{$dsn} > 0 and $now - 
$LastPingTime{$dsn} > $PingTimeOut{$dsn})) ? 1 : 0;
     print STDERR "$prefix need ping: ", $needping == 1 ? "yes" : "no", "\n" if 
$Apache::DBI::DEBUG > 1;
     $LastPingTime{$dsn} = $now;
 
@@ -112,6 +117,10 @@
     # RaiseError being on and the handle is invalid.
     if ($Connected{$Idx} and (!$needping or eval{$Connected{$Idx}->ping})) {
         print STDERR "$prefix already connected to '$Idx'\n" if $Apache::DBI::DEBUG > 
1;
+
+        # Force clean up of handle in case previous transaction failed to clean up 
the handle
+        &reset_startup_state();
+
         return (bless $Connected{$Idx}, 'Apache::DBI::db');
     }
 
@@ -121,6 +130,9 @@
     $Connected{$Idx} = $drh->connect(@args);
     return undef if !$Connected{$Idx};
 
+    # store the parameters of the initial connection in the handle
+    set_startup_state($Connected{$Idx});
+
     # return the new database handle
     print STDERR "$prefix new connect to '$Idx'\n" if $Apache::DBI::DEBUG;
     return (bless $Connected{$Idx}, 'Apache::DBI::db');
@@ -158,6 +170,47 @@
     1;
 }
 
+# Store the default start state of each dbh in the handle
+# Note: This uses private_Apache_DBI hash ref to store it in the handle itself
+
+sub set_startup_state {
+    foreach my $key qw{ AutoCommit Warn CompatMode InactiveDestroy 
+                        PrintError RaiseError HandleError 
+                        ShowErrorStatement TraceLevel FetchHashKeyName 
+                        ChopBlanks LongReadLen LongTruncOk 
+                        Taint Profile} {
+        $Connected{$Idx}->{private_Apache_DBI}{$key} = $Connected{$Idx}->{$key};
+    }
+    if ($TaintInOut) {
+        foreach my $key qw{ TaintIn TaintOut } {
+            $Connected{$Idx}->{private_Apache_DBI}{$key} = $Connected{$Idx}->{$key};
+        }
+    }
+    1;
+}
+
+
+# Restore the default start state of each dbh
+
+sub reset_startup_state {
+    # Rollback current transaction if currently in one
+    $Connected{$Idx}->{Active} and !$Connected{$Idx}->{AutoCommit} and eval 
{$Connected{$Idx}->rollback};
+
+    foreach my $key qw{ AutoCommit Warn CompatMode InactiveDestroy 
+                        PrintError RaiseError HandleError 
+                        ShowErrorStatement TraceLevel FetchHashKeyName 
+                        ChopBlanks LongReadLen LongTruncOk 
+                        Taint Profile } {
+        $Connected{$Idx}->{$key} = $Connected{$Idx}->{private_Apache_DBI}{$key};
+    }
+    if ($TaintInOut) {
+        foreach my $key qw{ TaintIn TaintOut } {
+            $Connected{$Idx}->{$key} = $Connected{$Idx}->{private_Apache_DBI}{$key};
+        }
+    }
+    1;
+}
+
 
 # This function can be called from other handlers to perform tasks on all cached 
database handles.
 
@@ -301,8 +354,10 @@
 AutoCommit is off and the script finishes without an explicit rollback, the 
 Apache::DBI module uses a PerlCleanupHandler to issue a rollback at the
 end of every request. Note, that this CleanupHandler will only be used, if 
-the initial data_source sets AutoCommit = 0. It will not be used, if AutoCommit 
-will be turned off, after the connect has been done. 
+the initial data_source sets AutoCommit = 0 or AutoCommit is turned off, after 
+the connect has been done (ie begin_work). However, because a connection may have
+set other parameters, the handle is reset to its initial connection state before 
+it is returned for a second time.
 
 This module plugs in a menu item for Apache::Status. The menu lists the 
 current database connections. It should be considered incomplete because of 

Attachment: pgp00000.pgp
Description: PGP signature

Reply via email to