Here's how this has all panned out...
Changes says:
Changed set_err() to append to errstr, with a leading \n if it's
not empty, so that multiple error/warning messages are recorded.
Added way for drivers to indicate 'success with info' or 'warning'
by setting err to 0 for warning and for information.
Both values are false and so don't trigger RaiseError etc.
Warnings (err=0) are automatically printed if PrintError is set.
Thanks to Steffen Goeldner for the original idea.
Added $h-{HandleSetError} = sub { ... } to be called at the
point that an error, warn, or info state is recorded.
The code can alter the err, errstr, and state values
(e.g., to promote an error to a warning, or the reverse).
The set_err() docs now read:
=item Cset_err
$rv = $h-set_err($err, $errstr);
$rv = $h-set_err($err, $errstr, $state);
$rv = $h-set_err($err, $errstr, $state, $method);
$rv = $h-set_err($err, $errstr, $state, $method, $rv);
Set the Cerr, Cerrstr, and Cstate values for the handle.
This method is typically only used by DBI drivers and DBI subclasses.
If the L/HandleSetError attribute holds a reference to a subroutine
it is called first. The subroutine can alter the $err, $errstr, $state,
and $method values. See L/HandleSetError for full details.
If the subroutine returns a true value then the handle Cerr,
Cerrstr, and Cstate values are not altered and set_err() returns
an empty list (it normally returns $rv which defaults to undef, see below).
Setting Cerr to a Itrue value indicates an error and will trigger
the normal DBI error handling mechanisms, such as CRaiseError and
CHandleError, if they are enabled, when execution returns from
the DBI back to the application.
Setting Cerr to C indicates an 'information' state, and setting
it to C0 indicates a 'warning' state.
The $method parameter provides an alternate method name for the
CRaiseError/CPrintError error string instead of the fairly
unhelpful 'Cset_err'.
The Cset_err method normally returns undef. The $rv parameter
provides an alternate return value.
Some special rules apply if the Cerr or Cerrstr
values for the handle are already set...
If Cerrstr is true then: C [err was %s now %s] is appended if
$err is true and Cerr is already true; C [state was %s now %s]
is appended if $state is true and Cstate is already true; then
C\n and the new $errstr are appended. Obviously the C%s's
above are replaced by the corresponding values.
The handle Cerr value is set to $err if: $err is true; or handle
Cerr value is undef; or $err is defined and the length is greater
than the handle Cerr length. The effect is that an 'information'
state only overides undef; a 'warning' overrides undef or 'information',
and an 'error' state overrides anything.
The handle Cstate value is set to $state if $state is true and
the handle Cerr value was set (by the rules above).
And HandleSetError docs are:
=item CHandleSetError (code ref, inherited)
The CHandleSetError attribute can be used to intercept
the setting of handle Cerr, Cerrstr, and Cstate values.
If set to a reference to a subroutine then that subroutine is called
whenever set_err() is called, typically by the driver or a subclass.
The subroutine is called with five arguments, the first five that
were passed to set_err(): the handle, the Cerr, Cerrstr, and
Cstate values being set, and the method name. These can be altered
by changing the values in the @_ array. The return value affects
set_err() behaviour, see L/set_err for details.
It is possible to 'stack' multiple HandleSetError handlers by using
closures. See L/HandleError for an example.
The CHandleSetError and CHandleError subroutines differ in subtle
but significant ways. HandleError is only invoked at the point where
the DBI is about to return to the application with Cerr set true.
It's not invoked by the failure of a method that's been caled by
another DBI method. HandleSetError, on the other hand, is called
whenever set_err() is called with a defined Cerr value, even if false.
So it's not just for errors, despite the name, but also warn and info states.
The set_err method, and thus HandleSetError, may be called multiple
times within a method and is usually invoked from deep within driver code.
In theory a driver can use the return value from HandleSetError via
set_err() to decide whether to continue or not. If set_err() returns
an empty list, indicating that the HandleSetError code has 'handled'
the 'error', the driver could then continue instead of failing (if
that's a reasonable thing to do). This isn't excepted to be
common and any such cases should be clearly marked in the driver
documentation.
Comments most welcome.
Pure-perl drivers should already be using $h-set_err to record errors.
Compiled drivers are probably not, just setting err and errstr directly.
I'll provide