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.


Reply via email to