pyodbc icon indicating copy to clipboard operation
pyodbc copied to clipboard

Inconsistent error tuples

Open nick-rossi opened this issue 2 years ago • 2 comments
trafficstars

I'm using pyodbc to perform tasks to insert data in sql server database. I wanted to catch certain errors and it looks like the error tuples generated do not follow a consistent structure. This makes it harder to handle errors dynamically in code.

For example:

pyodbc.IntegrityError: ('23000', "[23000] [Microsoft][ODBC SQL Server Driver][SQL Server]Violation of UNIQUE KEY constraint 'UC_EventId'. Cannot insert duplicate key in object 'table. (2627) (SQLExecDirectW); [23000] [Microsoft][ODBC SQL Server Driver][SQL Server]The statement has been terminated. (3621)")

pyodbc.ProgrammingError: ('The SQL contains 16 parameter markers, but 15 parameters were supplied', 'HY000')

So IntegrityError has structure: (code, message) and ProgrammingError has structure (message, code) .

I wanted to do something in python like:

handle_errors = ["23000", "HY000"]
if ex.args[0] in recoverable_errors:
    do_something()

But this will not work as intended because of pyodbc's inconsistent error tuple structure. For the above example, the ProgrammingError code will be overlooked.

nick-rossi avatar Apr 21 '23 10:04 nick-rossi

That is a problem. Also, I'd rather be able to get at the SQLSTATE directly via ex.sqlstate.

I wanted to end the 4.x line, but I would consider swapped constructor parameters a serious enough error to put out another release. I'll try to complete it this weekend.

mkleehammer avatar Apr 21 '23 14:04 mkleehammer

I'm having what I think to be related issue if only slightly. I'm handling errors returned from PYODBC dynamically as a way to map to HTTP Status in an API. In SQLSERVER I have a ID check as follows

  begin
        ; throw 51000, 'The Role does not exist.', 1;
  end;

Docs on throw: https://learn.microsoft.com/en-us/sql/t-sql/language-elements/throw-transact-sql?view=sql-server-ver16

and from this pyodbc returns [42000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]The Role does not exist. (51000) (SQLExecDirectW) in args[1].

I'd greatly appreciate some way to get the error-code (51000) out from the ProgrammingError object returned from pyodbc, seperate from the SQLSTATE itself. Currently I have a hack in place that relies on regex and that is less than ideal. What are your thoughts @mkleehammer?

Here is a link to the code that is related to this behavior I'm reporting

https://github.com/mkleehammer/pyodbc/blob/67162f0c4f0048de51e7cbd4eb511d6485def4f3/src/errors.cpp#L60

RobertLD avatar Aug 09 '23 19:08 RobertLD