Here's a possibly controversial point about error handlers.
When a DBD::Sybase method goes awry and a routine referenced by syb_err_handler is
called, we have two choices - return 0 to ignore the error or return 1 to go on and
launch the default handler.
This doesn't say anything explicit about what happens to the return status of the
method which invoked the handler, when we choose the "ignore" option.
It seems (from some limited experimentation on my part) that eg. $h->execute() can
return true in these circumstances when it has actually failed. Is this the intended
behaviour?
I'm mindful of your example Michael (in the docs I think) of using the handler to
"disarm" errors which are really no more than inconsequential warnings, where
returning success is clearly what's wanted. But I'd hoped to be able to use the
handler to _selectively_disarm_timeout_and_disconnection_errors_ pending a retry at
the end of the enclosing loop. If this were to work I would need to be able to get the
execute() to avoid a die() but _still_return_false_ to indicate (when its just such a
recoverable error) that we haven't succeeded but are OK to go round the loop and try
again.
The advantage of doing things this way would be to allow automatic retries when
possibly temporary error conditions occur, but minimizing method-specific post-checks.
If the current design is for "handler return zero" to always force the current method
to succeed, might I suggest that you provide a means of forcing the opposite
behaviour. eg. if one returns -1 perhaps.
Here are the salient parts to illustrate what I'm trying to do:
################################################################################
#__BEGIN__
################################################################################
use strict;
### snip ###
################################################################################
sub exec_SP_simple { # execute Stored Procedure which returns no rows
################################################################################
# Constraints: This executes a Stored Procedure which is not expected to
# return any rows. The return status code is checked for success or failure, but
# any failure for which we are expected to abort MUST raise an error.
my $self = shift;
my $storedproc_invocation = "@_";
my $exec_status;
while ( 1 ) {
if (
$self->{ sth } = $self->{ dbh }->prepare( $storedproc_invocation )
) {
$self->{ sth }->{ syb_do_proc_status } = 1;
}
else {
next;
}
last if $self->{ sth }->execute(); # ANY kind of error must make this fail...
} # But only very serious errors should make it die
continue {
warn "Warning: failed to execute Stored Procedure - retrying...\n";
if ( not $self->_still_connected() ) {
# actually ping() doesnt always work, see bug #456!
sleep 5;
}
else { # apparently, connection lost so try to reconnect
warn "Warning: Sybase connection lost - attempting to reconnect\n";
while ( not $self->_connect() ) { sleep 5; }
}
}
# failure always forces die anyway, so always return true if we get this far
return 1;
}
################################################################################
sub _resignal_fatal_errors { # asynchronous callback routine to trap errors
################################################################################
my @handler_arg_names = (
qw( ErrNum Severity State LineNum SrvNam SPName MsgTxt )
);
my %args; @args{ @handler_arg_names } = @_;
# if non-fatal error (i.e. a retry makes sense) then don't propagate error
# to default handler. If a retry would be pointless then die.
# First, specify what types of error do not invite a retry:
BEGIN { # only do this once at program initialization
use Sybase::CTlib qw( !:DEFAULT /^CS_/ );
no strict "vars"; # disable temporarily to avoid pkg name in declaration
%severity_retriable = (
&CS_SV_INFORM => 1, # Only a warning so go on
&CS_SV_API_FAIL => 0, # No, we're screwed, its probably a bug
&CS_SV_RETRY_FAIL => 1, # OK to retry
&CS_SV_RESOURCE_FAIL => 1, # Things may improve in a minute, OK to retry
&CS_SV_CONFIG_FAIL => 0, # No, we're screwed, we need to fix this first
&CS_SV_COMM_FAIL => 1, # Probably a timeout issue, OK to retry
&CS_SV_INTERNAL_FAIL => 0, # No, we're really, really screwed
&CS_SV_FATAL => 1, # Can still retry as the DB is probably
bouncing
);
}
our %severity_retriable;
return $severity_retriable{ $args{ Severity } } ? 0 : 1;
}
################################################################################
# __END__
################################################################################
Of course, you may know a better way to solve this particular problem (all suggestions
welcome) and I can probably kludge something up using nested eval {} blocks
(necessitating unwanted cruft) but I still think it would be cleaner and easier to
allow the handler to fail the method quietly without resignalling to the default
handler.
Regards,
Ralph Clark
Edo Support
CREDIT | FIRST
SUISSE | BOSTON
CREDIT SUISSE FIRST BOSTON (EUROPE) LIMITED
1 Cabot Square, London E14 4QJ
* Tel: +44 020 7888 2438
* Fax: +44 020 7905 6193
This message is for the named person's use only. It may contain sensitive and private
proprietary or legally privileged information. No confidentiality or privilege is
waived or lost by any mistransmission. If you are not the intended recipient, please
immediately delete it and all copies of it from your system, destroy any hard copies
of it and notify the sender. You must not, directly or indirectly, use, disclose,
distribute, print, or copy any part of this message if you are not the intended
recipient. CREDIT SUISSE GROUP and each legal entity in the CREDIT SUISSE FIRST BOSTON
or CREDIT SUISSE ASSET MANAGEMENT business units of CREDIT SUISSE FIRST BOSTON reserve
the right to monitor all e-mail communications through its networks. Any views
expressed in this message are those of the individual sender, except where the message
states otherwise and the sender is authorized to state them to be the views of any
such entity.
Unless otherwise stated, any pricing information given in this message is indicative
only, is subject to change and does not constitute an offer to deal at any price
quoted. Any reference to the terms of executed transactions should be treated as
preliminary only and subject to our formal written confirmation.