I've recently been asked why DBD::ODBC does not tell you which bound
parameter or bound column is in error when an insert/select specifies a
type which the driver cannot convert to e.g., column is varchar(10) and
bind column as an integer and the content cannot be converted to an
integer or you bind a string parameter 'fred' to an integer column;
there are other examples more complex. When you've only got a few
parameters/columns it is not difficult but when you've got tens of them
it is a different matter. The thing is many (most?) ODBC drivers can
tell you which bound column/parameter is in error via
SQLGetDiagField(SQL_DIAG_COLUMN_NUMBER).
set_err only allows a driver to add:
$rv = $h->set_err($err, $errstr, $state, $method, $rv);
native error code, error message, state, method and alternative return
value.
ODBC provides a number of other fields available per error - see
http://msdn.microsoft.com/en-us/library/windows/desktop/ms710181%28v=vs.85%29.aspx
Not all of them are that useful but a few like SQL_DIAG_COLUMN_NUMBER
are and SQL_DIAG_ROW_NUMBER is useful when doing execute_for_fetch as it
indicates the row in error. In the latter case I had to write special
code to handle that when I implemented execute_for_fetch as there was no
way in DBI to store it.
I can add methods or attributes to DBD::ODBC to allow you to retrieve
the additional fields for an error but it is problematic because which
error are we talking about if there are multiple ones for one ODBC call
- I think I'd end up simply adding Perl wrappers for the actual ODBC
calls below and I doubt anyone would use them. Basically in ODBC when an
error occurs the ODBC 3 way of doing things is:
assuming the last operation was on statement
recno = 1;
do {
SQLGetDiagRec(this_is_a_statement_handle, sth, recno, &state,
&native_error, &msg_text, msg_text_buf_len,
&length_of_returned_msg_text);
# these values are passed to set_err
# DBD::ODBC does not currently do the following except in
execute_for_fetch special case
# and it has nothing to do with set_err right now:
for (each additional field of interest) {
SQLGetDiagField(...);
}
# obviously there is logic to differentiate errors and warnings and
info here
set_err(...);
recno++;
} while we got an error
I'm looking for ideas of how best to do this. An obvious choice would be
to add a hash to the end of set_err where a DBD could add whatever
additional keys are meaningful and perhaps we could define some standard
ones - but that is just an option and I'm not sure what happens if there
are multiple errors (other than when you've got an error handler).
Any comments? What do other DBDs have access to that does not fit into
set_err? Even if people don't think there is any need to add anything to
DBI, do any other DBDs have anything to do this?
Martin