Joe Thomas wrote:
Hi Philip,
I notice that you're maintaining a new version of Apache::DBI. About a
year ago, I posted a couple of patches to the mod_perl list, and sent
them to Ask, but never received any response. My patch fixes a problem
with database rollback/cleanup when more than one database handle is
used. It fit well with another (similarly ignored) patch posted by
Patrick Mulvany in 2003. His patch caches many of the database state
attributes (AutoCommit, PrintError, RaiseError, etc.), and restores them
to their initial values when a handle is reused.
The attached patch applies to Apache-DBI-0.99 from your site, and
includes both changes. Can you take a look and let me know if you'd
consider including them?
I'll attempt take a look at this sometime this week. At first glance I
think I have some questions about it. I'll get back to you after more
thorough investigation.
Please CC the modperl@perl.apache.org list as I'm not technically the
maintainer, Ask still is, and its supposed to a community maintained module.
Thanks for the work and repeated effort.
P.S.
I CC'ed the list.
--
END
---------------------------------------------------------
What doesn't kill us can only make us stronger.
Nothing is impossible.
Philip M. Gollucci ([EMAIL PROTECTED]) 301.254.5198
Consultant / http://p6m7g8.net/Resume/resume.shtml
Senior Developer / Liquidity Services, Inc.
http://www.liquidityservicesinc.com
http://www.liquidation.com
http://www.uksurplus.com
http://www.govliquidation.com
http://www.gowholesale.com
diff -u Apache-DBI-0.99/Changes DBI/Changes
--- Apache-DBI-0.99/Changes Thu Aug 4 08:58:48 2005
+++ DBI/Changes Tue Aug 9 11:23:08 2005
@@ -1,5 +1,17 @@
Revision history for ApacheDBI.
+patch from Joe Thomas September 2, 2004
+ - Move $Idx from a file-scoped variable to a connect() scoped
+ variable, which gets passed to other subroutines as needed.
+ This will ensure that the cleanup/rollback feature will work
+ properly when a script uses more than one database handle.
+
+patch from Patrick Mulvany 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.99 08/03/2005
- Turn off Debugging by default.
Reported by <[EMAIL PROTECTED]>
diff -u Apache-DBI-0.99/DBI.pm DBI/DBI.pm
--- Apache-DBI-0.99/DBI.pm Thu Aug 4 08:57:06 2005
+++ DBI/DBI.pm Tue Aug 9 11:23:08 2005
@@ -22,8 +22,9 @@
my %Rollback; # keeps track of pushed PerlCleanupHandler which can do a
rollback after the request has finished
my %PingTimeOut; # stores the timeout values per data_source, a negative
value de-activates ping, default = 0
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
@@ -76,7 +77,7 @@
my $dsn = "dbi:$drh->{Name}:$args[0]";
my $prefix = "$$ Apache::DBI ";
- $Idx = join $;, $args[0], $args[1], $args[2];
+ my $Idx = join $;, $args[0], $args[1], $args[2]; # key of %Connected and
%Rollback.
# the hash-reference differs between calls even in the same
# process, so de-reference the hash-reference
@@ -110,18 +111,22 @@
}
}
- # 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;
- if(!$Rollback{$Idx} and $needCleanup and Apache->can('push_handlers')) {
- print STDERR "$prefix push PerlCleanupHandler \n" if
$Apache::DBI::DEBUG > 1;
- if ($ENV{MOD_PERL_API_VERSION} == 2) {
- require Apache2::ServerUtil;
- my $s = Apache2::ServerUtil->server;
- $s->push_handlers("PerlCleanupHandler",
\&cleanup);
- }
- else {
- Apache->push_handlers("PerlCleanupHandler", \&cleanup);
- }
+ # this PerlCleanupHandler is supposed to initiate a rollback after the
+ # script has finished if AutoCommit is off. however, cleanup can only
+ # be determined at end of handle life as begin_work may have been called
+ # to temporarily turn off AutoCommit.
+ if (!$Rollback{$Idx} and $ENV{MOD_PERL_API_VERSION} == 2) {
+ require Apache2::ServerUtil;
+ my $s = Apache2::ServerUtil->server;
+ $s->push_handlers("PerlCleanupHandler", sub { cleanup($Idx) });
+
+ # make sure, that the rollback is called only once for every
+ # request, even if the script calls connect more than once
+ $Rollback{$Idx} = 1;
+ }
+ elsif(!$Rollback{$Idx} and Apache->can('push_handlers')) {
+ Apache->push_handlers("PerlCleanupHandler", sub { cleanup($Idx) });
+
# make sure, that the rollback is called only once for every
# request, even if the script calls connect more than once
$Rollback{$Idx} = 1;
@@ -131,9 +136,11 @@
$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;
@@ -144,6 +151,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($Idx);
+
return (bless $Connected{$Idx}, 'Apache::DBI::db');
}
@@ -153,6 +164,9 @@
$Connected{$Idx} = $drh->connect(@args);
return undef if !$Connected{$Idx};
+ # store the parameters of the initial connection in the handle
+ set_startup_state($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');
@@ -180,6 +194,7 @@
# Note: the PerlCleanupHandler runs after the response has been sent to the
client
sub cleanup {
+ my $Idx = shift;
my $prefix = "$$ Apache::DBI ";
print STDERR "$prefix PerlCleanupHandler \n" if $Apache::DBI::DEBUG > 1;
my $dbh = $Connected{$Idx};
@@ -190,6 +205,49 @@
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 {
+ my $Idx = shift;
+ 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 {
+ my $Idx = shift;
+ # 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.
@@ -345,8 +403,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 or Apache2::Status.
The menu lists the current database connections. It should be considered